Skip to content

Commit

Permalink
feat: Add support for query parameters with new DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Jan 16, 2023
1 parent abbc3b5 commit 75ba28a
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package au.com.dius.pact.consumer.dsl

import au.com.dius.pact.core.model.HttpRequest
import au.com.dius.pact.core.model.generators.Category
import au.com.dius.pact.core.model.queryStringToMap

/**
* Pact HTTP Request builder DSL that supports V4 formatted Pact files
Expand Down Expand Up @@ -71,4 +72,147 @@ open class HttpRequestBuilder(private val request: HttpRequest): HttpPartBuilder
override fun body(body: String, contentTypeString: String?): HttpRequestBuilder {
return super.body(body, contentTypeString) as HttpRequestBuilder
}

/**
* Adds a query parameter to the request. You can setup a multiple value query parameter by passing a List as the
* value.
*/
open fun queryParameter(key: String, value: Any): HttpRequestBuilder {
val qValues = when (value) {
is List<*> -> value.mapIndexed { index, v ->
if (v is Matcher) {
if (v.matcher != null) {
request.matchingRules.addCategory("query").addRule("$key[$index]", v.matcher!!)
}
if (v.generator != null) {
request.generators.addGenerator(Category.QUERY, "$key[$index]", v.generator!!)
}
v.value.toString()
} else {
v.toString()
}
}
is Matcher -> {
if (value.matcher != null) {
request.matchingRules.addCategory("query").addRule(key, value.matcher!!)
}
if (value.generator != null) {
request.generators.addGenerator(Category.QUERY, key, value.generator!!)
}
listOf(value.value.toString())
}
else -> listOf(value.toString())
}
request.query[key] = qValues
return this
}

/**
* Adds all the query parameters to the request.
*/
open fun queryParameters(key: String, value: String, nameValuePairs: Array<out String>): HttpRequestBuilder {
require(nameValuePairs.size % 2 == 0) {
"Pairs of key/values should be provided, but there is one key without a value."
}

val qValue = mutableListOf(value)
val queryMap = nameValuePairs.toList().chunked(2).fold(mutableMapOf(key to qValue)) { acc, values ->
val k = values[0]
val v = listOf(values[1])
if (acc.containsKey(k)) {
acc[k]!!.addAll(v)
} else {
acc[k] = v.toMutableList()
}
acc
}

request.query.putAll(queryMap)

return this
}

/**
* Adds all the query parameters to the request.
*/
open fun queryParameters(nameValuePairs: Array<out Pair<String, Any>>): HttpRequestBuilder {
val queryMap = nameValuePairs.toList().fold(mutableMapOf<String, MutableList<String>>()) { acc, value ->
val k = value.first
val v = if (value.second is Matcher) {
val matcher = value.second as Matcher
if (matcher.matcher != null) {
request.matchingRules.addCategory("query").addRule(k, matcher.matcher!!)
}
if (matcher.generator != null) {
request.generators.addGenerator(Category.QUERY, k, matcher.generator!!)
}
listOf(matcher.value.toString())
} else {
listOf(value.second.toString())
}
if (acc.containsKey(k)) {
acc[k]!!.addAll(v)
} else {
acc[k] = v.toMutableList()
}
acc
}

request.query.putAll(queryMap)

return this
}

/**
* Adds all the query paraneters to the request. You can either pass a Map<String -> Object>, and values will be
* converted to a string (using the toString() method), or pass in a Map<String -> List<Object>> multi-value
* parameters.
*/
open fun queryParameters(values: Map<String, Any>): HttpRequestBuilder {
val queryMap = values.mapValues { entry ->
val k = entry.key
when (entry.value) {
is Matcher -> {
val matcher = entry.value as Matcher
if (matcher.matcher != null) {
request.matchingRules.addCategory("query").addRule(k, matcher.matcher!!)
}
if (matcher.generator != null) {
request.generators.addGenerator(Category.QUERY, k, matcher.generator!!)
}
listOf(matcher.value.toString())
}

is List<*> -> {
(entry.value as List<*>).mapIndexed { index, v ->
if (v is Matcher) {
if (v.matcher != null) {
request.matchingRules.addCategory("query").addRule("$k[$index]", v.matcher!!)
}
if (v.generator != null) {
request.generators.addGenerator(Category.QUERY, "$k[$index]", v.generator!!)
}
v.value.toString()
} else {
v.toString()
}
}
}

else -> listOf(entry.value.toString())
}
}

request.query.putAll(queryMap)

return this
}

/**
* Adds all the query parameters to the request.
*/
open fun queryParameters(query: String): HttpRequestBuilder {
request.query.putAll(queryStringToMap(query))
return this
}
}
23 changes: 14 additions & 9 deletions consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Matchers.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package au.com.dius.pact.consumer.dsl

import au.com.dius.pact.consumer.dsl.DslPart.Companion.DATE_2000
import au.com.dius.pact.core.model.generators.DateGenerator
import au.com.dius.pact.core.model.generators.DateTimeGenerator
import au.com.dius.pact.core.model.generators.Generator
Expand All @@ -18,6 +19,10 @@ import au.com.dius.pact.core.model.matchingrules.RegexMatcher
import org.apache.commons.lang3.time.DateFormatUtils
import org.apache.commons.lang3.time.DateUtils
import java.text.ParseException
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Date
import java.util.regex.Pattern

sealed class Matcher(
Expand All @@ -44,29 +49,29 @@ data class TypeMatcher(

data class TimestampMatcher(
val pattern: String = DateFormatUtils.ISO_DATETIME_FORMAT.pattern,
override val value: String?
val dateTimeValue: String?
) : Matcher(
value,
dateTimeValue ?: DateTimeFormatter.ofPattern(pattern).format(Instant.ofEpochMilli(DATE_2000).atOffset(ZoneOffset.UTC)),
au.com.dius.pact.core.model.matchingrules.TimestampMatcher(pattern),
if (value == null) DateTimeGenerator(pattern) else null
if (dateTimeValue == null) DateTimeGenerator(pattern) else null
)

data class TimeMatcher(
val pattern: String = DateFormatUtils.ISO_TIME_FORMAT.pattern,
override val value: String?
val timeValue: String?
) : Matcher(
value,
timeValue ?: DateTimeFormatter.ofPattern(pattern).format(Instant.ofEpochMilli(DATE_2000).atOffset(ZoneOffset.UTC)),
au.com.dius.pact.core.model.matchingrules.TimeMatcher(pattern),
if (value == null) TimeGenerator(pattern) else null
if (timeValue == null) TimeGenerator(pattern) else null
)

data class DateMatcher(
val pattern: String = DateFormatUtils.ISO_DATE_FORMAT.pattern,
override val value: String?
val dateValue: String?
) : Matcher(
value,
dateValue ?: DateTimeFormatter.ofPattern(pattern).format(Instant.ofEpochMilli(DATE_2000).atOffset(ZoneOffset.UTC)),
au.com.dius.pact.core.model.matchingrules.DateMatcher(pattern),
if (value == null) DateGenerator(pattern) else null
if (dateValue == null) DateGenerator(pattern) else null
)

data class UuidMatcher(override val value: String?) :
Expand Down
Loading

0 comments on commit 75ba28a

Please sign in to comment.