diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index c5bca50..2b2a567 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -11,7 +11,7 @@
postgresql
true
org.postgresql.Driver
- jdbc:postgresql://localhost:5432/test
+ jdbc:postgresql://localhost:5433/test
postgresql
diff --git a/.idea/runConfigurations/Migration.xml b/.idea/runConfigurations/Migration.xml
new file mode 100644
index 0000000..3159aef
--- /dev/null
+++ b/.idea/runConfigurations/Migration.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/TestSql.xml b/.idea/runConfigurations/TestSql.xml
new file mode 100644
index 0000000..8003a29
--- /dev/null
+++ b/.idea/runConfigurations/TestSql.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Test_All_SQL.xml b/.idea/runConfigurations/Test_All_SQL.xml
index 326058e..06d1935 100644
--- a/.idea/runConfigurations/Test_All_SQL.xml
+++ b/.idea/runConfigurations/Test_All_SQL.xml
@@ -1,5 +1,6 @@
+
@@ -9,6 +10,7 @@
+
diff --git a/build.gradle.kts b/build.gradle.kts
index a0ae987..7ffec68 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,13 +3,17 @@ import io.gitlab.arturbosch.detekt.Detekt
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.owasp.dependencycheck.reporting.ReportGenerator
import org.slf4j.LoggerFactory
+import fr.postgresjson.connexion.Connection
+import fr.postgresjson.migration.Migrations
+import com.typesafe.config.ConfigFactory
+import fr.postgresjson.connexion.Requester
-val ktor_version: String by project
-val kotlin_version: String by project
-val coroutinesVersion: String by project
-val logback_version: String by project
-val koinVersion: String by project
-val jackson_version: String by project
+val ktorVersion = "1.5.0"
+val kotlinVersion = "1.4.30"
+val coroutinesVersion = "1.4.2"
+val logbackVersion = "1.2.3"
+val koinVersion = "2.0.1"
+val jacksonVersion = "2.12.1"
group = "com.github.flecomte"
version = versioning.info.run {
@@ -36,17 +40,121 @@ plugins {
id("net.nemerosa.versioning") version "2.14.0"
id("io.gitlab.arturbosch.detekt") version "1.16.0-RC1"
id("info.solidsoft.pitest") version "1.5.2"
+ id("com.avast.gradle.docker-compose") version "0.14.0"
}
application {
mainClassName = "io.ktor.server.jetty.EngineMain"
}
+buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ jcenter()
+ maven { url = uri("https://jitpack.io") }
+ }
+ dependencies {
+ classpath("com.typesafe:config:1.4.1")
+ classpath("com.github.flecomte:postgres-json:2.1.1")
+ }
+}
+
tasks.withType {
kotlinOptions {
jvmTarget = "11"
}
}
+
+val migration by tasks.registering {
+ group = "application"
+ dependsOn(tasks.named("composeUp"))
+
+ doLast {
+ val config = ConfigFactory.parseFile(file("${buildDir}/../src/main/resources/application.conf")).resolve()
+ val connection = Connection(
+ host = config.getString("db.host"),
+ port = config.getInt("db.port"),
+ database = config.getString("db.database"),
+ username = config.getString("db.username"),
+ password = config.getString("db.password")
+ )
+ Migrations(
+ connection,
+ file("$buildDir/../src/main/resources/sql/migrations").toURI(),
+ file("$buildDir/../src/main/resources/sql/functions").toURI()
+ ).run {
+ run()
+ }
+ }
+}
+
+val migrationTest by tasks.registering {
+ group = "verification"
+ dependsOn(tasks.named("testComposeUp"))
+ finalizedBy(tasks.named("testComposeDown"))
+ doLast {
+ val config = ConfigFactory.parseFile(file("${buildDir}/../src/test/resources/application-test.conf")).resolve()
+ val connection = Connection(
+ host = config.getString("db.host"),
+ port = config.getInt("db.port"),
+ database = config.getString("db.database"),
+ username = config.getString("db.username"),
+ password = config.getString("db.password")
+ )
+ Migrations(
+ connection,
+ file("$buildDir/../src/main/resources/sql/migrations").toURI(),
+ file("$buildDir/../src/main/resources/sql/functions").toURI()
+ ).run {
+ run()
+ connection.disconnect()
+ }
+ }
+}
+
+val testSql by tasks.registering {
+ group = "verification"
+ dependsOn(tasks.named("testComposeUp"))
+ finalizedBy(tasks.named("testComposeDown"))
+
+ doLast {
+ val config = ConfigFactory.parseFile(file("${buildDir}/../src/test/resources/application-test.conf")).resolve()
+
+ val connection = Connection(
+ host = config.getString("db.host"),
+ port = config.getInt("db.port"),
+ database = config.getString("db.database"),
+ username = config.getString("db.username"),
+ password = config.getString("db.password")
+ )
+
+ Migrations(
+ connection,
+ file("$buildDir/../src/main/resources/sql/migrations").toURI(),
+ file("$buildDir/../src/main/resources/sql/functions").toURI(),
+ file("$buildDir/../src/test/sql/fixtures").toURI()
+ ).run {
+ run()
+ }
+
+ Requester.RequesterFactory(
+ connection = connection,
+ queriesDirectory = file("${buildDir}/../src/test/sql").toURI()
+ ).createRequester().run {
+ getQueries().map {
+ try {
+ it.sendQuery() == 0
+ } catch (e: Exception) {
+ false
+ }
+ }
+ }
+
+ connection.disconnect()
+ }
+}
+
tasks.withType {
manifest {
attributes(
@@ -57,23 +165,48 @@ tasks.withType {
}
}
-tasks {
- named("shadowJar") {
- mergeServiceFiles("META-INF/services")
- archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
- }
+tasks.named("shadowJar") {
+ mergeServiceFiles("META-INF/services")
+ archiveFileName.set("${archiveBaseName.get()}-latest-all.${archiveExtension.get()}")
}
-val sourcesJar by tasks.creating(Jar::class) {
+tasks.sonarqube.configure { dependsOn(tasks.jacocoTestReport) }
+
+val sourcesJar by tasks.registering(Jar::class) {
+ group = "build"
archiveClassifier.set("sources")
from(sourceSets.getByName("main").allSource)
}
+
tasks.test {
useJUnit()
useJUnitPlatform()
systemProperty("junit.jupiter.execution.parallel.enabled", true)
+ dependsOn(testSql)
+ dependsOn(tasks.pitest)
finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
-// maxHeapSize = "1G"
+}
+
+apply(plugin = "docker-compose")
+dockerCompose {
+ projectName = "dc-project"
+ useComposeFiles = listOf("docker-compose.yml")
+ startedServices = listOf("db", "elasticsearch", "rabbitmq", "redis")
+ stopContainers = false
+ isRequiredBy(project.tasks.run)
+ createNested("test").apply {
+ projectName = "dc-project_test"
+ useComposeFiles = listOf("docker-compose-test.yml")
+ stopContainers = false
+ isRequiredBy(project.tasks.test)
+ isRequiredBy(project.tasks.named("testSql"))
+ }
+ createNested("sonarqube").apply {
+ projectName = "dc-project"
+ useComposeFiles = listOf("docker-compose-sonar.yml")
+ stopContainers = false
+// isRequiredBy(project.tasks.sonarqube)
+ }
}
publishing {
@@ -106,10 +239,12 @@ jacoco {
toolVersion = "0.8.6"
applyTo(tasks.run.get())
}
+
tasks.register("applicationCodeCoverageReport") {
executionData(tasks.run.get())
sourceSets(sourceSets.main.get())
}
+
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
@@ -159,43 +294,45 @@ repositories {
}
dependencies {
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
+ implementation(gradleApi())
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
- implementation("io.ktor:ktor-server-jetty:$ktor_version")
- implementation("io.ktor:ktor-client-jetty:$ktor_version")
- implementation("ch.qos.logback:logback-classic:$logback_version")
- implementation("io.ktor:ktor-server-core:$ktor_version")
- implementation("io.ktor:ktor-locations:$ktor_version")
- implementation("io.ktor:ktor-auth:$ktor_version")
- implementation("io.ktor:ktor-auth-jwt:$ktor_version")
- implementation("io.ktor:ktor-websockets:$ktor_version")
+ implementation("io.ktor:ktor-server-jetty:$ktorVersion")
+ implementation("io.ktor:ktor-client-jetty:$ktorVersion")
+ implementation("ch.qos.logback:logback-classic:$logbackVersion")
+ implementation("io.ktor:ktor-server-core:$ktorVersion")
+ implementation("io.ktor:ktor-locations:$ktorVersion")
+ implementation("io.ktor:ktor-auth:$ktorVersion")
+ implementation("io.ktor:ktor-auth-jwt:$ktorVersion")
+ implementation("io.ktor:ktor-websockets:$ktorVersion")
implementation("org.koin:koin-ktor:$koinVersion")
- implementation("io.ktor:ktor-jackson:$ktor_version")
- implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")
- implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version")
+ implementation("io.ktor:ktor-jackson:$ktorVersion")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:$jacksonVersion")
implementation("net.pearx.kasechange:kasechange-jvm:1.3.0")
implementation("com.auth0:java-jwt:3.12.0")
implementation("com.github.jasync-sql:jasync-postgresql:1.1.6")
- implementation("com.github.flecomte:postgres-json:2.0.0")
+ implementation("com.github.flecomte:postgres-json:2.1.1")
implementation("com.sendgrid:sendgrid-java:4.7.1")
implementation("io.lettuce:lettuce-core:5.3.6.RELEASE") // TODO update to 6.0.2
implementation("com.rabbitmq:amqp-client:5.10.0")
implementation("org.elasticsearch.client:elasticsearch-rest-client:6.7.1")
implementation("com.jayway.jsonpath:json-path:2.5.0")
+ implementation("com.avast.gradle:gradle-docker-compose-plugin:0.14.0")
- testImplementation("io.ktor:ktor-server-tests:$ktor_version")
- testImplementation("io.ktor:ktor-client-mock:$ktor_version")
- testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
+ testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
+ testImplementation("io.ktor:ktor-client-mock:$ktorVersion")
+ testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion")
testImplementation("org.koin:koin-test:$koinVersion")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
- testImplementation("io.mockk:mockk:1.10.5")
+ testImplementation("io.mockk:mockk:1.10.6")
testImplementation("org.junit.jupiter:junit-jupiter:5.7.0")
testImplementation("org.amshove.kluent:kluent:1.61")
pitest("org.pitest:pitest-junit5-plugin:0.5")
- testImplementation("io.mockk:mockk-agent-api:1.10.5")
- testImplementation("io.mockk:mockk-agent-jvm:1.10.5")
- testImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
+ testImplementation("io.mockk:mockk-agent-api:1.10.6")
+ testImplementation("io.mockk:mockk-agent-jvm:1.10.6")
+ testImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
testImplementation("com.thedeanda:lorem:2.1")
}
diff --git a/docker-compose-sonar.yml b/docker-compose-sonar.yml
new file mode 100644
index 0000000..978c9c9
--- /dev/null
+++ b/docker-compose-sonar.yml
@@ -0,0 +1,48 @@
+version: '3.8'
+services:
+ sonarqube:
+ container_name: ${APP_NAME}_sonarqube
+ image: sonarqube:community
+ depends_on:
+ - sonarqube_db
+ ports:
+ - ${SONARQUBE_PORT}:9000
+ networks:
+ - sonarnet
+ environment:
+ SONAR_JDBC_URL: jdbc:postgresql://sonarqube_db:5432/sonar
+ SONAR_JDBC_USERNAME: sonar
+ SONAR_JDBC_PASSWORD: sonar
+ volumes:
+ - sonarqube_data:/opt/sonarqube/data
+ - sonarqube_extensions:/opt/sonarqube/extensions
+ - sonarqube_logs:/opt/sonarqube/logs
+ - sonarqube_temp:/opt/sonarqube/temp
+
+ sonarqube_db:
+ container_name: ${APP_NAME}_sonarqube_db
+ image: postgres:alpine
+ networks:
+ - sonarnet
+ environment:
+ POSTGRES_USER: sonar
+ POSTGRES_PASSWORD: sonar
+ ports:
+ - ${SONARQUBE_DB_PORT}:5432
+ volumes:
+ - sonarqube_postgresql:/var/lib/postgresql
+ # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
+ - sonarqube_postgresql_data:/var/lib/postgresql/data
+
+
+networks:
+ sonarnet:
+ driver: bridge
+
+volumes:
+ sonarqube_data:
+ sonarqube_extensions:
+ sonarqube_logs:
+ sonarqube_temp:
+ sonarqube_postgresql:
+ sonarqube_postgresql_data:
\ No newline at end of file
diff --git a/docker-compose-test.yml b/docker-compose-test.yml
new file mode 100644
index 0000000..7819168
--- /dev/null
+++ b/docker-compose-test.yml
@@ -0,0 +1,44 @@
+version: '3.8'
+services:
+ rabbitmq:
+ container_name: ${APP_NAME}_rabbitmq_test
+ image: rabbitmq:management-alpine
+ ports:
+ - 5672:5672
+ - 15672:15672
+
+ redis:
+ container_name: ${APP_NAME}_redis_test
+ image: redis:6-alpine
+ ports:
+ - 6380:6379
+
+ elasticsearch:
+ container_name: ${APP_NAME}_elasticsearch_test
+ image: elasticsearch:6.7.1
+ ports:
+ - 9201:9200
+ - 9301:9300
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
+ interval: 3s
+ timeout: 2s
+ retries: 20
+
+ db:
+ container_name: ${APP_NAME}_postgresql_test
+ build:
+ context: docker/postgresql
+ ports:
+ - 5433:5432
+ environment:
+ POSTGRES_PASSWORD: ${DB_NAME}
+ POSTGRES_USER: ${DB_USER}
+ POSTGRES_DB: ${DB_PWD}
+ depends_on:
+ - elasticsearch
+ healthcheck:
+ test: [ "CMD", "pg_isready", "-q", "-d", "${DB_NAME}", "-U", "${DB_USER}" ]
+ interval: 3s
+ timeout: 2s
+ retries: 20
diff --git a/docker-compose.yml b/docker-compose.yml
index 3e00b61..4d93bf9 100755
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,40 +1,7 @@
# To execute this docker-compose yml file use docker-compose -f up
# Add the "-d" flag at the end for detached execution
-version: '3.7'
+version: '3.8'
services:
- sonarqube:
- container_name: ${APP_NAME}_sonarqube
- image: sonarqube:community
- depends_on:
- - sonarqube_db
- ports:
- - ${SONARQUBE_PORT}:9000
- networks:
- - sonarnet
- environment:
- SONAR_JDBC_URL: jdbc:postgresql://sonarqube_db:5432/sonar
- SONAR_JDBC_USERNAME: sonar
- SONAR_JDBC_PASSWORD: sonar
- volumes:
- - sonarqube_data:/opt/sonarqube/data
- - sonarqube_extensions:/opt/sonarqube/extensions
- - sonarqube_logs:/opt/sonarqube/logs
- - sonarqube_temp:/opt/sonarqube/temp
- sonarqube_db:
- container_name: ${APP_NAME}_sonarqube_db
- image: postgres:alpine
- networks:
- - sonarnet
- environment:
- POSTGRES_USER: sonar
- POSTGRES_PASSWORD: sonar
- ports:
- - ${SONARQUBE_DB_PORT}:5432
- volumes:
- - sonarqube_postgresql:/var/lib/postgresql
- # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
- - sonarqube_postgresql_data:/var/lib/postgresql/data
-
openapi:
container_name: ${APP_NAME}_openapi
image: swaggerapi/swagger-ui
@@ -110,16 +77,6 @@ services:
timeout: 2s
retries: 20
-networks:
- sonarnet:
- driver: bridge
-
volumes:
db-data:
- redis-data:
- sonarqube_data:
- sonarqube_extensions:
- sonarqube_logs:
- sonarqube_temp:
- sonarqube_postgresql:
- sonarqube_postgresql_data:
\ No newline at end of file
+ redis-data:
\ No newline at end of file
diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile
index 2afe808..8d8fb06 100644
--- a/docker/app/Dockerfile
+++ b/docker/app/Dockerfile
@@ -1,5 +1,5 @@
#### BUILD ####
-FROM gradle:5.6.4-jdk11 AS build
+FROM gradle:6.8-jdk11 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
@@ -7,7 +7,7 @@ RUN gradle build -x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck
RUN gradle shadowJar
#### RUN ####
-FROM adoptopenjdk/openjdk11:jre-11.0.4_11-alpine
+FROM amazoncorretto:11-alpine as run
ENV APPLICATION_USER ktor
RUN adduser -D -g '' $APPLICATION_USER
diff --git a/gradle.properties b/gradle.properties
index bc21501..c799b29 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,10 +1,4 @@
-ktor_version=1.5.0
kotlin.code.style=official
-kotlin_version=1.4.21-2
-coroutinesVersion=1.4.2
-logback_version=1.2.3
-koinVersion=2.0.1
-jackson_version=2.12.1
systemProp.sonar.host.url=http://localhost:9002
systemProp.sonar.login=admin
systemProp.sonar.password=sonar
diff --git a/src/test/kotlin/functional/NotificationConsumerTest.kt b/src/test/kotlin/functional/NotificationConsumerTest.kt
index 9c706a1..b291564 100644
--- a/src/test/kotlin/functional/NotificationConsumerTest.kt
+++ b/src/test/kotlin/functional/NotificationConsumerTest.kt
@@ -86,14 +86,14 @@ class NotificationConsumerTest {
followArticleRepo = followArticleRepo,
followConstitutionRepo = mockk(),
notificationEmailSender = emailSender,
- exchangeName = "notification_test",
+ exchangeName = "notification",
).apply { start() }
verify { rabbitFactory.newConnection() }
/* Push message */
Publisher(
factory = rabbitFactory,
- exchangeName = "notification_test",
+ exchangeName = "notification",
).publish(
ArticleUpdateNotification(
ArticleForView(
diff --git a/src/test/resources/application-test.conf b/src/test/resources/application-test.conf
index 0c5f0fd..fe6fc92 100644
--- a/src/test/resources/application-test.conf
+++ b/src/test/resources/application-test.conf
@@ -1,7 +1,6 @@
ktor {
deployment {
- port = 8080
- port = ${?PORT}
+ port = 8181
}
application {
modules = [ fr.dcproject.ApplicationKt.module ]
@@ -15,26 +14,22 @@ app {
db {
host = localhost
- host = ${?DB_HOST}
database = test
username = test
password = test
- port = 5432
+ port = 5433
}
redis {
- connection = "redis://localhost:6379"
- connection = ${?REDIS_CONNECTION}
+ connection = "redis://localhost:6380"
}
rabbitmq {
connection = "amqp://localhost:5672"
- connection = ${?RABBITMQ_CONNECTION}
}
elasticsearch {
- connection = "http://localhost:9200"
- connection = ${?ELASTICSEARCH_CONNECTION}
+ connection = "http://localhost:9201"
}
mail {
diff --git a/src/test/sql/test.sh b/src/test/sql/test.sh
index 65a0dbe..83767dd 100644
--- a/src/test/sql/test.sh
+++ b/src/test/sql/test.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-options=("All" "article" "citizen" "comment" "constitution" "follow" "opinion" "user" "vote" "workgroup" "RESET DB" "Quit")
+options=("All" "RESET DB" "article" "citizen" "comment" "constitution" "follow" "opinion" "user" "vote" "workgroup" "Quit")
if [ -z "$1" ]; then
PS3='Please enter your choice: '
select ch in "${options[@]}"
@@ -17,7 +17,7 @@ case $opt in
awk 'FNR==1{print "--------------------"}1' \
../../main/resources/sql/migrations/*.down.sql \
../../main/resources/sql/migrations/*.up.sql > ./allSQL.sql
- docker exec -i dc-project_postgresql psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
+ docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
rm ./allSQL.sql
;;
"All")
@@ -26,7 +26,7 @@ case $opt in
../../main/resources/sql/functions/*/*.sql \
./fixtures/*.sql \
./*.sql > ./allSQL.sql
- docker exec -i dc-project_postgresql psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
+ docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
rm ./allSQL.sql
;;
"Quit")
@@ -37,7 +37,7 @@ case $opt in
../../main/resources/sql/functions/*/*.sql \
./fixtures/*.sql \
./"$opt".sql > ./allSQL.sql
- docker exec -i dc-project_postgresql psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
+ docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
rm ./allSQL.sql
;;
esac
\ No newline at end of file