Skip to content

Commit

Permalink
La til tester for v2 api
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsmsa committed Aug 26, 2024
1 parent 6a066e9 commit c382e20
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -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<Feil>()
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()
}
}
}
}
}
}
}
})

Original file line number Diff line number Diff line change
@@ -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<FeilV2>()
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()
}
}
}
}
}
}
}
})

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,9 +53,12 @@ fun MockOAuth2Server.ansattToken(navAnsatt: NavAnsatt): SignedJWT = issueToken(


fun verify(
actual: ProducerRecord<Long, Hendelse>,
actual: ProducerRecord<Long, Hendelse>?,
expected: ProducerRecord<Long, out Hendelse>
) {
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()
Expand Down Expand Up @@ -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
)
)
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<K, V> : Producer<K, V> {
private val queue = LinkedBlockingQueue<ProducerRecord<K, V>>(100)
fun next(): ProducerRecord<K, V> = queue.take()
fun next(): ProducerRecord<K, V>? = queue.poll(100, TimeUnit.MILLISECONDS)

override fun close() {}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Long, Hendelse>,
val kafkaKeys: KafkaKeysClient,
val startStoppRequestHandler: StartStoppRequestHandler
)

fun initTestCaseContext(): TestCaseContext {
val autorisasjonService = mockk<AutorisasjonService>()
val personInfoService = mockk<PersonInfoService>()
val producer: ProducerMock<Long, Hendelse> = 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
)
}
Loading

0 comments on commit c382e20

Please sign in to comment.