Test openapi schema requestBody

This commit is contained in:
2021-03-15 02:01:39 +01:00
parent 9c88adbabd
commit 97b07fb424
12 changed files with 155 additions and 87 deletions

View File

@@ -6,6 +6,7 @@ import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`with body`
import integration.steps.then.`whish contains` import integration.steps.then.`whish contains`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have article created by workgroup` import integration.steps.given.`Given I have article created by workgroup`
@@ -14,7 +15,6 @@ import integration.steps.given.`Given I have articles`
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
import integration.steps.given.`Given I have workgroup` import integration.steps.given.`Given I have workgroup`
import integration.steps.given.`authenticated as` import integration.steps.given.`authenticated as`
import integration.steps.then.`And schema must be valid`
import integration.steps.then.`And the response should contain list` import integration.steps.then.`And the response should contain list`
import integration.steps.then.`And the response should not contain` import integration.steps.then.`And the response should not contain`
import io.ktor.http.HttpStatusCode.Companion.OK import io.ktor.http.HttpStatusCode.Companion.OK
@@ -37,7 +37,6 @@ class `Article routes` : BaseTest() {
`And the response should contain pattern`("$.result[2].createdBy.name.firstName", "firstName.+") `And the response should contain pattern`("$.result[2].createdBy.name.firstName", "firstName.+")
`And the response should not contain`("$.result[3]") `And the response should not contain`("$.result[3]")
`And the response should contain list`("$.result", 3, 3) `And the response should contain list`("$.result", 3, 3)
`And schema must be valid`()
} }
} }
} }
@@ -52,7 +51,6 @@ class `Article routes` : BaseTest() {
`And the response should not be null`() `And the response should not be null`()
`And have property`("$.total") `whish contains` 1 `And have property`("$.total") `whish contains` 1
`And have property`("$.result[0]workgroup.name") `whish contains` "Les papy" `And have property`("$.result[0]workgroup.name") `whish contains` "Les papy"
`And schema must be valid`()
} }
} }
} }
@@ -64,7 +62,6 @@ class `Article routes` : BaseTest() {
`When I send a GET request`("/articles/65cda9f3-8991-4420-8d41-1da9da72c9bb") `Then the response should be` OK and { `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 the response should not be null`()
`And have property`("$.id") `whish contains` "65cda9f3-8991-4420-8d41-1da9da72c9bb" `And have property`("$.id") `whish contains` "65cda9f3-8991-4420-8d41-1da9da72c9bb"
`And schema must be valid`()
} }
} }
} }
@@ -77,7 +74,6 @@ class `Article routes` : BaseTest() {
`And the response should not be null`() `And the response should not be null`()
`And have property`("$.total") `whish contains` 1 `And have property`("$.total") `whish contains` 1
`And have property`("$.result[0].id") `whish contains` "13e6091c-8fed-4600-b079-a97a6b7a9800" `And have property`("$.result[0].id") `whish contains` "13e6091c-8fed-4600-b079-a97a6b7a9800"
`And schema must be valid`()
} }
} }
} }
@@ -88,7 +84,7 @@ class `Article routes` : BaseTest() {
`Given I have citizen`("John", "Doe") `Given I have citizen`("John", "Doe")
`When I send a POST request`("/articles") { `When I send a POST request`("/articles") {
`authenticated as`("John", "Doe") `authenticated as`("John", "Doe")
""" `with body`("""
{ {
"versionId": "09c418b6-63ba-448b-b38b-502b41cd500e", "versionId": "09c418b6-63ba-448b-b38b-502b41cd500e",
"title": "title2", "title": "title2",
@@ -99,11 +95,10 @@ class `Article routes` : BaseTest() {
"green" "green"
] ]
} }
""" """)
} `Then the response should be` OK and { } `Then the response should be` OK and {
`And the response should not be null`() `And the response should not be null`()
`And have property`("$.versionId") `whish contains` "09c418b6-63ba-448b-b38b-502b41cd500e" `And have property`("$.versionId") `whish contains` "09c418b6-63ba-448b-b38b-502b41cd500e"
`And schema must be valid`()
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`When I send a PUT request`
import integration.steps.`when`.`with body`
import integration.steps.then.`whish contains` import integration.steps.then.`whish contains`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
@@ -64,12 +65,12 @@ class `Citizen routes` : BaseTest() {
`Given I have citizen`("Georges", "Charpak", id = "0c966522-4071-43e5-a3ca-cfff2557f2cf") `Given I have citizen`("Georges", "Charpak", id = "0c966522-4071-43e5-a3ca-cfff2557f2cf")
`When I send a PUT request`("/citizens/0c966522-4071-43e5-a3ca-cfff2557f2cf/password/change") { `When I send a PUT request`("/citizens/0c966522-4071-43e5-a3ca-cfff2557f2cf/password/change") {
`authenticated as`("Georges", "Charpak") `authenticated as`("Georges", "Charpak")
""" `with body`("""
{ {
"old_password": "azerty", "old_password": "azerty",
"new_password": "qwerty" "new_password": "qwerty"
} }
""" """)
} `Then the response should be` Created } `Then the response should be` Created
} }
} }
@@ -80,12 +81,12 @@ class `Citizen routes` : BaseTest() {
`Given I have citizen`("Louis", "Breguet", id = "6cf2a19d-d15d-4ee5-b2a9-907afd26b525") `Given I have citizen`("Louis", "Breguet", id = "6cf2a19d-d15d-4ee5-b2a9-907afd26b525")
`When I send a PUT request`("/citizens/6cf2a19d-d15d-4ee5-b2a9-907afd26b525/password/change") { `When I send a PUT request`("/citizens/6cf2a19d-d15d-4ee5-b2a9-907afd26b525/password/change") {
`authenticated as`("Louis", "Breguet") `authenticated as`("Louis", "Breguet")
""" `with body`("""
{ {
"plup": "azerty", "plup": "azerty",
"gloup": "qwerty" "gloup": "qwerty"
} }
""" """)
} `Then the response should be` BadRequest } `Then the response should be` BadRequest
} }
} }

View File

@@ -7,6 +7,7 @@ import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`When I send a PUT request`
import integration.steps.`when`.`with body`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have article`
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
@@ -29,11 +30,11 @@ class `Comment articles routes` : BaseTest() {
`Given I have article`(id = "aa16c635-28da-46f0-9a89-934eef88c7ca") `Given I have article`(id = "aa16c635-28da-46f0-9a89-934eef88c7ca")
`When I send a POST request`("/articles/aa16c635-28da-46f0-9a89-934eef88c7ca/comments") { `When I send a POST request`("/articles/aa16c635-28da-46f0-9a89-934eef88c7ca/comments") {
`authenticated as`("Michael", "Faraday") `authenticated as`("Michael", "Faraday")
""" `with body`("""
{ {
"content": "Hello mister" "content": "Hello mister"
} }
""" """)
} `Then the response should be` Created and { } `Then the response should be` Created and {
`And the response should not be null`() `And the response should not be null`()
`And the response should contain`("$.target.id", "aa16c635-28da-46f0-9a89-934eef88c7ca") `And the response should contain`("$.target.id", "aa16c635-28da-46f0-9a89-934eef88c7ca")
@@ -98,9 +99,9 @@ class `Comment articles routes` : BaseTest() {
`Given I have comment on article`(article = "bb05e4a3-55a1-4088-85e7-8d8c23be29b1", createdBy = Name("Hubert", "Reeves"), id = "fd30d20f-656c-42c6-8955-f61c04537464") `Given I have comment on article`(article = "bb05e4a3-55a1-4088-85e7-8d8c23be29b1", createdBy = Name("Hubert", "Reeves"), id = "fd30d20f-656c-42c6-8955-f61c04537464")
`When I send a PUT request`("/comments/fd30d20f-656c-42c6-8955-f61c04537464") { `When I send a PUT request`("/comments/fd30d20f-656c-42c6-8955-f61c04537464") {
`authenticated as`("Hubert", "Reeves") `authenticated as`("Hubert", "Reeves")
""" `with body`("""
Hello boy Hello boy
""" """)
} `Then the response should be` OK and { } `Then the response should be` OK and {
`And the response should not be null`() `And the response should not be null`()
`And the response should contain`("$.content", "Hello boy") `And the response should contain`("$.content", "Hello boy")

View File

@@ -7,6 +7,7 @@ import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`with body`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
import integration.steps.given.`Given I have comment on constitution` import integration.steps.given.`Given I have comment on constitution`
@@ -14,6 +15,7 @@ import integration.steps.given.`Given I have constitution`
import integration.steps.given.`authenticated as` import integration.steps.given.`authenticated as`
import io.ktor.http.HttpStatusCode.Companion.Created import io.ktor.http.HttpStatusCode.Companion.Created
import io.ktor.http.HttpStatusCode.Companion.OK import io.ktor.http.HttpStatusCode.Companion.OK
import io.ktor.server.testing.setBody
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@@ -29,11 +31,11 @@ class `Comment constitutions routes` : BaseTest() {
`Given I have constitution`(id = "1707c287-a472-4a62-89f2-9e85030e915c") `Given I have constitution`(id = "1707c287-a472-4a62-89f2-9e85030e915c")
`When I send a POST request`("/constitutions/1707c287-a472-4a62-89f2-9e85030e915c/comments") { `When I send a POST request`("/constitutions/1707c287-a472-4a62-89f2-9e85030e915c/comments") {
`authenticated as`("Nicolas", "Copernic") `authenticated as`("Nicolas", "Copernic")
""" `with body`("""
{ {
"content": "Hello mister" "content": "Hello mister"
} }
""" """)
} `Then the response should be` Created and { } `Then the response should be` Created and {
`And the response should not be null`() `And the response should not be null`()
} }

View File

@@ -5,6 +5,7 @@ import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`with body`
import integration.steps.then.`whish contains` import integration.steps.then.`whish contains`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
@@ -62,7 +63,7 @@ class `Constitution routes` : BaseTest() {
`Given I have citizen`("Henri", "Poincaré") `Given I have citizen`("Henri", "Poincaré")
`When I send a POST request`("/constitutions") { `When I send a POST request`("/constitutions") {
`authenticated as`("Henri", "Poincaré") `authenticated as`("Henri", "Poincaré")
""" `with body`("""
{ {
"version_id":"15814bb6-8d90-4c6a-a456-c3939a8ec75e", "version_id":"15814bb6-8d90-4c6a-a456-c3939a8ec75e",
"title":"Hello world!", "title":"Hello world!",
@@ -74,7 +75,7 @@ class `Constitution routes` : BaseTest() {
} }
] ]
} }
""" """)
} `Then the response should be` OK and { } `Then the response should be` OK and {
`And the response should not be null`() `And the response should not be null`()
`And have property`("$.version_id") `whish contains` "15814bb6-8d90-4c6a-a456-c3939a8ec75e" `And have property`("$.version_id") `whish contains` "15814bb6-8d90-4c6a-a456-c3939a8ec75e"

View File

@@ -4,10 +4,12 @@ import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.then.`and should contains` import integration.steps.then.`and should contains`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`with body`
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
import integration.steps.given.`authenticated as` import integration.steps.given.`authenticated as`
import io.ktor.http.HttpStatusCode import integration.steps.then.and
import io.ktor.http.HttpStatusCode.Companion.NoContent import io.ktor.http.HttpStatusCode.Companion.NoContent
import io.ktor.http.HttpStatusCode.Companion.OK
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@@ -21,14 +23,15 @@ class `Login routes` : BaseTest() {
withIntegrationApplication { withIntegrationApplication {
`Given I have citizen`("Niels", "Bohr") `Given I have citizen`("Niels", "Bohr")
`When I send a POST request`("/login") { `When I send a POST request`("/login") {
""" `with body`("""
{ {
"username": "niels-bohr", "username": "niels-bohr",
"password": "azerty" "password": "azerty"
} }
""" """)
}.`Then the response should be`(HttpStatusCode.OK) { } `Then the response should be` OK and {
`And the response should not be null`() `and should contains` "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9." `And the response should not be null`() `and should contains` "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9."
//TODO valid requestBody
} }
} }
} }
@@ -39,12 +42,12 @@ class `Login routes` : BaseTest() {
`Given I have citizen`("Leonhard", "Euler", "fabrice.lecomte.be@gmail.com", id = "c606110c-ff0e-4d09-a79e-74632d7bf7bd") `Given I have citizen`("Leonhard", "Euler", "fabrice.lecomte.be@gmail.com", id = "c606110c-ff0e-4d09-a79e-74632d7bf7bd")
`When I send a POST request`("/auth/passwordless") { `When I send a POST request`("/auth/passwordless") {
`authenticated as`("Leonhard", "Euler") `authenticated as`("Leonhard", "Euler")
""" `with body`("""
{ {
"url": "https://dc-project.fr/password/reset", "url": "https://dc-project.fr/password/reset",
"email": "fabrice.lecomte.be@gmail.com" "email": "fabrice.lecomte.be@gmail.com"
} }
""" """)
} `Then the response should be` NoContent } `Then the response should be` NoContent
} }
} }

