diff --git a/.travis.yml b/.travis.yml index b27d96ceb63..073a166baf2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ go: - 1.13.x - 1.14.x - 1.15.x + - 1.16.x - tip matrix: @@ -38,6 +39,8 @@ matrix: go: 1.14.x - os: windows go: 1.15.x + - os: windows + go: 1.16.x - os: windows go: tip @@ -46,7 +49,8 @@ before_install: script: - if [ -z $(go env GOMOD) ]; then - if [ "$TRAVIS_GO_VERSION" == "1.13.x" ] || + if [ "$TRAVIS_GO_VERSION" == "1.14.x" ] || + [ "$TRAVIS_GO_VERSION" == "1.13.x" ] || [ "$TRAVIS_GO_VERSION" == "1.12.x" ] || [ "$TRAVIS_GO_VERSION" == "1.11.x" ] || [ "$TRAVIS_GO_VERSION" == "1.10.x" ]; then @@ -55,8 +59,8 @@ script: make get-deps; fi; if [ "$TRAVIS_GO_VERSION" == "tip" ] || - [ "$TRAVIS_GO_VERSION" == "1.15.x" ] || - [ "$TRAVIS_GO_VERSION" == "1.14.x" ]; then + [ "$TRAVIS_GO_VERSION" == "1.16.x" ] || + [ "$TRAVIS_GO_VERSION" == "1.15.x" ]; then if [ "$TRAVIS_OS_NAME" = "windows" ]; then make unit-no-verify; diff --git a/Makefile b/Makefile index dbb7f334cae..9f7b50a9379 100644 --- a/Makefile +++ b/Makefile @@ -187,6 +187,13 @@ sandbox-go1.15: sandbox-build-go1.15 sandbox-test-go1.15: sandbox-build-go1.15 docker run -t aws-sdk-go-1.15 +sandbox-build-go1.16: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.16 -t "aws-sdk-go-1.16" . +sandbox-go1.16: sandbox-build-go1.16 + docker run -i -t aws-sdk-go-1.16 bash +sandbox-test-go1.16: sandbox-build-go1.16 + docker run -t aws-sdk-go-1.16 + sandbox-build-gotip: @echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container" docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" . diff --git a/aws/credentials/credentials_bench_test.go b/aws/credentials/credentials_bench_test.go index 01a5d633bf8..5265cc1b8a4 100644 --- a/aws/credentials/credentials_bench_test.go +++ b/aws/credentials/credentials_bench_test.go @@ -25,7 +25,7 @@ func BenchmarkCredentials_Get(b *testing.B) { for j := 0; j < b.N; j++ { v, err := creds.Get() if err != nil { - b.Fatalf("expect no error %v, %v", v, err) + b.Errorf("expect no error %v, %v", v, err) } } wg.Done() @@ -55,7 +55,7 @@ func BenchmarkCredentials_Get_Expire(b *testing.B) { for j := 0; j < b.N; j++ { v, err := creds.Get() if err != nil { - b.Fatalf("expect no error %v, %v", v, err) + b.Errorf("expect no error %v, %v", v, err) } // periodically expire creds to cause rwlock if id == 0 && j%expRate == 0 { diff --git a/awstesting/assert.go b/awstesting/assert.go index 3854c6538d8..8ca3a425081 100644 --- a/awstesting/assert.go +++ b/awstesting/assert.go @@ -1,9 +1,7 @@ package awstesting import ( - "bytes" "encoding/json" - "encoding/xml" "fmt" "net/url" "reflect" @@ -12,7 +10,7 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/aws/aws-sdk-go/internal/smithytesting" ) // 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{}) return equal(t, expectVal, actualVal, msgAndArgs...) } -// AssertXML verifies that the expect xml string matches the actual. -// Elements in actual must match the order they appear in expect to match equally +// AssertXML verifies that the expect XML string matches the actual. func AssertXML(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool { - buffer := bytes.NewReader([]byte(expect)) - decoder := xml.NewDecoder(buffer) - - expectVal, err := xmlutil.XMLToStruct(decoder, nil) - if err != nil { - t.Fatalf("failed to umarshal xml to struct: %v", err) - } - - buffer = bytes.NewReader([]byte(actual)) - decoder = xml.NewDecoder(buffer) - - actualVal, err := xmlutil.XMLToStruct(decoder, nil) - if err != nil { - t.Fatalf("failed to umarshal xml to struct: %v", err) + if err := smithytesting.XMLEqual([]byte(expect), []byte(actual)); err != nil { + t.Error("expect XML match", err, messageFromMsgAndArgs(msgAndArgs)) + return false } - return equal(t, expectVal, actualVal, msgAndArgs...) + return true } // DidPanic returns if the function paniced and returns true if the function paniced. diff --git a/awstesting/sandbox/Dockerfile.test.go1.16 b/awstesting/sandbox/Dockerfile.test.go1.16 new file mode 100644 index 00000000000..95ad2637002 --- /dev/null +++ b/awstesting/sandbox/Dockerfile.test.go1.16 @@ -0,0 +1,12 @@ +FROM golang:1.16 + +ENV GOPROXY=direct + +ADD . /go/src/github.com/aws/aws-sdk-go + +RUN apt-get update && apt-get install -y --no-install-recommends \ + vim \ + && rm -rf /var/list/apt/lists/* + +WORKDIR /go/src/github.com/aws/aws-sdk-go +CMD ["make", "get-deps-verify", "unit"] diff --git a/internal/smithytesting/document.go b/internal/smithytesting/document.go new file mode 100644 index 00000000000..87c10eb8902 --- /dev/null +++ b/internal/smithytesting/document.go @@ -0,0 +1,32 @@ +package smithytesting + +import ( + "bytes" + "fmt" + "reflect" + + "github.com/aws/aws-sdk-go/internal/smithytesting/xml" +) + +// XMLEqual asserts two XML documents by sorting the XML and comparing the +// strings It returns an error in case of mismatch or in case of malformed XML +// found while sorting. In case of mismatched XML, the error string will +// contain the diff between the two XML documents. +func XMLEqual(expectBytes, actualBytes []byte) error { + actualString, err := xml.SortXML(bytes.NewBuffer(actualBytes), true) + if err != nil { + return err + } + + expectString, err := xml.SortXML(bytes.NewBuffer(expectBytes), true) + if err != nil { + return err + } + + if !reflect.DeepEqual(expectString, actualString) { + return fmt.Errorf("unexpected XML mismatch\nexpect: %+v\nactual: %+v", + expectString, actualString) + } + + return nil +} diff --git a/internal/smithytesting/document_test.go b/internal/smithytesting/document_test.go new file mode 100644 index 00000000000..db99b671d17 --- /dev/null +++ b/internal/smithytesting/document_test.go @@ -0,0 +1,157 @@ +// +build go1.9 + +package smithytesting + +import ( + "strings" + "testing" +) + +func TestEqualXMLUtil(t *testing.T) { + cases := map[string]struct { + expectedXML string + actualXML string + expectErr string + }{ + "empty": { + expectedXML: ``, + actualXML: ``, + }, + "emptyWithDiff": { + expectedXML: ``, + actualXML: ``, + expectErr: "XML mismatch", + }, + "simpleXML": { + expectedXML: ``, + actualXML: ``, + }, + "simpleXMLWithDiff": { + expectedXML: ``, + actualXML: `abc`, + expectErr: "XML mismatch", + }, + "nestedXML": { + expectedXML: `123xyz`, + actualXML: `123xyz`, + }, + "nestedXMLWithExpectedDiff": { + expectedXML: `123xyz234`, + actualXML: `123xyz`, + expectErr: "XML mismatch", + }, + "nestedXMLWithActualDiff": { + expectedXML: `123xyz`, + actualXML: `123xyz234`, + expectErr: "XML mismatch", + }, + "Array": { + expectedXML: `xyzabc`, + actualXML: `xyzabc`, + }, + "ArrayWithSecondDiff": { + expectedXML: `xyz123`, + actualXML: `xyz345`, + expectErr: "XML mismatch", + }, + "ArrayWithFirstDiff": { + expectedXML: `abc345`, + actualXML: `xyz345`, + expectErr: "XML mismatch", + }, + "ArrayWithMixedDiff": { + expectedXML: `345xyz`, + actualXML: `xyz345`, + }, + "ArrayWithRepetitiveMembers": { + expectedXML: `xyzxyz`, + actualXML: `xyzxyz`, + }, + "Map": { + expectedXML: `abc123cde356`, + actualXML: `abc123cde356`, + }, + "MapWithFirstDiff": { + expectedXML: `bcf123cde356`, + actualXML: `abc123cde356`, + expectErr: "XML mismatch", + }, + "MapWithSecondDiff": { + expectedXML: `abc123cdeabc`, + actualXML: `abc123cde356`, + expectErr: "XML mismatch", + }, + "MapWithMixedDiff": { + expectedXML: `cde356abc123`, + actualXML: `abc123cde356`, + }, + "MismatchCheckforKeyValue": { + expectedXML: `cdeabcabc356`, + actualXML: `abc123cde356`, + expectErr: "XML mismatch", + }, + "MixMapAndListNestedXML": { + expectedXML: `mem1mem2abcabcxyzgamma`, + actualXML: `mem1mem2abcabcxyzgamma`, + }, + "MixMapAndListNestedXMLWithDiff": { + expectedXML: `mem1mem2abcabcxyzgamma`, + actualXML: `mem1mem2abcabcxyzgamma`, + expectErr: "XML mismatch", + }, + "xmlWithNamespaceAndAttr": { + expectedXML: `value`, + actualXML: `value`, + }, + "xmlUnorderedAttributes": { + expectedXML: `v`, + actualXML: `v`, + }, + "xmlAttributesWithDiff": { + expectedXML: `v`, + actualXML: `v`, + expectErr: "XML mismatch", + }, + "xmlUnorderedNamespaces": { + expectedXML: `v`, + actualXML: `v`, + }, + "xmlNamespaceWithDiff": { + expectedXML: `v`, + actualXML: `v`, + expectErr: "XML mismatch", + }, + "NestedWithNamespaceAndAttributes": { + expectedXML: `mem1mem2abcabcxyzgamma`, + actualXML: `mem1mem2abcabcxyzgamma`, + }, + "NestedWithNamespaceAndAttributesWithDiff": { + expectedXML: `mem2mem2abcabcxyzgamma`, + actualXML: `mem1mem2abcabcxyzgamma`, + expectErr: "XML mismatch", + }, + "MalformedXML": { + expectedXML: `aa2vbb2w`, + actualXML: `aa2vbb2w`, + expectErr: "malformed xml", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actual := []byte(c.actualXML) + expected := []byte(c.expectedXML) + + err := XMLEqual(actual, expected) + if err != nil { + if len(c.expectErr) == 0 { + t.Fatalf("expected no error while parsing xml, got %v", err) + } else if !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expected expected XML err to contain %s, got %s", c.expectErr, err.Error()) + } + } else if len(c.expectErr) != 0 { + t.Fatalf("expected error %s, got none", c.expectErr) + } + }) + } +} diff --git a/internal/smithytesting/xml/doc.go b/internal/smithytesting/xml/doc.go new file mode 100644 index 00000000000..611fc441a76 --- /dev/null +++ b/internal/smithytesting/xml/doc.go @@ -0,0 +1,7 @@ +// Package xml is XML testing package that supports XML comparison utility. +// The package consists of ToStruct and StructToXML utils that help sort XML +// elements as per their nesting level. ToStruct function converts an XML +// document into a sorted tree node structure, while StructToXML converts the +// sorted XML nodes into a sorted XML document. SortXML function should be +// used to sort an XML document. It can be configured to ignore indentation +package xml diff --git a/internal/smithytesting/xml/sort.go b/internal/smithytesting/xml/sort.go new file mode 100644 index 00000000000..e4fcd328bf3 --- /dev/null +++ b/internal/smithytesting/xml/sort.go @@ -0,0 +1,48 @@ +package xml + +import ( + "bytes" + "encoding/xml" + "io" + "strings" +) + +type xmlAttrSlice []xml.Attr + +func (x xmlAttrSlice) Len() int { + return len(x) +} + +func (x xmlAttrSlice) Less(i, j int) bool { + spaceI, spaceJ := x[i].Name.Space, x[j].Name.Space + localI, localJ := x[i].Name.Local, x[j].Name.Local + valueI, valueJ := x[i].Value, x[j].Value + + spaceCmp := strings.Compare(spaceI, spaceJ) + localCmp := strings.Compare(localI, localJ) + valueCmp := strings.Compare(valueI, valueJ) + + if spaceCmp == -1 || (spaceCmp == 0 && (localCmp == -1 || (localCmp == 0 && valueCmp == -1))) { + return true + } + + return false +} + +func (x xmlAttrSlice) Swap(i, j int) { + x[i], x[j] = x[j], x[i] +} + +// SortXML sorts the reader's XML elements +func SortXML(r io.Reader, ignoreIndentation bool) (string, error) { + var buf bytes.Buffer + d := xml.NewDecoder(r) + root, err := ToStruct(d, nil, ignoreIndentation) + if err != nil { + return buf.String(), err + } + + e := xml.NewEncoder(&buf) + err = StructToXML(e, root, true) + return buf.String(), err +} diff --git a/internal/smithytesting/xml/sort_test.go b/internal/smithytesting/xml/sort_test.go new file mode 100644 index 00000000000..02f02019da9 --- /dev/null +++ b/internal/smithytesting/xml/sort_test.go @@ -0,0 +1,20 @@ +package xml + +import ( + "bytes" + "reflect" + "testing" +) + +func TestSortXML(t *testing.T) { + xmlInput := bytes.NewReader([]byte(`xyz1231`)) + sortedXML, err := SortXML(xmlInput, false) + expectedsortedXML := `123xyz1` + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if !reflect.DeepEqual(sortedXML, expectedsortedXML) { + t.Errorf("expect match\nexpect: %+v\nactual: %+v\n", expectedsortedXML, sortedXML) + } +} diff --git a/internal/smithytesting/xml/xmlToStruct.go b/internal/smithytesting/xml/xmlToStruct.go new file mode 100644 index 00000000000..cbbd52acfef --- /dev/null +++ b/internal/smithytesting/xml/xmlToStruct.go @@ -0,0 +1,339 @@ +package xml + +import ( + "encoding/xml" + "fmt" + "io" + "sort" + "strings" +) + +// A Node contains the values to be encoded or decoded. +type Node struct { + Name xml.Name `json:",omitempty"` + Children map[string][]*Node `json:",omitempty"` + Text string `json:",omitempty"` + Attr []xml.Attr `json:",omitempty"` + + namespaces map[string]string + parent *Node +} + +// NewXMLElement returns a pointer to a new Node initialized to default values. +func NewXMLElement(name xml.Name) *Node { + return &Node{ + Name: name, + Children: map[string][]*Node{}, + Attr: []xml.Attr{}, + } +} + +// AddChild adds child to the Node. +func (n *Node) AddChild(child *Node) { + child.parent = n + if _, ok := n.Children[child.Name.Local]; !ok { + // flattened will have multiple children with same tag name + n.Children[child.Name.Local] = []*Node{} + } + n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child) +} + +// ToStruct converts a xml.Decoder stream to Node with nested values. +func ToStruct(d *xml.Decoder, s *xml.StartElement, ignoreIndentation bool) (*Node, error) { + out := &Node{} + + for { + tok, err := d.Token() + if err != nil { + if err == io.EOF { + break + } else { + return out, err + } + } + + if tok == nil { + break + } + + switch typed := tok.(type) { + case xml.CharData: + text := string(typed.Copy()) + if ignoreIndentation { + text = strings.TrimSpace(text) + } + if len(text) != 0 { + out.Text = text + } + case xml.StartElement: + el := typed.Copy() + out.Attr = el.Attr + if out.Children == nil { + out.Children = map[string][]*Node{} + } + + name := typed.Name.Local + slice := out.Children[name] + if slice == nil { + slice = []*Node{} + } + node, e := ToStruct(d, &el, ignoreIndentation) + out.findNamespaces() + if e != nil { + return out, e + } + + node.Name = typed.Name + node.findNamespaces() + + // Add attributes onto the node + node.Attr = el.Attr + + tempOut := *out + // Save into a temp variable, simply because out gets squashed during + // loop iterations + node.parent = &tempOut + slice = append(slice, node) + out.Children[name] = slice + case xml.EndElement: + if s != nil && s.Name.Local == typed.Name.Local { // matching end token + return out, nil + } + out = &Node{} + } + } + return out, nil +} + +func (n *Node) findNamespaces() { + ns := map[string]string{} + for _, a := range n.Attr { + if a.Name.Space == "xmlns" { + ns[a.Value] = a.Name.Local + } + } + + n.namespaces = ns +} + +func (n *Node) findElem(name string) (string, bool) { + for node := n; node != nil; node = node.parent { + for _, a := range node.Attr { + namespace := a.Name.Space + if v, ok := node.namespaces[namespace]; ok { + namespace = v + } + if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) { + return a.Value, true + } + } + } + return "", false +} + +// StructToXML writes an Node to a xml.Encoder as tokens. +func StructToXML(e *xml.Encoder, node *Node, sorted bool) error { + var err error + // Sort Attributes + attrs := node.Attr + if sorted { + sortedAttrs := make([]xml.Attr, len(attrs)) + for _, k := range node.Attr { + sortedAttrs = append(sortedAttrs, k) + } + sort.Sort(xmlAttrSlice(sortedAttrs)) + attrs = sortedAttrs + } + + st := xml.StartElement{Name: node.Name, Attr: attrs} + e.EncodeToken(st) + // return fmt.Errorf("encoder string : %s, %s, %s", node.Name.Local, node.Name.Space, st.Attr) + + if node.Text != "" { + e.EncodeToken(xml.CharData([]byte(node.Text))) + } else if sorted { + sortedNames := []string{} + for k := range node.Children { + sortedNames = append(sortedNames, k) + } + sort.Strings(sortedNames) + + for _, k := range sortedNames { + // we should sort the []*xml.Node for each key if len >1 + flattenedNodes := node.Children[k] + // Meaning this has multiple nodes + if len(flattenedNodes) > 1 { + // sort flattened nodes + flattenedNodes, err = sortFlattenedNodes(flattenedNodes) + if err != nil { + return err + } + } + + for _, v := range flattenedNodes { + err = StructToXML(e, v, sorted) + if err != nil { + return err + } + } + } + } else { + for _, c := range node.Children { + for _, v := range c { + err = StructToXML(e, v, sorted) + if err != nil { + return err + } + } + } + } + + e.EncodeToken(xml.EndElement{Name: node.Name}) + return e.Flush() +} + +// sortFlattenedNodes sorts nodes with nodes having same element tag +// but overall different values. The function will return list of pointer to +// Node and an error. +// +// Overall sort order is followed is: +// Nodes with concrete value (no nested node as value) are given precedence +// and are added to list after sorting them +// +// Next nested nodes within a flattened list are given precedence. +// +// Next nodes within a flattened map are sorted based on either key or value +// which ever has lower value and then added to the global sorted list. +// If value was initially chosen, but has nested nodes; key will be chosen as comparable +// as it is unique and will always have concrete data ie. string. +func sortFlattenedNodes(nodes []*Node) ([]*Node, error) { + var sortedNodes []*Node + + // concreteNodeMap stores concrete value associated with a list of nodes + // This is possible in case multiple members of a flatList has same values. + concreteNodeMap := make(map[string][]*Node, 0) + + // flatListNodeMap stores flat list or wrapped list members associated with a list of nodes + // This will have only flattened list with members that are Nodes and not concrete values. + flatListNodeMap := make(map[string][]*Node, 0) + + // flatMapNodeMap stores flat map or map entry members associated with a list of nodes + // This will have only flattened map concrete value members. It is possible to limit this + // to concrete value as map key is expected to be concrete. + flatMapNodeMap := make(map[string][]*Node, 0) + + // nodes with concrete value are prioritized and appended based on sorting order + sortedNodesWithConcreteValue := []string{} + + // list with nested nodes are second in priority and appended based on sorting order + sortedNodesWithListValue := []string{} + + // map are last in priority and appended based on sorting order + sortedNodesWithMapValue := []string{} + + for _, node := range nodes { + // node has no children element, then we consider it as having concrete value + if len(node.Children) == 0 { + sortedNodesWithConcreteValue = append(sortedNodesWithConcreteValue, node.Text) + if v, ok := concreteNodeMap[node.Text]; ok { + concreteNodeMap[node.Text] = append(v, node) + } else { + concreteNodeMap[node.Text] = []*Node{node} + } + } + + // if node has a single child, then it is a flattened list node + if len(node.Children) == 1 { + for _, nestedNodes := range node.Children { + nestedNodeName := nestedNodes[0].Name.Local + + // append to sorted node name for list value + sortedNodesWithListValue = append(sortedNodesWithListValue, nestedNodeName) + + if v, ok := flatListNodeMap[nestedNodeName]; ok { + flatListNodeMap[nestedNodeName] = append(v, nestedNodes[0]) + } else { + flatListNodeMap[nestedNodeName] = []*Node{nestedNodes[0]} + } + } + } + + // if node has two children, then it is a flattened map node + if len(node.Children) == 2 { + nestedPair := []*Node{} + for _, k := range node.Children { + nestedPair = append(nestedPair, k[0]) + } + + comparableValues := []string{nestedPair[0].Name.Local, nestedPair[1].Name.Local} + sort.Strings(comparableValues) + + comparableValue := comparableValues[0] + for _, nestedNode := range nestedPair { + if comparableValue == nestedNode.Name.Local && len(nestedNode.Children) != 0 { + // if value was selected and is nested node, skip it and use key instead + comparableValue = comparableValues[1] + continue + } + + // now we are certain there is no nested node + if comparableValue == nestedNode.Name.Local { + // get chardata for comparison + comparableValue = nestedNode.Text + sortedNodesWithMapValue = append(sortedNodesWithMapValue, comparableValue) + + if v, ok := flatMapNodeMap[comparableValue]; ok { + flatMapNodeMap[comparableValue] = append(v, node) + } else { + flatMapNodeMap[comparableValue] = []*Node{node} + } + break + } + } + } + + // we don't support multiple same name nodes in an xml doc except for in flattened maps, list. + if len(node.Children) > 2 { + return nodes, fmt.Errorf("malformed xml: multiple nodes with same key name exist, " + + "but are not associated with flattened maps (2 children) or list (0 or 1 child)") + } + } + + // sort concrete value node name list and append corresponding nodes + // to sortedNodes + sort.Strings(sortedNodesWithConcreteValue) + for _, name := range sortedNodesWithConcreteValue { + for _, node := range concreteNodeMap[name] { + sortedNodes = append(sortedNodes, node) + } + } + + // sort nested nodes with a list and append corresponding nodes + // to sortedNodes + sort.Strings(sortedNodesWithListValue) + for _, name := range sortedNodesWithListValue { + // if two nested nodes have same name, then sort them separately. + if len(flatListNodeMap[name]) > 1 { + // return nodes, fmt.Errorf("flat list node name are %s %v", flatListNodeMap[name][0].Name.Local, len(flatListNodeMap[name])) + nestedFlattenedList, err := sortFlattenedNodes(flatListNodeMap[name]) + if err != nil { + return nodes, err + } + // append the identical but sorted nodes + for _, nestedNode := range nestedFlattenedList { + sortedNodes = append(sortedNodes, nestedNode) + } + } else { + // append the sorted nodes + sortedNodes = append(sortedNodes, flatListNodeMap[name][0]) + } + } + + // sorted nodes with a map and append corresponding nodes to sortedNodes + sort.Strings(sortedNodesWithMapValue) + for _, name := range sortedNodesWithMapValue { + sortedNodes = append(sortedNodes, flatMapNodeMap[name][0]) + } + + return sortedNodes, nil +} diff --git a/private/model/cli/gen-protocol-tests/main.go b/private/model/cli/gen-protocol-tests/main.go index cab5d5b7efb..f53699993e2 100644 --- a/private/model/cli/gen-protocol-tests/main.go +++ b/private/model/cli/gen-protocol-tests/main.go @@ -198,12 +198,7 @@ func (t tplInputTestCaseData) BodyAssertions() string { protocol := t.TestCase.TestSuite.API.Metadata.Protocol // Extract the body bytes - switch protocol { - case "rest-xml": - fmt.Fprintln(code, "body := util.SortXML(r.Body)") - default: - fmt.Fprintln(code, "body, _ := ioutil.ReadAll(r.Body)") - } + fmt.Fprintln(code, "body, _ := ioutil.ReadAll(r.Body)") // Generate the body verification code expectedBody := util.Trim(t.TestCase.InputTest.Body) @@ -213,7 +208,7 @@ func (t tplInputTestCaseData) BodyAssertions() string { expectedBody) case "rest-xml": if strings.HasPrefix(expectedBody, "<") { - fmt.Fprintf(code, "awstesting.AssertXML(t, `%s`, util.Trim(body))", + fmt.Fprintf(code, "awstesting.AssertXML(t, `%s`, util.Trim(string(body)))", expectedBody) } else { code.WriteString(fmtAssertEqual(fmt.Sprintf("%q", expectedBody), "util.Trim(string(body))")) @@ -294,7 +289,7 @@ func (i *testCase) TestCase(idx int) string { m, _ := url.ParseQuery(i.InputTest.Body) i.InputTest.Body = m.Encode() case "rest-xml": - i.InputTest.Body = util.SortXML(bytes.NewReader([]byte(i.InputTest.Body))) + // Nothing to do case "json", "rest-json": // Nothing to do } diff --git a/private/protocol/restxml/build_test.go b/private/protocol/restxml/build_test.go index 0069f5d2cab..aaad31323fe 100644 --- a/private/protocol/restxml/build_test.go +++ b/private/protocol/restxml/build_test.go @@ -6058,8 +6058,8 @@ func TestInputService1ProtocolTestBasicXMLSerializationCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `barfoo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foobar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6087,8 +6087,8 @@ func TestInputService1ProtocolTestBasicXMLSerializationCase2(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `barfoo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foobar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6137,8 +6137,8 @@ func TestInputService2ProtocolTestSerializeOtherScalarTypesCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `true3false1.2`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `truefalse1.23`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6169,8 +6169,8 @@ func TestInputService3ProtocolTestNestedStructuresCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `bazba`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `abbaz`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6200,8 +6200,8 @@ func TestInputService3ProtocolTestNestedStructuresCase2(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `baza`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `abaz`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6229,8 +6229,8 @@ func TestInputService4ProtocolTestNestedStructuresCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `baz`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `baz`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6261,8 +6261,8 @@ func TestInputService5ProtocolTestNonFlattenedListsCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `onetwothree`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `onetwothree`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6293,8 +6293,8 @@ func TestInputService6ProtocolTestNonFlattenedListsWithLocationNameCase1(t *test if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `onetwothree`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `onetwothree`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6325,8 +6325,8 @@ func TestInputService7ProtocolTestFlattenedListsCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `onetwothree`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `onetwothree`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6357,8 +6357,8 @@ func TestInputService8ProtocolTestFlattenedListsWithLocationNameCase1(t *testing if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `onetwothree`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `onetwothree`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6395,8 +6395,8 @@ func TestInputService9ProtocolTestListOfStructuresCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `onetwothree`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `onetwothree`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6425,8 +6425,8 @@ func TestInputService10ProtocolTestBlobShapesCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `Zm9v`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `Zm9v`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone", r.URL.String()) @@ -6461,8 +6461,8 @@ func TestInputService11ProtocolTestTimestampShapesCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `2015-01-25T08:00:00ZSun, 25 Jan 2015 08:00:00 GMTSun, 25 Jan 2015 08:00:00 GMT`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `2015-01-25T08:00:00ZSun, 25 Jan 2015 08:00:00 GMTSun, 25 Jan 2015 08:00:00 GMT`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/2014-01-01/hostedzone?TimeQuery=2015-01-25T08%3A00%3A00Z&TimeCustomQuery=1422172800&TimeFormatQuery=1422172800", r.URL.String()) @@ -6650,7 +6650,7 @@ func TestInputService17ProtocolTestStringPayloadCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) + body, _ := ioutil.ReadAll(r.Body) if e, a := "bar", util.Trim(string(body)); e != a { t.Errorf("expect %v, got %v", e, a) } @@ -6680,7 +6680,7 @@ func TestInputService18ProtocolTestBlobPayloadCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) + body, _ := ioutil.ReadAll(r.Body) if e, a := "bar", util.Trim(string(body)); e != a { t.Errorf("expect %v, got %v", e, a) } @@ -6731,8 +6731,8 @@ func TestInputService19ProtocolTestStructurePayloadCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `bar`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `bar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/", r.URL.String()) @@ -6778,8 +6778,8 @@ func TestInputService19ProtocolTestStructurePayloadCase3(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, ``, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, ``, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/", r.URL.String()) @@ -6830,8 +6830,8 @@ func TestInputService20ProtocolTestXMLAttributeCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foo@example.com`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foo@example.com`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/", r.URL.String()) @@ -6922,8 +6922,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foo`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -6954,8 +6954,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase2(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foo`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -6990,8 +6990,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase3(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foo`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7027,8 +7027,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase4(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foobar`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foobar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7066,8 +7066,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase5(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foobar`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foobar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7103,8 +7103,8 @@ func TestInputService23ProtocolTestRecursiveShapesCase6(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `barbarfoofoo`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `barbarfoofoo`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7131,8 +7131,8 @@ func TestInputService24ProtocolTestIdempotencyTokenAutoFillCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `abc123`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `abc123`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7157,8 +7157,8 @@ func TestInputService24ProtocolTestIdempotencyTokenAutoFillCase2(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `00000000-0000-4000-8000-000000000000`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `00000000-0000-4000-8000-000000000000`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/path", r.URL.String()) @@ -7197,8 +7197,8 @@ func TestInputService25ProtocolTestEnumCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `foofoobar`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `foofoobar`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://test/Enum/bar?ListEnums=0&ListEnums=&ListEnums=1", r.URL.String()) @@ -7249,8 +7249,8 @@ func TestInputService26ProtocolTestEndpointHostTraitCase1(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `myname`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `myname`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://data-service.region.amazonaws.com/path", r.URL.String()) @@ -7277,8 +7277,8 @@ func TestInputService26ProtocolTestEndpointHostTraitCase2(t *testing.T) { if r.Body == nil { t.Errorf("expect body not to be nil") } - body := util.SortXML(r.Body) - awstesting.AssertXML(t, `myname`, util.Trim(body)) + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertXML(t, `myname`, util.Trim(string(body))) // assert URL awstesting.AssertURL(t, "https://foo-myname.service.region.amazonaws.com/path", r.URL.String()) diff --git a/private/util/util.go b/private/util/util.go index 5f2dab25e20..73b492763d3 100644 --- a/private/util/util.go +++ b/private/util/util.go @@ -42,6 +42,8 @@ func Capitalize(s string) string { } // SortXML sorts the reader's XML elements +// +// Deprecated: incorrectly handles XML namespaces, should not be used. func SortXML(r io.Reader) string { var buf bytes.Buffer d := xml.NewDecoder(r) diff --git a/service/kinesis/cust_integ_eventstream_test.go b/service/kinesis/cust_integ_eventstream_test.go index 2e809c19a32..60638503530 100644 --- a/service/kinesis/cust_integ_eventstream_test.go +++ b/service/kinesis/cust_integ_eventstream_test.go @@ -52,7 +52,7 @@ func TestInteg_SubscribeToShard(t *testing.T) { sub, err := svc.SubscribeToShardWithContext(ctx, params) if err != nil { - t.Fatalf("expect no error, %v, %v", err, *s.ShardId) + t.Errorf("expect no error, %v, %v", err, *s.ShardId) } defer sub.EventStream.Close() @@ -66,7 +66,7 @@ func TestInteg_SubscribeToShard(t *testing.T) { atomic.AddInt32(&goodCount, 1) for _, r := range e.Records { if len(r.Data) == 0 { - t.Fatalf("expect data in record, got none") + t.Errorf("expect data in record, got none") } } } @@ -79,7 +79,7 @@ func TestInteg_SubscribeToShard(t *testing.T) { } if err := sub.EventStream.Err(); err != nil { - t.Fatalf("expect no error, %v, %v", err, *s.ShardId) + t.Errorf("expect no error, %v, %v", err, *s.ShardId) } }(i, shard) }