Move tests and create a command to run all tests

This commit is contained in:
2021-01-15 02:40:41 +01:00
parent 7c106f7cf8
commit 459397f8e7
40 changed files with 160 additions and 66 deletions

View File

@@ -0,0 +1,102 @@
package steps
import fr.dcproject.component.article.ArticleForUpdate
import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.article.ArticleRepository
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.component.comment.article.CommentArticleRepository
import fr.dcproject.component.comment.generic.CommentForUpdate
import fr.dcproject.entity.WorkgroupRef
import fr.dcproject.utils.toUUID
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import org.joda.time.DateTime
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
import fr.dcproject.entity.User as UserEntity
class ArticleSteps : En, KoinTest {
init {
Given("I have {int} article") { nb: Int ->
repeat(nb) {
createArticle()
}
}
Given("I have article") { extraData: DataTable? ->
createArticle(extraData)
}
Given("I have article with ID {string}") { id: String ->
createArticle(id = UUID.fromString(id))
}
Given("I have article created by workgroup ID {string}") { id: String ->
createArticle(workgroup = WorkgroupRef(UUID.fromString(id)))
}
Given("I have comment created by {word} {word} on article {string}:") { firstName: String, lastName: String, articleId: String, extraData: DataTable? ->
commentArticle(articleId, firstName, lastName, extraData)
}
Given("I have comment created by {word} {word} on article {string}") { firstName: String, lastName: String, articleId: String ->
commentArticle(articleId, firstName, lastName)
}
}
private fun createArticle(extraData: DataTable? = null, id: UUID? = null, workgroup: WorkgroupRef? = null) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val createdByUsername = params?.get("createdBy")
val username = (createdByUsername ?: "username" + UUID.randomUUID().toString())
.toLowerCase().replace(' ', '-')
val createdBy = if (createdByUsername != null) {
get<CitizenRepository>().findByUsername(username) ?: error("Citizen not exist")
} else {
val first = "firstName" + UUID.randomUUID().toString()
val last = "lastName" + UUID.randomUUID().toString()
Citizen(
birthday = DateTime.now(),
name = CitizenI.Name(
first,
last
),
email = "$first@fakeemail.com",
user = UserEntity(username = username, plainPassword = "azerty")
).also {
get<CitizenRepository>().insertWithUser(it)
}
}
val article = ArticleForUpdate(
id = id ?: params?.get("id")?.toUUID(),
title = "hello",
content = "bla bla bla",
description = "A super article",
createdBy = createdBy,
workgroup = workgroup,
versionId = UUID.randomUUID()
)
get<ArticleRepository>().upsert(article)
}
private fun commentArticle(articleId: String, firstName: String, lastName: String, extraData: DataTable? = null, id: UUID? = null) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val article = get<ArticleRepository>().findById(UUID.fromString(articleId)) ?: error("Article not exist")
val citizen = get<CitizenRepository>().findByUsername(
("$firstName-$lastName".toLowerCase()).toLowerCase().replace(' ', '-')
) ?: error("Citizen not exist")
val comment: CommentForUpdate<ArticleForView, Citizen> = CommentForUpdate(
id = id ?: params?.get("id")?.let { UUID.fromString(it) } ?: UUID.randomUUID(),
createdBy = citizen,
target = article,
content = params?.get("content") ?: "hello"
)
get<CommentArticleRepository>().comment(comment)
}
}

View File

@@ -0,0 +1,58 @@
package steps
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.User
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import org.joda.time.DateTime
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
class CitizenSteps : En, KoinTest {
init {
Given("I have citizen") { extraData: DataTable? ->
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
createCitizen(
params?.get("firstName") ?: "firstName" + UUID.randomUUID(),
params?.get("lastName") ?: "lastName" + UUID.randomUUID(),
extraData
)
}
Given("I have citizen {word} {word}") { firstName: String, lastName: String ->
createCitizen(firstName, lastName)
}
Given("I have citizen {word} {word} with") { firstName: String, lastName: String, extraData: DataTable? ->
createCitizen(firstName, lastName, extraData)
}
Given("I have citizen {word} {word} with ID {string}") { firstName: String, lastName: String, id: String ->
createCitizen(firstName, lastName, id = UUID.fromString(id))
}
}
private fun createCitizen(firstName: String, lastName: String, extraData: DataTable? = null, id: UUID? = null) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val id: UUID = id ?: params?.get("id")?.let { UUID.fromString(it) } ?: UUID.randomUUID()
val email = params?.get("email") ?: ("$firstName-$lastName".toLowerCase()) + "@dc-project.fr"
val user = User(
id = id,
username = "$firstName-$lastName".toLowerCase(),
plainPassword = "azerty"
)
val citizen = Citizen(
id = id,
name = CitizenI.Name(firstName, lastName),
email = email,
birthday = DateTime.now(),
user = user
)
get<CitizenRepository>().insertWithUser(citizen)
}
}

