@@ -11,7 +11,8 @@ import dev.mokkery.verify.VerifyMode.Companion.exactly
1111import dev.mokkery.verify.VerifyMode.Companion.not
1212import dev.mokkery.verify.VerifyMode.Companion.order
1313import dev.mokkery.verifySuspend
14- import io.github.trueangle.knative.lambda.runtime.LambdaEnvironmentException.*
14+ import io.github.trueangle.knative.lambda.runtime.LambdaEnvironmentException.BadRequestException
15+ import io.github.trueangle.knative.lambda.runtime.LambdaEnvironmentException.NonRecoverableStateException
1516import io.github.trueangle.knative.lambda.runtime.LambdaRuntimeException.Invocation.EventBodyParseException
1617import io.github.trueangle.knative.lambda.runtime.LambdaRuntimeException.Invocation.HandlerException
1718import io.github.trueangle.knative.lambda.runtime.ReservedRuntimeEnvironmentVariables.AWS_LAMBDA_FUNCTION_NAME
@@ -33,12 +34,8 @@ import io.ktor.client.engine.mock.MockRequestHandleScope
3334import io.ktor.client.engine.mock.respond
3435import io.ktor.client.engine.mock.respondBadRequest
3536import io.ktor.client.engine.mock.respondError
36- import io.ktor.client.engine.mock.respondOk
37- import io.ktor.client.request.HttpRequestData
3837import io.ktor.http.HttpHeaders
3938import io.ktor.http.HttpStatusCode
40- import io.ktor.http.content.ChannelWriterContent
41- import io.ktor.http.content.OutgoingContent
4239import io.ktor.http.headers
4340import io.ktor.http.headersOf
4441import io.ktor.util.reflect.typeInfo
@@ -48,16 +45,15 @@ import io.ktor.utils.io.copyTo
4845import kotlinx.cinterop.ExperimentalForeignApi
4946import kotlinx.cinterop.toKString
5047import kotlinx.coroutines.test.runTest
51- import kotlinx.io.Buffer
52- import kotlinx.io.RawSource
53- import kotlinx.io.Source
5448import kotlinx.serialization.json.Json
5549import platform.posix.getenv
5650import platform.posix.setenv
51+ import kotlin.experimental.ExperimentalNativeApi
52+ import kotlin.native.runtime.GC
53+ import kotlin.native.runtime.NativeRuntimeApi
5754import kotlin.test.BeforeTest
5855import kotlin.test.Test
5956import kotlin.test.assertFailsWith
60- import kotlin.test.assertTrue
6157
6258internal const val RESOURCES_PATH = " src/nativeTest/resources"
6359
@@ -197,10 +193,7 @@ class LambdaRuntimeTest {
197193 val lambdaRunner = createRunner(MockEngine { request ->
198194 val path = request.url.encodedPath
199195 when {
200- path.contains(" /invocation/next" ) -> {
201- respondError(HttpStatusCode .InternalServerError )
202- }
203-
196+ path.contains(" /invocation/next" ) -> respondError(HttpStatusCode .InternalServerError )
204197 else -> respondError(HttpStatusCode .Forbidden )
205198 }
206199 })
@@ -368,6 +361,68 @@ class LambdaRuntimeTest {
368361 verify(not ) { lambdaRunner.env.terminate() }
369362 }
370363
364+ @OptIn(NativeRuntimeApi ::class , ExperimentalStdlibApi ::class , ExperimentalNativeApi ::class )
365+ @Test
366+ fun `Validate leaks` () = runTest {
367+ val invocationCount = 3
368+ var invocationIndex = 0
369+ val events = buildList(invocationCount) {
370+ repeat(invocationCount) { add(" Hello world" ) }
371+ }
372+
373+ val lambdaRunner = createRunner(MockEngine { request ->
374+ val path = request.url.encodedPath
375+ when {
376+ path.contains(" invocation/next" ) -> {
377+ if (invocationIndex >= invocationCount) {
378+ respondError(HttpStatusCode .InternalServerError , headers = headers {
379+ append(HttpHeaders .ContentType , " application/json" )
380+ append(" Lambda-Runtime-Aws-Request-Id" , context.awsRequestId)
381+ append(" Lambda-Runtime-Deadline-Ms" , context.deadlineTimeInMs.toString())
382+ append(" Lambda-Runtime-Invoked-Function-Arn" , context.invokedFunctionArn)
383+ })
384+ } else {
385+ respondNextEventSuccess(events[invocationIndex++ ])
386+ }
387+ }
388+
389+ path.contains(" /invocation/${context.awsRequestId} /response" ) -> respond(
390+ content = ByteReadChannel (" Ok" ),
391+ status = HttpStatusCode .Accepted ,
392+ headers = headersOf(HttpHeaders .ContentType , " application/json" )
393+ )
394+
395+ else -> respondBadRequest()
396+ }
397+ })
398+
399+ val handler = object : LambdaBufferedHandler <String , String > {
400+ override suspend fun handleRequest (input : String , context : Context ): String = " Hello"
401+ }
402+
403+ assertFailsWith<TerminateException > {
404+ lambdaRunner.run { handler }
405+ }
406+
407+ GC .collect()
408+ GC .lastGCInfo?.let {gcInfo->
409+ println (
410+ " Heap Size Before: ${
411+ gcInfo.memoryUsageBefore.map {
412+ it.key + " - " + it.value.totalObjectsSizeBytes / 1024 / 1024
413+ }
414+ } "
415+ )
416+ println (
417+ " Heap Size After: ${
418+ gcInfo.memoryUsageAfter.map {
419+ it.key + " - " + it.value.totalObjectsSizeBytes / 1024 / 1024
420+ }
421+ } "
422+ )
423+ }
424+ }
425+
371426 @OptIn(ExperimentalForeignApi ::class )
372427 private fun mockEnvironment () {
373428 if (getenv(AWS_LAMBDA_FUNCTION_NAME )?.toKString().isNullOrEmpty()) {
0 commit comments