From c382e202f8dc4083f8ff2c93f10d76592fddcbbd Mon Sep 17 00:00:00 2001 From: Nils Martin Sande Date: Fri, 23 Aug 2024 11:35:29 +0200 Subject: [PATCH] La til tester for v2 api --- .../ApiV1TestCaseRunner.kt | 115 +++++++++++++++++ .../ApiV2TestCaseRunner.kt | 121 ++++++++++++++++++ .../ApplicationTestContext.kt | 23 +++- .../arbeidssokerregisteret/ProducerMock.kt | 4 +- .../arbeidssokerregisteret/TestCaseContext.kt | 47 +++++++ .../arbeidssokerregisteret/TestCaseRunner.kt | 119 ----------------- 6 files changed, 307 insertions(+), 122 deletions(-) create mode 100644 apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV1TestCaseRunner.kt create mode 100644 apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV2TestCaseRunner.kt create mode 100644 apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseContext.kt delete mode 100644 apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseRunner.kt diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV1TestCaseRunner.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV1TestCaseRunner.kt new file mode 100644 index 00000000..450a6337 --- /dev/null +++ b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV1TestCaseRunner.kt @@ -0,0 +1,115 @@ +package no.nav.paw.arbeidssokerregisteret + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.collections.shouldNotBeEmpty +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.should +import io.kotest.matchers.shouldBe +import io.ktor.client.call.* +import io.ktor.server.auth.* +import io.ktor.server.testing.* +import io.mockk.mockk +import no.nav.paw.arbeidssoekerregisteret.api.startstopp.models.Feil +import no.nav.paw.arbeidssoekerregisteret.api.startstopp.models.FeilV2 +import no.nav.paw.arbeidssokerregisteret.auth.configureAuthentication +import no.nav.paw.arbeidssokerregisteret.plugins.configureHTTP +import no.nav.paw.arbeidssokerregisteret.plugins.configureSerialization +import no.nav.paw.arbeidssokerregisteret.routes.arbeidssokerRoutes +import no.nav.paw.arbeidssokerregisteret.routes.arbeidssokerRoutesV2 +import no.nav.paw.arbeidssokerregisteret.testdata.TestCase +import no.nav.paw.arbeidssokerregisteret.testdata.TestCaseBuilder +import no.nav.security.mock.oauth2.MockOAuth2Server +import org.slf4j.LoggerFactory + + +class ApiV1TestCaseRunner : FreeSpec({ + val mockOAuthServer = MockOAuth2Server() + beforeSpec { + mockOAuthServer.start() + } + afterSpec { + mockOAuthServer.shutdown() + } + val testCases = TestCase::class.sealedSubclasses + "Verifiserer oppsett av test caser" - { + "Det må finnes minst en test" { + testCases.shouldNotBeEmpty() + } + "Alle tester må ha 'objectInstance" - { + testCases.forEach { case -> + "${case.simpleName} må ha 'objectInstance'" { + case.objectInstance.shouldNotBeNull() + } + } + } + } + "Test cases V1" - { + TestCase::class.sealedSubclasses + .mapNotNull { it.objectInstance } + .forEach { testCase -> + val logger = LoggerFactory.getLogger(testCase::class.java) + "Test ${testCase::class.simpleName?.readable()}" - { + "Verifiser API V1" - { + with(initTestCaseContext()) { + "Verifiser API response" { + testApplication { + application { + configureSerialization() + configureHTTP() + configureAuthentication(mockOAuthServer) + } + routing { + authenticate("tokenx", "azure") { + arbeidssokerRoutes(startStoppRequestHandler, mockk()) + arbeidssokerRoutesV2(startStoppRequestHandler) + } + } + val client = createClient { defaultConfig() } + val id = testCase.id + val person = testCase.person + logger.info("Running test for $id") + personInfoService.setPersonInfo(id, person) + val testConfiguration = TestCaseBuilder(mockOAuthServer, autorisasjonService) + .also { testCase.configure(it) } + val status = + client.startPeriode( + id, + testConfiguration.authToken, + testCase.forhaandsGodkjent + ) + status.status shouldBe testCase.producesHttpResponse + testCase.producesError?.also { expectedErrorResponse -> + val body = status.body() + body.feilKode.name shouldBe expectedErrorResponse.feilKode.name + body.melding shouldBe expectedErrorResponse.melding + body.aarsakTilAvvisning?.regel shouldBe expectedErrorResponse.aarsakTilAvvisning?.regel + expectedErrorResponse.aarsakTilAvvisning?.detaljer?.also { expectedDetails -> + body.aarsakTilAvvisning?.detaljer.shouldNotBeNull() + body.aarsakTilAvvisning?.detaljer?.shouldContainExactlyInAnyOrder( + expectedDetails + ) + } + } + } + } + "Verifiser Kafka melding" { + val expectedRecord = testCase.producesRecord(kafkaKeys) + if (expectedRecord != null) { + verify( + actual = producer.next(), + expected = expectedRecord + ) + producer.next().shouldBeNull() + } else { + producer.next().shouldBeNull() + } + } + } + } + } + } + } +}) + diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV2TestCaseRunner.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV2TestCaseRunner.kt new file mode 100644 index 00000000..f805a06c --- /dev/null +++ b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApiV2TestCaseRunner.kt @@ -0,0 +1,121 @@ +package no.nav.paw.arbeidssokerregisteret + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.collections.shouldNotBeEmpty +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.should +import io.kotest.matchers.shouldBe +import io.ktor.client.call.* +import io.ktor.server.auth.* +import io.ktor.server.testing.* +import io.mockk.mockk +import no.nav.paw.arbeidssoekerregisteret.api.startstopp.models.Feil +import no.nav.paw.arbeidssoekerregisteret.api.startstopp.models.FeilV2 +import no.nav.paw.arbeidssokerregisteret.auth.configureAuthentication +import no.nav.paw.arbeidssokerregisteret.plugins.configureHTTP +import no.nav.paw.arbeidssokerregisteret.plugins.configureSerialization +import no.nav.paw.arbeidssokerregisteret.routes.arbeidssokerRoutes +import no.nav.paw.arbeidssokerregisteret.routes.arbeidssokerRoutesV2 +import no.nav.paw.arbeidssokerregisteret.testdata.TestCase +import no.nav.paw.arbeidssokerregisteret.testdata.TestCaseBuilder +import no.nav.security.mock.oauth2.MockOAuth2Server +import org.slf4j.LoggerFactory + + +class ApiV2TestCaseRunner : FreeSpec({ + val mockOAuthServer = MockOAuth2Server() + beforeSpec { + mockOAuthServer.start() + } + afterSpec { + mockOAuthServer.shutdown() + } + val testCases = TestCase::class.sealedSubclasses + "Verifiserer oppsett av test caser" - { + "Det må finnes minst en test" { + testCases.shouldNotBeEmpty() + } + "Alle tester må ha 'objectInstance" - { + testCases.forEach { case -> + "${case.simpleName} må ha 'objectInstance'" { + case.objectInstance.shouldNotBeNull() + } + } + } + } + "Test cases V2" - { + TestCase::class.sealedSubclasses + .mapNotNull { it.objectInstance } + .forEach { testCase -> + val logger = LoggerFactory.getLogger(testCase::class.java) + "Test API V2 ${testCase::class.simpleName?.readable()}" - { + "Verifiser API V2" - { + with(initTestCaseContext()) { + "Verifiser API response" { + testApplication { + application { + configureSerialization() + configureHTTP() + configureAuthentication(mockOAuthServer) + } + routing { + authenticate("tokenx", "azure") { + arbeidssokerRoutes(startStoppRequestHandler, mockk()) + arbeidssokerRoutesV2(startStoppRequestHandler) + } + } + val client = createClient { defaultConfig() } + val id = testCase.id + val person = testCase.person + logger.info("Running test for $id") + personInfoService.setPersonInfo(id, person) + val testConfiguration = TestCaseBuilder(mockOAuthServer, autorisasjonService) + .also { testCase.configure(it) } + val statusV2 = + client.startPeriodeV2( + id, + testConfiguration.authToken, + testCase.forhaandsGodkjent + ) + statusV2.status shouldBe testCase.producesHttpResponse + testCase.producesError?.also { expectedErrorResponse -> + val body = statusV2.body() + body.feilKode.name shouldBe expectedErrorResponse.feilKode.name + val forventetMelding: String = + if (expectedErrorResponse.feilKode == Feil.FeilKode.IKKE_TILGANG) expectedErrorResponse.melding else "Avvist, se 'aarsakTilAvvisning' for detaljer" + body.melding shouldBe forventetMelding + expectedErrorResponse.aarsakTilAvvisning?.regel?.should { aarsak -> + body.aarsakTilAvvisning?.regler?.map { it.id?.name } shouldBe listOf( + aarsak.name + ) + } + expectedErrorResponse.aarsakTilAvvisning?.detaljer?.also { expectedDetails -> + body.aarsakTilAvvisning?.detaljer.shouldNotBeNull() + body.aarsakTilAvvisning?.detaljer?.shouldContainExactlyInAnyOrder( + expectedDetails + ) + } + } + } + } + "Verifiser Kafka melding" { + val expectedRecord = testCase.producesRecord(kafkaKeys) + if (expectedRecord != null) { + verify( + actual = producer.next(), + expected = expectedRecord + ) + producer.next().shouldBeNull() + } else { + producer.next().shouldBeNull() + } + } + } + } + } + } + } +}) + diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApplicationTestContext.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApplicationTestContext.kt index 94ecc721..ae3257f1 100644 --- a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApplicationTestContext.kt +++ b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ApplicationTestContext.kt @@ -3,6 +3,7 @@ package no.nav.paw.arbeidssokerregisteret import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.nimbusds.jwt.SignedJWT +import io.kotest.assertions.fail import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf @@ -52,9 +53,12 @@ fun MockOAuth2Server.ansattToken(navAnsatt: NavAnsatt): SignedJWT = issueToken( fun verify( - actual: ProducerRecord, + actual: ProducerRecord?, expected: ProducerRecord ) { + if (actual == null) { + fail("Forventet at melding skulle bli produsert, men ingen melding ble funnet") + } actual.key() shouldBe expected.key() val actualValue = actual.value() val expectedValue = expected.value() @@ -164,3 +168,20 @@ suspend fun HttpClient.startPeriode(identitetsnummer: String, token: SignedJWT?, ) ) } + +suspend fun HttpClient.startPeriodeV2(identitetsnummer: String, token: SignedJWT?, godkjent: Boolean = false): HttpResponse = + put("/api/v2/arbeidssoker/periode") { + token?.also { + bearerAuth(token.serialize()) + } + headers { + append(HttpHeaders.ContentType, ContentType.Application.Json) + } + setBody( + ApiV1ArbeidssokerPeriodePutRequest( + identitetsnummer = identitetsnummer, + periodeTilstand = ApiV1ArbeidssokerPeriodePutRequest.PeriodeTilstand.STARTET, + registreringForhaandsGodkjentAvAnsatt = godkjent + ) + ) + } diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ProducerMock.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ProducerMock.kt index d83f3c0c..11baa646 100644 --- a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ProducerMock.kt +++ b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/ProducerMock.kt @@ -1,6 +1,5 @@ package no.nav.paw.arbeidssokerregisteret -import no.nav.paw.arbeidssokerregisteret.intern.v1.Hendelse import org.apache.kafka.clients.consumer.ConsumerGroupMetadata import org.apache.kafka.clients.consumer.OffsetAndMetadata import org.apache.kafka.clients.producer.Callback @@ -13,10 +12,11 @@ import java.time.Instant import java.util.concurrent.CompletableFuture import java.util.concurrent.Future import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.TimeUnit class ProducerMock : Producer { private val queue = LinkedBlockingQueue>(100) - fun next(): ProducerRecord = queue.take() + fun next(): ProducerRecord? = queue.poll(100, TimeUnit.MILLISECONDS) override fun close() {} diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseContext.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseContext.kt new file mode 100644 index 00000000..b27cf665 --- /dev/null +++ b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseContext.kt @@ -0,0 +1,47 @@ +package no.nav.paw.arbeidssokerregisteret + +import io.mockk.mockk +import no.nav.paw.arbeidssokerregisteret.application.RequestValidator +import no.nav.paw.arbeidssokerregisteret.application.StartStoppRequestHandler +import no.nav.paw.arbeidssokerregisteret.intern.v1.Hendelse +import no.nav.paw.arbeidssokerregisteret.services.AutorisasjonService +import no.nav.paw.arbeidssokerregisteret.services.PersonInfoService +import no.nav.paw.kafkakeygenerator.client.KafkaKeysClient +import no.nav.paw.kafkakeygenerator.client.inMemoryKafkaKeysMock + +fun String.readable(): String = + map { letter -> if (letter.isUpperCase()) " ${letter.lowercase()}" else "$letter" } + .joinToString("") + .replace("oe", "ø") + .replace("aa", "å") + +data class TestCaseContext( + val autorisasjonService: AutorisasjonService, + val personInfoService: PersonInfoService, + val producer: ProducerMock, + val kafkaKeys: KafkaKeysClient, + val startStoppRequestHandler: StartStoppRequestHandler +) + +fun initTestCaseContext(): TestCaseContext { + val autorisasjonService = mockk() + val personInfoService = mockk() + val producer: ProducerMock = ProducerMock() + val kafkaKeys = inMemoryKafkaKeysMock() + val startStoppRequestHandler = StartStoppRequestHandler( + hendelseTopic = "any", + requestValidator = RequestValidator( + autorisasjonService = autorisasjonService, + personInfoService = personInfoService + ), + producer = producer, + kafkaKeysClient = kafkaKeys + ) + return TestCaseContext( + autorisasjonService = autorisasjonService, + personInfoService = personInfoService, + producer = producer, + kafkaKeys = kafkaKeys, + startStoppRequestHandler = startStoppRequestHandler + ) +} \ No newline at end of file diff --git a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseRunner.kt b/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseRunner.kt deleted file mode 100644 index 69ea4123..00000000 --- a/apps/api-start-stopp-perioder/src/test/kotlin/no/nav/paw/arbeidssokerregisteret/TestCaseRunner.kt +++ /dev/null @@ -1,119 +0,0 @@ -package no.nav.paw.arbeidssokerregisteret - -import io.kotest.core.spec.style.FreeSpec -import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder -import io.kotest.matchers.collections.shouldNotBeEmpty -import io.kotest.matchers.nulls.shouldBeNull -import io.kotest.matchers.nulls.shouldNotBeNull -import io.kotest.matchers.shouldBe -import io.ktor.client.call.* -import io.ktor.server.auth.* -import io.ktor.server.testing.* -import io.mockk.mockk -import no.nav.paw.arbeidssoekerregisteret.api.startstopp.models.Feil -import no.nav.paw.arbeidssokerregisteret.application.RequestValidator -import no.nav.paw.arbeidssokerregisteret.application.StartStoppRequestHandler -import no.nav.paw.arbeidssokerregisteret.auth.configureAuthentication -import no.nav.paw.arbeidssokerregisteret.intern.v1.Hendelse -import no.nav.paw.arbeidssokerregisteret.plugins.configureHTTP -import no.nav.paw.arbeidssokerregisteret.plugins.configureSerialization -import no.nav.paw.arbeidssokerregisteret.routes.arbeidssokerRoutes -import no.nav.paw.arbeidssokerregisteret.services.AutorisasjonService -import no.nav.paw.arbeidssokerregisteret.services.PersonInfoService -import no.nav.paw.arbeidssokerregisteret.testdata.TestCase -import no.nav.paw.arbeidssokerregisteret.testdata.TestCaseBuilder -import no.nav.paw.kafkakeygenerator.client.inMemoryKafkaKeysMock -import no.nav.security.mock.oauth2.MockOAuth2Server -import org.slf4j.LoggerFactory - -class TestCaseRunner : FreeSpec({ - val mockOAuthServer = MockOAuth2Server() - beforeSpec { - mockOAuthServer.start() - } - afterSpec { - mockOAuthServer.shutdown() - } - val testCases = TestCase::class.sealedSubclasses - "Verifiserer oppsett av test caser" - { - "Det må finnes minst en test" { - testCases.shouldNotBeEmpty() - } - "Alle tester må ha 'objectInstance" - { - testCases.forEach { case -> - "${case.simpleName} må ha 'objectInstance'" { - case.objectInstance.shouldNotBeNull() - } - } - } - } - "Test cases" - { - TestCase::class.sealedSubclasses - .mapNotNull { it.objectInstance } - .forEach { testCase -> - val logger = LoggerFactory.getLogger(testCase::class.java) - "Test ${testCase::class.simpleName?.readable()}" { - testApplication { - application { - configureSerialization() - configureHTTP() - configureAuthentication(mockOAuthServer) - } - val autorisasjonService = mockk() - val personInfoService = mockk() - val producer: ProducerMock = ProducerMock() - val kafkaKeys = inMemoryKafkaKeysMock() - val startStoppRequestHandler = StartStoppRequestHandler( - hendelseTopic = "any", - requestValidator = RequestValidator( - autorisasjonService = autorisasjonService, - personInfoService = personInfoService - ), - producer = producer, - kafkaKeysClient = kafkaKeys - ) - routing { - authenticate("tokenx", "azure") { - arbeidssokerRoutes(startStoppRequestHandler, mockk()) - } - } - val client = createClient { defaultConfig() } - val id = testCase.id - val person = testCase.person - logger.info("Running test for $id") - personInfoService.setPersonInfo(id, person) - val testConfiguration = TestCaseBuilder(mockOAuthServer, autorisasjonService) - .also { testCase.configure(it) } - val status = client.startPeriode(id, testConfiguration.authToken, testCase.forhaandsGodkjent) - status.status shouldBe testCase.producesHttpResponse - testCase.producesError?.also { expectedErrorResponse -> - val body = status.body() - body.feilKode shouldBe expectedErrorResponse.feilKode - body.melding shouldBe expectedErrorResponse.melding - body.aarsakTilAvvisning?.regel shouldBe expectedErrorResponse.aarsakTilAvvisning?.regel - expectedErrorResponse.aarsakTilAvvisning?.detaljer?.also { expectedDetails -> - body.aarsakTilAvvisning?.detaljer.shouldNotBeNull() - body.aarsakTilAvvisning?.detaljer?.shouldContainExactlyInAnyOrder(expectedDetails) - body.aarsakTilAvvisning?.beskrivelse shouldBe expectedErrorResponse.aarsakTilAvvisning?.beskrivelse - } - } - val expectedRecord = testCase.producesRecord(kafkaKeys) - if (expectedRecord != null) { - verify( - actual = producer.next(), - expected = expectedRecord - ) - } else { - producer.next().shouldBeNull() - } - } - } - } - } -}) - -fun String.readable(): String = - map { letter -> if (letter.isUpperCase()) " ${letter.lowercase()}" else "$letter" } - .joinToString("") - .replace("oe", "ø") - .replace("aa", "å")