View File

@@ -0,0 +1,107 @@
package steps
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.component.citizen.CitizenWithUserI
import fr.dcproject.component.comment.generic.CommentForUpdate
import fr.dcproject.entity.ConstitutionRef
import fr.dcproject.entity.ConstitutionSimple
import fr.dcproject.repository.CommentConstitutionRepository
import fr.dcproject.utils.toUUID
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import org.joda.time.DateTime
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
import fr.dcproject.entity.User as UserEntity
import fr.dcproject.repository.Constitution as ConstitutionRepository
class ConstitutionSteps : En, KoinTest {
init {
Given("I have {int} constitution") { nb: Int ->
repeat(nb) {
createConstitution()
}
}
Given("I have constitution") { extraData: DataTable? ->
createConstitution(extraData)
}
Given("I have constitution with ID {string}") { id: String? ->
createConstitution(id = UUID.fromString(id))
}
Given("I have comment created by {word} {word} on constitution {string}:") { firstName: String, lastName: String, constitutionId: String, extraData: DataTable? ->
commentConstitution(constitutionId, firstName, lastName, extraData)
}
Given("I have comment created by {word} {word} on constitution {string}") { firstName: String, lastName: String, constitutionId: String ->
commentConstitution(constitutionId, firstName, lastName)
}
}
private fun createConstitution(extraData: DataTable? = null, id: UUID? = null) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val createdByUsername = params?.get("createdBy")
val username = (createdByUsername ?: "username" + UUID.randomUUID().toString())
.toLowerCase().replace(' ', '-')
val createdBy = if (createdByUsername != null) {
get<CitizenRepository>().findByUsername(username) ?: error("Citizen not exist")
} else {
val first = "firstName" + UUID.randomUUID().toString()
val last = "lastName" + UUID.randomUUID().toString()
Citizen(
birthday = DateTime.now(),
name = CitizenI.Name(
first,
last
),
email = "$first@fakeemail.com",
user = UserEntity(username = username, plainPassword = "azerty")
).also {
get<CitizenRepository>().insertWithUser(it)
}
}
val title1 = ConstitutionSimple.TitleSimple<ArticleRef>(
name = "My Title"
)
val constitution = ConstitutionSimple<CitizenWithUserI, ConstitutionSimple.TitleSimple<ArticleRef>>(
id = id ?: params?.get("id")?.toUUID() ?: UUID.randomUUID(),
title = "hello",
titles = mutableListOf(title1),
anonymous = false,
createdBy = createdBy
)
get<ConstitutionRepository>().upsert(constitution)
}
private fun commentConstitution(
constitutionId: String,
firstName: String,
lastName: String,
extraData: DataTable? = null
) {
val params = extraData?.asMap<String, String>(String::class.java, String::class.java)
val constitution =
get<ConstitutionRepository>().findById(UUID.fromString(constitutionId)) ?: error("Constitution not exist")
val citizen = get<CitizenRepository>().findByUsername(
("$firstName-$lastName".toLowerCase()).toLowerCase().replace(' ', '-')
) ?: error("Citizen not exist")
val comment: CommentForUpdate<ConstitutionRef, Citizen> = CommentForUpdate(
id = params?.get("id")?.let { UUID.fromString(it) } ?: UUID.randomUUID(),
createdBy = citizen,
target = constitution,
content = params?.get("content") ?: "hello"
)
get<CommentConstitutionRepository>().comment(comment)
}
}

View File

@@ -0,0 +1,29 @@
package steps
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.ConstitutionRef
import fr.dcproject.entity.FollowForUpdate
import fr.dcproject.utils.toUUID
import io.cucumber.java8.En
import org.koin.test.KoinTest
import org.koin.test.get
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
class FollowSteps : En, KoinTest {
init {
Given("I have follow of {word} {word} on article {string}") { firstName: String, lastName: String, articleId: String ->
val username = "$firstName-$lastName".toLowerCase()
val citizen = get<CitizenRepository>().findByUsername(username) ?: error("Citizen not exist")
val follow = FollowForUpdate(createdBy = citizen, target = ArticleRef(articleId.toUUID()))
get<FollowArticleRepository>().follow(follow)
}
Given("I have follow of {word} {word} on constitution {string}") { firstName: String, lastName: String, constitutionId: String ->
val username = "$firstName-$lastName".toLowerCase()
val citizen = get<CitizenRepository>().findByUsername(username) ?: error("Citizen not exist")
val follow = FollowForUpdate(createdBy = citizen, target = ConstitutionRef(constitutionId.toUUID()))
get<FollowConstitutionRepository>().follow(follow)
}
}
}

