diff --git a/felles/src/main/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiver.kt b/felles/src/main/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiver.kt index 48c7825fb..132867679 100644 --- a/felles/src/main/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiver.kt +++ b/felles/src/main/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiver.kt @@ -5,6 +5,7 @@ import no.nav.helsearbeidsgiver.felles.EventName import no.nav.helsearbeidsgiver.felles.Key import no.nav.helsearbeidsgiver.felles.json.krev import no.nav.helsearbeidsgiver.felles.json.les +import no.nav.helsearbeidsgiver.felles.json.toMap import no.nav.helsearbeidsgiver.felles.json.toPretty import no.nav.helsearbeidsgiver.felles.loeser.ObjectRiver import no.nav.helsearbeidsgiver.felles.rapidsrivers.model.Fail @@ -24,8 +25,13 @@ class ServiceRiver( private val logger = logger() private val sikkerLogger = sikkerLogger() - override fun les(json: Map): ServiceMelding? = - when { + override fun les(json: Map): ServiceMelding? { + val nestedData = json[Key.DATA] + ?.runCatching { toMap() } + ?.getOrNull() + .orEmpty() + + return when { Key.FAIL in json -> { FailMelding( eventName = Key.EVENT_NAME.krev(service.eventName, EventName.serializer(), json), @@ -34,6 +40,7 @@ class ServiceRiver( ) } + // Støtter Key.DATA som flagg med datafelt på rot (metode på vei ut) Key.DATA in json && ( service.startKeys.all(json::containsKey) || @@ -48,10 +55,24 @@ class ServiceRiver( ) } + // Støtter Key.DATA som objekt som inneholder datafelt (metode på vei inn) + // TODO Når all data er nested under Key.DATA så kan startKeys og dataKeys få visibility protected + service.startKeys.all(nestedData::containsKey) || + service.dataKeys.any(nestedData::containsKey) -> { + DataMelding( + eventName = Key.EVENT_NAME.krev(service.eventName, EventName.serializer(), json), + transaksjonId = Key.UUID.les(UuidSerializer, json), + dataMap = nestedData.filterKeys { + (service.startKeys + service.dataKeys).contains(it) + } + ) + } + else -> { null } } + } override fun ServiceMelding.haandter(json: Map): Map? { when (this) { diff --git a/felles/src/test/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiverTest.kt b/felles/src/test/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiverTest.kt index a13789710..846768676 100644 --- a/felles/src/test/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiverTest.kt +++ b/felles/src/test/kotlin/no/nav/helsearbeidsgiver/felles/rapidsrivers/service/ServiceRiverTest.kt @@ -3,7 +3,6 @@ package no.nav.helsearbeidsgiver.felles.rapidsrivers.service import io.kotest.core.spec.style.FunSpec import io.kotest.datatest.withData import io.kotest.matchers.ints.shouldBeExactly -import io.kotest.matchers.maps.shouldNotContainKey import io.kotest.matchers.maps.shouldNotContainValue import io.kotest.matchers.shouldBe import io.mockk.clearAllMocks @@ -41,16 +40,19 @@ class ServiceRiverTest : FunSpec({ testRapid.reset() clearAllMocks() mockRedis.setup() - - // For å passere sjekk for inaktivitet - every { - mockRedis.store.getAll(any()) - } returns Mock.values(mockService.startKeys).mapKeys { it.key.toString() } } context("fail-melding har presedens") { withData( mapOf( + "over start" to mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.FAIL to Mock.fail.toJson(Fail.serializer()), + Key.DATA to "".toJson() + ) + .plus(Mock.values(mockService.startKeys)), + "over data" to mapOf( Key.EVENT_NAME to mockService.eventName.toJson(), Key.UUID to UUID.randomUUID().toJson(), @@ -59,14 +61,26 @@ class ServiceRiverTest : FunSpec({ ) .plus(Mock.values(mockService.dataKeys)), - "over start" to mapOf( + "over start med nested data" to mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.FAIL to Mock.fail.toJson(Fail.serializer()), + Key.DATA to Mock.values(mockService.startKeys).toJson() + ), + + "over nested data" to mapOf( Key.EVENT_NAME to mockService.eventName.toJson(), Key.UUID to UUID.randomUUID().toJson(), - Key.FAIL to Mock.fail.toJson(Fail.serializer()) + Key.FAIL to Mock.fail.toJson(Fail.serializer()), + Key.DATA to Mock.values(mockService.dataKeys).toJson() ) - .plus(Mock.values(mockService.startKeys)) ) ) { innkommendeMelding -> + // For å passere sjekk for inaktivitet + every { + mockRedis.store.getAll(any()) + } returns Mock.values(mockService.startKeys).mapKeys { it.key.toString() } + testRapid.sendJson(innkommendeMelding) verify { @@ -105,16 +119,45 @@ class ServiceRiverTest : FunSpec({ } } - test("datamelding håndteres korrekt") { - val eksisterendeRedisValues = Mock.values(mockService.startKeys + Key.PERSONER) + test("datamelding med nested startdata håndteres korrekt") { + val transaksjonId = UUID.randomUUID() + val data = Mock.values(mockService.startKeys) - every { - mockRedis.store.getAll(any()) - } returns eksisterendeRedisValues.mapKeys { it.key.toString() } + val innkommendeMelding = mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to transaksjonId.toJson(), + Key.DATA to data.toJson() + ) + + testRapid.sendJson(innkommendeMelding) + + val redisStartValues = data.mapKeys { + RedisKey.of(transaksjonId, it.key) + } + + val beriketMelding = data + innkommendeMelding + + verifyOrder { + redisStartValues.forEach { (key, value) -> + mockRedis.store.set(key, value) + } + mockService.onData(beriketMelding) + } + verify(exactly = 0) { + mockService.onError(any(), any()) + } + } + test("datamelding håndteres korrekt") { val transaksjonId = UUID.randomUUID() val virksomhetNavn = "Fredrikssons Fabrikk" + val eksisterendeRedisValues = Mock.values(mockService.startKeys + Key.PERSONER) + + eksisterendeRedisValues.forEach { + mockRedis.store.set(RedisKey.of(transaksjonId, it.key), it.value) + } + val innkommendeMelding = mapOf( Key.EVENT_NAME to mockService.eventName.toJson(), Key.UUID to transaksjonId.toJson(), @@ -124,10 +167,46 @@ class ServiceRiverTest : FunSpec({ testRapid.sendJson(innkommendeMelding) + val allKeys = (mockService.startKeys + mockService.dataKeys).map { RedisKey.of(transaksjonId, it) }.toSet() + val beriketMelding = eksisterendeRedisValues + innkommendeMelding + verifyOrder { + mockRedis.store.set(RedisKey.of(transaksjonId, Key.VIRKSOMHETER), virksomhetNavn.toJson()) + mockRedis.store.getAll(allKeys) + mockService.onData(beriketMelding) + } + verify(exactly = 0) { + mockService.onError(any(), any()) + } + } + + test("datamelding med nested data håndteres korrekt") { + val transaksjonId = UUID.randomUUID() + val virksomhetNavn = "Fredrikssons Fabrikk" + + val eksisterendeRedisValues = Mock.values(mockService.startKeys + Key.PERSONER) + + eksisterendeRedisValues.forEach { + mockRedis.store.set(RedisKey.of(transaksjonId, it.key), it.value) + } + + val data = mapOf( + Key.VIRKSOMHETER to virksomhetNavn.toJson() + ) + + val innkommendeMelding = mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to transaksjonId.toJson(), + Key.DATA to data.toJson() + ) + + testRapid.sendJson(innkommendeMelding) + val allKeys = (mockService.startKeys + mockService.dataKeys).map { RedisKey.of(transaksjonId, it) }.toSet() + val beriketMelding = eksisterendeRedisValues + data + innkommendeMelding + verifyOrder { mockRedis.store.set(RedisKey.of(transaksjonId, Key.VIRKSOMHETER), virksomhetNavn.toJson()) mockRedis.store.getAll(allKeys) @@ -191,7 +270,31 @@ class ServiceRiverTest : FunSpec({ } } - test("redis-data med feil ignoreres") { + test("ved feil så publiseres ingenting (nested data)") { + every { mockRedis.store.set(any(), any()) } throws NullPointerException() + + val innkommendeMelding = mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.DATA to mapOf( + Key.VIRKSOMHETER to "Barry Eagles Language Course".toJson() + ).toJson() + ) + + testRapid.sendJson(innkommendeMelding) + + testRapid.inspektør.size shouldBeExactly 0 + + verify { + mockRedis.store.set(any(), any()) + } + verify(exactly = 0) { + mockService.onData(any()) + mockService.onError(any(), any()) + } + } + + test("redis-data med ugyldig key ignoreres") { val validJson = "gyldig json pga. -->".toJson() val validRedisValues = Mock.values(mockService.startKeys) @@ -219,7 +322,6 @@ class ServiceRiverTest : FunSpec({ mockService.onError( withArg { it shouldBe beriketMelding - it shouldNotContainKey Key.PERSONER it shouldNotContainValue validJson }, Mock.fail @@ -257,6 +359,34 @@ class ServiceRiverTest : FunSpec({ } } + test("datamelding (med nested data) trigger ikke service ved manglende startdata (inaktiv service)") { + every { + mockRedis.store.getAll(any()) + } returns Mock.values(setOf(Key.PERSONER)).mapKeys { it.key.toString() } + + val transaksjonId = UUID.randomUUID() + val virksomhetNavn = "Terkels Sabeltannisbutikk" + + val innkommendeMelding = mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to transaksjonId.toJson(), + Key.DATA to mapOf( + Key.VIRKSOMHETER to virksomhetNavn.toJson() + ).toJson() + ) + + testRapid.sendJson(innkommendeMelding) + + verifyOrder { + mockRedis.store.set(RedisKey.of(transaksjonId, Key.VIRKSOMHETER), virksomhetNavn.toJson()) + mockRedis.store.getAll(any()) + } + verify(exactly = 0) { + mockService.onData(any()) + mockService.onError(any(), any()) + } + } + test("fail-melding trigger ikke service ved manglende startdata (inaktiv service)") { every { mockRedis.store.getAll(any()) @@ -317,17 +447,39 @@ class ServiceRiverTest : FunSpec({ Key.FNR_LISTE to "mock fnr_liste".toJson() ), + "uten alle startdataverdier (nested data)" to mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.DATA to mapOf( + Key.FNR_LISTE to "mock fnr_liste".toJson() + ).toJson() + ), + "uten noen dataverdier" to mapOf( Key.EVENT_NAME to mockService.eventName.toJson(), Key.UUID to UUID.randomUUID().toJson(), Key.DATA to "".toJson() ), + "uten noen dataverdier (nested data)" to mapOf( + Key.EVENT_NAME to mockService.eventName.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.DATA to emptyMap().toJson() + ), + "med uønsket event" to mapOf( Key.EVENT_NAME to EventName.MANUELL_SLETT_SAK_REQUESTED.toJson(), Key.UUID to UUID.randomUUID().toJson(), Key.DATA to "".toJson(), Key.PERSONER to "mock personer".toJson() + ), + + "med uønsket event (nested data)" to mapOf( + Key.EVENT_NAME to EventName.MANUELL_SLETT_SAK_REQUESTED.toJson(), + Key.UUID to UUID.randomUUID().toJson(), + Key.DATA to mapOf( + Key.PERSONER to "mock personer".toJson() + ).toJson() ) ) ) { innkommendeMelding ->