Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.

Commit 8dfbe6f

Browse files
authored
private/protocol: Fix protocol unit test for Go 1.16. (#3790)
Fixes the SDK's handling of XML protocol tests to correctly compare two XML document strings without mangling the XML namespace.
1 parent a4592ea commit 8dfbe6f

15 files changed

Lines changed: 701 additions & 92 deletions

File tree

.travis.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ go:
1717
- 1.13.x
1818
- 1.14.x
1919
- 1.15.x
20+
- 1.16.x
2021
- tip
2122

2223
matrix:
@@ -38,6 +39,8 @@ matrix:
3839
go: 1.14.x
3940
- os: windows
4041
go: 1.15.x
42+
- os: windows
43+
go: 1.16.x
4144
- os: windows
4245
go: tip
4346

@@ -46,7 +49,8 @@ before_install:
4649

4750
script:
4851
- if [ -z $(go env GOMOD) ]; then
49-
if [ "$TRAVIS_GO_VERSION" == "1.13.x" ] ||
52+
if [ "$TRAVIS_GO_VERSION" == "1.14.x" ] ||
53+
[ "$TRAVIS_GO_VERSION" == "1.13.x" ] ||
5054
[ "$TRAVIS_GO_VERSION" == "1.12.x" ] ||
5155
[ "$TRAVIS_GO_VERSION" == "1.11.x" ] ||
5256
[ "$TRAVIS_GO_VERSION" == "1.10.x" ]; then
@@ -55,8 +59,8 @@ script:
5559
make get-deps;
5660
fi;
5761
if [ "$TRAVIS_GO_VERSION" == "tip" ] ||
58-
[ "$TRAVIS_GO_VERSION" == "1.15.x" ] ||
59-
[ "$TRAVIS_GO_VERSION" == "1.14.x" ]; then
62+
[ "$TRAVIS_GO_VERSION" == "1.16.x" ] ||
63+
[ "$TRAVIS_GO_VERSION" == "1.15.x" ]; then
6064

6165
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
6266
make unit-no-verify;

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ sandbox-go1.15: sandbox-build-go1.15
187187
sandbox-test-go1.15: sandbox-build-go1.15
188188
docker run -t aws-sdk-go-1.15
189189

190+
sandbox-build-go1.16:
191+
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.16 -t "aws-sdk-go-1.16" .
192+
sandbox-go1.16: sandbox-build-go1.16
193+
docker run -i -t aws-sdk-go-1.16 bash
194+
sandbox-test-go1.16: sandbox-build-go1.16
195+
docker run -t aws-sdk-go-1.16
196+
190197
sandbox-build-gotip:
191198
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
192199
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .

aws/credentials/credentials_bench_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func BenchmarkCredentials_Get(b *testing.B) {
2525
for j := 0; j < b.N; j++ {
2626
v, err := creds.Get()
2727
if err != nil {
28-
b.Fatalf("expect no error %v, %v", v, err)
28+
b.Errorf("expect no error %v, %v", v, err)
2929
}
3030
}
3131
wg.Done()
@@ -55,7 +55,7 @@ func BenchmarkCredentials_Get_Expire(b *testing.B) {
5555
for j := 0; j < b.N; j++ {
5656
v, err := creds.Get()
5757
if err != nil {
58-
b.Fatalf("expect no error %v, %v", v, err)
58+
b.Errorf("expect no error %v, %v", v, err)
5959
}
6060
// periodically expire creds to cause rwlock
6161
if id == 0 && j%expRate == 0 {

awstesting/assert.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package awstesting
22

33
import (
4-
"bytes"
54
"encoding/json"
6-
"encoding/xml"
75
"fmt"
86
"net/url"
97
"reflect"
@@ -12,7 +10,7 @@ import (
1210
"strings"
1311
"testing"
1412

15-
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
13+
"github.com/aws/aws-sdk-go/internal/smithytesting"
1614
)
1715

1816
// Match is a testing helper to test for testing error by comparing expected
@@ -114,26 +112,14 @@ func AssertJSON(t *testing.T, expect, actual string, msgAndArgs ...interface{})
114112
return equal(t, expectVal, actualVal, msgAndArgs...)
115113
}
116114

117-
// AssertXML verifies that the expect xml string matches the actual.
118-
// Elements in actual must match the order they appear in expect to match equally
115+
// AssertXML verifies that the expect XML string matches the actual.
119116
func AssertXML(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
120-
buffer := bytes.NewReader([]byte(expect))
121-
decoder := xml.NewDecoder(buffer)
122-
123-
expectVal, err := xmlutil.XMLToStruct(decoder, nil)
124-
if err != nil {
125-
t.Fatalf("failed to umarshal xml to struct: %v", err)
126-
}
127-
128-
buffer = bytes.NewReader([]byte(actual))
129-
decoder = xml.NewDecoder(buffer)
130-
131-
actualVal, err := xmlutil.XMLToStruct(decoder, nil)
132-
if err != nil {
133-
t.Fatalf("failed to umarshal xml to struct: %v", err)
117+
if err := smithytesting.XMLEqual([]byte(expect), []byte(actual)); err != nil {
118+
t.Error("expect XML match", err, messageFromMsgAndArgs(msgAndArgs))
119+
return false
134120
}
135121

136-
return equal(t, expectVal, actualVal, msgAndArgs...)
122+
return true
137123
}
138124

139125
// DidPanic returns if the function paniced and returns true if the function paniced.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM golang:1.16
2+
3+
ENV GOPROXY=direct
4+
5+
ADD . /go/src/github.com/aws/aws-sdk-go
6+
7+
RUN apt-get update && apt-get install -y --no-install-recommends \
8+
vim \
9+
&& rm -rf /var/list/apt/lists/*
10+
11+
WORKDIR /go/src/github.com/aws/aws-sdk-go
12+
CMD ["make", "get-deps-verify", "unit"]

internal/smithytesting/document.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package smithytesting
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"reflect"
7+
8+
"github.com/aws/aws-sdk-go/internal/smithytesting/xml"
9+
)
10+
11+
// XMLEqual asserts two XML documents by sorting the XML and comparing the
12+
// strings It returns an error in case of mismatch or in case of malformed XML
13+
// found while sorting. In case of mismatched XML, the error string will
14+
// contain the diff between the two XML documents.
15+
func XMLEqual(expectBytes, actualBytes []byte) error {
16+
actualString, err := xml.SortXML(bytes.NewBuffer(actualBytes), true)
17+
if err != nil {
18+
return err
19+
}
20+
21+
expectString, err := xml.SortXML(bytes.NewBuffer(expectBytes), true)
22+
if err != nil {
23+
return err
24+
}
25+
26+
if !reflect.DeepEqual(expectString, actualString) {
27+
return fmt.Errorf("unexpected XML mismatch\nexpect: %+v\nactual: %+v",
28+
expectString, actualString)
29+
}
30+
31+
return nil
32+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// +build go1.9
2+
3+
package smithytesting
4+
5+
import (
6+
"strings"
7+
"testing"
8+
)
9+
10+
func TestEqualXMLUtil(t *testing.T) {
11+
cases := map[string]struct {
12+
expectedXML string
13+
actualXML string
14+
expectErr string
15+
}{
16+
"empty": {
17+
expectedXML: ``,
18+
actualXML: ``,
19+
},
20+
"emptyWithDiff": {
21+
expectedXML: ``,
22+
actualXML: `<Root></Root>`,
23+
expectErr: "XML mismatch",
24+
},
25+
"simpleXML": {
26+
expectedXML: `<Root></Root>`,
27+
actualXML: `<Root></Root>`,
28+
},
29+
"simpleXMLWithDiff": {
30+
expectedXML: `<Root></Root>`,
31+
actualXML: `<Root>abc</Root>`,
32+
expectErr: "XML mismatch",
33+
},
34+
"nestedXML": {
35+
expectedXML: `<Root><abc>123</abc><cde>xyz</cde></Root>`,
36+
actualXML: `<Root><abc>123</abc><cde>xyz</cde></Root>`,
37+
},
38+
"nestedXMLWithExpectedDiff": {
39+
expectedXML: `<Root><abc>123</abc><cde>xyz</cde><pqr>234</pqr></Root>`,
40+
actualXML: `<Root><abc>123</abc><cde>xyz</cde></Root>`,
41+
expectErr: "XML mismatch",
42+
},
43+
"nestedXMLWithActualDiff": {
44+
expectedXML: `<Root><abc>123</abc><cde>xyz</cde></Root>`,
45+
actualXML: `<Root><abc>123</abc><cde>xyz</cde><pqr>234</pqr></Root>`,
46+
expectErr: "XML mismatch",
47+
},
48+
"Array": {
49+
expectedXML: `<Root><list><member><nested>xyz</nested></member><member><nested>abc</nested></member></list></Root>`,
50+
actualXML: `<Root><list><member><nested>xyz</nested></member><member><nested>abc</nested></member></list></Root>`,
51+
},
52+
"ArrayWithSecondDiff": {
53+
expectedXML: `<Root><list><member><nested>xyz</nested></member><member><nested>123</nested></member></list></Root>`,
54+
actualXML: `<Root><list><member><nested>xyz</nested></member><member><nested>345</nested></member></list></Root>`,
55+
expectErr: "XML mismatch",
56+
},
57+
"ArrayWithFirstDiff": {
58+
expectedXML: `<Root><list><member><nested>abc</nested></member><member><nested>345</nested></member></list></Root>`,
59+
actualXML: `<Root><list><member><nested>xyz</nested></member><member><nested>345</nested></member></list></Root>`,
60+
expectErr: "XML mismatch",
61+
},
62+
"ArrayWithMixedDiff": {
63+
expectedXML: `<Root><list><member><nested>345</nested></member><member><nested>xyz</nested></member></list></Root>`,
64+
actualXML: `<Root><list><member><nested>xyz</nested></member><member><nested>345</nested></member></list></Root>`,
65+
},
66+
"ArrayWithRepetitiveMembers": {
67+
expectedXML: `<Root><list><member><nested>xyz</nested></member><member><nested>xyz</nested></member></list></Root>`,
68+
actualXML: `<Root><list><member><nested>xyz</nested></member><member><nested>xyz</nested></member></list></Root>`,
69+
},
70+
"Map": {
71+
expectedXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
72+
actualXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
73+
},
74+
"MapWithFirstDiff": {
75+
expectedXML: `<Root><map><entry><key>bcf</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
76+
actualXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
77+
expectErr: "XML mismatch",
78+
},
79+
"MapWithSecondDiff": {
80+
expectedXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>abc</value></entry></map></Root>`,
81+
actualXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
82+
expectErr: "XML mismatch",
83+
},
84+
"MapWithMixedDiff": {
85+
expectedXML: `<Root><map><entry><key>cde</key><value>356</value></entry><entry><key>abc</key><value>123</value></entry></map></Root>`,
86+
actualXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
87+
},
88+
"MismatchCheckforKeyValue": {
89+
expectedXML: `<Root><map><entry><key>cde</key><value>abc</value></entry><entry><key>abc</key><value>356</value></entry></map></Root>`,
90+
actualXML: `<Root><map><entry><key>abc</key><value>123</value></entry><entry><key>cde</key><value>356</value></entry></map></Root>`,
91+
expectErr: "XML mismatch",
92+
},
93+
"MixMapAndListNestedXML": {
94+
expectedXML: `<Root><list>mem1</list><list>mem2</list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
95+
actualXML: `<Root><list>mem1</list><list>mem2</list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
96+
},
97+
"MixMapAndListNestedXMLWithDiff": {
98+
expectedXML: `<Root><list>mem1</list><list>mem2</list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
99+
actualXML: `<Root><list>mem1</list><list>mem2</list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><beta><x>gamma</x></beta></nested></v></map></Root>`,
100+
expectErr: "XML mismatch",
101+
},
102+
"xmlWithNamespaceAndAttr": {
103+
expectedXML: `<Root xmlns:ab="https://example.com" attr="apple">value</Root>`,
104+
actualXML: `<Root xmlns:ab="https://example.com" attr="apple">value</Root>`,
105+
},
106+
"xmlUnorderedAttributes": {
107+
expectedXML: `<Root atr="banana" attrNew="apple">v</Root>`,
108+
actualXML: `<Root attrNew="apple" atr="banana">v</Root>`,
109+
},
110+
"xmlAttributesWithDiff": {
111+
expectedXML: `<Root atr="someAtr" attrNew="apple">v</Root>`,
112+
actualXML: `<Root attrNew="apple" atr="banana">v</Root>`,
113+
expectErr: "XML mismatch",
114+
},
115+
"xmlUnorderedNamespaces": {
116+
expectedXML: `<Root xmlns:ab="https://example.com" xmlns:baz="https://example2.com">v</Root>`,
117+
actualXML: `<Root xmlns:baz="https://example2.com" xmlns:ab="https://example.com">v</Root>`,
118+
},
119+
"xmlNamespaceWithDiff": {
120+
expectedXML: `<Root xmlns:ab="https://example-diff.com" xmlns:baz="https://example2.com">v</Root>`,
121+
actualXML: `<Root xmlns:baz="https://example2.com" xmlns:ab="https://example.com">v</Root>`,
122+
expectErr: "XML mismatch",
123+
},
124+
"NestedWithNamespaceAndAttributes": {
125+
expectedXML: `<Root xmlns:ab="https://example.com" xmlns:un="https://example2.com" attr="test" attr2="test2"><ab:list>mem1</ab:list><ab:list>mem2</ab:list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
126+
actualXML: `<Root xmlns:ab="https://example.com" xmlns:un="https://example2.com" attr="test" attr2="test2"><ab:list>mem1</ab:list><ab:list>mem2</ab:list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
127+
},
128+
"NestedWithNamespaceAndAttributesWithDiff": {
129+
expectedXML: `<Root xmlns:ab="https://example.com" xmlns:un="https://example2.com" attr="test" attr2="test2"><list>mem2</list><ab:list>mem2</ab:list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
130+
actualXML: `<Root xmlns:ab="https://example.com" xmlns:un="https://example2.com" attr="test" attr2="test2"><list>mem1</list><ab:list>mem2</ab:list><map><k>abc</k><v><nested><enorm>abc</enorm></nested></v><k>xyz</k><v><nested><alpha><x>gamma</x></alpha></nested></v></map></Root>`,
131+
expectErr: "XML mismatch",
132+
},
133+
"MalformedXML": {
134+
expectedXML: `<Root><fmap><key>a</key><key2>a2</key2><value>v</value></fmap><fmap><key>b</key><key2>b2</key2><value>w</value></fmap></Root>`,
135+
actualXML: `<Root><fmap><key>a</key><key2>a2</key2><value>v</value></fmap><fmap><key>b</key><key2>b2</key2><value>w</value></fmap></Root>`,
136+
expectErr: "malformed xml",
137+
},
138+
}
139+
140+
for name, c := range cases {
141+
t.Run(name, func(t *testing.T) {
142+
actual := []byte(c.actualXML)
143+
expected := []byte(c.expectedXML)
144+
145+
err := XMLEqual(actual, expected)
146+
if err != nil {
147+
if len(c.expectErr) == 0 {
148+
t.Fatalf("expected no error while parsing xml, got %v", err)
149+
} else if !strings.Contains(err.Error(), c.expectErr) {
150+
t.Fatalf("expected expected XML err to contain %s, got %s", c.expectErr, err.Error())
151+
}
152+
} else if len(c.expectErr) != 0 {
153+
t.Fatalf("expected error %s, got none", c.expectErr)
154+
}
155+
})
156+
}
157+
}

internal/smithytesting/xml/doc.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Package xml is XML testing package that supports XML comparison utility.
2+
// The package consists of ToStruct and StructToXML utils that help sort XML
3+
// elements as per their nesting level. ToStruct function converts an XML
4+
// document into a sorted tree node structure, while StructToXML converts the
5+
// sorted XML nodes into a sorted XML document. SortXML function should be
6+
// used to sort an XML document. It can be configured to ignore indentation
7+
package xml

internal/smithytesting/xml/sort.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package xml
2+
3+
import (
4+
"bytes"
5+
"encoding/xml"
6+
"io"
7+
"strings"
8+
)
9+
10+
type xmlAttrSlice []xml.Attr
11+
12+
func (x xmlAttrSlice) Len() int {
13+
return len(x)
14+
}
15+
16+
func (x xmlAttrSlice) Less(i, j int) bool {
17+
spaceI, spaceJ := x[i].Name.Space, x[j].Name.Space
18+
localI, localJ := x[i].Name.Local, x[j].Name.Local
19+
valueI, valueJ := x[i].Value, x[j].Value
20+
21+
spaceCmp := strings.Compare(spaceI, spaceJ)
22+
localCmp := strings.Compare(localI, localJ)
23+
valueCmp := strings.Compare(valueI, valueJ)
24+
25+
if spaceCmp == -1 || (spaceCmp == 0 && (localCmp == -1 || (localCmp == 0 && valueCmp == -1))) {
26+
return true
27+
}
28+
29+
return false
30+
}
31+
32+
func (x xmlAttrSlice) Swap(i, j int) {
33+
x[i], x[j] = x[j], x[i]
34+
}
35+
36+
// SortXML sorts the reader's XML elements
37+
func SortXML(r io.Reader, ignoreIndentation bool) (string, error) {
38+
var buf bytes.Buffer
39+
d := xml.NewDecoder(r)
40+
root, err := ToStruct(d, nil, ignoreIndentation)
41+
if err != nil {
42+
return buf.String(), err
43+
}
44+
45+
e := xml.NewEncoder(&buf)
46+
err = StructToXML(e, root, true)
47+
return buf.String(), err
48+
}

0 commit comments

Comments
 (0)