Init Integration test without cucumber
This commit is contained in:
2
.idea/runConfigurations/All_Tests.xml
generated
2
.idea/runConfigurations/All_Tests.xml
generated
@@ -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">
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
119
src/test/kotlin/integration/BaseTest.kt
Normal file
119
src/test/kotlin/integration/BaseTest.kt
Normal 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)
|
||||||
|
}
|
||||||
40
src/test/kotlin/integration/LoginTest.kt
Normal file
40
src/test/kotlin/integration/LoginTest.kt
Normal 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.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user