View File

@@ -0,0 +1,26 @@
package steps
import com.auth0.jwt.JWT
import fr.dcproject.JwtConfig
import fr.dcproject.component.citizen.CitizenRepository
import io.cucumber.java8.En
import io.ktor.http.*
import org.koin.test.KoinTest
import org.koin.test.get
class KtorServerAuthSteps : En, KoinTest {
init {
Given("I am authenticated as {word} {word}") { firstName: String, lastName: String ->
val username = "$firstName-$lastName".toLowerCase()
val citizen = get<CitizenRepository>().findByUsername(username) ?: error("Cititzen not exist with username $username")
val jwtAsString: String = JWT.create()
.withIssuer("dc-project.fr")
.withClaim("id", citizen.user.id.toString())
.sign(JwtConfig.algorithm)
KtorServerContext.defaultServer.addPreRequestSetup {
addHeader(HttpHeaders.Authorization, "Bearer $jwtAsString")
}
}
}
}

View File

@@ -0,0 +1,51 @@
package steps
import io.ktor.application.*
import io.ktor.server.testing.*
import java.util.concurrent.TimeUnit
import kotlin.test.fail
class KtorServerContext(useByDefault: Boolean = true, val module: Application.() -> Unit) {
init { if (useByDefault) setDefault() }
companion object {
lateinit var defaultServer: KtorServerContext
}
private val engine = TestApplicationEngine(createTestEnvironment())
private data class RequestSetup(val setup: TestApplicationRequest.() -> Unit, val keepSetup: Boolean = true)
private val preRequestSetup = mutableListOf<RequestSetup>()
var call: TestApplicationCall? = null
fun addPreRequestSetup(keepSetup: Boolean = true, hook: TestApplicationRequest.() -> Unit) {
preRequestSetup.add(RequestSetup(hook, keepSetup))
}
fun handleRequest(setup: TestApplicationRequest.() -> Unit) =
try {
call = engine.handleRequest {
preRequestSetup.forEach { it.setup(this) }
setup(this)
}
} catch (e: Throwable) {
fail("Request fail, $e")
} finally {
preRequestSetup.removeAll { !it.keepSetup }
}
fun setDefault() {
defaultServer = this
}
fun start() {
engine.start()
module(engine.application)
}
fun stop() {
engine.stop(0L, 0L, TimeUnit.MILLISECONDS)
}
}

View File

@@ -0,0 +1,68 @@
package steps
import com.jayway.jsonpath.JsonPath
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import io.ktor.http.*
import io.ktor.server.testing.*
import io.ktor.util.*
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
@ImplicitReflectionSerializer
@KtorExperimentalAPI
class KtorServerRequestSteps : En {
init {
Given("Next request as headers:") { dataTable: DataTable ->
KtorServerContext.defaultServer.addPreRequestSetup(false) {
dataTable.asMap<String, String>(String::class.java, String::class.java).forEach { key, value ->
this.addHeader(key, value)
}
}
}
Given("I send a {word} request to {string} with body:") { method: String, uri: String, body: String ->
KtorServerContext.defaultServer.handleRequest {
this.method = HttpMethod.parse(method)
this.uri = uri
this.addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setBody(body)
}
}
Given("I send a {word} request to {string}") { method: String, uri: String ->
KtorServerContext.defaultServer.handleRequest {
this.method = HttpMethod.parse(method.toUpperCase())
this.uri = uri
}
}
Then("the response status code should be {int}") { statusCode: Int ->
assertEquals(
HttpStatusCode.fromValue(statusCode),
KtorServerContext.defaultServer.call?.response?.status(),
KtorServerContext.defaultServer.call?.response?.content
)
}
Then("the response should contain object:") { expected: DataTable ->
expected.asMap<String, String>(String::class.java, String::class.java).forEach { (key, valueExpected) ->
assertEquals(valueExpected, JsonPath.read<Any>(response, key)?.toString() ?: throw AssertionError("\"$key\" element not found on json response"))
}
}
Then("the response should not contain object:") { expected: DataTable ->
expected.asMap<String, String>(String::class.java, String::class.java).forEach { (key, valueExpected) ->
assertNotEquals(valueExpected, JsonPath.read<Any>(response, key)?.toString() ?: throw AssertionError("\"$key\" element not found on json response"))
}
}
Then("print last response") {
print(KtorServerContext.defaultServer.call?.response?.content)
}
}
private val response: String?
get() = KtorServerContext.defaultServer.call?.response?.content
}

