From d99b1937bd3bf0ba30321f5bfe116e6d05c81e39 Mon Sep 17 00:00:00 2001 From: Mikael Bjerga Date: Wed, 6 Nov 2024 16:42:51 +0100 Subject: [PATCH] =?UTF-8?q?Sett=20ikke=20funnet=20foresp=C3=B8rsel=20til?= =?UTF-8?q?=20utg=C3=A5tt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integrasjonstest/HentForespoerselIT.kt | 51 ++++++- .../integrasjonstest/utils/EndToEndTest.kt | 8 +- .../river/UtgaattForespoerselRiver.kt | 62 ++++++-- .../river/UtgaattForespoerselRiverTest.kt | 134 +++++++++++++++++- 4 files changed, 240 insertions(+), 15 deletions(-) diff --git a/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/HentForespoerselIT.kt b/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/HentForespoerselIT.kt index 242de5b2c..ea14cfe15 100644 --- a/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/HentForespoerselIT.kt +++ b/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/HentForespoerselIT.kt @@ -9,6 +9,7 @@ import no.nav.helsearbeidsgiver.felles.EventName import no.nav.helsearbeidsgiver.felles.Key import no.nav.helsearbeidsgiver.felles.domene.HentForespoerselResultat import no.nav.helsearbeidsgiver.felles.domene.ResultJson +import no.nav.helsearbeidsgiver.felles.json.lesOrNull import no.nav.helsearbeidsgiver.felles.json.toJson import no.nav.helsearbeidsgiver.felles.rapidsrivers.redis.RedisPrefix import no.nav.helsearbeidsgiver.inntektsmelding.integrasjonstest.mock.mockForespoerselSvarSuksess @@ -49,7 +50,6 @@ class HentForespoerselIT : EndToEndTest() { .filter(BehovType.HENT_TRENGER_IM) .firstAsMap() .let { - // Ble lagret i databasen it[Key.UUID]?.fromJson(UuidSerializer) shouldBe transaksjonId } @@ -58,7 +58,6 @@ class HentForespoerselIT : EndToEndTest() { .filter(BehovType.HENT_VIRKSOMHET_NAVN) .firstAsMap() .let { - // Ble lagret i databasen it[Key.UUID]?.fromJson(UuidSerializer) shouldBe transaksjonId } @@ -67,7 +66,6 @@ class HentForespoerselIT : EndToEndTest() { .filter(BehovType.HENT_PERSONER) .firstAsMap() .let { - // Ble lagret i databasen it[Key.UUID]?.fromJson(UuidSerializer) shouldBe transaksjonId } @@ -76,7 +74,6 @@ class HentForespoerselIT : EndToEndTest() { .filter(BehovType.HENT_INNTEKT) .firstAsMap() .let { - // Ble lagret i databasen it[Key.UUID]?.fromJson(UuidSerializer) shouldBe transaksjonId } @@ -99,4 +96,50 @@ class HentForespoerselIT : EndToEndTest() { feil.shouldBeEmpty() } } + + @Test + fun `dersom forespørsel ikke blir funnet så settes sak og oppgave til utgått`() { + val transaksjonId: UUID = UUID.randomUUID() + val forespoerselId: UUID = UUID.randomUUID() + + mockForespoerselSvarFraHelsebro( + forespoerselId = forespoerselId, + forespoerselSvar = null, + ) + + publish( + Key.EVENT_NAME to EventName.TRENGER_REQUESTED.toJson(), + Key.UUID to transaksjonId.toJson(UuidSerializer), + Key.DATA to + mapOf( + Key.FORESPOERSEL_ID to forespoerselId.toJson(UuidSerializer), + Key.ARBEIDSGIVER_FNR to Fnr.genererGyldig().toJson(), + ).toJson(), + ) + + messages + .filter(EventName.TRENGER_REQUESTED) + .filter(BehovType.HENT_TRENGER_IM) + .firstAsMap() + .let { + Key.UUID.lesOrNull(UuidSerializer, it) shouldBe transaksjonId + } + + messages + .filter(EventName.SAK_OG_OPPGAVE_UTGAATT) + .firstAsMap() + .let { + Key.UUID.lesOrNull(UuidSerializer, it) shouldBe transaksjonId + Key.FORESPOERSEL_ID.lesOrNull(UuidSerializer, it) shouldBe forespoerselId + } + + val resultJson = + redisConnection + .get(RedisPrefix.HentForespoersel, transaksjonId) + ?.fromJson(ResultJson.serializer()) + .shouldNotBeNull() + + resultJson.success.shouldBeNull() + resultJson.failure.shouldNotBeNull() + } } diff --git a/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/utils/EndToEndTest.kt b/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/utils/EndToEndTest.kt index 8ce56164e..6490820a5 100644 --- a/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/utils/EndToEndTest.kt +++ b/integrasjonstest/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/integrasjonstest/utils/EndToEndTest.kt @@ -284,7 +284,7 @@ abstract class EndToEndTest : ContainerTest() { fun mockForespoerselSvarFraHelsebro( forespoerselId: UUID, - forespoerselSvar: ForespoerselFraBro, + forespoerselSvar: ForespoerselFraBro?, ) { var boomerang: JsonElement? = null @@ -308,6 +308,12 @@ abstract class EndToEndTest : ContainerTest() { ForespoerselSvar( forespoerselId = forespoerselId, resultat = forespoerselSvar, + feil = + if (forespoerselSvar == null) { + ForespoerselSvar.Feil.FORESPOERSEL_IKKE_FUNNET + } else { + null + }, boomerang = boomerang.shouldNotBeNull(), ).toJson(ForespoerselSvar.serializer()), ) diff --git a/notifikasjon/src/main/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiver.kt b/notifikasjon/src/main/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiver.kt index a233903e1..de255c650 100644 --- a/notifikasjon/src/main/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiver.kt +++ b/notifikasjon/src/main/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiver.kt @@ -2,11 +2,12 @@ package no.nav.helsearbeidsgiver.inntektsmelding.notifikasjon.river import kotlinx.serialization.json.JsonElement import no.nav.helsearbeidsgiver.arbeidsgivernotifikasjon.ArbeidsgiverNotifikasjonKlient +import no.nav.helsearbeidsgiver.felles.BehovType 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.toJson +import no.nav.helsearbeidsgiver.felles.json.toMap import no.nav.helsearbeidsgiver.felles.json.toPretty import no.nav.helsearbeidsgiver.felles.rapidsrivers.model.Fail import no.nav.helsearbeidsgiver.felles.rapidsrivers.river.ObjectRiver @@ -34,17 +35,60 @@ class UtgaattForespoerselRiver( private val sikkerLogger = sikkerLogger() override fun les(json: Map): UtgaattForespoerselMelding? = - if (setOf(Key.BEHOV, Key.FAIL).any(json::containsKey)) { + // Obs!: Ignorerer ikke fail blankt så lenge vi vil sette sak og oppgave til utgått for forespørsler som ikke ble funnet. + if (setOf(Key.BEHOV, Key.DATA).any(json::containsKey)) { null } else { - UtgaattForespoerselMelding( - eventName = Key.EVENT_NAME.krev(EventName.FORESPOERSEL_FORKASTET, EventName.serializer(), json), - transaksjonId = Key.UUID.les(UuidSerializer, json), - forespoerselId = Key.FORESPOERSEL_ID.les(UuidSerializer, json), - ) + val eventName = Key.EVENT_NAME.les(EventName.serializer(), json) + val transaksjonId = Key.UUID.les(UuidSerializer, json) + + when (eventName) { + // Forespørsler som ble forkastet nylig matcher her + EventName.FORESPOERSEL_FORKASTET -> { + if (Key.FAIL in json) { + null + } else { + UtgaattForespoerselMelding( + eventName = eventName, + transaksjonId = transaksjonId, + forespoerselId = Key.FORESPOERSEL_ID.les(UuidSerializer, json), + ) + } + } + + // Forespørsler som ble forkastet for lenge siden matcher her dersom noen prøver å hente dem + EventName.TRENGER_REQUESTED -> { + val fail = Key.FAIL.les(Fail.serializer(), json) + val behovType = Key.BEHOV.les(BehovType.serializer(), fail.utloesendeMelding.toMap()) + + if ( + behovType != BehovType.HENT_TRENGER_IM || + fail.feilmelding != "Klarte ikke hente forespørsel. Feilet med kode 'FORESPOERSEL_IKKE_FUNNET'." + ) { + null + } else { + val data = + fail.utloesendeMelding + .toMap()[Key.DATA] + ?.toMap() + .orEmpty() + val forespoerselId = Key.FORESPOERSEL_ID.les(UuidSerializer, data) + + "Setter sak og oppgave til utgått for forespørsel '$forespoerselId' som ikke ble funnet.".also { + logger.info(it) + sikkerLogger.info(it) + } + + UtgaattForespoerselMelding(eventName, transaksjonId, forespoerselId) + } + } + + // Alle andre eventer ignoreres + else -> null + } } - override fun UtgaattForespoerselMelding.haandter(json: Map): Map? { + override fun UtgaattForespoerselMelding.haandter(json: Map): Map { logger.info("Mottok melding med event '$eventName'.") sikkerLogger.info("Mottok melding:\n${json.toPretty()}") @@ -55,8 +99,8 @@ class UtgaattForespoerselRiver( return mapOf( Key.EVENT_NAME to EventName.SAK_OG_OPPGAVE_UTGAATT.toJson(), - Key.FORESPOERSEL_ID to forespoerselId.toJson(), Key.UUID to transaksjonId.toJson(), + Key.FORESPOERSEL_ID to forespoerselId.toJson(), ) } diff --git a/notifikasjon/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiverTest.kt b/notifikasjon/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiverTest.kt index 31491c3cc..84f928366 100644 --- a/notifikasjon/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiverTest.kt +++ b/notifikasjon/src/test/kotlin/no/nav/helsearbeidsgiver/inntektsmelding/notifikasjon/river/UtgaattForespoerselRiverTest.kt @@ -2,16 +2,20 @@ package no.nav.helsearbeidsgiver.inntektsmelding.notifikasjon.river import com.github.navikt.tbd_libs.rapids_and_rivers.test_support.TestRapid import io.kotest.core.spec.style.FunSpec +import io.kotest.datatest.withData import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.maps.shouldContainExactly +import io.kotest.matchers.nulls.shouldNotBeNull import io.mockk.clearAllMocks import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.coVerifySequence import io.mockk.mockk import kotlinx.serialization.json.JsonElement import no.nav.helsearbeidsgiver.arbeidsgivernotifikasjon.ArbeidsgiverNotifikasjonKlient import no.nav.helsearbeidsgiver.arbeidsgivernotifikasjon.SakEllerOppgaveFinnesIkkeException import no.nav.helsearbeidsgiver.arbeidsgivernotifkasjon.graphql.generated.enums.SaksStatus +import no.nav.helsearbeidsgiver.felles.BehovType import no.nav.helsearbeidsgiver.felles.EventName import no.nav.helsearbeidsgiver.felles.Key import no.nav.helsearbeidsgiver.felles.json.toJson @@ -20,6 +24,8 @@ import no.nav.helsearbeidsgiver.felles.rapidsrivers.model.Fail import no.nav.helsearbeidsgiver.felles.test.rapidsrivers.firstMessage import no.nav.helsearbeidsgiver.felles.test.rapidsrivers.sendJson import no.nav.helsearbeidsgiver.inntektsmelding.notifikasjon.river.Mock.toMap +import no.nav.helsearbeidsgiver.utils.json.fromJson +import no.nav.helsearbeidsgiver.utils.json.serializer.UuidSerializer import no.nav.helsearbeidsgiver.utils.json.toJson import java.util.UUID @@ -30,7 +36,7 @@ class UtgaattForespoerselRiverTest : UtgaattForespoerselRiver(Mock.LINK_URL, mockAgNotifikasjonKlient).connect(testRapid) - beforeEach { + beforeTest { testRapid.reset() clearAllMocks() } @@ -208,6 +214,109 @@ class UtgaattForespoerselRiverTest : ) } } + + context("Ved mislykket henting av forkastet (ikke funnet) forespørsel") { + + test("med korrekt fail så settes oppgaven til utgått og sak til ferdig") { + val innkommendeFail = Mock.forespoerselIkkeFunnetFail() + val forespoerselId = + innkommendeFail.utloesendeMelding + .toMap()[Key.DATA] + .shouldNotBeNull() + .toMap()[Key.FORESPOERSEL_ID] + .shouldNotBeNull() + .fromJson(UuidSerializer) + + testRapid.sendJson(innkommendeFail.tilMelding()) + + testRapid.inspektør.size shouldBeExactly 1 + testRapid.firstMessage().toMap() shouldContainExactly + mapOf( + Key.EVENT_NAME to EventName.SAK_OG_OPPGAVE_UTGAATT.toJson(), + Key.UUID to innkommendeFail.transaksjonId.toJson(), + Key.FORESPOERSEL_ID to forespoerselId.toJson(), + ) + + coVerifySequence { + mockAgNotifikasjonKlient.oppgaveUtgaattByEksternId( + merkelapp = "Inntektsmelding sykepenger", + eksternId = forespoerselId.toString(), + nyLenke = "${Mock.LINK_URL}/im-dialog/utgatt", + ) + mockAgNotifikasjonKlient.nyStatusSakByGrupperingsid( + grupperingsid = forespoerselId.toString(), + merkelapp = "Inntektsmelding sykepenger", + status = SaksStatus.FERDIG, + tidspunkt = null, + statusTekst = "Avbrutt av Nav", + nyLenke = "${Mock.LINK_URL}/im-dialog/utgatt", + ) + } + } + + test("med feil behovtype så ignoreres meldingen") { + val innkommendeFail = + Mock.forespoerselIkkeFunnetFail().let { + it.copy( + utloesendeMelding = + it.utloesendeMelding + .toMap() + .plus(Key.BEHOV to BehovType.HENT_INNTEKT.toJson()) + .toJson(), + ) + } + + testRapid.sendJson(innkommendeFail.tilMelding()) + + testRapid.inspektør.size shouldBeExactly 0 + + coVerify(exactly = 0) { + mockAgNotifikasjonKlient.oppgaveUtgaattByEksternId(any(), any(), any()) + mockAgNotifikasjonKlient.nyStatusSakByGrupperingsid(any(), any(), any(), any(), any(), any()) + } + } + + test("med feil feilmelding så ignoreres meldingen") { + val innkommendeFail = + Mock.forespoerselIkkeFunnetFail().copy( + feilmelding = "Klarte ikke hente forespørsel. Ukjent feil.", + ) + + testRapid.sendJson(innkommendeFail.tilMelding()) + + testRapid.inspektør.size shouldBeExactly 0 + + coVerify(exactly = 0) { + mockAgNotifikasjonKlient.oppgaveUtgaattByEksternId(any(), any(), any()) + mockAgNotifikasjonKlient.nyStatusSakByGrupperingsid(any(), any(), any(), any(), any(), any()) + } + } + } + + context("ignorerer melding") { + withData( + mapOf( + "melding med uønsket event" to Pair(Key.EVENT_NAME, EventName.FORESPOERSEL_BESVART.toJson()), + "melding med uønsket behov" to Pair(Key.BEHOV, BehovType.HENT_INNTEKT.toJson()), + "melding med data som flagg" to Pair(Key.DATA, "".toJson()), + "melding med fail" to Pair(Key.FAIL, Mock.forventetFail(Mock.innkommendeMelding()).toJson(Fail.serializer())), + ), + ) { uoensketKeyMedVerdi -> + testRapid.sendJson( + Mock + .innkommendeMelding() + .toMap() + .plus(uoensketKeyMedVerdi), + ) + + testRapid.inspektør.size shouldBeExactly 0 + + coVerify(exactly = 0) { + mockAgNotifikasjonKlient.oppgaveUtgaattByEksternId(any(), any(), any()) + mockAgNotifikasjonKlient.nyStatusSakByGrupperingsid(any(), any(), any(), any(), any(), any()) + } + } + } }) private object Mock { @@ -242,4 +351,27 @@ private object Mock { forespoerselId = innkommendeMelding.forespoerselId, utloesendeMelding = innkommendeMelding.toMap().toJson(), ) + + fun forespoerselIkkeFunnetFail(): Fail { + val eventName = EventName.TRENGER_REQUESTED + val transaksjonId = UUID.randomUUID() + val forespoerselId = UUID.randomUUID() + + return Fail( + feilmelding = "Klarte ikke hente forespørsel. Feilet med kode 'FORESPOERSEL_IKKE_FUNNET'.", + event = eventName, + transaksjonId = transaksjonId, + forespoerselId = forespoerselId, + utloesendeMelding = + mapOf( + Key.EVENT_NAME to eventName.toJson(), + Key.BEHOV to BehovType.HENT_TRENGER_IM.toJson(), + Key.UUID to transaksjonId.toJson(), + Key.DATA to + mapOf( + Key.FORESPOERSEL_ID to forespoerselId.toJson(), + ).toJson(), + ).toJson(), + ) + } }