Skip to content

Commit

Permalink
Legg til postgres database, og faktisk lagring og henting av journalp…
Browse files Browse the repository at this point in the history
…ostIder.

Co-authored-by: Giao The Cung <giaothe@gmail.com>
  • Loading branch information
MariusEriksen and gtcno committed May 22, 2024
1 parent 88aa94b commit b27bb67
Show file tree
Hide file tree
Showing 14 changed files with 263 additions and 18 deletions.
20 changes: 20 additions & 0 deletions .nais/nais.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,23 @@ spec:
- application: dp-saksbehandling
kafka:
pool: {{ kafka_pool }}
gcp:
sqlInstances:
- collation: nb_NO.UTF8
databases:
- envVarPrefix: DB
name: oppslag_journalpostid
diskAutoresize: true
diskType: SSD
highAvailability: { { db.highAvailability } }
insights:
enabled: true
queryStringLength: 4500
recordApplicationTags: true
recordClientAddress: true
maintenance:
day: 1
hour: 4
pointInTimeRecovery: { { db.pointInTimeRecovery } }
tier: { { db.tier } }
type: POSTGRES_15
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
testImplementation(libs.mockk)
testImplementation(libs.kotest.assertions.core)
testImplementation("io.ktor:ktor-server-test-host-jvm:${libs.versions.ktor.get()}")
testImplementation(libs.bundles.postgres.test)
}

application {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package no.nav.dagpenger.oppslag.journalpost.id

import mu.KotlinLogging
import no.nav.dagpenger.oppslag.journalpost.id.PostgresDataSourceBuilder.runMigration
import no.nav.helse.rapids_rivers.RapidApplication
import no.nav.helse.rapids_rivers.RapidsConnection

Expand All @@ -9,7 +10,7 @@ internal class ApplicationBuilder(config: Map<String, String>) : RapidsConnectio
private val logger = KotlinLogging.logger { }
}

val repository = InmemoryRepository()
val repository = InMemoryJournalpostRepository()

private val rapidsConnection: RapidsConnection =
RapidApplication.Builder(RapidApplication.RapidApplicationConfig.fromEnv(config))
Expand All @@ -32,7 +33,7 @@ internal class ApplicationBuilder(config: Map<String, String>) : RapidsConnectio
}

