diff --git a/.dockerignore b/.dockerignore index f4f6743..ab06d4a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ * -!checklister-web/build/libs/app.jar +!subprojects/web/build/libs/app.jar diff --git a/.gitignore b/.gitignore index 04fd74b..f0ffda2 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ # Generated resources /subprojects/web/src/main/resources/checklister-build.properties /subprojects/web/src/main/resources/banner.txt + +# KotlinTest +/subprojects/integrationTest/.kotlintest diff --git a/Dockerfile b/Dockerfile index f590d92..1a360c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,6 @@ FROM openjdk:10-jre EXPOSE 8080 CMD ["java", "-jar", "/app.jar"] -ADD /checklister-web/build/libs/app.jar /app.jar +ADD /subprojects/web/build/libs/app.jar /app.jar diff --git a/settings.gradle.kts b/settings.gradle.kts index ec359a4..a289335 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,7 +6,8 @@ include("dto", "eventsink-logger", "eventsink-kafka", "web", - "history") + "history", + "integrationTest") for (project in rootProject.children) { project.apply { diff --git a/subprojects/integrationTest/integrationTest.gradle.kts b/subprojects/integrationTest/integrationTest.gradle.kts new file mode 100644 index 0000000..101981c --- /dev/null +++ b/subprojects/integrationTest/integrationTest.gradle.kts @@ -0,0 +1,46 @@ +plugins { + `java-library` + kotlin("jvm") version "1.3.21" + // https://github.com/avast/gradle-docker-compose-plugin + id("com.avast.gradle.docker-compose") version "0.9.2" +} + +repositories { + mavenCentral() + + // jitpack required by Fuel + maven(url = "https://jitpack.io") { + name = "jitpack" + } +} + +val bootJar = tasks.getByPath(":web:bootJar") + +val test by tasks.getting(Test::class) { + useJUnitPlatform { } +} + +val composeUp = tasks.getByName("composeUp") +composeUp.dependsOn(bootJar) +dockerCompose.isRequiredBy(test) + +dependencies { + // Kotlin + implementation(kotlin("stdlib-jdk8")) + + // KotlinTest: https://github.com/kotlintest/kotlintest + testImplementation("io.kotlintest:kotlintest-runner-junit5:3.3.2") + + // Fuel HTTP library: https://github.com/kittinunf/fuel + testImplementation("com.github.kittinunf.fuel:fuel:2.0.1") + + // Fuel Jackson (de)serializer: https://github.com/kittinunf/fuel/blob/master/fuel-jackson/README.md + testImplementation("com.github.kittinunf.fuel:fuel-jackson:2.0.1") + + // Jackson support for Java time classes: https://github.com/FasterXML/jackson-modules-java8 + testImplementation("com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.0") + testImplementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.0") + testImplementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.0") + + implementation(project(":dto")) +} \ No newline at end of file diff --git a/subprojects/integrationTest/src/test/kotlin/cloud/cosmin/checklister/it/TimestampSpec.kt b/subprojects/integrationTest/src/test/kotlin/cloud/cosmin/checklister/it/TimestampSpec.kt new file mode 100644 index 0000000..a504e14 --- /dev/null +++ b/subprojects/integrationTest/src/test/kotlin/cloud/cosmin/checklister/it/TimestampSpec.kt @@ -0,0 +1,72 @@ +package cloud.cosmin.checklister.it + +import cloud.cosmin.checklister.lib.dto.ItemGetDto +import cloud.cosmin.checklister.lib.dto.ListGetDto +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule +import com.github.kittinunf.fuel.Fuel +import com.github.kittinunf.fuel.jackson.responseObject +import io.kotlintest.matchers.boolean.shouldBeTrue +import io.kotlintest.matchers.string.shouldMatch +import io.kotlintest.shouldBe +import io.kotlintest.specs.WordSpec + +class TimestampSpec : WordSpec({ + val baseUrl = "http://localhost:8180/api/v1" + val contentType = "Content-Type" to "application/json" + + val mapper = ObjectMapper() + .registerKotlinModule() + .registerModule(ParameterNamesModule()) + .registerModule(Jdk8Module()) + .registerModule(JavaTimeModule()) + + val timestampRegex = Regex("[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}Z") + + "Checklister" When { + "creating an item" should { + "return the lastModified field" { + val (_, _, listResult) = Fuel.post("$baseUrl/list") + .header(contentType) + .body("{\"title\":\"test list\"}") + .responseObject(mapper) + + val list = listResult.get() + list.title.shouldBe("test list") + + val (_, _, createItemResult) = Fuel.post("$baseUrl/item") + .header(contentType) + .body(""" + { + "list": "${list.id}", + "content": "content", + "contentType": "contentType" + } + """.trimIndent()) + .responseObject(mapper) + + val item = createItemResult.get() + item.createdAt.toString().shouldMatch(timestampRegex) + item.lastModified.toString().shouldMatch(timestampRegex) + + val (_, _, updateItemResult) = Fuel.put("$baseUrl/item/${item.id}") + .header(contentType) + .body(""" + { + "list": "${list.id}", + "content": "content1", + "contentType": "contentType1" + } + """.trimIndent()) + .responseObject(mapper) + + val updatedItem = updateItemResult.get() + updatedItem.createdAt.shouldBe(item.createdAt) + updatedItem.lastModified.isAfter(item.lastModified).shouldBeTrue() + } + } + } +}) \ No newline at end of file diff --git a/subprojects/web/web.gradle.kts b/subprojects/web/web.gradle.kts index 775ffb1..34b7d01 100644 --- a/subprojects/web/web.gradle.kts +++ b/subprojects/web/web.gradle.kts @@ -150,7 +150,7 @@ dependencies { // database implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.hibernate:hibernate-java8") - runtime("org.postgresql:postgresql:42.2.2") + runtimeOnly("org.postgresql:postgresql:42.2.2") implementation("org.flywaydb:flyway-core:5.0.7") implementation("org.bitbucket.cowwoc:requirements-core:4.0.4-RC")