diff --git a/.nais/nais.yaml b/.nais/nais.yaml index 8c1f94ed..99ac8ed3 100644 --- a/.nais/nais.yaml +++ b/.nais/nais.yaml @@ -14,6 +14,9 @@ spec: - "azp_name" image: {{image}} port: 8090 + prometheus: + enabled: true + path: /meldekortservice/internal/metrics secureLogs: enabled: true ingresses: @@ -46,7 +49,7 @@ spec: webproxy: true resources: limits: - cpu: '1' + cpu: 1000m memory: 1500Mi requests: cpu: 500m diff --git a/README.md b/README.md index 90335afc..3cbe0baf 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,18 @@ Microservice / proxy som henter data fra meldekort ORDS (Arena DB). ## Kom i gang -1. Bygg meldekortservice ved å kjøre `./gradlew clean build`. Dette vil også kjøre testene. Det er også mulig å kjøre `gradle clean build`, men da må man ha en riktig versjon av gradle installert (som støtter Java 17) -2. Start lokal instans av Postgres ved å kjøre `docker-compose up -d`. -3. For å være sikker på at man får en ny tom database, kan man kjøre kommandoen: `docker-compose down -v`. +Bygg meldekortservice ved å kjøre `./gradlew clean build`. Dette vil også kjøre testene. +Det er også mulig å kjøre `gradle clean build`, men da må man ha en riktig versjon av gradle installert (som støtter Java 17) ## Lokal kjøring -Start appen ved å kjøre Server.kt sin main-metode eller kjør `gradle runServer`. +0. Ikke nødvendig: for å være sikker på at man får en ny tom database, kan man kjøre kommandoen: `docker-compose down -v`. +1. Start lokal instans av Postgres ved å kjøre `docker-compose up -d`. +2. Start appen ved å kjøre `./gradlew runServerTest`. +Det er også mulig å kjøre Server.kt sin main-metode eller `./gradlew runServer`, men da må man sette miljøvariablene: +IDPORTEN_WELL_KNOWN_URL +IDPORTEN_ACCEPTED_AUDIENCE +TOKEN_X_WELL_KNOWN_URL +TOKEN_X_ACCEPTED_AUDIENCE For å kjøre mot f.eks Q1 kan man enten sette riktige miljøvariabler (manuelt eller ved hjelp av bat/bash script) eller midlertidig skrive disse inn i Environment.kt i stedet for defaultValue'er. For eksempel, for å bruke ORDS i Q1 må man erstatte ``` @@ -23,7 +29,7 @@ val ordsClientId: String = getEnvVar("CLIENT_ID", "%CLIENT_ID_FRA_VAULT%"), val ordsClientSecret: String = getEnvVar("CLIENT_SECRET", "%CLIENT_SECRET_FRA_VAULT%"), ``` Appen starter på http://localhost:8090. Sjekk for eksempel at ping svarer på http://localhost:8090/meldekortservice/internal/ping. -Swagger er tilgjengelig på http://localhost:8090/meldekortservice/internal/apidocs/index.html?url=swagger.json +Swagger er tilgjengelig på http://localhost:8090/meldekortservice/internal/apidocs/index.html ## Feilsøking For å være sikker på at man får en ny tom database, kan man kjøre kommandoen: `docker-compose down -v`. diff --git a/build.gradle.kts b/build.gradle.kts index dd2f79fe..fc981e82 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,62 +2,56 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer import org.gradle.api.tasks.testing.logging.TestExceptionFormat -val flywayVersion = "8.4.0" -val h2Version = "1.4.200" -val jacksonVersion = "2.13.1" +val flywayVersion = "9.0.1" +val h2Version = "2.1.214" +val jacksonVersion = "2.13.3" val javaxActivationVersion = "1.1.1" val javaxAnnotationApiVersion = "1.3.2" -val javaxJaxwsApiVersion = "2.3.1" val jaxbApiVersion = "2.4.0-b180830.0359" -val jaxbRuntimeVersion = "3.0.2" +val jaxbRuntimeVersion = "4.0.0" val jaxwsApiVersion = "2.3.1" -val jaxwsToolsVersion = "2.3.5" -val junitVersion = "5.8.2" -val kluentVersion = "1.68" -val kotestVersion = "5.0.3" -val kotlinLoggerVersion = "2.1.21" -val ktorVersion = "1.6.7" -val logbackVersion = "1.2.7" -val logstashVersion = "7.0.1" -val mockOauthVersion = "0.4.1" -val mockitoVersion = "4.2.0" -val mockkVersion = "1.12.2" +val jaxwsToolsVersion = "2.3.5" // Senere versjoner har ikke javax.jws.WebService +val kotlinLoggerVersion = "2.1.23" +val ktorVersion = "2.0.3" +val logbackVersion = "1.2.11" +val logstashVersion = "7.2" +val micrometerVersion = "1.9.2" +val mockOauthVersion = "0.5.1" +val mockkVersion = "1.12.4" val navCommonCacheVersion = "2.2020.03.18_12.19-ac82e907ebc9" -val navCommonVersion = "1.2021.07.07_10.18-72bd65c546f6" +val navCommonVersion = "2.2022.07.01_07.12-6a0864fa6938" val ojdbc8Version = "19.3.0.0" -val postgresVersion = "42.3.1" -val prometheusVersion = "0.14.1" -val slf4jVersion = "1.7.32" -val swaggerVersion = "3.23.8" -val tjenestespecVersion = "1.2019.09.25-00.21-49b69f0625e0" -val tokenValidationVersion = "2.0.17" +val postgresVersion = "42.4.0" +val swaggerVersion = "4.11.1" // Husk å endre versjonen også i SwaggerUi.kt +val tjenestespecVersion = "2589.e85bf84" +val tokenValidationVersion = "2.1.2" val vaultJdbcVersion = "1.3.9" val vaultVersion = "5.1.0" -val cxfVersion = "3.5.2" +val cxfVersion = "3.5.3" project.setProperty("mainClassName", "io.ktor.server.netty.EngineMain") repositories { mavenCentral() - jcenter() maven("https://plugins.gradle.org/m2/") + maven("https://jitpack.io") } plugins { id("com.github.ManifestClasspath") version "0.1.0-RELEASE" - id("org.jetbrains.kotlin.jvm") version "1.6.21" - id("org.jetbrains.kotlin.plugin.allopen") version "1.6.21" + id("org.jetbrains.kotlin.jvm") version "1.7.10" + id("org.jetbrains.kotlin.plugin.allopen") version "1.7.10" id("com.github.johnrengelman.shadow") version "7.1.2" - id("org.flywaydb.flyway") version ("8.4.0") + id("org.flywaydb.flyway") version ("9.0.1") - id("org.sonarqube") version "3.3" + id("org.sonarqube") version "3.4.0.2513" - id("com.github.ben-manes.versions") version "0.41.0" + id("com.github.ben-manes.versions") version "0.42.0" jacoco @@ -75,68 +69,66 @@ application { dependencies { implementation(kotlin("stdlib")) - implementation("no.nav:vault-jdbc:$vaultJdbcVersion") implementation("ch.qos.logback:logback-classic:$logbackVersion") implementation("ch.qos.logback:logback-core:$logbackVersion") - implementation("net.logstash.logback:logstash-logback-encoder:$logstashVersion") - implementation("io.prometheus:simpleclient_common:$prometheusVersion") - implementation("io.prometheus:simpleclient_hotspot:$prometheusVersion") - implementation("io.ktor:ktor-server-netty:$ktorVersion") - implementation("io.ktor:ktor-auth:$ktorVersion") - implementation("io.ktor:ktor-auth-jwt:$ktorVersion") - implementation("io.ktor:ktor-client-apache:$ktorVersion") - implementation("io.ktor:ktor-client-json:$ktorVersion") - implementation("io.ktor:ktor-client-jackson:$ktorVersion") - implementation("io.ktor:ktor-locations:$ktorVersion") + implementation("com.bettercloud:vault-java-driver:$vaultVersion") + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:$jacksonVersion") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion") - implementation("com.fasterxml.jackson.module:jackson-module-parameter-names:$jacksonVersion") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:$jacksonVersion") - implementation("io.ktor:ktor-jackson:$ktorVersion") + implementation("com.fasterxml.jackson.module:jackson-module-parameter-names:$jacksonVersion") + implementation("com.oracle.ojdbc:ojdbc8:$ojdbc8Version") + implementation("com.sun.xml.ws:jaxws-tools:$jaxwsToolsVersion") { + exclude(group = "com.sun.xml.ws", module = "policy") + } + implementation("io.github.microutils:kotlin-logging:$kotlinLoggerVersion") + implementation("io.ktor:ktor-client-apache:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-client-jackson:$ktorVersion") + implementation("io.ktor:ktor-client-jackson:$ktorVersion") + implementation("io.ktor:ktor-client-json:$ktorVersion") + implementation("io.ktor:ktor-serialization-jackson:$ktorVersion") + implementation("io.ktor:ktor-server-auth-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion") + implementation("io.ktor:ktor-server-call-logging:$ktorVersion") + implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-server-default-headers:$ktorVersion") + implementation("io.ktor:ktor-server-locations:$ktorVersion") + implementation("io.ktor:ktor-server-metrics-micrometer:$ktorVersion") + implementation("io.ktor:ktor-server-netty:$ktorVersion") + implementation("io.micrometer:micrometer-registry-prometheus:$micrometerVersion") + implementation("javax.activation:activation:$javaxActivationVersion") + implementation("javax.annotation:javax.annotation-api:$javaxAnnotationApiVersion") + implementation("javax.xml.bind:jaxb-api:$jaxbApiVersion") + implementation("javax.xml.ws:jaxws-api:$jaxwsApiVersion") + implementation("net.logstash.logback:logstash-logback-encoder:$logstashVersion") implementation("no.nav.common:cache:$navCommonCacheVersion") implementation("no.nav.common:cxf:$navCommonVersion") - implementation("no.nav.common:log:$navCommonVersion") - implementation("no.nav.common:types:$navCommonVersion") - implementation("org.slf4j:slf4j-api:$slf4jVersion") - implementation("io.github.microutils:kotlin-logging:$kotlinLoggerVersion") - implementation("com.bettercloud:vault-java-driver:$vaultVersion") - implementation("no.nav.tjenestespesifikasjoner:arena-sakOgAktivitet_v1:$tjenestespecVersion") + implementation("no.nav.security:token-validation-ktor-v2:$tokenValidationVersion") + implementation("com.github.navikt.tjenestespesifikasjoner:arena-sakogaktivitet_v1:$tjenestespecVersion") + implementation("org.apache.cxf:cxf-core:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-bindings-soap:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-features-logging:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-frontend-jaxws:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-frontend-simple:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-transports-http:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-ws-policy:$cxfVersion") + implementation("org.apache.cxf:cxf-rt-ws-security:$cxfVersion") implementation("org.flywaydb:flyway-core:$flywayVersion") + implementation("org.glassfish.jaxb:jaxb-runtime:$jaxbRuntimeVersion") implementation("org.postgresql:postgresql:$postgresVersion") - implementation("no.nav.security:token-validation-ktor:$tokenValidationVersion") - implementation("no.nav.security:token-client-spring:$tokenValidationVersion") - implementation("com.oracle.ojdbc:ojdbc8:$ojdbc8Version") + implementation("org.webjars:swagger-ui:$swaggerVersion") + implementation("no.nav:vault-jdbc:$vaultJdbcVersion") - testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") testImplementation(kotlin("test-junit5")) - testImplementation("org.mockito:mockito-core:$mockitoVersion") - testImplementation("io.ktor:ktor-server-test-host:$ktorVersion") - testImplementation("io.ktor:ktor-client-mock:$ktorVersion") - testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion") - testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") - testImplementation("com.h2database:h2:$h2Version") - testImplementation("org.amshove.kluent:kluent:$kluentVersion") + testImplementation("io.ktor:ktor-client-mock:$ktorVersion") + testImplementation("io.ktor:ktor-server-test-host:$ktorVersion") testImplementation("io.mockk:mockk:$mockkVersion") testImplementation("no.nav.security:mock-oauth2-server:$mockOauthVersion") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion") - implementation("org.webjars:swagger-ui:$swaggerVersion") - implementation("javax.xml.ws:jaxws-api:$jaxwsApiVersion") - implementation("javax.annotation:javax.annotation-api:$javaxAnnotationApiVersion") - implementation("javax.xml.bind:jaxb-api:$jaxbApiVersion") - implementation("org.glassfish.jaxb:jaxb-runtime:$jaxbRuntimeVersion") - implementation("javax.activation:activation:$javaxActivationVersion") - implementation("com.sun.xml.ws:jaxws-tools:$jaxwsToolsVersion") { - exclude(group = "com.sun.xml.ws", module = "policy") - } - - implementation("org.apache.cxf:cxf-rt-frontend-jaxws:$cxfVersion") - implementation("org.apache.cxf:cxf-rt-transports-http:$cxfVersion") - implementation("org.apache.cxf:cxf-rt-ws-security:$cxfVersion") } -configure { +configure { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } @@ -156,6 +148,8 @@ tasks { } withType { + isZip64 = true + transform(ServiceFileTransformer::class.java) { setPath("META-INF/cxf") } @@ -171,7 +165,7 @@ tasks { jacocoTestReport { reports { - xml.isEnabled = true + xml.required.set(true) } } @@ -180,7 +174,17 @@ tasks { } register("runServer", JavaExec::class) { - main = project.property("mainClassName").toString() + mainClass.set(project.property("mainClassName").toString()) + classpath = sourceSets["main"].runtimeClasspath + } + + register("runServerTest", JavaExec::class) { + systemProperties["IDPORTEN_WELL_KNOWN_URL"] = "idporten.dev.nav.no" + systemProperties["IDPORTEN_ACCEPTED_AUDIENCE"] = "nav.no" + systemProperties["TOKEN_X_WELL_KNOWN_URL"] = "tokenx.dev.nav.no" + systemProperties["TOKEN_X_ACCEPTED_AUDIENCE"] = "nav.no" + + mainClass.set(project.property("mainClassName").toString()) classpath = sourceSets["main"].runtimeClasspath } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ea1ac04b..0fdc607e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Internal.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Internal.kt index 2d3979fd..c5c1f1d1 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Internal.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Internal.kt @@ -1,47 +1,83 @@ package no.nav.meldeplikt.meldekortservice.api -import io.ktor.application.* import io.ktor.http.* -import io.ktor.response.* -import io.ktor.routing.* +import io.ktor.server.application.* +import io.ktor.server.locations.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.micrometer.prometheus.PrometheusMeterRegistry import no.nav.meldeplikt.meldekortservice.config.SWAGGER_URL_V1 import no.nav.meldeplikt.meldekortservice.config.swagger -import no.nav.meldeplikt.meldekortservice.utils.API_PATH import no.nav.meldeplikt.meldekortservice.utils.BASE_PATH import no.nav.meldeplikt.meldekortservice.utils.INTERNAL_PATH import no.nav.meldeplikt.meldekortservice.utils.swagger.SwaggerUi -fun Route.healthApi() { +@KtorExperimentalLocationsAPI +fun Route.healthApi(appMicrometerRegistry: PrometheusMeterRegistry) { route(INTERNAL_PATH) { + val swaggerUI = SwaggerUi() + + get("") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/apidocs") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/apidocs/") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/apidocs/{fileName}") { + val fileName = call.parameters["fileName"] + if (fileName == "swagger.json") { + call.respond(swagger) + } else { + swaggerUI.serve(fileName, call) + } + } get("/isAlive") { - call.respondText(text = "Alive", contentType = ContentType.Text.Plain) + call.respondText("Alive") } get("/isReady") { - call.respondText(text = "Ready", contentType = ContentType.Text.Plain) + call.respondText("Ready") } get("/ping") { val pingJsonResponse = """{"ping": "pong"}""" call.respondText(text = pingJsonResponse, contentType = ContentType.Application.Json) } + + get("/metrics") { + call.respondText(appMicrometerRegistry.scrape()) + } } } fun Routing.swaggerRoutes() { - val swaggerUI = SwaggerUi() - - get(BASE_PATH) { call.respondRedirect(SWAGGER_URL_V1) } - get(API_PATH) { call.respondRedirect(SWAGGER_URL_V1) } - get("$INTERNAL_PATH/apidocs") { call.respondRedirect(SWAGGER_URL_V1) } - get("$INTERNAL_PATH/apidocs/{fileName}") { - val fileName = call.parameters["fileName"] - if (fileName == "swagger.json") { - call.respond(swagger) - } else { - swaggerUI.serve(fileName, call) + route(BASE_PATH) { + get("") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/api") { + call.respondRedirect(SWAGGER_URL_V1) + } + + get("/api/") { + call.respondRedirect(SWAGGER_URL_V1) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Meldekort.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Meldekort.kt index f8f46817..639d81cd 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Meldekort.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Meldekort.kt @@ -1,7 +1,7 @@ package no.nav.meldeplikt.meldekortservice.api -import io.ktor.locations.* -import io.ktor.routing.* +import io.ktor.server.locations.* +import io.ktor.server.routing.* import no.nav.meldeplikt.meldekortservice.config.userIdent import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer import no.nav.meldeplikt.meldekortservice.service.ArenaOrdsService @@ -71,4 +71,4 @@ fun Routing.getKorrigertMeldekort(arenaOrdsService: ArenaOrdsService) = arenaOrdsService.kopierMeldekort(korrigertMeldekortInput.meldekortId) } - } \ No newline at end of file + } diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Person.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Person.kt index 1cf655d1..b3659420 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Person.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Person.kt @@ -1,10 +1,10 @@ package no.nav.meldeplikt.meldekortservice.api -import io.ktor.application.* import io.ktor.http.* -import io.ktor.locations.* -import io.ktor.response.* -import io.ktor.routing.Routing +import io.ktor.server.application.* +import io.ktor.server.locations.* +import io.ktor.server.response.* +import io.ktor.server.routing.* import no.nav.meldeplikt.meldekortservice.config.userIdent import no.nav.meldeplikt.meldekortservice.mapper.MeldekortMapper import no.nav.meldeplikt.meldekortservice.mapper.MeldekortkontrollMapper @@ -16,7 +16,10 @@ import no.nav.meldeplikt.meldekortservice.model.feil.NoContentException import no.nav.meldeplikt.meldekortservice.model.meldekort.Person import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer import no.nav.meldeplikt.meldekortservice.model.response.EmptyResponse -import no.nav.meldeplikt.meldekortservice.service.* +import no.nav.meldeplikt.meldekortservice.service.ArenaOrdsService +import no.nav.meldeplikt.meldekortservice.service.DBService +import no.nav.meldeplikt.meldekortservice.service.DokarkivService +import no.nav.meldeplikt.meldekortservice.service.KontrollService import no.nav.meldeplikt.meldekortservice.utils.* import no.nav.meldeplikt.meldekortservice.utils.swagger.* diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Weblogic.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Weblogic.kt index c88879ac..0f45c994 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Weblogic.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/api/Weblogic.kt @@ -1,7 +1,7 @@ package no.nav.meldeplikt.meldekortservice.api -import io.ktor.locations.* -import io.ktor.routing.* +import io.ktor.server.locations.* +import io.ktor.server.routing.* import no.nav.meldeplikt.meldekortservice.config.SoapConfig import no.nav.meldeplikt.meldekortservice.model.WeblogicPing import no.nav.meldeplikt.meldekortservice.utils.Error @@ -33,4 +33,4 @@ fun Routing.pingWeblogic() = respondOrError { SoapConfig.soapService().pingWeblogic() } - } \ No newline at end of file + } diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/AadServiceConfiguration.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/AadServiceConfiguration.kt index c2c1716d..24993290 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/AadServiceConfiguration.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/AadServiceConfiguration.kt @@ -4,10 +4,14 @@ import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.DeserializationFeature import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.engine.apache.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* +import io.ktor.http.* +import io.ktor.serialization.jackson.* import kotlinx.coroutines.runBlocking +import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais import org.apache.http.impl.conn.SystemDefaultRoutePlanner import java.net.ProxySelector @@ -22,7 +26,7 @@ data class AadServiceConfiguration( val authorityEndpoint: String = Environment().oauthEndpoint.removeSuffix("/"), val openIdConfiguration: AzureAdOpenIdConfiguration = if (isCurrentlyRunningOnNais()) { runBlocking { - defaultHttpClient.get("$authorityEndpoint/$tenant/v2.0/.well-known/openid-configuration") + defaultHttpClient.get("$authorityEndpoint/$tenant/v2.0/.well-known/openid-configuration").body() } } else { AzureAdOpenIdConfiguration("test", "test", "test", "test") @@ -31,11 +35,15 @@ data class AadServiceConfiguration( } internal val defaultHttpClient = HttpClient(Apache) { - install(JsonFeature) { - serializer = JacksonSerializer { - configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - setSerializationInclusion(JsonInclude.Include.NON_NULL) - } + install(ContentNegotiation) { + register( + ContentType.Application.Json, + JacksonConverter( + defaultObjectMapper + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + ) + ) } engine { customizeClient { setRoutePlanner(SystemDefaultRoutePlanner(ProxySelector.getDefault())) } diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Security.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Security.kt index 12f3a936..bc9ad6c9 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Security.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Security.kt @@ -1,8 +1,8 @@ package no.nav.meldeplikt.meldekortservice.config import com.auth0.jwt.JWT -import io.ktor.application.* import io.ktor.http.* +import io.ktor.server.application.* import io.ktor.util.pipeline.* import no.nav.meldeplikt.meldekortservice.utils.defaultLog @@ -61,4 +61,4 @@ private fun extractSubject(authToken: String?): String { } return "subject (ident) ikke funnet" -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Server.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Server.kt index eb43cabe..4c73d7ec 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Server.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/Server.kt @@ -1,16 +1,27 @@ package no.nav.meldeplikt.meldekortservice.config -import io.ktor.application.* -import io.ktor.auth.* -import io.ktor.features.* -import io.ktor.jackson.* -import io.ktor.locations.* -import io.ktor.request.* -import io.ktor.routing.* -import io.prometheus.client.hotspot.DefaultExports +import io.ktor.serialization.jackson.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.locations.* +import io.ktor.server.metrics.micrometer.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.request.* +import io.ktor.server.routing.* +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics +import io.micrometer.core.instrument.binder.system.ProcessorMetrics +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry import no.nav.cache.Cache import no.nav.cache.CacheConfig import no.nav.cache.CacheUtils +import no.nav.common.utils.EnvironmentUtils.Type.PUBLIC +import no.nav.common.utils.EnvironmentUtils.Type.SECRET +import no.nav.common.utils.EnvironmentUtils.setProperty import no.nav.meldeplikt.meldekortservice.api.* import no.nav.meldeplikt.meldekortservice.coroutine.SendJournalposterPaaNytt import no.nav.meldeplikt.meldekortservice.database.OracleDatabase @@ -24,22 +35,19 @@ import no.nav.meldeplikt.meldekortservice.utils.* import no.nav.meldeplikt.meldekortservice.utils.swagger.Contact import no.nav.meldeplikt.meldekortservice.utils.swagger.Information import no.nav.meldeplikt.meldekortservice.utils.swagger.Swagger -import no.nav.sbl.dialogarena.common.cxf.StsSecurityConstants -import no.nav.sbl.util.EnvironmentUtils.Type.PUBLIC -import no.nav.sbl.util.EnvironmentUtils.Type.SECRET -import no.nav.sbl.util.EnvironmentUtils.setProperty -import no.nav.security.token.support.ktor.tokenValidationSupport +import no.nav.security.token.support.v2.tokenValidationSupport fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args) +@KtorExperimentalLocationsAPI val swagger = Swagger( info = Information( version = "1", - title = "Meldekortservice. Proxy-api for meldekort-applikasjonen (front-end). Api'et benyttes mot Arena og meldekortkontroll-api", - description = "[Meldekortservice](https://github.com/navikt/meldekortservice)", + title = "Meldekortservice", + description = "Proxy-api for meldekort-applikasjonen (front-end). Api'et benyttes mot Arena og meldekortkontroll-api \n" + + "GitHub repo: [https://github.com/navikt/meldekortservice](https://github.com/navikt/meldekortservice) \n" + + "Slack: [#team-meldeplikt](https://nav-it.slack.com/archives/CQ61EHWP9)", contact = Contact( - name = "#meldeplikt på Slack", - url = "https://github.com/navikt/meldekortservice", email = "meldeplikt@nav.no" ) ) @@ -52,7 +60,7 @@ private const val cacheAntallMinutter = 55 private const val cacheTimeout: Long = cacheAntallMinutter.toLong() * 60 * 1000 * 2 val CACHE: Cache = CacheUtils.buildCache(CacheConfig.DEFAULT.withTimeToLiveMillis(cacheTimeout)) -const val SWAGGER_URL_V1 = "/meldekortservice/internal/apidocs/index.html?url=swagger.json" +const val SWAGGER_URL_V1 = "/meldekortservice/internal/apidocs/index.html" @KtorExperimentalLocationsAPI fun Application.mainModule( @@ -64,14 +72,25 @@ fun Application.mainModule( mockFlywayConfig: org.flywaydb.core.Flyway? = null ) { setAppProperties(env) + val dbService: DBService = mockDBService ?: initializeInnsendtMeldekortServiceApi(env) val flywayConfig: org.flywaydb.core.Flyway = mockFlywayConfig ?: initializeFlyway(env) - DefaultExports.initialize() + val appMicrometerRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + install(MicrometerMetrics) { + registry = appMicrometerRegistry + meterBinders = listOf( + JvmMemoryMetrics(), + JvmGcMetrics(), + JvmThreadMetrics(), + ProcessorMetrics() + ) + } + install(DefaultHeaders) install(ContentNegotiation) { - jackson { objectMapper } + jackson { defaultObjectMapper } } val conf = this.environment.config @@ -79,14 +98,16 @@ fun Application.mainModule( if (isCurrentlyRunningOnNais()) { tokenValidationSupport(config = conf) } else { - provider { skipWhen { true } } + basic { + skipWhen { true } + } } } install(Locations) install(Routing) { - healthApi() + healthApi(appMicrometerRegistry) swaggerRoutes() weblogicApi() meldekortApi(arenaOrdsService) @@ -105,9 +126,9 @@ fun Application.mainModule( } private fun setAppProperties(environment: Environment) { - setProperty(StsSecurityConstants.STS_URL_KEY, environment.stsUrl, PUBLIC) - setProperty(StsSecurityConstants.SYSTEMUSER_USERNAME, environment.srvMeldekortservice.username, PUBLIC) - setProperty(StsSecurityConstants.SYSTEMUSER_PASSWORD, environment.srvMeldekortservice.password, SECRET) + setProperty(SOAP_STS_URL_KEY, environment.stsUrl, PUBLIC) + setProperty(SOAP_SYSTEMUSER_USERNAME, environment.srvMeldekortservice.username, PUBLIC) + setProperty(SOAP_SYSTEMUSER_PASSWORD, environment.srvMeldekortservice.password, SECRET) setProperty(SBL_ARBEID_USERNAME, environment.srvSblArbeid.username, PUBLIC) setProperty(SBL_ARBEID_PASSWORD, environment.srvSblArbeid.password, SECRET) setProperty(DB_ORACLE_USERNAME, environment.dbUserOracle.username, PUBLIC) @@ -127,4 +148,3 @@ private fun initializeInnsendtMeldekortServiceApi(env: Environment): DBService { private fun initializeFlyway(env: Environment): org.flywaydb.core.Flyway { return Flyway.configure(env).load() } - diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/SoapConfig.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/SoapConfig.kt index 3d441f82..20c13c11 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/SoapConfig.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/config/SoapConfig.kt @@ -1,12 +1,12 @@ package no.nav.meldeplikt.meldekortservice.config +import no.nav.common.cxf.CXFClient import no.nav.meldeplikt.meldekortservice.service.SoapService import no.nav.meldeplikt.meldekortservice.service.SoapServiceImpl import no.nav.meldeplikt.meldekortservice.service.SoapServiceMock import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais -import no.nav.sbl.dialogarena.common.cxf.CXFClient import no.nav.tjeneste.virksomhet.sakogaktivitet.v1.SakOgAktivitetV1 -import org.apache.cxf.interceptor.LoggingOutInterceptor +import org.apache.cxf.ext.logging.LoggingOutInterceptor object SoapConfig { diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNytt.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNytt.kt index bff1f778..a1be3cea 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNytt.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNytt.kt @@ -97,4 +97,4 @@ class SendJournalposterPaaNytt( delay(interval) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortdetaljerMapper.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortdetaljerMapper.kt index 21fadf31..39fdab3d 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortdetaljerMapper.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortdetaljerMapper.kt @@ -4,10 +4,9 @@ import no.nav.meldeplikt.meldekortservice.model.enum.KortType import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.MeldekortDag import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Sporsmal -import no.nav.meldeplikt.meldekortservice.utils.defaultLog import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.arena.Meldekort as ArenaMeldekort -import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.arena.Spm as ArenaSpm import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.arena.MeldekortDag as ArenaMeldekortDag +import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.arena.Spm as ArenaSpm object MeldekortdetaljerMapper { diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/model/enum/KortType.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/model/enum/KortType.kt index f9ad0a84..0fd14c76 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/model/enum/KortType.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/model/enum/KortType.kt @@ -1,7 +1,6 @@ package no.nav.meldeplikt.meldekortservice.model.enum import com.fasterxml.jackson.annotation.JsonCreator -import java.util.* enum class KortType constructor(val code: String) { ORDINAER("01"), diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/AadService.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/AadService.kt index b9f22a0e..7f682889 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/AadService.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/AadService.kt @@ -3,14 +3,17 @@ package no.nav.meldeplikt.meldekortservice.service import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.DeserializationFeature import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.engine.apache.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.forms.* import io.ktor.http.* +import io.ktor.serialization.jackson.* import no.nav.meldeplikt.meldekortservice.config.AadServiceConfiguration import no.nav.meldeplikt.meldekortservice.config.Environment import no.nav.meldeplikt.meldekortservice.model.AccessToken import no.nav.meldeplikt.meldekortservice.utils.defaultLog +import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais import org.apache.http.impl.conn.SystemDefaultRoutePlanner import java.net.ProxySelector @@ -30,11 +33,15 @@ class AadService( ) private val aadClient = HttpClient(Apache) { - install(JsonFeature) { - serializer = JacksonSerializer { - configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - setSerializationInclusion(JsonInclude.Include.NON_NULL) - } + install(ContentNegotiation) { + register( + ContentType.Application.Json, + JacksonConverter( + defaultObjectMapper + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + ) + ) } engine { customizeClient { setRoutePlanner(SystemDefaultRoutePlanner(ProxySelector.getDefault())) } @@ -75,7 +82,7 @@ class AadService( return aadClient.submitForm( url = config.azureAd.openIdConfiguration.tokenEndpoint, formParameters = formParameters - ) + ).body() } internal object GrantType { diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsService.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsService.kt index e56ef327..255293e1 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsService.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsService.kt @@ -2,9 +2,11 @@ package no.nav.meldeplikt.meldekortservice.service import io.ktor.client.* import io.ktor.client.call.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.jackson.* import kotlinx.coroutines.runBlocking import no.nav.meldeplikt.meldekortservice.config.CACHE import no.nav.meldeplikt.meldekortservice.config.DUMMY_TOKEN @@ -24,8 +26,8 @@ import java.util.* class ArenaOrdsService( private val ordsClient: HttpClient = HttpClient { - install(JsonFeature) { - serializer = JacksonSerializer { objectMapper } + install(ContentNegotiation) { + register(ContentType.Application.Json, JacksonConverter(defaultObjectMapper)) } }, private val env: Environment = Environment() @@ -43,33 +45,33 @@ class ArenaOrdsService( throw OrdsException("Kunne ikke hente meldekort fra Arena Ords.") } - return OrdsStringResponse(meldekort.status, meldekort.receive()) + return OrdsStringResponse(meldekort.status, meldekort.body()) } suspend fun hentHistoriskeMeldekort(fnr: String, antallMeldeperioder: Int): Person { - val person = ordsClient.get( + val person: String = ordsClient.get( "${env.ordsUrl}$ARENA_ORDS_HENT_HISTORISKE_MELDEKORT$fnr" + "$ARENA_ORDS_MELDEPERIODER_PARAM$antallMeldeperioder" ) { setupOrdsRequest() - } + }.body() return mapFraXml(person, Person::class.java) } suspend fun hentMeldekortdetaljer(meldekortId: Long): Meldekortdetaljer { - val detaljer = ordsClient.get("${env.ordsUrl}$ARENA_ORDS_HENT_MELDEKORTDETALJER$meldekortId") { + val detaljer: String = ordsClient.get("${env.ordsUrl}$ARENA_ORDS_HENT_MELDEKORTDETALJER$meldekortId") { setupOrdsRequest() - } + }.body() return MeldekortdetaljerMapper.mapOrdsMeldekortTilMeldekortdetaljer(mapFraXml(detaljer, Meldekort::class.java)) } suspend fun kopierMeldekort(meldekortId: Long): Long { try { - val responseMedNyMeldekortId = ordsClient.post("${env.ordsUrl}$ARENA_ORDS_KOPIER_MELDEKORT") { + val responseMedNyMeldekortId: String = ordsClient.post("${env.ordsUrl}$ARENA_ORDS_KOPIER_MELDEKORT") { setupOrdsRequest(meldekortId) - } + }.body() val nyMeldekortId = mapFraXml(responseMedNyMeldekortId, KopierMeldekortResponse::class.java).meldekortId defaultLog.info("Meldekort med id $nyMeldekortId er opprettet for korrigering. Kopiert fra meldekort med id $meldekortId") @@ -102,7 +104,7 @@ class ArenaOrdsService( runBlocking { token = ordsClient.post("${env.ordsUrl}$ARENA_ORDS_TOKEN_PATH?grant_type=client_credentials") { setupTokenRequest() - } + }.body() } } else { defaultLog.info("Henter ikke ORDS-token, da appen kjører lokalt") diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivService.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivService.kt index e4e7f274..9e8eedb1 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivService.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivService.kt @@ -1,11 +1,13 @@ package no.nav.meldeplikt.meldekortservice.service import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.engine.apache.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.http.* +import io.ktor.serialization.jackson.* import kotlinx.coroutines.runBlocking import no.nav.meldeplikt.meldekortservice.config.CACHE import no.nav.meldeplikt.meldekortservice.config.Environment @@ -17,8 +19,8 @@ import java.util.* class DokarkivService( private val httpClient: HttpClient = HttpClient(Apache) { - install(JsonFeature) { - serializer = JacksonSerializer { objectMapper } + install(ContentNegotiation) { + register(ContentType.Application.Json, JacksonConverter(defaultObjectMapper)) } install(HttpTimeout) { // max time periods @@ -35,8 +37,8 @@ class DokarkivService( return httpClient.post("${env.dokarkivUrl}$JOURNALPOST_PATH?forsoekFerdigstill=true") { contentType(ContentType.Application.Json) header("Authorization", "Bearer " + hentToken().accessToken) - body = journalpost - } + setBody(journalpost) + }.body() } private fun hentToken(): AccessToken { @@ -51,7 +53,7 @@ class DokarkivService( runBlocking { token = httpClient.post("${env.stsNaisUrl}$STS_PATH?grant_type=client_credentials&scope=openid") { setupTokenRequest() - } + }.body() } } else { defaultLog.info("Henter ikke AccessToken for Dokarkiv, da appen kjører lokalt") @@ -65,4 +67,4 @@ class DokarkivService( val base = "${env.srvMeldekortservice.username}:${env.srvMeldekortservice.password}" header("Authorization", "Basic ${Base64.getEncoder().encodeToString(base.toByteArray())}") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollService.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollService.kt index 82162cbe..282e05b6 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollService.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollService.kt @@ -1,9 +1,11 @@ package no.nav.meldeplikt.meldekortservice.service import io.ktor.client.* -import io.ktor.client.features.json.* +import io.ktor.client.call.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.http.* +import io.ktor.serialization.jackson.* import no.nav.meldeplikt.meldekortservice.config.AadServiceConfiguration import no.nav.meldeplikt.meldekortservice.config.Environment import no.nav.meldeplikt.meldekortservice.mapper.KontrollertTypeMapper @@ -11,25 +13,24 @@ import no.nav.meldeplikt.meldekortservice.model.MeldekortKontrollertType import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.kontroll.Meldekortkontroll import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.kontroll.response.KontrollResponse import no.nav.meldeplikt.meldekortservice.utils.KONTROLL_KONTROLL -import no.nav.meldeplikt.meldekortservice.utils.objectMapper +import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper class KontrollService( private val env: Environment = Environment(), private val responseMapper: KontrollertTypeMapper = KontrollertTypeMapper(), private val aadService: AadService = AadService(AadServiceConfiguration()), private val kontrollClient: HttpClient = HttpClient { - install(JsonFeature) { - serializer = JacksonSerializer { objectMapper } + install(ContentNegotiation) { + register(ContentType.Application.Json, JacksonConverter(defaultObjectMapper)) } } ) { suspend fun kontroller(meldekort: Meldekortkontroll): MeldekortKontrollertType { - val message = kontrollClient.post { - url("${env.meldekortKontrollUrl}$KONTROLL_KONTROLL") + val message: KontrollResponse = kontrollClient.post("${env.meldekortKontrollUrl}$KONTROLL_KONTROLL") { contentType(ContentType.Application.Json) header("Authorization", "Bearer " + aadService.fetchAadToken()) - body = meldekort - } + setBody(meldekort) + }.body() return responseMapper.mapKontrollResponseToKontrollertType(message) } } diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapService.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapService.kt index 1c863523..426a94e5 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapService.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapService.kt @@ -1,8 +1,6 @@ package no.nav.meldeplikt.meldekortservice.service -import no.nav.meldeplikt.meldekortservice.model.MeldekortKontrollertType import no.nav.meldeplikt.meldekortservice.model.WeblogicPing -import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer interface SoapService { fun pingWeblogic(): WeblogicPing diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapServiceImpl.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapServiceImpl.kt index dbaa333d..0e0a08c3 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapServiceImpl.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/service/SoapServiceImpl.kt @@ -1,12 +1,22 @@ package no.nav.meldeplikt.meldekortservice.service +import no.nav.common.cxf.StsConfig import no.nav.meldeplikt.meldekortservice.config.SoapConfig import no.nav.meldeplikt.meldekortservice.model.WeblogicPing +import no.nav.meldeplikt.meldekortservice.utils.SOAP_STS_URL_KEY +import no.nav.meldeplikt.meldekortservice.utils.SOAP_SYSTEMUSER_PASSWORD +import no.nav.meldeplikt.meldekortservice.utils.SOAP_SYSTEMUSER_USERNAME import no.nav.meldeplikt.meldekortservice.utils.defaultLog import no.nav.tjeneste.virksomhet.sakogaktivitet.v1.SakOgAktivitetV1 +import java.lang.System.getProperty class SoapServiceImpl( - private val oppfoelgingPing: SakOgAktivitetV1? = SoapConfig.sakOgAktivitet().configureStsForSystemUser().build() + private val oppfoelgingPing: SakOgAktivitetV1? = SoapConfig.sakOgAktivitet().configureStsForSystemUser( + StsConfig.builder() + .url(getProperty(SOAP_STS_URL_KEY)) + .username(getProperty(SOAP_SYSTEMUSER_USERNAME)) + .password(getProperty(SOAP_SYSTEMUSER_PASSWORD)).build() + ).build() ) : SoapService { override fun pingWeblogic(): WeblogicPing { diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/LoggUtils.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/LoggUtils.kt index 46b18753..188ea865 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/LoggUtils.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/LoggUtils.kt @@ -1,6 +1,5 @@ package no.nav.meldeplikt.meldekortservice.utils -import org.slf4j.Logger -import org.slf4j.LoggerFactory +import mu.KotlinLogging -val defaultLog: Logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) \ No newline at end of file +val defaultLog = KotlinLogging.logger {} diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/Utils.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/Utils.kt index 91d59d90..619f5baa 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/Utils.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/Utils.kt @@ -6,11 +6,13 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.kotlin.* +import com.fasterxml.jackson.module.kotlin.KotlinFeature +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.fasterxml.jackson.module.paramnames.ParameterNamesModule -import io.ktor.application.* import io.ktor.http.* -import io.ktor.response.* +import io.ktor.server.application.* +import io.ktor.server.response.* import io.ktor.util.pipeline.* import no.nav.meldeplikt.meldekortservice.model.feil.NoContentException @@ -22,7 +24,6 @@ internal const val INTERNAL_PATH = "$BASE_PATH/internal" internal const val MELDEKORT_PATH = "$API_PATH/meldekort" internal const val PERSON_PATH = "$API_PATH/person" internal const val WEBLOGIC_PING_PATH = "$API_PATH/weblogic" -internal const val TEKST_PATH = "$API_PATH/tekst" internal const val KONTROLL_KONTROLL = "/api/v1/kontroll" @@ -46,8 +47,9 @@ internal const val STS_PATH = "/rest/v1/sts/token" internal const val JOURNALPOSTAPI_PATH = "/rest/journalpostapi/v1" internal const val JOURNALPOST_PATH = "$JOURNALPOSTAPI_PATH/journalpost" -const val vaultUrl = "https://vault.adeo.no" -const val vaultTokenPath = "/var/run/secrets/nais.io/vault/vault_token" +internal const val SOAP_STS_URL_KEY = "no.nav.modig.security.sts.url" +internal const val SOAP_SYSTEMUSER_USERNAME = "no.nav.modig.security.systemuser.username" +internal const val SOAP_SYSTEMUSER_PASSWORD = "no.nav.modig.security.systemuser.password" internal val HTTP_STATUS_CODES_2XX = IntRange(200, 299) @@ -95,13 +97,11 @@ val defaultXmlMapper: ObjectMapper = XmlMapper().registerModule( .build() ) -val defaultObjectMapper = jacksonObjectMapper() - -val objectMapper: ObjectMapper = ObjectMapper() +val defaultObjectMapper: ObjectMapper = ObjectMapper() .registerKotlinModule() .registerModule(JavaTimeModule()) .registerModule(ParameterNamesModule()) .enable(SerializationFeature.INDENT_OUTPUT) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) \ No newline at end of file + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Api.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Api.kt index 45c72087..58e87496 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Api.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Api.kt @@ -1,7 +1,5 @@ package no.nav.meldeplikt.meldekortservice.utils.swagger -import io.ktor.application.* -import io.ktor.auth.* import io.ktor.http.* import io.ktor.http.HttpStatusCode.Companion.BadRequest import io.ktor.http.HttpStatusCode.Companion.InternalServerError @@ -9,22 +7,16 @@ import io.ktor.http.HttpStatusCode.Companion.NoContent import io.ktor.http.HttpStatusCode.Companion.OK import io.ktor.http.HttpStatusCode.Companion.ServiceUnavailable import io.ktor.http.HttpStatusCode.Companion.Unauthorized -import io.ktor.locations.* -import io.ktor.request.* -import io.ktor.routing.Route +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.locations.* +import io.ktor.server.request.* +import io.ktor.server.routing.Route import io.ktor.util.pipeline.* import no.nav.meldeplikt.meldekortservice.config.swagger import no.nav.meldeplikt.meldekortservice.utils.defaultLog import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais import java.util.* -import kotlin.collections.List -import kotlin.collections.Map -import kotlin.collections.emptyList -import kotlin.collections.forEach -import kotlin.collections.getOrPut -import kotlin.collections.listOf -import kotlin.collections.mapOf -import kotlin.collections.mutableMapOf import kotlin.collections.set import kotlin.reflect.KClass @@ -67,6 +59,7 @@ inline fun Metadata.apply(me applyOperations(location, tags, method, LOCATION::class, ENTITY_TYPE::class) } +@KtorExperimentalLocationsAPI fun Metadata.applyResponseDefinitions() = responses.values.forEach { addDefinition(it) } @@ -81,6 +74,10 @@ fun Metadata.applyOperations( swagger.paths .getOrPut(location.path) { mutableMapOf() }[method.value.lowercase(Locale.getDefault())] = Operation(this, location, group, locationType, entityType, method) + + if (group != null && swagger.tags.find { tag -> tag.name == group.name } == null) { + swagger.tags.add(Tag(group.name, group.description)) + } } fun String.responds(vararg pairs: Pair>): Metadata = diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Swagger.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Swagger.kt index a9e2147b..2568b064 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Swagger.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/Swagger.kt @@ -2,8 +2,9 @@ package no.nav.meldeplikt.meldekortservice.utils.swagger +import com.fasterxml.jackson.annotation.JsonInclude import io.ktor.http.* -import io.ktor.locations.* +import io.ktor.server.locations.* import no.nav.meldeplikt.meldekortservice.config.swagger import no.nav.meldeplikt.meldekortservice.utils.defaultLog import java.time.Instant @@ -26,10 +27,13 @@ import kotlin.reflect.full.memberProperties typealias ModelName = String typealias PropertyName = String typealias Path = String +@OptIn(KtorExperimentalLocationsAPI::class) typealias Definitions = MutableMap +@OptIn(KtorExperimentalLocationsAPI::class) typealias Paths = MutableMap typealias MethodName = String typealias HttpStatus = String +@OptIn(KtorExperimentalLocationsAPI::class) typealias Methods = MutableMap typealias Content = MutableMap> @@ -40,10 +44,12 @@ data class Key( val `in`: String ) +@KtorExperimentalLocationsAPI +@JsonInclude(JsonInclude.Include.NON_NULL) data class Swagger( val openapi: String = "3.0.0", - val swagger: String = "3.0", val info: Information, + val tags: MutableList = mutableListOf(), val paths: Paths = mutableMapOf(), val components: Components = Components( SecuritySchemes( @@ -56,6 +62,7 @@ data class Swagger( ) ) +@KtorExperimentalLocationsAPI data class Components( val securitySchemes: SecuritySchemes, val schemas: Definitions = mutableMapOf() @@ -78,17 +85,20 @@ data class Information( val contact: Contact ) +@JsonInclude(JsonInclude.Include.NON_NULL) data class Contact( - val name: String, - val url: String, - val email: String + val name: String? = null, + val url: String? = null, + val email: String? = null ) data class Tag( - val name: String + val name: String, + val description: String ) @KtorExperimentalLocationsAPI +@JsonInclude(JsonInclude.Include.NON_NULL) class Operation( metadata: Metadata, location: Location, @@ -97,7 +107,7 @@ class Operation( entityType: KClass<*>, method: HttpMethod ) { - val tags = group?.toList() + val tags = group?.toList() // Operation tags are not objects, but strings, don't mix with toplevel tags val summary = metadata.summary val parameters = setParameterList(entityType, locationType, location, metadata, method) val requestBody = setRequestBody(entityType, locationType, location, metadata, method) @@ -129,11 +139,11 @@ private fun setRequestBody( add(entityType.bodyRequest()) } addAll(locationType.memberProperties.map { it.toRequestBody(location.path) }) - metadata.parameter?.let { - addAll(it.memberProperties.map { it.toRequestBody(location.path, ParameterInputType.query) }) + metadata.parameter?.let { param -> + addAll(param.memberProperties.map { it.toRequestBody(location.path, ParameterInputType.Query) }) } - metadata.headers?.let { - addAll(it.memberProperties.map { it.toRequestBody(location.path, ParameterInputType.header) }) + metadata.headers?.let { header -> + addAll(header.memberProperties.map { it.toRequestBody(location.path, ParameterInputType.Header) }) } }.firstOrNull() ?: emptyList() } else { @@ -156,11 +166,11 @@ private fun setParameterList( add(entityType.bodyParameter()) } addAll(locationType.memberProperties.map { it.toParameter(location.path) }) - metadata.parameter?.let { - addAll(it.memberProperties.map { it.toParameter(location.path, ParameterInputType.query) }) + metadata.parameter?.let { param -> + addAll(param.memberProperties.map { it.toParameter(location.path, ParameterInputType.Query) }) } - metadata.headers?.let { - addAll(it.memberProperties.map { it.toParameter(location.path, ParameterInputType.header) }) + metadata.headers?.let { header -> + addAll(header.memberProperties.map { it.toParameter(location.path, ParameterInputType.Header) }) } } } else { @@ -168,23 +178,28 @@ private fun setParameterList( } } -private fun Group.toList(): List { - return listOf(Tag(name)) +private fun Group.toList(): List { + return listOf(name) } +@KtorExperimentalLocationsAPI fun KProperty1.toParameter( path: String, inputType: ParameterInputType = if (path.contains("{$name}")) - ParameterInputType.path + ParameterInputType.Path else - ParameterInputType.query + ParameterInputType.Query ): Parameter { + val property = toModelProperty() + return Parameter( - toModelProperty(), + property, name, - inputType, - required = !returnType.isMarkedNullable + inputType.name.lowercase(), + required = !returnType.isMarkedNullable, + type = if (inputType == ParameterInputType.Query) null else property.type, + format = if (inputType == ParameterInputType.Query) null else property.format ) } @@ -193,7 +208,7 @@ private fun KClass<*>.bodyParameter() = referenceProperty(), name = "body", description = modelName(), - `in` = ParameterInputType.body + `in` = ParameterInputType.Body.name.lowercase() ) @KtorExperimentalLocationsAPI @@ -201,9 +216,9 @@ fun KProperty1.toRequestBody( path: String, inputType: ParameterInputType = if (path.contains("{$name}")) - ParameterInputType.path + ParameterInputType.Path else - ParameterInputType.query + ParameterInputType.Query ): RequestBody { return RequestBody( toModelProperty(), @@ -219,7 +234,11 @@ private fun KClass<*>.bodyRequest() = class Response(httpStatusCode: HttpStatusCode, kClass: KClass<*>) { val description = if (kClass == Unit::class) httpStatusCode.description else kClass.responseDescription() - val schema = if (kClass == Unit::class) null else ModelReference("#/components/schemas/" + kClass.modelName()) + val content: MutableMap> = mutableMapOf( + "application/json" to mutableMapOf( + "schema" to if (kClass == Unit::class) null else ModelReference("#/components/schemas/" + kClass.modelName()) + ) + ) } fun KClass<*>.responseDescription(): String = modelName() @@ -237,10 +256,11 @@ class RequestBody( ) ) +@JsonInclude(JsonInclude.Include.NON_NULL) class Parameter( property: Property, val name: String, - val `in`: ParameterInputType, + val `in`: String, val description: String = property.description, val required: Boolean = true, val type: String? = property.type, @@ -251,14 +271,13 @@ class Parameter( ) enum class ParameterInputType { - query, path, body, header + Query, Path, Body, Header } +@KtorExperimentalLocationsAPI class ModelData(kClass: KClass<*>) { val properties: Map = - kClass.memberProperties - .map { it.name to it.toModelProperty() } - .toMap() + kClass.memberProperties.associate { it.name to it.toModelProperty() } } private const val DATE_TIME: String = "date-time" @@ -274,10 +293,12 @@ val propertyTypes = mapOf( LocalDate::class to Property("string", "date") ).mapKeys { it.key.qualifiedName } +@KtorExperimentalLocationsAPI fun KProperty1.toModelProperty(): Property = (returnType.classifier as KClass<*>) .toModelProperty(returnType) +@KtorExperimentalLocationsAPI private fun KClass<*>.toModelProperty(returnType: KType? = null): Property = propertyTypes[qualifiedName?.removeSuffix("?")] ?: if (returnType != null && (isSubclassOf(Collection::class) || this.isSubclassOf(Set::class))) { @@ -302,6 +323,7 @@ private fun KClass<*>.referenceProperty(): Property = type = null ) +@JsonInclude(JsonInclude.Include.NON_NULL) open class Property( val type: String?, val format: String = "", @@ -311,6 +333,7 @@ open class Property( val `$ref`: String = "" ) +@KtorExperimentalLocationsAPI fun addDefinition(kClass: KClass<*>) { if ((kClass != Unit::class) && !swagger.components.schemas.containsKey(kClass.modelName())) { defaultLog.debug("Generating swagger spec for model ${kClass.modelName()}") @@ -320,4 +343,4 @@ fun addDefinition(kClass: KClass<*>) { private fun KClass<*>.modelName(): ModelName = simpleName ?: toString() -annotation class Group(val name: String) +annotation class Group(val name: String, val description: String = "") diff --git a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/SwaggerUi.kt b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/SwaggerUi.kt index c2b4335f..058fbd53 100644 --- a/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/SwaggerUi.kt +++ b/src/main/kotlin/no/nav/meldeplikt/meldekortservice/utils/swagger/SwaggerUi.kt @@ -1,8 +1,9 @@ package no.nav.meldeplikt.meldekortservice.utils.swagger -import io.ktor.application.* +import io.ktor.http.* import io.ktor.http.content.* -import io.ktor.response.* +import io.ktor.server.application.* +import io.ktor.server.response.* /** * @author Niels Falk, changed by Torstein Nesby and Yrjan Fraschetti @@ -17,11 +18,27 @@ class SwaggerUi { in notFound -> return null -> return else -> { - val resource = this::class.java.getResource("/META-INF/resources/webjars/swagger-ui/3.23.8/$filename") + val resource = this::class.java.getResource("/META-INF/resources/webjars/swagger-ui/4.11.1/$filename") if (resource == null) { notFound.add(filename) return } + + // OBS! Etter SwaggerUI 4.1.2 kan man ikke sende "url"-parameteren gjennom query string uten å sette queryConfigEnabled=true + // Uten "url"-parameteren åpnes SwaggerUI med dummy Petstore swagger.json + // Jeg kan ikke finne ut hvordan queryConfigEnabled=true kan settes siden vi bruker allerede ferdige JS-filer fra prekompilerte webjars + // Derfor må vi endre configen "post factum" i JS, dvs. erstatte dummy Petstore URL med vår swagger.json + if (filename == "swagger-initializer.js") { + val originalBody = resource.readText(); + val newBody = originalBody.replace( + "https://petstore.swagger.io/v2/swagger.json", + "swagger.json" + ) + + call.respondText(newBody, ContentType.Text.Html) + return + } + call.respond(content.getOrPut(filename) { URIFileContent(resource) }) } } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 196b1836..2f543192 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,4 +1,11 @@ - + + + + + + + + - \ No newline at end of file + diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/InternalKtTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/InternalKtTest.kt index ba950292..b2e0f0e6 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/InternalKtTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/InternalKtTest.kt @@ -1,46 +1,51 @@ package no.nav.meldeplikt.meldekortservice.api +import io.ktor.client.request.* +import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.locations.* +import io.ktor.server.locations.* import io.ktor.server.testing.* import io.mockk.every import io.mockk.mockk -import io.mockk.mockkStatic import no.nav.meldeplikt.meldekortservice.config.mainModule -import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais import org.flywaydb.core.Flyway import org.flywaydb.core.api.output.MigrateResult import org.junit.jupiter.api.Test import kotlin.test.assertEquals @KtorExperimentalLocationsAPI -class InternalKtTest { +class InternalKtTest : TestBase() { + @Test - fun `test isready, isalive, og ping`() { + fun testInternal() = testApplication { val flywayConfig = mockk() - - mockkStatic(::isCurrentlyRunningOnNais) - every { isCurrentlyRunningOnNais() } returns false every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ + environment { + config = setOidcConfig() + } + application { mainModule( arenaOrdsService = mockk(), kontrollService = mockk(), mockDBService = mockk(), mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/internal/isReady") {}.apply { - assertEquals(HttpStatusCode.OK, response.status()) - handleRequest(HttpMethod.Get, "/meldekortservice/internal/isAlive") {}.apply { - assertEquals(HttpStatusCode.OK, response.status()) - handleRequest(HttpMethod.Get, "/meldekortservice/internal/ping") {}.apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals("""{"ping": "pong"}""", response.content) - } - } - } } + + val response1 = client.get("/meldekortservice/internal/isReady") + assertEquals(HttpStatusCode.OK, response1.status) + assertEquals("Ready", response1.bodyAsText()) + + val response2 = client.get("/meldekortservice/internal/isAlive") + assertEquals(HttpStatusCode.OK, response2.status) + assertEquals("Alive", response2.bodyAsText()) + + val response3 = client.get("/meldekortservice/internal/ping") + assertEquals(HttpStatusCode.OK, response3.status) + assertEquals("""{"ping": "pong"}""", response3.bodyAsText()) + + val response4 = client.get("/meldekortservice/internal/metrics") + assertEquals(HttpStatusCode.OK, response4.status) } } diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/MeldekortKtTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/MeldekortKtTest.kt index 9cc31026..94549b10 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/MeldekortKtTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/MeldekortKtTest.kt @@ -1,103 +1,30 @@ package no.nav.meldeplikt.meldekortservice.api import com.fasterxml.jackson.module.kotlin.readValue -import io.ktor.config.* +import io.ktor.client.request.* +import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.locations.* +import io.ktor.server.locations.* import io.ktor.server.testing.* import io.mockk.coEvery import io.mockk.every import io.mockk.mockk -import io.mockk.mockkStatic -import no.nav.meldeplikt.meldekortservice.config.Environment import no.nav.meldeplikt.meldekortservice.config.mainModule import no.nav.meldeplikt.meldekortservice.model.enum.KortType import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer -import no.nav.meldeplikt.meldekortservice.service.ArenaOrdsService -import no.nav.meldeplikt.meldekortservice.service.DBService -import no.nav.meldeplikt.meldekortservice.service.DokarkivService -import no.nav.meldeplikt.meldekortservice.service.KontrollService import no.nav.meldeplikt.meldekortservice.utils.ErrorMessage import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper -import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais -import no.nav.security.mock.oauth2.MockOAuth2Server -import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback -import org.amshove.kluent.shouldBe import org.flywaydb.core.Flyway import org.flywaydb.core.api.output.MigrateResult -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @KtorExperimentalLocationsAPI -class MeldekortKtTest { - private fun MapApplicationConfig.setOidcConfig() { - put("no.nav.security.jwt.issuers.size", "1") - put("no.nav.security.jwt.issuers.0.issuer_name", ISSUER_ID) - put("no.nav.security.jwt.issuers.0.discoveryurl", mockOAuth2Server.wellKnownUrl(ISSUER_ID).toString()) - put("no.nav.security.jwt.issuers.0.accepted_audience", REQUIRED_AUDIENCE) - put("ktor.environment", "local") - } - - private fun issueTokenWithSub(): String = - mockOAuth2Server.issueToken( - ISSUER_ID, - "myclient", - DefaultOAuth2TokenCallback( - audience = listOf(REQUIRED_AUDIENCE), - claims = mapOf( - "sub" to "01020312345" - ) - ) - ).serialize() - - private fun issueTokenWithPid(): String = - mockOAuth2Server.issueToken( - ISSUER_ID, - "myclient", - DefaultOAuth2TokenCallback( - audience = listOf(REQUIRED_AUDIENCE), - claims = mapOf( - "pid" to "01020312345" - ) - ) - ).serialize() - - companion object { - private const val ISSUER_ID = "default" - private const val REQUIRED_AUDIENCE = "default" - - private val mockOAuth2Server = MockOAuth2Server() - - private val env = Environment(dokarkivResendInterval = 0L) - - private var dbService = mockk() - private var arenaOrdsService = mockk() - private var kontrollService = mockk() - private var dokarkivService = mockk() - private var flywayConfig = mockk() - - @BeforeAll - @JvmStatic - fun setup() { - mockOAuth2Server.start(8091) - every { flywayConfig.migrate() } returns MigrateResult("", "", "") - - mockkStatic(::isCurrentlyRunningOnNais) - every { isCurrentlyRunningOnNais() } returns true - } - - @AfterAll - @JvmStatic - fun cleanup() { - mockOAuth2Server.shutdown() - } - } +class MeldekortKtTest : TestBase() { @Test - fun `get meldekortdetaljer returns ok with valid JWT`() { + fun `get meldekortdetaljer returns ok with valid JWT`() = testApplication { val id: Long = 1 val meldekortdetaljer = Meldekortdetaljer( id = "1", @@ -106,9 +33,13 @@ class MeldekortKtTest { ) coEvery { arenaOrdsService.hentMeldekortdetaljer(any()) } returns (meldekortdetaljer) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -117,20 +48,20 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(meldekortdetaljer.id, responseObject.id) - } } + + val response = client.get("/meldekortservice/api/meldekort?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(meldekortdetaljer.id, responseObject.id) } @Test - fun `get meldekortdetaljer returns Bad request with invalid fnr`() { + fun `get meldekortdetaljer returns Bad request with invalid fnr`() = testApplication { val id: Long = 1 val meldekortdetaljer = Meldekortdetaljer( id = "1", @@ -139,9 +70,13 @@ class MeldekortKtTest { ) coEvery { arenaOrdsService.hentMeldekortdetaljer(any()) } returns (meldekortdetaljer) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -150,23 +85,22 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.BadRequest - assertEquals( - "Personidentifikator matcher ikke. Bruker kan derfor ikke hente ut meldekortdetaljer.", - responseObject.error - ) - } } + + val response = client.get("/meldekortservice/api/meldekort?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") + } + + assertEquals(HttpStatusCode.BadRequest, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals( + "Personidentifikator matcher ikke. Bruker kan derfor ikke hente ut meldekortdetaljer.", responseObject.error + ) } @Test - fun `get meldekortdetaljer returns 401-Unauthorized with missing JWT`() { + fun `get meldekortdetaljer returns 401-Unauthorized with missing JWT`() = testApplication { val id: Long = 1 val meldekortdetaljer = Meldekortdetaljer( id = "1", @@ -175,9 +109,13 @@ class MeldekortKtTest { ) coEvery { arenaOrdsService.hentMeldekortdetaljer(any()) } returns (meldekortdetaljer) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -186,23 +124,26 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort?meldekortId=${id}") { - }.apply { - response.status() shouldBe HttpStatusCode.Unauthorized - } } + + val response = client.get("/meldekortservice/api/meldekort?meldekortId=${id}") + + assertEquals(HttpStatusCode.Unauthorized, response.status) } @Test - fun `get korrigert meldekortid returns 401-Unauthorized with invalid JWT`() { + fun `get korrigert meldekortid returns 401-Unauthorized with invalid JWT`() = testApplication { val id: Long = 1 val nyId: Long = 123 coEvery { arenaOrdsService.kopierMeldekort(any()) } returns (nyId) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -211,17 +152,17 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer Token AD") - }.apply { - response.status() shouldBe HttpStatusCode.Unauthorized - } } + + val response = client.get("/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer Token AD") + } + + assertEquals(HttpStatusCode.Unauthorized, response.status) } @Test - fun `get meldekortdetaljer returns 401-Unauthorized with invalid JWT`() { + fun `get meldekortdetaljer returns 401-Unauthorized with invalid JWT`() = testApplication { val id: Long = 1 val meldekortdetaljer = Meldekortdetaljer( id = "1", @@ -230,9 +171,13 @@ class MeldekortKtTest { ) coEvery { arenaOrdsService.hentMeldekortdetaljer(any()) } returns (meldekortdetaljer) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -241,24 +186,28 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer Token AD") - }.apply { - response.status() shouldBe HttpStatusCode.Unauthorized - } } + + val response = client.get("/meldekortservice/api/meldekort?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer Token AD") + } + + assertEquals(HttpStatusCode.Unauthorized, response.status) } @Test - fun `get korrigert meldekortid returns OK with valid JWT with sub`() { + fun `get korrigert meldekortid returns OK with valid JWT with sub`() = testApplication { val id: Long = 1 val nyId: Long = 123 coEvery { arenaOrdsService.kopierMeldekort(any()) } returns (nyId) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -267,27 +216,31 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(nyId, responseObject) - } } + + val response = client.get("/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithSub()}") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(nyId, responseObject) } @Test - fun `get korrigert meldekortid returns OK with valid JWT with pid`() { + fun `get korrigert meldekortid returns OK with valid JWT with pid`() = testApplication { val id: Long = 1 val nyId: Long = 123 coEvery { arenaOrdsService.kopierMeldekort(any()) } returns (nyId) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -296,15 +249,15 @@ class MeldekortKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(nyId, responseObject) - } } + + val response = client.get("/meldekortservice/api/meldekort/korrigering?meldekortId=${id}") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(nyId, responseObject) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/PersonKtTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/PersonKtTest.kt index d3267ff8..df2fb897 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/PersonKtTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/PersonKtTest.kt @@ -3,12 +3,12 @@ package no.nav.meldeplikt.meldekortservice.api import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue -import io.ktor.config.* +import io.ktor.client.request.* +import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.locations.* +import io.ktor.server.locations.* import io.ktor.server.testing.* import io.mockk.* -import no.nav.meldeplikt.meldekortservice.config.Environment import no.nav.meldeplikt.meldekortservice.config.mainModule import no.nav.meldeplikt.meldekortservice.database.hentMidlertidigLagredeJournalposter import no.nav.meldeplikt.meldekortservice.model.MeldekortKontrollertType @@ -22,83 +22,34 @@ import no.nav.meldeplikt.meldekortservice.model.meldekort.Person import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Meldekortdetaljer import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.Sporsmal import no.nav.meldeplikt.meldekortservice.model.response.OrdsStringResponse -import no.nav.meldeplikt.meldekortservice.service.* import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper import no.nav.meldeplikt.meldekortservice.utils.defaultXmlMapper -import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais -import no.nav.security.mock.oauth2.MockOAuth2Server -import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback -import org.amshove.kluent.shouldBe -import org.amshove.kluent.shouldEndWith -import org.amshove.kluent.shouldStartWith import org.flywaydb.core.Flyway import org.flywaydb.core.api.output.MigrateResult -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import java.sql.SQLException import java.time.LocalDate import kotlin.test.assertEquals import kotlin.test.assertNotNull +import kotlin.test.assertTrue @KtorExperimentalLocationsAPI -class PersonKtTest { - private fun MapApplicationConfig.setOidcConfig() { - put("no.nav.security.jwt.issuers.size", "1") - put("no.nav.security.jwt.issuers.0.issuer_name", ISSUER_ID) - put("no.nav.security.jwt.issuers.0.discoveryurl", mockOAuth2Server.wellKnownUrl(ISSUER_ID).toString()) - put("no.nav.security.jwt.issuers.0.accepted_audience", REQUIRED_AUDIENCE) - put("ktor.environment", "local") - } - - private fun issueToken(): String = - mockOAuth2Server.issueToken( - ISSUER_ID, - "myclient", - DefaultOAuth2TokenCallback(audience = listOf(REQUIRED_AUDIENCE), claims = mapOf("pid" to "01020312345")) - ).serialize() - - companion object { - private const val ISSUER_ID = "default" - private const val REQUIRED_AUDIENCE = "default" - - private val mockOAuth2Server = MockOAuth2Server() - - private val env = Environment(dokarkivResendInterval = 0L) - - private var dbService = mockk() - private var arenaOrdsService = mockk() - private var kontrollService = mockk() - private var dokarkivService = mockk() - private var flywayConfig = mockk() - - @BeforeAll - @JvmStatic - fun setup() { - mockOAuth2Server.start(8091) - every { flywayConfig.migrate() } returns MigrateResult("", "", "") - - mockkStatic(::isCurrentlyRunningOnNais) - every { isCurrentlyRunningOnNais() } returns true - } - - @AfterAll - @JvmStatic - fun cleanup() { - mockOAuth2Server.shutdown() - } - } +class PersonKtTest : TestBase() { @Test - fun `get historiske meldekort returns ok with valid JWT`() { + fun `get historiske meldekort returns ok with valid JWT`() = testApplication { val period = 1 val fnr = "01020312345" val person = Person(1L, "Bob", "Kåre", "No", "Papp", listOf(), 10, listOf()) coEvery { arenaOrdsService.hentHistoriskeMeldekort(fnr, period) } returns (person) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -107,31 +58,32 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest( - HttpMethod.Get, - "/meldekortservice/api/person/historiskemeldekort?antallMeldeperioder=${period}" - ) { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(person.personId, responseObject.personId) - } } + + val response = client.get("/meldekortservice/api/person/historiskemeldekort?antallMeldeperioder=${period}") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(person.personId, responseObject.personId) } @Test - fun `get historiske meldekort returns 401-Unauthorized with missing JWT`() { + fun `get historiske meldekort returns 401-Unauthorized with missing JWT`() = testApplication { val period = 1 val fnr = "01020312345" val person = Person(1L, "Bob", "Kåre", "No", "Papp", listOf(), 10, listOf()) coEvery { arenaOrdsService.hentHistoriskeMeldekort(fnr, period) } returns (person) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -140,19 +92,15 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest( - HttpMethod.Get, - "/meldekortservice/api/person/historiskemeldekort?antallMeldeperioder=${period}" - ) { - }.apply { - response.status() shouldBe HttpStatusCode.Unauthorized - } } + + val response = client.get("/meldekortservice/api/person/historiskemeldekort?antallMeldeperioder=${period}") + + assertEquals(HttpStatusCode.Unauthorized, response.status) } @Test - fun `get person meldekort returns ok with valid JWT`() { + fun `get person meldekort returns ok with valid JWT`() = testApplication { val meldekort1 = Meldekort( 1L, KortType.MASKINELT_OPPDATERT.code, @@ -187,15 +135,21 @@ class PersonKtTest { 10, listOf() ) - val ordsStringResponse = - OrdsStringResponse(status = HttpStatusCode.OK, content = defaultXmlMapper.writeValueAsString(person)) + val ordsStringResponse = OrdsStringResponse( + status = HttpStatusCode.OK, + content = defaultXmlMapper.writeValueAsString(person) + ) coEvery { arenaOrdsService.hentMeldekort(any()) } returns (ordsStringResponse) coEvery { dbService.hentInnsendtMeldekort(1L) } returns (InnsendtMeldekort(meldekortId = 1L)) coEvery { dbService.hentInnsendtMeldekort(2L) } throws SQLException("Found no rows") + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -204,27 +158,31 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/person/meldekort") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(person.personId, responseObject.personId) - assertEquals(1, responseObject.meldekortListe?.size) - } } + + val response = client.get("/meldekortservice/api/person/meldekort") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(person.personId, responseObject.personId) + assertEquals(1, responseObject.meldekortListe?.size) } @Test - fun `get person meldekort returns NoContent status when no response from ORDS`() { + fun `get person meldekort returns NoContent status when no response from ORDS`() = testApplication { val ordsStringResponse = OrdsStringResponse(status = HttpStatusCode.BadRequest, content = "") coEvery { arenaOrdsService.hentMeldekort(any()) } returns (ordsStringResponse) + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -233,17 +191,17 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/person/meldekort") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - }.apply { - response.status() shouldBe HttpStatusCode.NoContent - } } + + val response = client.get("/meldekortservice/api/person/meldekort") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + } + + assertEquals(HttpStatusCode.NoContent, response.status) } @Test - fun `Kontroll or innsending of meldekort returns OK`() { + fun `Kontroll or innsending of meldekort returns OK`() = testApplication { val meldekortdetaljer = Meldekortdetaljer( id = "1", fodselsnr = "01020312345", @@ -259,9 +217,13 @@ class PersonKtTest { coEvery { dbService.settInnInnsendtMeldekort(any()) } just Runs coEvery { kontrollService.kontroller(any()) } returns meldekortKontrollertType + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -270,22 +232,22 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Post, "/meldekortservice/api/person/meldekort") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(ObjectMapper().writeValueAsString(meldekortdetaljer)) - }.apply { - assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - assertEquals(meldekortKontrollertType.meldekortId, responseObject.meldekortId) - } } + + val response = client.post("/meldekortservice/api/person/meldekort") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setBody(ObjectMapper().writeValueAsString(meldekortdetaljer)) + } + + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertEquals(meldekortKontrollertType.meldekortId, responseObject.meldekortId) } @Test - fun `Kontroll of meldekort returns ServiceUnavailable`() { + fun `Kontroll of meldekort returns ServiceUnavailable`() = testApplication { val meldekortdetaljer = Meldekortdetaljer( id = "1", fodselsnr = "01020312345", @@ -300,9 +262,13 @@ class PersonKtTest { coEvery { dbService.settInnInnsendtMeldekort(any()) } just Runs coEvery { kontrollService.kontroller(any()) } throws RuntimeException("Feil i meldekortkontroll-api") + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -311,19 +277,19 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Post, "/meldekortservice/api/person/meldekort") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(ObjectMapper().writeValueAsString(meldekortdetaljer)) - }.apply { - response.status() shouldBe HttpStatusCode.ServiceUnavailable - } } + + val response = client.post("/meldekortservice/api/person/meldekort") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setBody(ObjectMapper().writeValueAsString(meldekortdetaljer)) + } + + assertEquals(HttpStatusCode.ServiceUnavailable, response.status) } @Test - fun `OpprettJournalpost returnerer OK hvis DokarkivService er ok`() { + fun `OpprettJournalpost returnerer OK hvis DokarkivService er ok`() = testApplication { val journalpostId = 123456780L val dokumentInfoId = 123456781L @@ -339,9 +305,13 @@ class PersonKtTest { coEvery { dokarkivService.createJournalpost(any()) } returns journalpostResponse every { dbService.lagreJournalpostData(any(), any(), any()) } just Runs + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -350,30 +320,34 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Post, "/meldekortservice/api/person/opprettJournalpost") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(this::class.java.getResource("/journalpost.json")!!.readText()) - }.apply { - response.status() shouldBe HttpStatusCode.OK - } } + val response = client.post("/meldekortservice/api/person/opprettJournalpost") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setBody(this::class.java.getResource("/journalpost.json")!!.readText()) + } + + assertEquals(HttpStatusCode.OK, response.status) + // MeldekortId kommer fra tilleggsopplysninger i journalpost.json verify { dbService.lagreJournalpostData(journalpostId, dokumentInfoId, 1011121315) } } @Test - fun `OpprettJournalpost returnerer ServiceUnavailable hvis DokarkivService ikke er ok`() { + fun `OpprettJournalpost returnerer ServiceUnavailable hvis DokarkivService ikke er ok`() = testApplication { val journalpost = this::class.java.getResource("/journalpost.json") coEvery { dokarkivService.createJournalpost(any()) } throws Exception() every { dbService.lagreJournalpostMidlertidig(any()) } just Runs every { dbService.getConnection().hentMidlertidigLagredeJournalposter() } returns emptyList() + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") - withTestApplication({ - (environment.config as MapApplicationConfig).setOidcConfig() + environment { + config = setOidcConfig() + } + application { mainModule( env = env, mockDBService = dbService, @@ -382,18 +356,22 @@ class PersonKtTest { dokarkivService = dokarkivService, mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Post, "/meldekortservice/api/person/opprettJournalpost") { - addHeader(HttpHeaders.Authorization, "Bearer ${issueToken()}") - addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(journalpost!!.readText()) - }.apply { - response.status() shouldBe HttpStatusCode.OK - response.content?.shouldStartWith("{\"error\":\"Kan ikke opprette journalpost i dokumentarkiv med eksternReferanseId ") - response.content?.shouldEndWith("for meldekort med id 1011121315\"}") - } } + val response = client.post("/meldekortservice/api/person/opprettJournalpost") { + header(HttpHeaders.Authorization, "Bearer ${issueTokenWithPid()}") + header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setBody(journalpost!!.readText()) + } + + assertEquals(HttpStatusCode.OK, response.status) + assertTrue( + response.bodyAsText() + .startsWith("{\"error\":\"Kan ikke opprette journalpost i dokumentarkiv med eksternReferanseId ") + ) + // MeldekortId kommer fra tilleggsopplysninger i journalpost.json + assertTrue(response.bodyAsText().endsWith("for meldekort med id 1011121315\"}")) + verify { dbService.lagreJournalpostMidlertidig( jacksonObjectMapper().readValue( diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/TestBase.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/TestBase.kt new file mode 100644 index 00000000..d8f07efd --- /dev/null +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/TestBase.kt @@ -0,0 +1,78 @@ +package no.nav.meldeplikt.meldekortservice.api + +import io.ktor.server.config.* +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import no.nav.meldeplikt.meldekortservice.config.Environment +import no.nav.meldeplikt.meldekortservice.service.ArenaOrdsService +import no.nav.meldeplikt.meldekortservice.service.DBService +import no.nav.meldeplikt.meldekortservice.service.DokarkivService +import no.nav.meldeplikt.meldekortservice.service.KontrollService +import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais +import no.nav.security.mock.oauth2.MockOAuth2Server +import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll + +open class TestBase { + + companion object { + const val ISSUER_ID = "default" + const val REQUIRED_AUDIENCE = "default" + + var mockOAuth2Server = MockOAuth2Server() + + val env = Environment(dokarkivResendInterval = 0L) + + var dbService = mockk() + var arenaOrdsService = mockk() + var kontrollService = mockk() + var dokarkivService = mockk() + + @BeforeAll + @JvmStatic + fun setup() { + mockOAuth2Server = MockOAuth2Server() + mockOAuth2Server.start(8091) + + mockkStatic(::isCurrentlyRunningOnNais) + every { isCurrentlyRunningOnNais() } returns true + } + + @AfterAll + @JvmStatic + fun cleanup() { + mockOAuth2Server.shutdown() + } + } + + fun setOidcConfig(): MapApplicationConfig { + return MapApplicationConfig( + "ktor.environment" to "test", + "no.nav.security.jwt.issuers.size" to "1", + "no.nav.security.jwt.issuers.0.issuer_name" to ISSUER_ID, + "no.nav.security.jwt.issuers.0.discoveryurl" to mockOAuth2Server.wellKnownUrl(ISSUER_ID).toString(), + "no.nav.security.jwt.issuers.0.accepted_audience" to REQUIRED_AUDIENCE, + "ktor.environment" to "local" + ) + } + + fun issueTokenWithSub(): String = mockOAuth2Server.issueToken( + ISSUER_ID, + "myclient", + DefaultOAuth2TokenCallback( + audience = listOf(REQUIRED_AUDIENCE), + claims = mapOf("sub" to "01020312345") + ) + ).serialize() + + fun issueTokenWithPid(): String = mockOAuth2Server.issueToken( + ISSUER_ID, + "myclient", + DefaultOAuth2TokenCallback( + audience = listOf(REQUIRED_AUDIENCE), + claims = mapOf("pid" to "01020312345") + ) + ).serialize() +} \ No newline at end of file diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/WeblogicKtTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/WeblogicKtTest.kt index 46216a96..ae2c203a 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/WeblogicKtTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/api/WeblogicKtTest.kt @@ -1,84 +1,84 @@ package no.nav.meldeplikt.meldekortservice.api import com.fasterxml.jackson.module.kotlin.readValue +import io.ktor.client.request.* +import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.locations.* +import io.ktor.server.locations.* import io.ktor.server.testing.* import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject -import io.mockk.mockkStatic import no.nav.meldeplikt.meldekortservice.config.SoapConfig import no.nav.meldeplikt.meldekortservice.config.mainModule import no.nav.meldeplikt.meldekortservice.model.WeblogicPing import no.nav.meldeplikt.meldekortservice.service.SoapServiceImpl import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper -import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais -import org.amshove.kluent.shouldBe import org.flywaydb.core.Flyway import org.flywaydb.core.api.output.MigrateResult import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue @KtorExperimentalLocationsAPI -class WeblogicKtTest { - private val flywayConfig = mockk() +class WeblogicKtTest : TestBase() { + private val soapServiceImpl = mockk() @Test - fun `test weblogic returns true when Arena is up`() { - val soapServiceImpl = mockk() - - mockkStatic(::isCurrentlyRunningOnNais) - every { isCurrentlyRunningOnNais() } returns false + fun `test weblogic returns true when Arena is up`() = testApplication { + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") mockkObject(SoapConfig) - every { flywayConfig.migrate() } returns MigrateResult("", "", "") every { SoapConfig.soapService() } returns soapServiceImpl every { soapServiceImpl.pingWeblogic() } returns WeblogicPing(erWeblogicOppe = true) - withTestApplication({ + environment { + config = setOidcConfig() + } + application { mainModule( arenaOrdsService = mockk(), kontrollService = mockk(), mockDBService = mockk(), mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/weblogic") { - }.apply { - kotlin.test.assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - kotlin.test.assertTrue(responseObject.erWeblogicOppe) - } } + + val response = client.get("/meldekortservice/api/weblogic") + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertTrue(responseObject.erWeblogicOppe) } @Test - fun `test weblogic returns false when Arena is not up`() { - val soapServiceImpl = mockk() + fun `test weblogic returns false when Arena is not up`() = testApplication { + val flywayConfig = mockk() + every { flywayConfig.migrate() } returns MigrateResult("", "", "") mockkObject(SoapConfig) - mockkStatic(::isCurrentlyRunningOnNais) - every { isCurrentlyRunningOnNais() } returns false - every { flywayConfig.migrate() } returns MigrateResult("", "", "") every { SoapConfig.soapService() } returns soapServiceImpl every { soapServiceImpl.pingWeblogic() } returns WeblogicPing(erWeblogicOppe = false) - withTestApplication({ + environment { + config = setOidcConfig() + } + application { mainModule( arenaOrdsService = mockk(), kontrollService = mockk(), mockDBService = mockk(), mockFlywayConfig = flywayConfig ) - }) { - handleRequest(HttpMethod.Get, "/meldekortservice/api/weblogic") { - }.apply { - kotlin.test.assertNotNull(response.content) - val responseObject = defaultObjectMapper.readValue(response.content!!) - response.status() shouldBe HttpStatusCode.OK - kotlin.test.assertFalse(responseObject.erWeblogicOppe) - } } + + val response = client.get("/meldekortservice/api/weblogic") + assertEquals(HttpStatusCode.OK, response.status) + assertNotNull(response.bodyAsText()) + val responseObject = defaultObjectMapper.readValue(response.bodyAsText()) + assertFalse(responseObject.erWeblogicOppe) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNyttTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNyttTest.kt index d29cbd1a..c439d196 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNyttTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/coroutine/SendJournalposterPaaNyttTest.kt @@ -239,4 +239,4 @@ class SendJournalposterPaaNyttTest { assertEquals(1, journalpostData[0].second) // Retries } } -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/DatabaseTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/DatabaseTest.kt index 28e1a5db..6dccbeae 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/DatabaseTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/DatabaseTest.kt @@ -2,10 +2,13 @@ package no.nav.meldeplikt.meldekortservice.database import kotlinx.coroutines.runBlocking import no.nav.meldeplikt.meldekortservice.model.database.InnsendtMeldekort -import org.amshove.kluent.* import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import java.sql.SQLException +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals class DatabaseTest { @@ -34,8 +37,8 @@ class DatabaseTest { fun `Henter ut alle innsendte meldekort`() { runBlocking { val result = database.dbQuery { hentAlleInnsendteMeldekort() } - result.size `should be equal to` alleInnsendtMeldekort.size - result `should contain all` alleInnsendtMeldekort + assertEquals(alleInnsendtMeldekort.size, result.size) + assertContentEquals(alleInnsendtMeldekort, result) } } @@ -43,16 +46,17 @@ class DatabaseTest { fun `Henter ut et innsendt meldekort`() { runBlocking { val result = database.dbQuery { hentInnsendtMeldekort(innsendtMeldekort1.meldekortId) } - result.meldekortId `should be equal to` innsendtMeldekort1.meldekortId + assertEquals(innsendtMeldekort1.meldekortId, result.meldekortId) } } @Test fun `Henter ut et innsendt meldekort som ikke finnes`() { - invoking { + val exception = assertThrows { runBlocking { database.dbQuery { hentInnsendtMeldekort(123L) } } - } shouldThrow SQLException::class `with message` "Found no rows" + } + Assertions.assertEquals("Found no rows", exception.localizedMessage) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/TestQueries.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/TestQueries.kt index a707dab9..083f25e5 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/TestQueries.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/database/TestQueries.kt @@ -63,4 +63,4 @@ fun Connection.hentAlleMidlertidigLagredeJournalposter(): List } return list -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortMapperTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortMapperTest.kt index 020eb951..e5c2c024 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortMapperTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/mapper/MeldekortMapperTest.kt @@ -1,13 +1,14 @@ package no.nav.meldeplikt.meldekortservice.mapper +import io.mockk.every +import io.mockk.mockk +import no.nav.meldeplikt.meldekortservice.model.database.InnsendtMeldekort import no.nav.meldeplikt.meldekortservice.model.enum.KortType import no.nav.meldeplikt.meldekortservice.model.meldekort.FravaerType import no.nav.meldeplikt.meldekortservice.model.meldekort.Meldekort import no.nav.meldeplikt.meldekortservice.model.meldekort.Person import no.nav.meldeplikt.meldekortservice.service.DBService import org.junit.jupiter.api.Test -import org.mockito.Mockito.`when` -import org.mockito.Mockito.mock import java.sql.SQLException import java.time.LocalDate @@ -15,8 +16,10 @@ class MeldekortMapperTest { @Test fun testMeldekortMapper() { - val mockMeldekortService = mock(DBService::class.java) - `when`(mockMeldekortService.hentInnsendtMeldekort(2L)).thenAnswer { throw SQLException("Found no rows") } + val mockDBService = mockk() + every { mockDBService.hentInnsendtMeldekort(1) } returns InnsendtMeldekort(1) + every { mockDBService.hentInnsendtMeldekort(2) } throws SQLException("Found no rows") + val meldekort1 = Meldekort( 1L, KortType.MASKINELT_OPPDATERT.code, @@ -44,7 +47,7 @@ class MeldekortMapperTest { val meldekortListe = listOf(meldekort1, meldekort2) val fravaerListe = listOf() val person = Person(1L, "Bob", "Kåre", "No", "Papp", meldekortListe, 10, fravaerListe) - val filtrert = MeldekortMapper.filtrerMeldekortliste(person, mockMeldekortService) + val filtrert = MeldekortMapper.filtrerMeldekortliste(person, mockDBService) assert(filtrert.meldekortListe?.size == 1) } diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsServiceTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsServiceTest.kt index 474c9c48..047301f1 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsServiceTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/ArenaOrdsServiceTest.kt @@ -2,9 +2,6 @@ package no.nav.meldeplikt.meldekortservice.service import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue -import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe -import io.kotest.matchers.string.shouldStartWith import io.ktor.client.* import io.ktor.client.engine.mock.* import io.ktor.http.* @@ -16,10 +13,10 @@ import no.nav.meldeplikt.meldekortservice.model.feil.OrdsException import no.nav.meldeplikt.meldekortservice.model.response.OrdsStringResponse import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper import no.nav.meldeplikt.meldekortservice.utils.isCurrentlyRunningOnNais -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import kotlin.test.assertEquals class ArenaOrdsServiceTest { private val fnr = "1111111111" @@ -93,10 +90,13 @@ class ArenaOrdsServiceTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> - request.method shouldBe HttpMethod.Get - request.headers["Authorization"] shouldNotBe null - request.headers["Authorization"] shouldStartWith "Bearer $DUMMY_TOKEN" - request.url.toString() shouldBe "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/historiske?fnr=1234&antMeldeperioder=10" + assertEquals(HttpMethod.Get, request.method) + assertEquals("Bearer $DUMMY_TOKEN", request.headers["Authorization"]) + assertEquals( + "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/historiske?fnr=1234&antMeldeperioder=10", + request.url.toString() + ) + respond( xmlString ) @@ -139,10 +139,13 @@ class ArenaOrdsServiceTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> - request.method shouldBe HttpMethod.Get - request.headers["Authorization"] shouldNotBe null - request.headers["Authorization"] shouldStartWith "Bearer $DUMMY_TOKEN" - request.url.toString() shouldBe "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/detaljer?meldekortId=1" + assertEquals(HttpMethod.Get, request.method) + assertEquals("Bearer $DUMMY_TOKEN", request.headers["Authorization"]) + assertEquals( + "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/detaljer?meldekortId=1", + request.url.toString() + ) + respond( xmlString ) @@ -163,11 +166,14 @@ class ArenaOrdsServiceTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> - request.method shouldBe HttpMethod.Post - request.headers["Authorization"] shouldNotBe null - request.headers["Authorization"] shouldStartWith "Bearer $DUMMY_TOKEN" - request.headers["meldekortId"] shouldBe "123" - request.url.toString() shouldBe "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/kopi" + assertEquals(HttpMethod.Post, request.method) + assertEquals("Bearer $DUMMY_TOKEN", request.headers["Authorization"]) + assertEquals("123", request.headers["meldekortId"]) + assertEquals( + "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/kopi", + request.url.toString() + ) + respondOk( xmlString ) @@ -189,11 +195,14 @@ class ArenaOrdsServiceTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> - request.method shouldBe HttpMethod.Post - request.headers["Authorization"] shouldNotBe null - request.headers["Authorization"] shouldStartWith "Bearer $DUMMY_TOKEN" - request.headers["meldekortId"] shouldBe "123" - request.url.toString() shouldBe "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/kopi" + assertEquals(HttpMethod.Post, request.method) + assertEquals("Bearer $DUMMY_TOKEN", request.headers["Authorization"]) + assertEquals("123", request.headers["meldekortId"]) + assertEquals( + "https://dummyurl.nav.no/api/v1/meldeplikt/meldekort/kopi", + request.url.toString() + ) + respondOk( xmlString ) diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DBServiceTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DBServiceTest.kt index 12a534b6..eadf788d 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DBServiceTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DBServiceTest.kt @@ -5,12 +5,10 @@ import kotlinx.coroutines.runBlocking import no.nav.meldeplikt.meldekortservice.database.* import no.nav.meldeplikt.meldekortservice.model.database.InnsendtMeldekort import no.nav.meldeplikt.meldekortservice.model.dokarkiv.Journalpost -import org.amshove.kluent.`with message` -import org.amshove.kluent.invoking -import org.amshove.kluent.shouldThrow import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import java.sql.SQLException class DBServiceTest { @@ -37,11 +35,12 @@ class DBServiceTest { fun `skal kaste Exception hvis henter ikke eksisterende innsendt meldekort`() { val dbService = DBService(database) - invoking { + val exception = assertThrows { runBlocking { dbService.hentInnsendtMeldekort(2L) } - } shouldThrow SQLException::class `with message` "Found no rows" + } + assertEquals("Found no rows", exception.localizedMessage) } @Test @@ -54,8 +53,10 @@ class DBServiceTest { journalpostJson, Journalpost::class.java ) - val journalpost1 = journalpost.copy(eksternReferanseId = "11") - val journalpost2 = journalpost.copy(eksternReferanseId = "22") + val id1 = "123456789012345678901234567890123456" + val id2 = "223456789012345678901234567890123456" + val journalpost1 = journalpost.copy(eksternReferanseId = id1) + val journalpost2 = journalpost.copy(eksternReferanseId = id2) runBlocking { // Lagre @@ -65,19 +66,19 @@ class DBServiceTest { // Hente var journalpostData = connection.hentMidlertidigLagredeJournalposter() assertEquals(2, journalpostData.size) - assertEquals(1, journalpostData.filter { it.first == "11" }.size) - assertEquals(1, journalpostData.filter { it.first == "22" }.size) + assertEquals(1, journalpostData.filter { it.first == id1 }.size) + assertEquals(1, journalpostData.filter { it.first == id2 }.size) // Slette - connection.sletteMidlertidigLagretJournalpost("11") + connection.sletteMidlertidigLagretJournalpost(id1) // Oppdater - connection.oppdaterMidlertidigLagretJournalpost("22", 5) + connection.oppdaterMidlertidigLagretJournalpost(id2, 5) // Hente journalpostData = connection.hentMidlertidigLagredeJournalposter() assertEquals(1, journalpostData.size) - val data = journalpostData.first { it.first == "22" } + val data = journalpostData.first { it.first == id2 } assertEquals(5, data.third) } } diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivServiceTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivServiceTest.kt index a5a7afe1..b6defe3c 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivServiceTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/DokarkivServiceTest.kt @@ -2,8 +2,9 @@ package no.nav.meldeplikt.meldekortservice.service import io.ktor.client.* import io.ktor.client.engine.mock.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.http.* +import io.ktor.serialization.jackson.* import io.mockk.every import io.mockk.mockkStatic import kotlinx.coroutines.runBlocking @@ -57,8 +58,11 @@ class DokarkivServiceTest { val token = AccessToken("dG9rZW4=", "Bearer", 3600) val client = HttpClient(MockEngine) { - install(JsonFeature) { - serializer = JacksonSerializer { defaultObjectMapper } + install(ContentNegotiation) { + register( + ContentType.Application.Json, + JacksonConverter(defaultObjectMapper) + ) } expectSuccess = false engine { @@ -106,4 +110,4 @@ class DokarkivServiceTest { assertEquals(journalpostResponse.dokumenter[0].dokumentInfoId, response.dokumenter[0].dokumentInfoId) } } -} \ No newline at end of file +} diff --git a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollServiceTest.kt b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollServiceTest.kt index b0e16f65..a09d4523 100644 --- a/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollServiceTest.kt +++ b/src/test/kotlin/no/nav/meldeplikt/meldekortservice/service/KontrollServiceTest.kt @@ -1,12 +1,10 @@ package no.nav.meldeplikt.meldekortservice.service -import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe -import io.kotest.matchers.string.shouldStartWith import io.ktor.client.* import io.ktor.client.engine.mock.* -import io.ktor.client.features.json.* +import io.ktor.client.plugins.contentnegotiation.* import io.ktor.http.* +import io.ktor.serialization.jackson.* import io.mockk.coEvery import io.mockk.mockk import kotlinx.coroutines.runBlocking @@ -15,7 +13,6 @@ import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.kontroll.Melde import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.kontroll.response.KontrollFeil import no.nav.meldeplikt.meldekortservice.model.meldekortdetaljer.kontroll.response.KontrollResponse import no.nav.meldeplikt.meldekortservice.utils.defaultObjectMapper -import no.nav.meldeplikt.meldekortservice.utils.objectMapper import org.junit.jupiter.api.Test import java.time.LocalDate import java.time.format.DateTimeFormatter @@ -70,17 +67,19 @@ class KontrollServiceTest { ) val client = HttpClient(MockEngine) { - install(JsonFeature) { - serializer = JacksonSerializer { objectMapper } + install(ContentNegotiation) { + register( + ContentType.Application.Json, + JacksonConverter(defaultObjectMapper) + ) } engine { addHandler { request -> - request.method shouldBe HttpMethod.Post - request.headers["Authorization"] shouldNotBe null - request.headers["Authorization"] shouldStartWith "Bearer token" - request.body.contentType.toString() shouldBe "application/json" - request.url.toString() shouldBe "https://dummyurl.nav.no/api/v1/kontroll" + assertEquals(HttpMethod.Post, request.method) + assertEquals("Bearer token", request.headers["Authorization"]) + assertEquals(ContentType.Application.Json, request.body.contentType) + assertEquals("https://dummyurl.nav.no/api/v1/kontroll", request.url.toString()) respond( defaultObjectMapper.writeValueAsString(kontrollResponse), HttpStatusCode.OK, diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 8a485d3b..2f543192 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -1,3 +1,11 @@ - - \ No newline at end of file + + + + + + + + + +