Skip to content

Commit

Permalink
feat: add the remaining status code methods to response DSL builder
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Jan 17, 2023
1 parent 01dda6c commit 859fff2
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package au.com.dius.pact.consumer.dsl

import au.com.dius.pact.core.model.HttpResponse
import au.com.dius.pact.core.model.matchingrules.HttpStatus
import au.com.dius.pact.core.model.matchingrules.RegexMatcher
import au.com.dius.pact.core.model.matchingrules.RuleLogic
import au.com.dius.pact.core.model.matchingrules.StatusCodeMatcher
import java.util.regex.Pattern

/**
* Pact HTTP Response builder DSL that supports V4 formatted Pact files
Expand Down Expand Up @@ -29,6 +34,27 @@ open class HttpResponseBuilder(private val response: HttpResponse): HttpPartBuil
return super.headers(values) as HttpResponseBuilder
}

/**
* Match a set cookie header
* @param cookie Cookie name to match
* @param regex Regex to match the cookie value with
* @param example Example value
*/
fun matchSetCookie(cookie: String, regex: String, example: String): HttpResponseBuilder {
val headerCategory = response.matchingRules.addCategory("header")
if (headerCategory.numRules("set-cookie") > 0) {
headerCategory.addRule("set-cookie", RegexMatcher(Pattern.quote("$cookie=") + regex))
} else {
headerCategory.setRule("set-cookie", RegexMatcher(Pattern.quote("$cookie=") + regex), RuleLogic.OR)
}
if (response.headers.containsKey("set-cookie")) {
response.headers["set-cookie"] = response.headers["set-cookie"]!!.plus("$cookie=$example")
} else {
response.headers["set-cookie"] = listOf("$cookie=$example")
}
return this
}

/**
* Sets the status code of the response
*/
Expand All @@ -37,6 +63,85 @@ open class HttpResponseBuilder(private val response: HttpResponse): HttpPartBuil
return this
}

/**
* Match any HTTP Information response status (100-199)
*/
fun informationStatus(): HttpResponseBuilder {
response.matchingRules.addCategory("status").addRule(StatusCodeMatcher(HttpStatus.Information))
response.status = 100
return this
}

/**
* Match any HTTP success response status (200-299)
*/
fun successStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.Success)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 200
return this
}

/**
* Match any HTTP redirect response status (300-399)
*/
fun redirectStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.Redirect)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 300
return this
}

/**
* Match any HTTP client error response status (400-499)
*/
fun clientErrorStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.ClientError)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 400
return this
}

/**
* Match any HTTP server error response status (500-599)
*/
fun serverErrorStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.ServerError)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 500
return this
}

/**
* Match any HTTP non-error response status (< 400)
*/
fun nonErrorStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.NonError)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 200
return this
}

/**
* Match any HTTP error response status (>= 400)
*/
fun errorStatus(): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.Error)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = 400
return this
}

/**
* Match any HTTP status code in the provided list
*/
fun statusCodes(statusCodes: List<Int>): HttpResponseBuilder {
val matcher = StatusCodeMatcher(HttpStatus.StatusCodes, statusCodes)
response.matchingRules.addCategory("status").addRule(matcher)
response.status = statusCodes.first()
return this
}

