diff --git a/build.gradle.kts b/build.gradle.kts index e97c8f4..457e316 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,24 +18,19 @@ repositories { } dependencies { - implementation(kotlin("stdlib-jdk8")) implementation("org.http4k:http4k-core:6.28.1.0") implementation("org.http4k:http4k-server-jetty:6.28.1.0") implementation("org.http4k:http4k-format-moshi:6.28.1.0") implementation("com.natpryce:konfig:1.6.10.0") implementation("com.squareup.moshi:moshi:1.15.2") implementation("com.squareup.moshi:moshi-kotlin:1.15.2") - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.10") implementation("org.jetbrains.kotlin:kotlin-reflect:2.3.10") implementation("com.github.ben-manes.caffeine:caffeine:3.2.3") implementation("ch.qos.logback:logback-classic:1.5.29") - implementation("ch.qos.logback.contrib:logback-json-classic:0.1.5") - implementation("de.gessnerfl.logback:logback-gson-formatter:0.1.0") implementation("io.github.oshai:kotlin-logging:7.0.14") testImplementation("io.kotest:kotest-assertions-core:6.1.3") - testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.19") testImplementation("io.mockk:mockk:1.14.9") - testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.19") + testImplementation("io.kotest:kotest-runner-junit5:6.1.3") testRuntimeOnly("org.junit.platform:junit-platform-launcher") testImplementation("com.karumi.kotlinsnapshot:core:2.3.0") } @@ -53,9 +48,7 @@ tasks.withType { } tasks.withType { - useJUnitPlatform { - includeEngines("spek2") - } + useJUnitPlatform() } tasks.register("dockerBuildProperties") { diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index e2cc6a5..b9839a2 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,13 +1,7 @@ - - - yyyy-MM-dd'T'HH:mm:ss.SSSXXX - - true - - + diff --git a/src/test/kotlin/no/foreningenbs/usersapi/MainSpec.kt b/src/test/kotlin/no/foreningenbs/usersapi/MainSpec.kt index 62fec77..abad544 100644 --- a/src/test/kotlin/no/foreningenbs/usersapi/MainSpec.kt +++ b/src/test/kotlin/no/foreningenbs/usersapi/MainSpec.kt @@ -1,8 +1,6 @@ package no.foreningenbs.usersapi -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import io.kotest.core.spec.style.DescribeSpec import io.kotest.matchers.shouldBe import no.foreningenbs.usersapi.hmac.Hmac import org.http4k.core.ContentType @@ -12,195 +10,159 @@ import org.http4k.core.Status import org.http4k.core.body.form import org.http4k.core.with import org.http4k.lens.Header.CONTENT_TYPE -import org.spekframework.spek2.Spek -import org.spekframework.spek2.lifecycle.CachingMode -import org.spekframework.spek2.style.specification.describe - -object MainSpec : Spek({ - describe("Main") { - describe("app") { - val ldap = createLdapMock() - val dataProvider = DataProvider(Config, ldap) - val app = app(ldap, dataProvider) - - describe("hmac protected route") { - describe("request with missing hmac") { - val res by memoized(mode = CachingMode.EACH_GROUP) { - app(Request(Method.GET, "/users")) - } - it("should fail") { - res.status shouldBe Status.UNAUTHORIZED +class MainSpec : + DescribeSpec({ + describe("Main") { + describe("app") { + val ldap = createLdapMock() + val dataProvider = DataProvider(Config, ldap) + val app = app(ldap, dataProvider) + + describe("hmac protected route") { + describe("request with missing hmac") { + it("should fail") { + val res = app(Request(Method.GET, "/users")) + res.status shouldBe Status.UNAUTHORIZED + } } - } - describe("request with bad hmac") { - val res by memoized(mode = CachingMode.EACH_GROUP) { - val hmac = Hmac(100, "some invalid key") + describe("request with bad hmac") { + it("should fail") { + val hmac = Hmac(100, "some invalid key") - fun Request.withHmac() = hmac.withHmac(this) - app(Request(Method.GET, "/users").withHmac()) - } - - it("should fail") { - res.status shouldBe Status.UNAUTHORIZED + fun Request.withHmac() = hmac.withHmac(this) + val res = app(Request(Method.GET, "/users").withHmac()) + res.status shouldBe Status.UNAUTHORIZED + } } } - } - data class Row( - val title: String, - val requestBuilder: () -> Request, - val snapshotName: String, - val status: Status = Status.OK, - ) - - listOf( - Row( - "GET /groups", - { Request(Method.GET, "/groups") }, - "GET_groups_body", - ), - Row( - "GET /group/beboer", - { Request(Method.GET, "/group/beboer") }, - "GET_group_beboer_body", - ), - Row( - "GET /groups", - { Request(Method.GET, "/groups") }, - "GET_groups_body", - ), - Row( - "GET /group/beboer", - { Request(Method.GET, "/group/beboer") }, - "GET_group_beboer_body", - ), - Row( - "GET /user/unknown", - { Request(Method.GET, "/user/unknown") }, - "GET_user_unknown_body", - Status.NOT_FOUND, - ), - Row( - "GET /user/halvargimnes", - { Request(Method.GET, "/user/halvargimnes") }, - "GET_user_halvargimnes_body", - ), - Row( - "GET /user/halvargimnes?grouplevel=2", - { Request(Method.GET, "/user/halvargimnes?grouplevel=2") }, - "GET_user_halvargimnes_grouplevel_2_body", - ), - Row( - "GET /users", - { Request(Method.GET, "/users") }, - "GET_users_body", - ), - Row( - "GET /users?grouplevel=1", - { Request(Method.GET, "/users?grouplevel=1") }, - "GET_users_grouplevel_1_body", - ), - Row( - "GET /users?emails=example%40example.com", - { Request(Method.GET, "/users?emails=example%40example.com") }, - "GET_users_email_no_match_body", - ), - Row( - "GET /users?emails=halvargimnes%40foreningenbs.no", - { Request(Method.GET, "/users?emails=halvargimnes%40foreningenbs.no") }, - "GET_users_email_with_match_body", - ), - ).map { row -> - describe(row.title) { - val res by memoized(mode = CachingMode.EACH_GROUP) { - app(row.requestBuilder().withHmac()) - } - - it("should return expected status") { - res.status shouldBe row.status - } - - it("should return expected body") { - res.bodyString() matchWithSnapshot row.snapshotName + data class Row( + val title: String, + val requestBuilder: () -> Request, + val snapshotName: String, + val status: Status = Status.OK, + ) + + listOf( + Row( + "GET /groups", + { Request(Method.GET, "/groups") }, + "GET_groups_body", + ), + Row( + "GET /group/beboer", + { Request(Method.GET, "/group/beboer") }, + "GET_group_beboer_body", + ), + Row( + "GET /user/unknown", + { Request(Method.GET, "/user/unknown") }, + "GET_user_unknown_body", + Status.NOT_FOUND, + ), + Row( + "GET /user/halvargimnes", + { Request(Method.GET, "/user/halvargimnes") }, + "GET_user_halvargimnes_body", + ), + Row( + "GET /user/halvargimnes?grouplevel=2", + { Request(Method.GET, "/user/halvargimnes?grouplevel=2") }, + "GET_user_halvargimnes_grouplevel_2_body", + ), + Row( + "GET /users", + { Request(Method.GET, "/users") }, + "GET_users_body", + ), + Row( + "GET /users?grouplevel=1", + { Request(Method.GET, "/users?grouplevel=1") }, + "GET_users_grouplevel_1_body", + ), + Row( + "GET /users?emails=example%40example.com", + { Request(Method.GET, "/users?emails=example%40example.com") }, + "GET_users_email_no_match_body", + ), + Row( + "GET /users?emails=halvargimnes%40foreningenbs.no", + { Request(Method.GET, "/users?emails=halvargimnes%40foreningenbs.no") }, + "GET_users_email_with_match_body", + ), + ).map { row -> + describe(row.title) { + val res = app(row.requestBuilder().withHmac()) + + it("should return expected status") { + res.status shouldBe row.status + } + + it("should return expected body") { + res.bodyString() matchWithSnapshot row.snapshotName + } } } - } - describe("POST /simpleauth using urlencoded form") { - describe("using invalid credentials") { - val res by memoized(mode = CachingMode.EACH_GROUP) { - val req = - Request(Method.POST, "/simpleauth") - .with(CONTENT_TYPE of ContentType.APPLICATION_FORM_URLENCODED) - .form("username", "somethingInvalid") - .form("password", "test1234") - .withHmac() - app(req) + describe("POST /simpleauth using urlencoded form") { + describe("using invalid credentials") { + it("should fail") { + val res = + app( + Request(Method.POST, "/simpleauth") + .with(CONTENT_TYPE of ContentType.APPLICATION_FORM_URLENCODED) + .form("username", "somethingInvalid") + .form("password", "test1234") + .withHmac(), + ) + res.status shouldBe Status.UNAUTHORIZED + } } - it("should fail") { - res.status shouldBe Status.UNAUTHORIZED - } - } - - describe("using valid credentials") { - val res by memoized(mode = CachingMode.EACH_GROUP) { - val req = - Request(Method.POST, "/simpleauth") - .with(CONTENT_TYPE of ContentType.APPLICATION_FORM_URLENCODED) - .form("username", MOCK_AUTH_VALID_USERNAME) - .form("password", MOCK_AUTH_VALID_PASSWORD) - .withHmac() - app(req) - } + describe("using valid credentials") { + val res = + app( + Request(Method.POST, "/simpleauth") + .with(CONTENT_TYPE of ContentType.APPLICATION_FORM_URLENCODED) + .form("username", MOCK_AUTH_VALID_USERNAME) + .form("password", MOCK_AUTH_VALID_PASSWORD) + .withHmac(), + ) - it("should be successful") { - res.status shouldBe Status.OK - } + it("should be successful") { + res.status shouldBe Status.OK + } - it("should return expected data") { - res.bodyString() matchWithSnapshot "POST_simpleauth_body" + it("should return expected data") { + res.bodyString() matchWithSnapshot "POST_simpleauth_body" + } } } - } - describe("POST /simpleauth using JSON body") { - describe("using valid credentials") { - val res by memoized(mode = CachingMode.EACH_GROUP) { - val type = Types.newParameterizedType(Map::class.java, String::class.java, String::class.java) - val adapter = - Moshi - .Builder() - .add(KotlinJsonAdapterFactory()) - .build() - .adapter>(type) + describe("POST /simpleauth using JSON body") { + describe("using valid credentials") { val body = - adapter.toJson( - mapOf( - "username" to MOCK_AUTH_VALID_USERNAME, - "password" to MOCK_AUTH_VALID_PASSWORD, - ), + """{"username":"$MOCK_AUTH_VALID_USERNAME","password":"$MOCK_AUTH_VALID_PASSWORD"}""" + + val res = + app( + Request(Method.POST, "/simpleauth") + .with(CONTENT_TYPE of ContentType.APPLICATION_JSON) + .body(body) + .withHmac(), ) - val req = - Request(Method.POST, "/simpleauth") - .with(CONTENT_TYPE of ContentType.APPLICATION_JSON) - .body(body) - .withHmac() - app(req) - } - - it("should be successful") { - res.status shouldBe Status.OK - } + it("should be successful") { + res.status shouldBe Status.OK + } - it("should return expected data") { - res.bodyString() matchWithSnapshot "POST_simpleauth_body" + it("should return expected data") { + res.bodyString() matchWithSnapshot "POST_simpleauth_body" + } } } } } - } -}) + }) diff --git a/src/test/kotlin/no/foreningenbs/usersapi/TestHelpers.kt b/src/test/kotlin/no/foreningenbs/usersapi/TestHelpers.kt index 0d29c7c..8f9baa8 100644 --- a/src/test/kotlin/no/foreningenbs/usersapi/TestHelpers.kt +++ b/src/test/kotlin/no/foreningenbs/usersapi/TestHelpers.kt @@ -66,7 +66,7 @@ val mockGroups = ), ), mockAdminGroup, - ).map { GroupRef(it.name) to it }.toMap() + ).associate { GroupRef(it.name) to it } fun createLdapMock(): Ldap = spyk(Ldap(Config)).also { diff --git a/src/test/kotlin/no/foreningenbs/usersapi/api/InvalidateCacheSpec.kt b/src/test/kotlin/no/foreningenbs/usersapi/api/InvalidateCacheSpec.kt index a495aa3..be5a75d 100644 --- a/src/test/kotlin/no/foreningenbs/usersapi/api/InvalidateCacheSpec.kt +++ b/src/test/kotlin/no/foreningenbs/usersapi/api/InvalidateCacheSpec.kt @@ -1,5 +1,6 @@ package no.foreningenbs.usersapi.api +import io.kotest.core.spec.style.DescribeSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.mockk.every @@ -7,26 +8,26 @@ import no.foreningenbs.usersapi.Config import no.foreningenbs.usersapi.DataProvider import no.foreningenbs.usersapi.createLdapMock import org.http4k.core.Method -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe +import org.http4k.core.Request -object InvalidateCacheSpec : Spek({ - val ldap = createLdapMock() - val dataProvider = DataProvider(Config, ldap) - val handler = InvalidateCache(dataProvider).handler +class InvalidateCacheSpec : + DescribeSpec({ + val ldap = createLdapMock() + val dataProvider = DataProvider(Config, ldap) + val handler = InvalidateCache(dataProvider).handler - describe("cache invalidation") { - it("should invalidate cache") { - val data = dataProvider.getData() + describe("cache invalidation") { + it("should invalidate cache") { + val data = dataProvider.getData() - every { ldap.getGroups(any()) } returns mapOf() - every { ldap.getUsers(any()) } returns mapOf() + every { ldap.getGroups(any()) } returns mapOf() + every { ldap.getUsers(any()) } returns mapOf() - dataProvider.getData() shouldBe data + dataProvider.getData() shouldBe data - handler(org.http4k.core.Request(Method.POST, "/dummy")) + handler(Request(Method.POST, "/dummy")) - dataProvider.getData() shouldNotBe data + dataProvider.getData() shouldNotBe data + } } - } -}) + }) diff --git a/src/test/kotlin/no/foreningenbs/usersapi/hmac/HmacSpec.kt b/src/test/kotlin/no/foreningenbs/usersapi/hmac/HmacSpec.kt index a85d013..2c5899e 100644 --- a/src/test/kotlin/no/foreningenbs/usersapi/hmac/HmacSpec.kt +++ b/src/test/kotlin/no/foreningenbs/usersapi/hmac/HmacSpec.kt @@ -1,26 +1,26 @@ package no.foreningenbs.usersapi.hmac +import io.kotest.core.spec.style.DescribeSpec import io.kotest.matchers.shouldBe import org.http4k.core.Method import org.http4k.core.Uri -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe -object HmacSpec : Spek({ - describe("generateHash") { - it("should generate expected hash") { - val hmac = Hmac(100, "some-key") - val generated = - hmac.generateHash( - 1546066592L, - Method.GET, - Uri.of("/users"), - hmac.prepareFormPayload(mapOf()), - ) +class HmacSpec : + DescribeSpec({ + describe("generateHash") { + it("should generate expected hash") { + val hmac = Hmac(100, "some-key") + val generated = + hmac.generateHash( + 1546066592L, + Method.GET, + Uri.of("/users"), + hmac.prepareFormPayload(mapOf()), + ) - val expected = "8623a8a04b33f9e02e0eb0654ea658420b2da418b5755a72d4cc231649c1aa7a" + val expected = "8623a8a04b33f9e02e0eb0654ea658420b2da418b5755a72d4cc231649c1aa7a" - generated shouldBe expected + generated shouldBe expected + } } - } -}) + })