override fun onStartup(rapidsConnection: RapidsConnection) {
// runMigration()
runMigration()
logger.info { "Starter opp dp-oppslag-journalpost-id" }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import java.util.UUID

private val logger = KotlinLogging.logger { }

class InnsendingFerdigstiltMottak(rapidsConnection: RapidsConnection, private val repository: Repository) :
class InnsendingFerdigstiltMottak(rapidsConnection: RapidsConnection, private val journalpostRepository: JournalpostRepository) :
River.PacketListener {
init {
River(rapidsConnection).apply {
Expand All @@ -28,7 +28,7 @@ class InnsendingFerdigstiltMottak(rapidsConnection: RapidsConnection, private va
) {
val journalpostId = packet["journalpostId"].asText()
val søknadId = packet["søknadsData.søknad_uuid"].asUUID()
repository.lagre(søknadId, journalpostId)
journalpostRepository.lagre(søknadId, journalpostId)
logger.info { "Lagret $søknadId -> $journalpostId" }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import java.util.UUID

fun Application.journalpostApi(repository: Repository) {
fun Application.journalpostApi(journalpostRepository: JournalpostRepository) {
apiConfig()

routing {
route("v1/journalpost/{søknadId}") {
get {
call.respond(HttpStatusCode.OK, repository.hent(call.søknadId()))
call.respond(HttpStatusCode.OK, journalpostRepository.hent(call.søknadId()))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package no.nav.dagpenger.oppslag.journalpost.id

import java.util.UUID

interface Repository {
interface JournalpostRepository {
fun lagre(
knadId: UUID,
journalpostId: String,
Expand All @@ -13,7 +13,7 @@ interface Repository {
class JournalpostIkkeFunnet(msg: String) : RuntimeException(msg)
}

class InmemoryRepository : Repository {
class InMemoryJournalpostRepository : JournalpostRepository {
private val storage = mutableMapOf<UUID, String>()

override fun lagre(
Expand All @@ -25,5 +25,5 @@ class InmemoryRepository : Repository {

override fun hent(søknadId: UUID): String =
storage[søknadId]
?: throw Repository.JournalpostIkkeFunnet("Fant ikke journalpost for søknadId $søknadId")
?: throw JournalpostRepository.JournalpostIkkeFunnet("Fant ikke journalpost for søknadId $søknadId")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package no.nav.dagpenger.oppslag.journalpost.id

import ch.qos.logback.core.util.OptionHelper.getEnv
import ch.qos.logback.core.util.OptionHelper.getSystemProperty
import com.zaxxer.hikari.HikariDataSource
import org.flywaydb.core.Flyway
import org.flywaydb.core.api.configuration.FluentConfiguration

// Understands how to create a data source from environment variables
internal object PostgresDataSourceBuilder {
const val DB_USERNAME_KEY = "DB_USERNAME"
const val DB_PASSWORD_KEY = "DB_PASSWORD"
const val DB_DATABASE_KEY = "DB_DATABASE"
const val DB_HOST_KEY = "DB_HOST"
const val DB_PORT_KEY = "DB_PORT"

private fun getOrThrow(key: String): String = getEnv(key) ?: getSystemProperty(key)

val dataSource by lazy {
HikariDataSource().apply {
dataSourceClassName = "org.postgresql.ds.PGSimpleDataSource"
addDataSourceProperty("serverName", getOrThrow(DB_HOST_KEY))
addDataSourceProperty("portNumber", getOrThrow(DB_PORT_KEY))
addDataSourceProperty("databaseName", getOrThrow(DB_DATABASE_KEY))
addDataSourceProperty("user", getOrThrow(DB_USERNAME_KEY))
addDataSourceProperty("password", getOrThrow(DB_PASSWORD_KEY))
maximumPoolSize = 10
minimumIdle = 1
idleTimeout = 10001
connectionTimeout = 1000
maxLifetime = 30001
}
}

private fun flyWayBuilder() = Flyway.configure().connectRetries(10)

private val flyWayBuilder: FluentConfiguration = Flyway.configure().connectRetries(10)

fun clean() = flyWayBuilder.cleanDisabled(false).dataSource(dataSource).load().clean()

internal fun runMigration(initSql: String? = null): Int =
flyWayBuilder
.dataSource(dataSource)
.initSql(initSql)
.load()
.migrate()
.migrations
.size

internal fun runMigrationTo(target: String): Int =
flyWayBuilder()
.dataSource(dataSource)
.target(target)
.load()
.migrate()
.migrations
.size
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package no.nav.dagpenger.oppslag.journalpost.id

import kotliquery.queryOf
import kotliquery.sessionOf
import java.util.UUID
import javax.sql.DataSource

class PostgresJournalpostRepository(private val dataSource: DataSource) : JournalpostRepository {
override fun lagre(
knadId: UUID,
journalpostId: String,
) {
sessionOf(dataSource).use { session ->
session.run(
queryOf(
//language=PostgreSQL
statement =
"""
INSERT INTO soknad_id_journalpost_id_mapping_v1
(soknad_id, journalpost_id)
VALUES
(:soknad_id, :journalpost_id)
ON CONFLICT (soknad_id) DO NOTHING
""".trimIndent(),
paramMap =
mapOf(
"soknad_id" to søknadId,
"journalpost_id" to journalpostId,
),
).asUpdate,
)
}
}

override fun hent(søknadId: UUID): String {
sessionOf(dataSource).use { session ->
return session.run(
queryOf(
//language=PostgreSQL
statement =
"""
SELECT journalpost_id
FROM soknad_id_journalpost_id_mapping_v1
WHERE soknad_id = :soknad_id
""".trimIndent(),
paramMap = mapOf("soknad_id" to søknadId),
).map { row ->
row.string("journalpost_id")
}.asSingle,
) ?: throw JournalpostRepository.JournalpostIkkeFunnet("Fant ikke journapostId for søknadId: $søknadId")
}
}
}
6 changes: 6 additions & 0 deletions src/main/resources/db/migration/V1__CREATE_TABLES.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS soknad_id_journalpost_id_mapping_v1
(
soknad_id UUID PRIMARY KEY,
journalpost_id TEXT NOT NULL,
registrert_tidspunkt TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ class InnsendingFerdigstiltMottakTest {

@Test
fun `Skal ta tak i riktige pakker`() {
val repository =
mockk<Repository>().also {
val journalpostRepository =
mockk<JournalpostRepository>().also {
every { it.lagre(any(), any()) } just runs
}

InnsendingFerdigstiltMottak(testRapid, repository)
InnsendingFerdigstiltMottak(testRapid, journalpostRepository)

//language=JSON
testRapid.sendTestMessage(
Expand All @@ -36,6 +36,6 @@ class InnsendingFerdigstiltMottakTest {
""".trimIndent(),
)

verify(exactly = 1) { repository.lagre(UUID.fromString("f0509e9a-f913-45cb-9aa7-ed7bafcb9e93"), "662317896") }
verify(exactly = 1) { journalpostRepository.lagre(UUID.fromString("f0509e9a-f913-45cb-9aa7-ed7bafcb9e93"), "662317896") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import io.mockk.mockk
import org.junit.jupiter.api.Test
import java.util.UUID.randomUUID

class JournalpostidApiTest {
class JournalpostIdApiTest {
@Test
fun `Skal kunne finne journalpost id fra søknad id`() {
val journalpostId = "123"
val søknadId = randomUUID()
val repository =
InmemoryRepository().also {
InMemoryJournalpostRepository().also {
it.lagre(søknadId, journalpostId)
}
withOppgaveApi(repository = repository) {
withOppgaveApi(journalpostRepository = repository) {
client.get("v1/journalpost/$søknadId").let { response ->
response.status shouldBe HttpStatusCode.OK
response.bodyAsText() shouldBe journalpostId
Expand All @@ -29,11 +29,11 @@ class JournalpostidApiTest {
}

private fun withOppgaveApi(
repository: Repository = mockk<Repository>(relaxed = true),
journalpostRepository: JournalpostRepository = mockk<JournalpostRepository>(relaxed = true),
test: suspend ApplicationTestBuilder.() -> Unit,
) {
testApplication {
application { journalpostApi(repository) }
application { journalpostApi(journalpostRepository) }
test()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package no.nav.dagpenger.oppslag.journalpost.id

import com.zaxxer.hikari.HikariDataSource
import org.flywaydb.core.internal.configuration.ConfigUtils
import org.testcontainers.containers.PostgreSQLContainer
import javax.sql.DataSource

internal object Postgres {
val instance by lazy {
PostgreSQLContainer<Nothing>("postgres:15.5").apply {
start()
}
}

fun withMigratedDb(block: (ds: DataSource) -> Unit) {
withCleanDb {
PostgresDataSourceBuilder.runMigration()
block(PostgresDataSourceBuilder.dataSource)
}
}

fun withMigratedDb(): HikariDataSource {
setup()
PostgresDataSourceBuilder.runMigration()
return PostgresDataSourceBuilder.dataSource
}

fun setup() {
System.setProperty(PostgresDataSourceBuilder.DB_HOST_KEY, instance.host)
System.setProperty(
PostgresDataSourceBuilder.DB_PORT_KEY,
instance.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT).toString(),
)
System.setProperty(PostgresDataSourceBuilder.DB_DATABASE_KEY, instance.databaseName)
System.setProperty(PostgresDataSourceBuilder.DB_PASSWORD_KEY, instance.password)
System.setProperty(PostgresDataSourceBuilder.DB_USERNAME_KEY, instance.username)
}

fun tearDown() {
System.clearProperty(PostgresDataSourceBuilder.DB_PASSWORD_KEY)
System.clearProperty(PostgresDataSourceBuilder.DB_USERNAME_KEY)
System.clearProperty(PostgresDataSourceBuilder.DB_HOST_KEY)
System.clearProperty(PostgresDataSourceBuilder.DB_PORT_KEY)
System.clearProperty(PostgresDataSourceBuilder.DB_DATABASE_KEY)
System.clearProperty(ConfigUtils.CLEAN_DISABLED)
}

fun withCleanDb(block: () -> Unit) {
setup()
PostgresDataSourceBuilder.clean().run {
block()
}.also {
tearDown()
}
}

fun withCleanDb(
target: String,
setup: () -> Unit,
test: () -> Unit,
) {
this.setup()
PostgresDataSourceBuilder.clean().run {
PostgresDataSourceBuilder.runMigrationTo(target)
setup()
PostgresDataSourceBuilder.runMigration()
test()
}.also {
tearDown()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.nav.dagpenger.oppslag.journalpost.id

import io.kotest.matchers.shouldBe
import no.nav.dagpenger.oppslag.journalpost.id.Postgres.withMigratedDb
import org.junit.jupiter.api.Test
import java.util.UUID

class PostgresJournalpostRepositoryTest {
@Test
fun `Skal kunne lagre og hente journalpostId basert på søknadId`() =
withMigratedDb { ds ->
val journalpostRepository = PostgresJournalpostRepository(dataSource = ds)
val søknadId = UUID.randomUUID()
val journalpostId = "123"
journalpostRepository.lagre(søknadId, journalpostId)
journalpostRepository.hent(søknadId) shouldBe journalpostId
}
}
Loading

0 comments on commit b27bb67

Please sign in to comment.