View File

@@ -0,0 +1,67 @@
package steps
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.parse
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
@ImplicitReflectionSerializer
class KtorServerRestSteps : En {
init {
Then("the JSON should contain:") { dataTable: DataTable ->
dataTable.asMap<String, String>(String::class.java, String::class.java).forEach { (key, value) ->
val jsonPrimitive = findJsonElement(key) as? JsonPrimitive ?: fail("\"$key\" element isn't json primitive")
assertEquals(jsonPrimitive.content, value)
}
}
Then("the JSON element {word} should have {int} item(s)") { node: String, count: Int ->
val jsonArray = findJsonElement(node) as? JsonArray ?: fail("\"$node\" element isn't json array")
assertEquals(count, jsonArray.size)
}
Then("the JSON should have {int} item(s)") { count: Int ->
val jsonArray = responseJsonElement as? JsonArray ?: fail("The json response isn't array")
assertEquals(count, jsonArray.size)
}
Then("the Response should be:") { body: String ->
assertEquals(body, response)
}
Then("the Response should contain:") { body: String ->
assertTrue(response.contains(body))
}
}
private fun findJsonElement(path: String): JsonElement {
var jsonElement: JsonElement = responseJsonElement
path
.split("].", "]", "[", ".")
.filter { it.trim().isNotBlank() }
.map { it.trim() }
.forEach {
jsonElement = if (jsonElement is JsonArray) {
jsonElement.jsonArray[it.toInt()]
} else {
jsonElement.jsonObject[it]
} ?: throw AssertionError("\"$path\" element not found on json response")
}
return jsonElement
}
private val responseJsonElement: JsonElement
get() = Json.parse(KtorServerContext.defaultServer.call?.response?.content ?: fail("The response isn't valid JSON"))
private val response: String
get() = KtorServerContext.defaultServer.call?.response?.content ?: fail("The response isn't valid")
}

View File

@@ -0,0 +1,82 @@
package steps
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.article.ArticleRepository
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.OpinionChoice
import fr.dcproject.entity.OpinionForUpdate
import fr.dcproject.utils.toUUID
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
import fr.dcproject.repository.OpinionArticle as OpinionRepository
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
class OpinionSteps : En, KoinTest {
init {
Given("I have an opinion choice {string}") { name: String ->
val opinionChoice = OpinionChoice(
name = name,
target = listOf()
)
get<OpinionRepository>().upsertOpinionChoice(opinionChoice)
}
Given("I have an opinion choice {string} with ID {string}") { name: String, id: String ->
val opinionChoice = OpinionChoice(
id = id.toUUID(),
name = name,
target = listOf()
)
get<OpinionRepository>().upsertOpinionChoice(opinionChoice)
}
Given("I have an opinion {string} on article {string} created by {word} {word}") { opinionChoiceName: String, articleId: String, firstName: String, lastName: String ->
createOpinion(opinionChoiceName, articleId, firstName, lastName)
}
Given("I have an opinion {string} on article {string} created by {word} {word} with ID {string}") { opinionChoiceName: String, articleId: String, firstName: String, lastName: String, id: String ->
createOpinion(opinionChoiceName, articleId, firstName, lastName, id)
}
Given("I have an opinion") { extraInfo: DataTable ->
createOpinionOnArticle(extraInfo)
}
}
private fun createOpinion(
opinionChoiceName: String,
articleId: String,
firstName: String,
lastName: String,
id: String? = null
) {
val opinion = OpinionForUpdate(
id = id?.toUUID() ?: UUID.randomUUID(),
choice = get<OpinionChoiceRepository>().findOpinionsChoiceByName(opinionChoiceName)
?: error("Opinion Choice not exist"),
target = ArticleRef(articleId.toUUID()),
createdBy = get<CitizenRepository>().findByUsername("$firstName-$lastName".toLowerCase().replace(' ', '-'))
?: error("Citizen not exist")
)
get<OpinionRepository>().addOpinion(opinion)
}
private fun createOpinionOnArticle(extraInfo: DataTable? = null) {
val params = extraInfo?.asMap<String, String>(String::class.java, String::class.java)
val username = params?.get("createdBy")?.toLowerCase()?.replace(' ', '-')
?: error("You must provide the 'createdBy' parameter")
val opinion = OpinionForUpdate(
choice = params["opinion"]?.let {
get<OpinionChoiceRepository>().findOpinionsChoiceByName(it) ?: error("Opinion Choice not exist")
} ?: error("You must provide the 'opinion' parameter"),
target = params["article"]?.let {
get<ArticleRepository>().findById(it.toUUID()) ?: error("Article not exist")
} ?: error("You must provide the 'article' parameter"),
createdBy = get<CitizenRepository>().findByUsername(username) ?: error("Citizen not exist")
)
get<OpinionRepository>().updateOpinions(opinion.choice, opinion.createdBy, opinion.target)
}
}

