Skip to content

Commit 05b60b1

Browse files
#55 Support of XML body in response (#56)
1 parent 5334713 commit 05b60b1

File tree

9 files changed

+914
-34
lines changed

9 files changed

+914
-34
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ Assertions are a big part of api-scenario, this is the acceptance tests of your
347347
|--- |---
348348
|**source** | The location of the data to extract for comparison.<br>See [available source type](#available-source-type) to have authorized values.
349349
|**comparison** | The type of operation to perform when comparing the extracted data with the target value. _([see Available comparison type](#available-comparison-type))_.
350-
|**property** | The property of the source data to retrieve.<br><ul><li>For **HTTP headers**, this is the name of the header.</li><li>Data from a **JSON** response body can be extracted by specifying the path of the data using standard JavaScript notation.</li><li>Unused for text content, status code, response time and response size.</li>
350+
|**property** | The property of the source data to retrieve.<br><ul><li>For **HTTP headers**, this is the name of the header.</li><li>Data from a **JSON / XML** response body can be extracted by specifying the path of the data using standard JavaScript notation.</li><li>Unused for text content, status code, response time and response size.</li>
351351
|**value** | The expected value used to compare against the actual value.
352352

353353

@@ -385,6 +385,7 @@ Assertions are a big part of api-scenario, this is the acceptance tests of your
385385
|**Response Headers** |`response_header` |Target headers of the response.
386386
|**Body response _(JSON)_** |`response_json` |Target the response body extract in JSON.
387387
|**Body response _(plain text)_** |`response_text` |Target the response body extract in plain text.
388+
|**Body response _(XML)_** |`response_xml ` |Target the response body extract in XML.
388389

389390
#### Available comparison type
390391

@@ -398,7 +399,7 @@ Assertions are a big part of api-scenario, this is the acceptance tests of your
398399
|**does not contain** |`does_not_contain` |The target value is not found within the actual value.
399400
|**has key** |`has_key` |Checks for the existence of the expected value within a dictionary's keys. The actual value must point to a dictionary **(JSON only)**.
400401
|**has value** |`has_value` |Checks a list or dictionary for the existence of the expected value in any of the list or dictionary values. The actual value must point to a JSON list or dictionary **(JSON only)**.
401-
|**is null** |`is_null` |Checks that a value for a given JSON key is null.
402+
|**is null** |`is_null` |Checks that a value for a given JSON or XML key is null.
402403
|**is a number** |`is_a_number` |Validates the actual value is (or can be cast to) a valid numeric value.
403404
|**less than** |`is_less_than` |Validates the actual value is (or can be cast to) a number less than the target value.
404405
|**less than or equal** |`is_less_than_or_equals`|Validates the actual value is (or can be cast to) a number less than or equal to the target value.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.14
44

55
require (
66
github.com/alvaroloes/enumer v1.1.2 // indirect
7+
github.com/clbanning/mxj v1.8.4
78
github.com/fatih/color v1.9.0
89
github.com/fsnotify/fsnotify v1.4.9 // indirect
910
github.com/ghodss/yaml v1.0.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
2929
github.com/campoy/jsonenums v0.0.0-20180221195324-eec6d38da64e h1:mvV9x2xFIhLJiVOGQsOJzkOOZ++cP7jELzkUSXGo32M=
3030
github.com/campoy/jsonenums v0.0.0-20180221195324-eec6d38da64e/go.mod h1:Q9wN7HDfRAAFkNeQbMKz9G8lzkS75y2tTzcE/HMNMrc=
3131
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
32+
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
33+
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
3234
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
3335
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
3436
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=

pkg/controller/assertion_ctrl.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package controller
33
import (
44
"errors"
55
"fmt"
6+
"github.com/clbanning/mxj"
7+
"github.com/google/go-cmp/cmp"
68
"github.com/jmoiron/jsonq"
79
"github.com/thomaspoignant/api-scenario/pkg/context"
810
"github.com/thomaspoignant/api-scenario/pkg/model"
@@ -49,14 +51,19 @@ func (ctrl *assertionControllerImpl) Assert(assertion model.Assertion, resp mode
4951
res.Source = assertion.Source
5052
return res
5153

54+
case model.ResponseXml:
55+
res := ctrl.assertResponseXml(assertion, resp.Body)
56+
res.Source = assertion.Source
57+
return res
58+
5259
case model.ResponseHeader:
5360
res := ctrl.assertResponseHeader(assertion, resp.Header)
5461
res.Source = assertion.Source
5562
return res
5663

5764
case model.ResponseText:
5865
var res model.ResultAssertion
59-
66+
assertion.Property = "body"
6067
if util.IsNumeric(resp.Body) {
6168
bodyAsFloat, _ := strconv.ParseFloat(resp.Body, 64)
6269
res = ctrl.assertNumber(assertion, bodyAsFloat)
@@ -101,7 +108,7 @@ func (ctrl *assertionControllerImpl) assertResponseHeader(assertion model.Assert
101108
return result
102109
}
103110

104-
// assertResponseHeader is testing an assertion on the JSON body of the response.
111+
// assertResponseJson is testing an assertion on the JSON body of the response.
105112
func (ctrl *assertionControllerImpl) assertResponseJson(assertion model.Assertion, bodyAsString string) model.ResultAssertion {
106113

107114
if len(bodyAsString) > 0 && !util.IsJson(bodyAsString) {
@@ -114,6 +121,26 @@ func (ctrl *assertionControllerImpl) assertResponseJson(assertion model.Assertio
114121
return model.ResultAssertion{Success: false, Message: err.Error(), Err: err, Property: assertion.Property}
115122
}
116123

124+
return ctrl.assertResponseMap(assertion, body)
125+
}
126+
127+
// assertResponseXml is testing an assertion on the XML body of the response.
128+
func (ctrl *assertionControllerImpl) assertResponseXml(assertion model.Assertion, bodyAsString string) model.ResultAssertion {
129+
130+
if len(bodyAsString) == 0 {
131+
message := "there is a result and this is not a valid XML api Response"
132+
return model.ResultAssertion{Success: false, Message: message, Err: errors.New(message), Property: assertion.Property}
133+
}
134+
135+
body, err := mxj.NewMapXml([]byte(bodyAsString))
136+
if err != nil {
137+
return model.ResultAssertion{Success: false, Message: err.Error(), Err: err, Property: assertion.Property}
138+
}
139+
140+
return ctrl.assertResponseMap(assertion, body.Old())
141+
}
142+
143+
func (ctrl *assertionControllerImpl) assertResponseMap(assertion model.Assertion, body map[string]interface{}) model.ResultAssertion {
117144
// Convert property from Json syntax to an array of fields
118145
jqPath := util.JsonConvertKeyName(assertion.Property)
119146

@@ -252,7 +279,11 @@ func (ctrl *assertionControllerImpl) assertString(assertion model.Assertion, api
252279

253280
case model.IsANumber:
254281
success := util.IsNumeric(apiValue)
255-
return model.NewResultAssertion(comparison, success, apiValue)
282+
var paramToDisplay string
283+
if paramToDisplay = assertion.Property; len(paramToDisplay) == 0 {
284+
paramToDisplay = apiValue
285+
}
286+
return model.NewResultAssertion(comparison, success, paramToDisplay)
256287

257288
case model.EqualNumber:
258289
if util.IsNumeric(apiValue) {
@@ -284,7 +315,7 @@ func (ctrl *assertionControllerImpl) assertString(assertion model.Assertion, api
284315

285316
case model.Empty:
286317
success := strings.TrimSpace(apiValue) == ""
287-
return model.NewResultAssertion(comparison, success, apiValue)
318+
return model.NewResultAssertion(comparison, success, propertyName)
288319

289320
default:
290321
message := fmt.Sprintf(ComparisonNotSupportedMessage, comparison)
@@ -332,7 +363,7 @@ func (ctrl *assertionControllerImpl) assertArray(assertion model.Assertion, apiV
332363

333364
switch comparison {
334365
case model.IsANumber:
335-
return model.NewResultAssertion(comparison, false, apiValue)
366+
return model.NewResultAssertion(comparison, false, propertyName)
336367

337368
case model.IsNull:
338369
return model.NewResultAssertion(comparison, false, propertyName)
@@ -409,6 +440,14 @@ func (ctrl *assertionControllerImpl) assertMap(assertion model.Assertion, apiVal
409440
}
410441
return model.NewResultAssertion(comparison, false, propertyName)
411442

443+
case model.IsNull:
444+
// This is a bit hacky but it allows to check null from XML body.
445+
nullValue := map[string]interface{}{"-null": "true"}
446+
if cmp.Equal(apiValue, nullValue) {
447+
return model.NewResultAssertion(comparison, true, propertyName)
448+
}
449+
return model.NewResultAssertion(comparison, false, propertyName)
450+
412451
default:
413452
message := fmt.Sprintf(ComparisonNotSupportedMessage, comparison)
414453
return model.ResultAssertion{Success: false, Message: message, Err: errors.New(message)}

0 commit comments

Comments
 (0)