From e8716a1e7f7193c935f1263b03bfb9490c8136fa Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Wed, 10 Feb 2021 14:30:23 +0100 Subject: [PATCH] Add Integration test for article --- src/test/kotlin/integration/Article routes.kt | 97 +++++++++++++++++++ src/test/kotlin/integration/BaseTest.kt | 7 +- src/test/kotlin/integration/Citizen routes.kt | 7 -- src/test/kotlin/integration/Login routes.kt | 7 -- .../kotlin/integration/Register routes.kt | 7 -- .../kotlin/integration/asserts/asserts.kt | 2 +- .../integration/asserts/given/Article.kt | 76 +++++++++++++++ .../integration/asserts/given/Workgroup.kt | 68 +++++++++++++ 8 files changed, 245 insertions(+), 26 deletions(-) create mode 100644 src/test/kotlin/integration/Article routes.kt create mode 100644 src/test/kotlin/integration/asserts/given/Article.kt create mode 100644 src/test/kotlin/integration/asserts/given/Workgroup.kt diff --git a/src/test/kotlin/integration/Article routes.kt b/src/test/kotlin/integration/Article routes.kt new file mode 100644 index 0000000..74307f9 --- /dev/null +++ b/src/test/kotlin/integration/Article routes.kt @@ -0,0 +1,97 @@ +package integration + +import integration.asserts.`And have property` +import integration.asserts.`And the response should not be null` +import integration.asserts.`Then the response should be` +import integration.asserts.`when`.`When I send a GET request` +import integration.asserts.`when`.`When I send a POST request` +import integration.asserts.`whish contains` +import integration.asserts.and +import integration.asserts.given.`Given I have article created by workgroup` +import integration.asserts.given.`Given I have article` +import integration.asserts.given.`Given I have articles` +import integration.asserts.given.`Given I have citizen` +import integration.asserts.given.`Given I have workgroup` +import integration.asserts.given.`authenticated as` +import io.ktor.http.HttpStatusCode.Companion.OK +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Tags +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Tags(Tag("integration"), Tag("citizen")) +class `Article routes` : BaseTest() { + @Test + fun `I can get article list`() { + withIntegrationApplication { + `Given I have articles`(3) + `When I send a GET request`("/articles") `Then the response should be` OK and { + `And the response should not be null` + } + } + } + + @Test + fun `I can get articles filtered by workgroup`() { + withIntegrationApplication { + `Given I have articles`(3) + `Given I have workgroup`(name = "Les papy", id = "2bccd5a7-9082-4b31-88f8-e25d70b22b12") + `Given I have article created by workgroup`("2bccd5a7-9082-4b31-88f8-e25d70b22b12") + `When I send a GET request`("/articles?workgroup=2bccd5a7-9082-4b31-88f8-e25d70b22b12") `Then the response should be` OK and { + `And the response should not be null` + `And have property`("$.total") `whish contains` 1 + `And have property`("$.result[0]workgroup.name") `whish contains` "Les papy" + } + } + } + + @Test + fun `I can get versions of article by the id`() { + withIntegrationApplication { + `Given I have article`(id = "13e6091c-8fed-4600-b079-a97a6b7a9800") + `When I send a GET request`("/articles/13e6091c-8fed-4600-b079-a97a6b7a9800/versions") `Then the response should be` OK and { + `And the response should not be null` + `And have property`("$.total") `whish contains` 1 + `And have property`("$.result[0].id") `whish contains` "13e6091c-8fed-4600-b079-a97a6b7a9800" + } + } + } + + @Test + fun `I can get article by id`() { + withIntegrationApplication { + `Given I have article`(id = "65cda9f3-8991-4420-8d41-1da9da72c9bb") + `When I send a GET request`("/articles/65cda9f3-8991-4420-8d41-1da9da72c9bb") `Then the response should be` OK and { + `And the response should not be null` + `And have property`("$.id") `whish contains` "65cda9f3-8991-4420-8d41-1da9da72c9bb" + } + } + } + + @Test + fun `I can create an article`() { + withIntegrationApplication { + `Given I have citizen`("John", "Doe") + `When I send a POST request`("/articles") { + `authenticated as`("John", "Doe") + """ + { + "version_id": "09c418b6-63ba-448b-b38b-502b41cd500e", + "title": "title2", + "annonymous": false, + "content": "content2", + "description": "description2", + "tags": [ + "green" + ] + } + """ + } `Then the response should be` OK and { + `And the response should not be null` + `And have property`("$.version_id") `whish contains` "09c418b6-63ba-448b-b38b-502b41cd500e" + `And have property`("$.title") `whish contains` "title2" + } + } + } +} diff --git a/src/test/kotlin/integration/BaseTest.kt b/src/test/kotlin/integration/BaseTest.kt index eb48ade..e531440 100644 --- a/src/test/kotlin/integration/BaseTest.kt +++ b/src/test/kotlin/integration/BaseTest.kt @@ -14,7 +14,6 @@ import io.ktor.util.KtorExperimentalAPI import io.lettuce.core.RedisClient import io.lettuce.core.api.sync.RedisCommands import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.isActive import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeAll @@ -22,9 +21,6 @@ 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 @@ -44,6 +40,9 @@ abstract class BaseTest : KoinTest { return engine.test() } + @ExperimentalCoroutinesApi + @KtorExperimentalAPI + @KtorExperimentalLocationsAPI @BeforeAll fun before() { engine.start() diff --git a/src/test/kotlin/integration/Citizen routes.kt b/src/test/kotlin/integration/Citizen routes.kt index 8cfe0d5..557a4f9 100644 --- a/src/test/kotlin/integration/Citizen routes.kt +++ b/src/test/kotlin/integration/Citizen routes.kt @@ -1,6 +1,5 @@ package integration -import integration.BaseTest import integration.asserts.`And have property` import integration.asserts.`And the response should not be null` import integration.asserts.`Then the response should be` @@ -13,17 +12,11 @@ import integration.asserts.given.`authenticated as` import io.ktor.http.HttpStatusCode.Companion.BadRequest import io.ktor.http.HttpStatusCode.Companion.Created import io.ktor.http.HttpStatusCode.Companion.OK -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.util.KtorExperimentalAPI -import kotlinx.coroutines.ExperimentalCoroutinesApi 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"), Tag("citizen")) class `Citizen routes` : BaseTest() { diff --git a/src/test/kotlin/integration/Login routes.kt b/src/test/kotlin/integration/Login routes.kt index 3f3ef48..4e3bda0 100644 --- a/src/test/kotlin/integration/Login routes.kt +++ b/src/test/kotlin/integration/Login routes.kt @@ -1,6 +1,5 @@ package integration -import integration.BaseTest import integration.asserts.`And the response should not be null` import integration.asserts.`Then the response should be` import integration.asserts.`and should contains` @@ -9,17 +8,11 @@ import integration.asserts.given.`Given I have citizen` import integration.asserts.given.`authenticated as` import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode.Companion.NoContent -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.util.KtorExperimentalAPI -import kotlinx.coroutines.ExperimentalCoroutinesApi 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"), Tag("auth")) class `Login routes` : BaseTest() { diff --git a/src/test/kotlin/integration/Register routes.kt b/src/test/kotlin/integration/Register routes.kt index 83acdcb..21b92fd 100644 --- a/src/test/kotlin/integration/Register routes.kt +++ b/src/test/kotlin/integration/Register routes.kt @@ -3,21 +3,14 @@ package integration import integration.asserts.`Then the response should be` import integration.asserts.`when`.`When I send a POST request` 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 null` import org.amshove.kluent.`should contain` import org.amshove.kluent.`should not be null` -import org.junit.experimental.categories.Category 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"), Tag("auth")) class `Register routes` : BaseTest() { diff --git a/src/test/kotlin/integration/asserts/asserts.kt b/src/test/kotlin/integration/asserts/asserts.kt index cd38ea0..c653886 100644 --- a/src/test/kotlin/integration/asserts/asserts.kt +++ b/src/test/kotlin/integration/asserts/asserts.kt @@ -40,7 +40,7 @@ infix fun TestApplicationResponse.`And have property`(path: String): Pair.`whish contains`(expected: Any): Pair = this.apply { - expected `should be equal to` second + second `should be equal to` expected } fun TestApplicationResponse.`And the response should contain`(path: String, valueExpected: String) { diff --git a/src/test/kotlin/integration/asserts/given/Article.kt b/src/test/kotlin/integration/asserts/given/Article.kt new file mode 100644 index 0000000..4769ab6 --- /dev/null +++ b/src/test/kotlin/integration/asserts/given/Article.kt @@ -0,0 +1,76 @@ +package integration.asserts.given + +import fr.dcproject.common.utils.toUUID +import fr.dcproject.component.article.ArticleForUpdate +import fr.dcproject.component.article.ArticleRepository +import fr.dcproject.component.auth.UserForCreate +import fr.dcproject.component.citizen.CitizenForCreate +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.workgroup.WorkgroupRef +import io.ktor.server.testing.TestApplicationEngine +import org.joda.time.DateTime +import org.koin.core.context.GlobalContext +import java.util.UUID + +fun TestApplicationEngine.`Given I have article`( + id: String? = null, + workgroup: WorkgroupRef? = null, + createdByUsername: String? = null +) { + createArticle(id?.toUUID(), workgroup, createdByUsername) +} + +fun TestApplicationEngine.`Given I have articles`( + numbers: Int, +) { + repeat(numbers) { + createArticle() + } +} +fun TestApplicationEngine.`Given I have article created by workgroup`( + workgroupId: String, +) { + createArticle(workgroup = WorkgroupRef(workgroupId.toUUID())) +} + +private fun createArticle( + id: UUID? = null, + workgroup: WorkgroupRef? = null, + createdByUsername: String? = null +) { + val username = (createdByUsername ?: "username" + UUID.randomUUID().toString()) + .toLowerCase().replace(' ', '-') + + val citizenRepository: CitizenRepository by lazy { GlobalContext.get().koin.get() } + val articleRepository: ArticleRepository by lazy { GlobalContext.get().koin.get() } + + val createdBy = if (createdByUsername != null) { + citizenRepository.findByUsername(username) ?: error("Citizen not exist") + } else { + val first = "firstName" + UUID.randomUUID().toString() + val last = "lastName" + UUID.randomUUID().toString() + CitizenForCreate( + birthday = DateTime.now(), + name = CitizenI.Name( + first, + last + ), + email = "$first@fakeemail.com", + user = UserForCreate(username = username, password = "azerty") + ).let { + citizenRepository.insertWithUser(it) ?: error("Unable to create User") + } + } + + val article = ArticleForUpdate( + id = id ?: UUID.randomUUID(), + title = "hello", + content = "bla bla bla", + description = "A super article", + createdBy = createdBy, + workgroup = workgroup, + versionId = UUID.randomUUID() + ) + articleRepository.upsert(article) +} diff --git a/src/test/kotlin/integration/asserts/given/Workgroup.kt b/src/test/kotlin/integration/asserts/given/Workgroup.kt new file mode 100644 index 0000000..b5ef95e --- /dev/null +++ b/src/test/kotlin/integration/asserts/given/Workgroup.kt @@ -0,0 +1,68 @@ +package integration.asserts.given + +import fr.dcproject.common.utils.toUUID +import fr.dcproject.component.auth.UserForCreate +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenForCreate +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.workgroup.Workgroup +import fr.dcproject.component.workgroup.WorkgroupRepository +import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member +import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role.MASTER +import io.ktor.server.testing.TestApplicationEngine +import org.joda.time.DateTime +import org.koin.core.context.GlobalContext +import org.koin.test.get +import java.util.UUID + +fun TestApplicationEngine.`Given I have workgroup`( + id: String? = null, + name: String? = null, + description: String? = null, + anonymous: Boolean? = null, + createdByUsername: String? = null +) { + createWorkgroup(id?.toUUID(), name, description, anonymous, createdByUsername) +} + +private fun createWorkgroup( + id: UUID? = null, + name: String? = null, + description: String? = null, + anonymous: Boolean? = null, + createdByUsername: String? = null +): Workgroup { + val username = (createdByUsername ?: "username" + UUID.randomUUID().toString()) + .toLowerCase().replace(' ', '-') + + val citizenRepository: CitizenRepository by lazy { GlobalContext.get().koin.get() } + val workgroupRepository: WorkgroupRepository by lazy { GlobalContext.get().koin.get() } + + val creator = citizenRepository.findByUsername(username.toLowerCase().replace(' ', '-')) + ?: run { + val user = UserForCreate( + username = username, + password = "azerty", + ) + CitizenForCreate( + name = CitizenI.Name("Paul", "Langevin"), + email = "$username@dc-project.fr", + birthday = DateTime.now(), + user = user + ).let { + citizenRepository.insertWithUser(it) ?: error("Unable to create User") + } + } + + val workgroup = Workgroup( + id = id ?: UUID.randomUUID(), + name = name ?: "Les Incoruptible", + description = description ?: "La vie est notre jeux", + createdBy = creator, + anonymous = (anonymous ?: false) == true, + members = listOf(Member(creator, listOf(MASTER))) + ) + + return workgroupRepository.upsert(workgroup) +}