View File

@@ -0,0 +1,33 @@
package steps
import fr.dcproject.component.article.ArticleRepository
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.VoteForUpdate
import fr.dcproject.utils.toUUID
import io.cucumber.java8.En
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
import fr.dcproject.repository.VoteArticle as VoteRepository
class VoteSteps : En, KoinTest {
init {
Given("I have an vote {int} on article {string} created by {word} {word}") { note: Int, articleId: String, firstName: String, lastName: String ->
createVote(note, articleId, firstName, lastName)
}
Given("I have an vote {int} on article {string} created by {word} {word} with ID {string}") { note: Int, articleId: String, firstName: String, lastName: String, id: String ->
createVote(note, articleId, firstName, lastName, id)
}
}
private fun createVote(note: Int, articleId: String, firstName: String, lastName: String, id: String? = null) {
val vote = VoteForUpdate(
id = id?.toUUID() ?: UUID.randomUUID(),
note = note,
target = get<ArticleRepository>().findById(articleId.toUUID()) ?: error("Article not exist"),
createdBy = get<CitizenRepository>().findByUsername("$firstName-$lastName".toLowerCase().replace(' ', '-')) ?: error("Citizen not exist")
)
get<VoteRepository>().vote(vote)
}
}

View File

@@ -0,0 +1,72 @@
package steps
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.*
import fr.dcproject.entity.WorkgroupWithMembersI.Member
import fr.dcproject.utils.toUUID
import io.cucumber.datatable.DataTable
import io.cucumber.java8.En
import org.joda.time.DateTime
import org.junit.Assert
import org.koin.test.KoinTest
import org.koin.test.get
import java.util.*
import fr.dcproject.repository.Workgroup as WorkgroupRepository
class WorkgroupSteps : En, KoinTest {
init {
When("I have members in workgroup {string}:") { workgroupId: String, members: DataTable ->
val membersRefs = members.asList()
.map { Member(
citizen = CitizenRef(it.toUUID()),
roles = listOf(Member.Role.MASTER)
) }
get<WorkgroupRepository>().addMembers(WorkgroupRef(workgroupId.toUUID()), membersRefs)
}
When("I have workgroup:") { body: DataTable ->
val data = body.asMap<String, String>(String::class.java, String::class.java)
val creator = data["created_by"]?.let {
get<CitizenRepository>().findByUsername(it.toLowerCase().replace(' ', '-'))
} ?: run {
val username = "paul-langevin".toLowerCase() + UUID.randomUUID()
val user = User(
username = username,
plainPassword = "azerty"
)
Citizen(
name = CitizenI.Name("Paul", "Langevin"),
email = "$username@dc-project.fr",
birthday = DateTime.now(),
user = user
).also {
get<CitizenRepository>().insertWithUser(it)
}
}
val workgroup = Workgroup(
id = UUID.fromString(data["id"] ?: UUID.randomUUID().toString()),
name = data["name"] ?: "Les Incoruptible",
description = data["description"] ?: "La vie est notre jeux",
createdBy = creator,
anonymous = (data["anonymous"] ?: false) == true,
members = listOf(Member(creator, listOf(Member.Role.MASTER)))
)
get<WorkgroupRepository>().upsert(workgroup)
}
Then("The workgroup {string} exists") { id: String ->
Assert.assertNotNull(get<WorkgroupRepository>().findById(id.toUUID()))
}
Then("The workgroup {string} not exists") { id: String ->
Assert.assertNull(get<WorkgroupRepository>().findById(id.toUUID()))
}
}
}