Init Integration test without cucumber

This commit is contained in:
2021-02-09 02:51:23 +01:00
parent dcf35eaccd
commit edf0c00cf1
6 changed files with 200 additions and 3 deletions

View File

@@ -1,6 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true"> <configuration default="false" name="All Tests" type="JUnit" factoryName="JUnit" singleton="false" show_console_on_std_err="true">
<output_file path="$PROJECT_DIR$/var/log/test/out.log" is_save="true" />
<useClassPathOnly /> <useClassPathOnly />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="ALTERNATIVE_JRE_PATH" value="corretto-11" /> <option name="ALTERNATIVE_JRE_PATH" value="corretto-11" />
@@ -21,6 +20,7 @@
<pattern testClass="unit..*" /> <pattern testClass="unit..*" />
<pattern testClass="functional..*" /> <pattern testClass="functional..*" />
<pattern testClass="CucumberTest" /> <pattern testClass="CucumberTest" />
<pattern testClass="integration..*" />
</patterns> </patterns>
<tag value="!functional" /> <tag value="!functional" />
<method v="2"> <method v="2">

View File

@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.joda.JodaModule import com.fasterxml.jackson.datatype.joda.JodaModule
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
import fr.dcproject.application.Env.PROD import fr.dcproject.application.Env.PROD
import fr.dcproject.application.Env.TEST
import fr.dcproject.common.security.AccessDeniedException import fr.dcproject.common.security.AccessDeniedException
import fr.dcproject.component.article.articleKoinModule import fr.dcproject.component.article.articleKoinModule
import fr.dcproject.component.article.routes.installArticleRoutes import fr.dcproject.component.article.routes.installArticleRoutes
@@ -68,6 +69,7 @@ import io.ktor.util.KtorExperimentalAPI
import io.ktor.websocket.WebSockets import io.ktor.websocket.WebSockets
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.eclipse.jetty.util.log.Slf4jLog import org.eclipse.jetty.util.log.Slf4jLog
import org.koin.dsl.module
import org.koin.ktor.ext.Koin import org.koin.ktor.ext.Koin
import org.koin.ktor.ext.get import org.koin.ktor.ext.get
import org.slf4j.event.Level import org.slf4j.event.Level
@@ -87,6 +89,8 @@ fun Application.module(env: Env = PROD) {
Slf4jLog() Slf4jLog()
modules( modules(
listOf( listOf(
if (env == TEST) module { single { Configuration("application-test.conf") } }
else module { single { Configuration() } },
KoinModule, KoinModule,
articleKoinModule, articleKoinModule,
authKoinModule, authKoinModule,

View File

@@ -25,8 +25,6 @@ import org.koin.dsl.module
@KtorExperimentalAPI @KtorExperimentalAPI
val KoinModule = module { val KoinModule = module {
single { Configuration() }
// SQL connection // SQL connection
single { single {
val config: Configuration = get() val config: Configuration = get()

View File

@@ -0,0 +1,119 @@
package integration
import com.rabbitmq.client.Channel
import com.rabbitmq.client.ConnectionFactory
import fr.dcproject.application.Configuration
import fr.dcproject.application.Env.TEST
import fr.dcproject.application.module
import fr.postgresjson.connexion.Connection
import fr.postgresjson.migration.Migrations
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.server.testing.TestApplicationCall
import io.ktor.server.testing.TestApplicationEngine
import io.ktor.server.testing.TestApplicationRequest
import io.ktor.server.testing.TestApplicationResponse
import io.ktor.server.testing.createTestEnvironment
import io.ktor.server.testing.setBody
import io.ktor.util.KtorExperimentalAPI
import io.lettuce.core.RedisClient
import io.lettuce.core.api.sync.RedisCommands
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.amshove.kluent.`should be`
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.koin.test.KoinTest
import org.koin.test.get
@ExperimentalCoroutinesApi
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
abstract class BaseTest : KoinTest {
companion object {
private var init = false
private val config = Configuration("application-test.conf")
private val redis: RedisCommands<String, String> = RedisClient.create(config.redis).connect().sync()
private val rabbit: Channel = ConnectionFactory()
.apply { setUri(config.rabbitmq) }
.newConnection()
.createChannel()
private val engine = TestApplicationEngine(createTestEnvironment())
}
protected fun <R> withIntegrationApplication(
test: TestApplicationEngine.() -> R
): R {
return engine.test()
}
public fun TestApplicationEngine.handleGetRequest(uri: String? = null, body: TestApplicationRequest.() -> String): TestApplicationCall {
val setupOveride: TestApplicationRequest.() -> Unit = {
method = HttpMethod.Get
if (uri != null) {
this.uri = uri
}
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setBody(body().trimIndent())
}
return handleRequest(true, setupOveride)
}
public fun TestApplicationEngine.handlePostRequest(uri: String? = null, body: TestApplicationRequest.() -> String): TestApplicationCall {
val setupOveride: TestApplicationRequest.() -> Unit = {
method = HttpMethod.Post
if (uri != null) {
this.uri = uri
}
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setBody(body().trimIndent())
}
return handleRequest(true, setupOveride)
}
@BeforeAll
fun before() {
if (init == false) {
engine.start()
engine.application.module(TEST)
init = true
get<Migrations>().run {
forceAllDown()
run()
}
get<Connection>()
.sendQuery("start transaction;", listOf())
}
}
@BeforeEach
fun beforeEach() {
redis.flushall()
/* Purge rabbit notification queues */
rabbit.run {
queuePurge("push")
queuePurge("email")
}
get<Connection>()
.sendQuery("savepoint test_begin;", listOf())
}
@AfterEach
fun afterEach() {
get<Connection>()
.sendQuery("rollback to savepoint test_begin;", listOf())
}
}
fun TestApplicationCall.`should be respond`(status: HttpStatusCode? = null, block: TestApplicationResponse.() -> Unit) {
if (status != null) {
response.status().`should be`(status)
}
block(response)
}

View File

@@ -0,0 +1,40 @@
package integration
import integration.prerequisite.CitizenPrerequisite
import io.ktor.http.HttpStatusCode
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.util.KtorExperimentalAPI
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.amshove.kluent.`should be`
import org.amshove.kluent.`should contain`
import org.amshove.kluent.`should not be null`
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@ExperimentalCoroutinesApi
@KtorExperimentalLocationsAPI
@KtorExperimentalAPI
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Tags(Tag("integration"))
class LoginTest : BaseTest() {
@Test
fun `I can login`() {
withIntegrationApplication {
CitizenPrerequisite().createCitizen("Niels", "Bohr")
handlePostRequest("/login") {
"""
{
"username": "niels-bohr",
"password": "azerty"
}
"""
}.`should be respond` (HttpStatusCode.OK) {
content
.`should not be null`()
.`should contain`("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.")
}
}
}
}

View File

@@ -0,0 +1,36 @@
package integration.prerequisite
import fr.dcproject.component.auth.UserForCreate
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenForCreate
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRepository
import org.joda.time.DateTime
import org.koin.core.KoinComponent
import org.koin.core.get
import java.util.UUID
class CitizenPrerequisite : KoinComponent {
fun createCitizen(
firstName: String,
lastName: String,
email: String = ("$firstName-$lastName".toLowerCase()) + "@dc-project.fr",
id: UUID = UUID.randomUUID()
): Citizen? {
val user = UserForCreate(
id = id,
username = "$firstName-$lastName".toLowerCase(),
password = "azerty",
)
val citizen = CitizenForCreate(
id = id,
name = CitizenI.Name(firstName, lastName),
email = email,
birthday = DateTime.now(),
user = user
)
return get<CitizenRepository>().insertWithUser(citizen)
}
}