override fun body(body: String): HttpResponseBuilder {
return super.body(body) as HttpResponseBuilder
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ class HttpRequestBuilderSpec extends Specification {
.build()

then:
request.body.valueAsString() == '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<test id="100"/>\n'
request.body.valueAsString() == '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
System.lineSeparator() + '<test id="100"/>' + System.lineSeparator()
request.body.contentType.toString() == 'application/xml'
request.headers['content-type'] == ['application/xml']
request.matchingRules.rulesForCategory('body') == new MatchingRuleCategory('body',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import au.com.dius.pact.core.model.HttpResponse
import au.com.dius.pact.core.model.generators.Category
import au.com.dius.pact.core.model.generators.ProviderStateGenerator
import au.com.dius.pact.core.model.matchingrules.ContentTypeMatcher
import au.com.dius.pact.core.model.matchingrules.HttpStatus
import au.com.dius.pact.core.model.matchingrules.MatchingRuleCategory
import au.com.dius.pact.core.model.matchingrules.MatchingRuleGroup
import au.com.dius.pact.core.model.matchingrules.NumberTypeMatcher
import au.com.dius.pact.core.model.matchingrules.RegexMatcher
import au.com.dius.pact.core.model.matchingrules.StatusCodeMatcher
import au.com.dius.pact.core.model.matchingrules.RuleLogic
import kotlin.Pair
import spock.lang.Specification

Expand Down Expand Up @@ -97,6 +100,21 @@ class HttpResponseBuilderSpec extends Specification {
response.generators.categoryFor(Category.HEADER) == [A: new ProviderStateGenerator('$a')]
}

def 'supports matching set-cookie response headers'() {
when:
def response = builder
.matchSetCookie('A', '\\d+', '100')
.build()

then:
response.headers == [
'set-cookie': ['A=100']
]
response.matchingRules.rulesForCategory('header') == new MatchingRuleCategory('header', [
'set-cookie': new MatchingRuleGroup([new RegexMatcher('\\QA=\\E\\d+')], RuleLogic.OR)
])
}

def 'allows setting the response status'() {
when:
def response = builder
Expand All @@ -107,6 +125,36 @@ class HttpResponseBuilderSpec extends Specification {
response.status == 204
}

def 'allows setting the response status using common status groups'() {
when:
def response
if (args.empty) {
response = builder."$method"().build()
} else {
response = builder."$method"(args).build()
}

then:
response.status == status
response.matchingRules.rulesForCategory('status') == new MatchingRuleCategory('status',
[
'': new MatchingRuleGroup([matchingRule])
]
)

where:

method | args | status | matchingRule
'informationStatus' | [] | 100 | new StatusCodeMatcher(HttpStatus.Information, [])
'successStatus' | [] | 200 | new StatusCodeMatcher(HttpStatus.Success, [])
'redirectStatus' | [] | 300 | new StatusCodeMatcher(HttpStatus.Redirect, [])
'clientErrorStatus' | [] | 400 | new StatusCodeMatcher(HttpStatus.ClientError, [])
'serverErrorStatus' | [] | 500 | new StatusCodeMatcher(HttpStatus.ServerError, [])
'nonErrorStatus' | [] | 200 | new StatusCodeMatcher(HttpStatus.NonError, [])
'errorStatus' | [] | 400 | new StatusCodeMatcher(HttpStatus.Error, [])
'statusCodes' | [200, 201, 204] | 200 | new StatusCodeMatcher(HttpStatus.StatusCodes, [200, 201, 204])
}

def 'allows setting the body of the response as a string value'() {
when:
def response = builder
Expand Down Expand Up @@ -195,7 +243,8 @@ class HttpResponseBuilderSpec extends Specification {
.build()

then:
response.body.valueAsString() == '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<test id="100"/>\n'
response.body.valueAsString() == '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
System.lineSeparator() + '<test id="100"/>' + System.lineSeparator()
response.body.contentType.toString() == 'application/xml'
response.headers['content-type'] == ['application/xml']
response.matchingRules.rulesForCategory('body') == new MatchingRuleCategory('body',
Expand Down Expand Up @@ -226,105 +275,4 @@ class HttpResponseBuilderSpec extends Specification {
]
)
}

// /**
// * Match a set cookie header
// * @param cookie Cookie name to match
// * @param regex Regex to match the cookie value with
// * @param example Example value
// */
// fun matchSetCookie(cookie: String, regex: String, example: String): PactDslResponse {
// val header = responseMatchers.addCategory("header")
// if (header.numRules("set-cookie") > 0) {
// header.addRule("set-cookie", RegexMatcher(Pattern.quote("$cookie=") + regex))
// } else {
// header.setRule("set-cookie", RegexMatcher(Pattern.quote("$cookie=") + regex), RuleLogic.OR)
// }
// if (responseHeaders.containsKey("set-cookie")) {
// responseHeaders["set-cookie"] = responseHeaders["set-cookie"]!!.plus("$cookie=$example")
// } else {
// responseHeaders["set-cookie"] = listOf("$cookie=$example")
// }
// return this
// }

// /**
// * Match any HTTP Information response status (100-199)
// */
// fun informationStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.Information)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 100
// return this
// }
//
// /**
// * Match any HTTP success response status (200-299)
// */
// fun successStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.Success)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 200
// return this
// }
//
// /**
// * Match any HTTP redirect response status (300-399)
// */
// fun redirectStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.Redirect)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 300
// return this
// }
//
// /**
// * Match any HTTP client error response status (400-499)
// */
// fun clientErrorStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.ClientError)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 400
// return this
// }
//
// /**
// * Match any HTTP server error response status (500-599)
// */
// fun serverErrorStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.ServerError)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 500
// return this
// }
//
// /**
// * Match any HTTP non-error response status (< 400)
// */
// fun nonErrorStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.NonError)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 200
// return this
// }
//
// /**
// * Match any HTTP error response status (>= 400)
// */
// fun errorStatus(): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.Error)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = 400
// return this
// }
//
// /**
// * Match any HTTP status code in the provided list
// */
// fun statusCodes(statusCodes: List<Int>): PactDslResponse {
// val matcher = StatusCodeMatcher(HttpStatus.StatusCodes, statusCodes)
// responseMatchers.addCategory("status").addRule(matcher)
// responseStatus = statusCodes.first()
// return this
// }
}

0 comments on commit 859fff2

Please sign in to comment.