View File

@@ -6,6 +6,7 @@ import integration.steps.then.`And the response should contain`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`When I send a PUT request`
import integration.steps.`when`.`with body`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have an opinion choice` import integration.steps.given.`Given I have an opinion choice`
import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have article`
@@ -54,13 +55,13 @@ class `Opinion routes` : BaseTest() {
`Given I have article`(id = "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b", createdBy = Name("Isaac", "Newton")) `Given I have article`(id = "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b", createdBy = Name("Isaac", "Newton"))
`When I send a PUT request`("/articles/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/opinions") { `When I send a PUT request`("/articles/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/opinions") {
`authenticated as`("Isaac", "Newton") `authenticated as`("Isaac", "Newton")
""" `with body`("""
{ {
"ids": [ "ids": [
"0f4f1721-3136-44f1-9f31-1459f3317b15" "0f4f1721-3136-44f1-9f31-1459f3317b15"
] ]
} }
""" """)
} `Then the response should be` Created } `Then the response should be` Created
} }
} }

View File

@@ -2,6 +2,7 @@ package integration
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`with body`
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import org.amshove.kluent.`should be null` import org.amshove.kluent.`should be null`
import org.amshove.kluent.`should contain` import org.amshove.kluent.`should contain`
@@ -18,7 +19,7 @@ class `Register routes` : BaseTest() {
fun `I can register`() { fun `I can register`() {
withIntegrationApplication { withIntegrationApplication {
`When I send a POST request`("/register") { `When I send a POST request`("/register") {
""" `with body`("""
{ {
"name": {"first_name":"George", "last_name":"MICHEL"}, "name": {"first_name":"George", "last_name":"MICHEL"},
"birthday": "2001-01-01", "birthday": "2001-01-01",
@@ -28,7 +29,7 @@ class `Register routes` : BaseTest() {
}, },
"email": "george-junior@gmail.com" "email": "george-junior@gmail.com"
} }
""" """)
}.`Then the response should be`(HttpStatusCode.OK) { }.`Then the response should be`(HttpStatusCode.OK) {
content content
.`should not be null`() .`should not be null`()
@@ -41,7 +42,7 @@ class `Register routes` : BaseTest() {
fun `I cannot register if no username was sent`() { fun `I cannot register if no username was sent`() {
withIntegrationApplication { withIntegrationApplication {
`When I send a POST request`("/register") { `When I send a POST request`("/register") {
""" `with body`("""
{ {
"name": {"first_name":"George2", "last_name":"MICHEL2"}, "name": {"first_name":"George2", "last_name":"MICHEL2"},
"birthday": "2001-01-01", "birthday": "2001-01-01",
@@ -50,7 +51,7 @@ class `Register routes` : BaseTest() {
"password": "" "password": ""
} }
} }
""" """)
}.`Then the response should be`(HttpStatusCode.BadRequest) { }.`Then the response should be`(HttpStatusCode.BadRequest) {
content.`should be null`() content.`should be null`()
} }

View File

@@ -5,6 +5,7 @@ import integration.steps.then.`And the response should contain`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`When I send a PUT request`
import integration.steps.`when`.`with body`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have article`
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
@@ -30,11 +31,11 @@ class `Vote routes` : BaseTest() {
`Given I have article`(id = "835c5101-ca39-4038-a4e6-da6ee62ca6d5") `Given I have article`(id = "835c5101-ca39-4038-a4e6-da6ee62ca6d5")
`When I send a PUT request`("/articles/835c5101-ca39-4038-a4e6-da6ee62ca6d5/vote") { `When I send a PUT request`("/articles/835c5101-ca39-4038-a4e6-da6ee62ca6d5/vote") {
`authenticated as`("Thalès", "Milet") `authenticated as`("Thalès", "Milet")
""" `with body`("""
{ {
"note": 1 "note": 1
} }
""" """)
} `Then the response should be` Created } `Then the response should be` Created
} }
} }
@@ -46,11 +47,11 @@ class `Vote routes` : BaseTest() {
`Given I have constitution`(id = "76e79c89-efc1-492d-9e8f-dc9717363a11") `Given I have constitution`(id = "76e79c89-efc1-492d-9e8f-dc9717363a11")
`When I send a PUT request`("/constitutions/76e79c89-efc1-492d-9e8f-dc9717363a11/vote") { `When I send a PUT request`("/constitutions/76e79c89-efc1-492d-9e8f-dc9717363a11/vote") {
`authenticated as`("Gregor", "Mendel") `authenticated as`("Gregor", "Mendel")
""" `with body`("""
{ {
"note": 1 "note": 1
} }
""" """)
} `Then the response should be` Created } `Then the response should be` Created
} }
} }
@@ -101,11 +102,11 @@ class `Vote routes` : BaseTest() {
) )
`When I send a PUT request`("/comments/e793eccc-456b-4450-a292-46d592229b74/vote") { `When I send a PUT request`("/comments/e793eccc-456b-4450-a292-46d592229b74/vote") {
`authenticated as`("Antoine", "Lavoisier") `authenticated as`("Antoine", "Lavoisier")
""" `with body`("""
{ {
"note": -1 "note": -1
} }
""" """)
} `Then the response should be` Created and { } `Then the response should be` Created and {
`And the response should contain`("$.down", 1) `And the response should contain`("$.down", 1)
} }

View File

@@ -9,6 +9,7 @@ import integration.steps.`when`.`When I send a DELETE request`
import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request` import integration.steps.`when`.`When I send a POST request`
import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`When I send a PUT request`
import integration.steps.`when`.`with body`
import integration.steps.then.and import integration.steps.then.and
import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have citizen`
import integration.steps.given.`Given I have workgroup` import integration.steps.given.`Given I have workgroup`
@@ -66,14 +67,14 @@ class `Workgroup routes` : BaseTest() {
`Given I have citizen`("Werner", "Heisenberg") `Given I have citizen`("Werner", "Heisenberg")
`When I send a POST request`("/workgroups") { `When I send a POST request`("/workgroups") {
`authenticated as`("Werner", "Heisenberg") `authenticated as`("Werner", "Heisenberg")
""" `with body`("""
{ {
"id":"f496d86d-6654-4068-91ff-90e1dbcc5f38", "id":"f496d86d-6654-4068-91ff-90e1dbcc5f38",
"name":"Les Bouffons", "name":"Les Bouffons",
"description":"La vie est belle", "description":"La vie est belle",
"anonymous":false "anonymous":false
} }
""" """)
} `Then the response should be` Created and { } `Then the response should be` Created and {
`And the response should contain`("$.id", "f496d86d-6654-4068-91ff-90e1dbcc5f38") `And the response should contain`("$.id", "f496d86d-6654-4068-91ff-90e1dbcc5f38")
`And the response should contain`("$.name", "Les Bouffons") `And the response should contain`("$.name", "Les Bouffons")
@@ -128,7 +129,7 @@ class `Workgroup routes` : BaseTest() {
`Given I have workgroup`("b0ea1922-3bc6-44e2-aa7c-40158998cfbb", createdBy = Name("Blaise", "Pascal")) `Given I have workgroup`("b0ea1922-3bc6-44e2-aa7c-40158998cfbb", createdBy = Name("Blaise", "Pascal"))
`When I send a POST request`("/workgroups/b0ea1922-3bc6-44e2-aa7c-40158998cfbb/members") { `When I send a POST request`("/workgroups/b0ea1922-3bc6-44e2-aa7c-40158998cfbb/members") {
`authenticated as`("Blaise", "Pascal") `authenticated as`("Blaise", "Pascal")
""" `with body`("""
[ [
{ {
"citizen": {"id":"6d883fe7-5fc0-4a50-8858-72230673eba4"}, "citizen": {"id":"6d883fe7-5fc0-4a50-8858-72230673eba4"},
@@ -139,7 +140,7 @@ class `Workgroup routes` : BaseTest() {
"roles": ["MASTER"] "roles": ["MASTER"]
} }
] ]
""" """)
} `Then the response should be` Created } `Then the response should be` Created
} }
} }
@@ -189,7 +190,7 @@ class `Workgroup routes` : BaseTest() {
} }
`When I send a PUT request`("/workgroups/784fe6bc-7635-4ae2-b080-3a4743b998bf/members") { `When I send a PUT request`("/workgroups/784fe6bc-7635-4ae2-b080-3a4743b998bf/members") {
`authenticated as`("Leon", "Foucault") `authenticated as`("Leon", "Foucault")
""" `with body`("""
[ [
{ {
"citizen": {"id":"be3b0926-8628-4426-804a-75188a6eb315"}, "citizen": {"id":"be3b0926-8628-4426-804a-75188a6eb315"},
@@ -200,7 +201,7 @@ class `Workgroup routes` : BaseTest() {
"roles": ["MASTER"] "roles": ["MASTER"]
} }
] ]
""" """)
} `Then the response should be` OK and { } `Then the response should be` OK and {
`And the response should contain list`("$", 2, 2) `And the response should contain list`("$", 2, 2)
`And the response should contain`("$.[0]citizen.id", "be3b0926-8628-4426-804a-75188a6eb315") `And the response should contain`("$.[0]citizen.id", "be3b0926-8628-4426-804a-75188a6eb315")

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.TextNode import com.fasterxml.jackson.databind.node.TextNode
import fr.dcproject.common.utils.getResource import fr.dcproject.common.utils.getResource
import io.ktor.http.ContentType
import io.ktor.http.Url import io.ktor.http.Url
import io.ktor.request.contentType import io.ktor.request.contentType
import io.ktor.request.httpMethod import io.ktor.request.httpMethod
@@ -11,14 +12,27 @@ import io.ktor.request.uri
import io.ktor.server.testing.TestApplicationResponse import io.ktor.server.testing.TestApplicationResponse
import org.openapi4j.core.model.v3.OAI3 import org.openapi4j.core.model.v3.OAI3
import org.openapi4j.parser.OpenApi3Parser import org.openapi4j.parser.OpenApi3Parser
import org.openapi4j.parser.model.v3.OpenApi3
import org.openapi4j.parser.model.v3.Operation
import org.openapi4j.parser.model.v3.Schema
import org.openapi4j.schema.validator.ValidationContext import org.openapi4j.schema.validator.ValidationContext
import org.openapi4j.schema.validator.ValidationData import org.openapi4j.schema.validator.ValidationData
import org.openapi4j.schema.validator.v3.SchemaValidator import org.openapi4j.schema.validator.v3.SchemaValidator
import java.io.File import java.io.File
import kotlin.test.assertTrue import kotlin.test.assertTrue
fun TestApplicationResponse.`And schema must be valid`(route: String? = null) { fun Schema.validate(api: OpenApi3, toValidate: JsonNode) {
OpenApi3Parser().parse(File("/openapi2.yaml".getResource().toURI()), true).let { api -> val validationContext: ValidationContext<OAI3> = ValidationContext(api.context)
val schemaValidator = SchemaValidator(validationContext, "", this.toNode())
val results = ValidationData<Unit>()
schemaValidator.validate(toValidate, results)
assertTrue(results.isValid, results.results().toString())
}
fun TestApplicationResponse.operation(route: String? = null, callback: Operation.(OpenApi3, String) -> Unit): Operation {
return OpenApi3Parser().parse(File("/openapi2.yaml".getResource().toURI()), true).let { api: OpenApi3 ->
val operation = call.request.httpMethod val operation = call.request.httpMethod
val uri = route ?: "/" + Url(call.request.uri).encodedPath val uri = route ?: "/" + Url(call.request.uri).encodedPath
val path = api.paths val path = api.paths
@@ -28,38 +42,43 @@ fun TestApplicationResponse.`And schema must be valid`(route: String? = null) {
api.getPath(path) api.getPath(path)
?.getOperation(operation.value.toLowerCase()) ?.getOperation(operation.value.toLowerCase())
?.apply { ?.apply {
val mediaType = call.request.contentType() this.callback(api, uri)
val status = call.response.status()
getResponse(status?.value?.toString() ?: error("HttpStatus not found"))
?.getContentMediaType(mediaType.toString())
?.schema?.let { schema ->
val validationContext: ValidationContext<OAI3> = ValidationContext(api.context)
val jsonNode: JsonNode = schema.toNode()
val schemaValidator = SchemaValidator(validationContext, "", jsonNode)
val results = ValidationData<Unit>()
val mapper = ObjectMapper()
schemaValidator.validate(mapper.readTree(content), results)
assertTrue(results.isValid, results.results().toString())
}
?: error("""No path found for "$operation $uri" for status ${status.value} with media type "$mediaType".""")
}
?.apply {
Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> ->
getParametersIn(api.context, "query")
?.firstOrNull { it.name == parameter }?.schema?.let { schema ->
val validationContext: ValidationContext<OAI3> = ValidationContext(api.context)
val jsonNode: JsonNode = schema.toNode()
val schemaValidator = SchemaValidator(validationContext, "", jsonNode)
val params = ValidationData<Unit>()
schemaValidator.validate(TextNode(values.first()), params)
assertTrue(params.isValid, params.results().toString())
}
?: error("""No path found for "$operation $uri" for status "$parameter".""")
}
} }
?: error("""No path found for "$operation $uri".""") ?: error("""No path found for "$operation $uri".""")
} }
} }
fun TestApplicationResponse.`And the schema must be valid`(route: String? = null, contentType: ContentType? = ContentType.Application.Json) {
operation(route) { api, uri ->
/* Validate Response */
this.apply {
val status = call.response.status()
getResponse(status?.value?.toString() ?: error("HttpStatus not found"))
?.getContentMediaType(contentType.toString())
?.schema
?.validate(api, ObjectMapper().readTree(content))
?: error("""No path found for "$this $uri" for status ${status.value} with media type "$contentType".""")
}
/* Validate Request URL */
this.apply {
Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> ->
getParametersIn(api.context, "query")
?.firstOrNull { it.name == parameter }?.schema
?.validate(api, TextNode(values.first()))
?: error("""No path found for "$this $uri" for status "$parameter".""")
}
}
}
}
/**
* Validate request body
*/
fun TestApplicationResponse.`And the schema request body must be valid`(body: String) {
operation { api, uri ->
requestBody
.getContentMediaType(call.request.contentType().toString())
.schema
.validate(api, ObjectMapper().readTree(body))
}
}

View File

@@ -1,5 +1,8 @@
package integration.steps.`when` package integration.steps.`when`
import integration.steps.then.`And the schema must be valid`
import integration.steps.then.`And the schema request body must be valid`
import io.ktor.application.ApplicationCall
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod import io.ktor.http.HttpMethod
@@ -8,7 +11,7 @@ import io.ktor.server.testing.TestApplicationEngine
import io.ktor.server.testing.TestApplicationRequest import io.ktor.server.testing.TestApplicationRequest
import io.ktor.server.testing.setBody import io.ktor.server.testing.setBody
fun TestApplicationEngine.`When I send a GET request`(uri: String? = null, setup: (TestApplicationRequest.() -> Unit)? = null): TestApplicationCall { fun TestApplicationEngine.`When I send a GET request`(uri: String? = null, validate: Boolean = true, setup: (TestApplicationRequest.() -> Unit)? = null): TestApplicationCall {
return handleRequest(true) { return handleRequest(true) {
method = HttpMethod.Get method = HttpMethod.Get
if (uri != null) { if (uri != null) {
@@ -16,36 +19,54 @@ fun TestApplicationEngine.`When I send a GET request`(uri: String? = null, setup
} }
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setup?.let { it() } setup?.let { it() }
}.apply {
if (validate) {
response.`And the schema must be valid`()
requestBody?.let { body ->
response.`And the schema request body must be valid`(body)
}
}
} }
} }
fun TestApplicationEngine.`When I send a POST request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { fun TestApplicationEngine.`When I send a POST request`(uri: String? = null, validate: Boolean = true, setup: (TestApplicationRequest.() -> Unit)? = null): TestApplicationCall {
return handleRequest(true) { return handleRequest(true) {
method = HttpMethod.Post method = HttpMethod.Post
if (uri != null) { if (uri != null) {
this.uri = uri this.uri = uri
} }
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setup?.let { it() }?.let { addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
setBody(it.trimIndent()) setup?.let { it() }
}.apply {
if (validate) {
response.`And the schema must be valid`()
requestBody?.let { body ->
response.`And the schema request body must be valid`(body)
}
} }
} }
} }
fun TestApplicationEngine.`When I send a PUT request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { fun TestApplicationEngine.`When I send a PUT request`(uri: String? = null, validate: Boolean = true, setup: (TestApplicationRequest.() -> Unit)? = null): TestApplicationCall {
return handleRequest(true) { return handleRequest(true) {
method = HttpMethod.Put method = HttpMethod.Put
if (uri != null) { if (uri != null) {
this.uri = uri this.uri = uri
} }
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setup?.let { it() }?.let { setup?.let { it() }
setBody(it.trimIndent()) }.apply {
if (validate) {
response.`And the schema must be valid`()
requestBody?.let { body ->
response.`And the schema request body must be valid`(body)
}
} }
} }
} }
fun TestApplicationEngine.`When I send a DELETE request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { fun TestApplicationEngine.`When I send a DELETE request`(uri: String? = null, validate: Boolean = true, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall {
return handleRequest(true) { return handleRequest(true) {
method = HttpMethod.Delete method = HttpMethod.Delete
if (uri != null) { if (uri != null) {
@@ -55,9 +76,30 @@ fun TestApplicationEngine.`When I send a DELETE request`(uri: String? = null, se
setup?.let { it() }?.let { setup?.let { it() }?.let {
setBody(it.trimIndent()) setBody(it.trimIndent())
} }
}.apply {
if (validate) {
response.`And the schema must be valid`()
requestBody?.let { body ->
response.`And the schema request body must be valid`(body)
}
}
} }
} }
fun TestApplicationRequest.`with body`(body: String) { private val requestBodies: MutableMap<ApplicationCall, String> = mutableMapOf()
setBody(body.trimIndent()) var TestApplicationCall.requestBody: String?
get() = requestBodies[this]
set(value) {
if (value == null) {
requestBodies.remove(this)
} else {
requestBodies[this] = value
}
}
infix fun TestApplicationRequest.`with body`(body: String) {
return body.trimIndent().let {
setBody(it)
(call as TestApplicationCall).requestBody = it
}
} }