Skip to content

Commit dac9219

Browse files
authored
Add timestamp support for SDK's generated API smoke tests (#477)
1 parent 496ccd0 commit dac9219

File tree

55 files changed

+964
-755
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+964
-755
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"version": 1,
3+
"defaultRegion": "us-east-1",
4+
"testCases": [
5+
{
6+
"operationName": "GenerateDataSet",
7+
"input": {
8+
"dataSetType": "fake-type",
9+
"dataSetPublicationDate": 0,
10+
"roleNameArn": "fake-arn",
11+
"destinationS3BucketName": "fake-bucket",
12+
"snsTopicArn": "fake-arn"
13+
},
14+
"errorExpectedFromService": true
15+
}
16+
]
17+
}

private/model/api/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type API struct {
2727
Examples Examples
2828
SmokeTests SmokeTestSuite
2929

30+
KeepUnsupportedAPIs bool
31+
3032
// Set to true to avoid removing unused shapes
3133
NoRemoveUnusedShapes bool
3234

private/model/api/docstring.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,29 @@ type shapeDocumentation struct {
2828
}
2929

3030
// AttachDocs attaches documentation from a JSON filename.
31-
func (a *API) AttachDocs(filename string) {
31+
func (a *API) AttachDocs(filename string) error {
3232
var d apiDocumentation
3333

3434
f, err := os.Open(filename)
3535
defer f.Close()
3636
if err != nil {
37-
panic(err)
37+
return err
3838
}
3939
err = json.NewDecoder(f).Decode(&d)
4040
if err != nil {
41-
panic(err)
41+
return fmt.Errorf("failed to decode %s, err: %v", filename, err)
4242
}
4343

44-
d.setup(a)
44+
return d.setup(a)
4545
}
4646

47-
func (d *apiDocumentation) setup(a *API) {
47+
func (d *apiDocumentation) setup(a *API) error {
4848
a.Documentation = docstring(d.Service)
4949

5050
for opName, doc := range d.Operations {
5151
if _, ok := a.Operations[opName]; !ok {
52-
panic(fmt.Sprintf("%s, doc op %q not found in API op set",
53-
a.ServiceID(), opName),
54-
)
52+
return fmt.Errorf("%s, doc op %q not found in API op set",
53+
a.ServiceID(), opName)
5554
}
5655
a.Operations[opName].Documentation = docstring(doc)
5756
}
@@ -80,6 +79,8 @@ func (d *apiDocumentation) setup(a *API) {
8079
}
8180
}
8281
}
82+
83+
return nil
8384
}
8485

8586
var reNewline = regexp.MustCompile(`\r?\n`)

private/model/api/eventstream.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,43 @@
22

33
package api
44

5-
func (a *API) suppressEventStreams() {
6-
const eventStreamMemberName = "EventStream"
5+
import (
6+
"fmt"
7+
"os"
8+
)
79

8-
for name, op := range a.Operations {
9-
outbound := hasEventStream(op.InputRef.Shape)
10-
inbound := hasEventStream(op.OutputRef.Shape)
10+
func (a *API) suppressEventStreams() error {
11+
for opName, op := range a.Operations {
12+
inputRef := getEventStreamMember(op.InputRef.Shape)
13+
outputRef := getEventStreamMember(op.OutputRef.Shape)
1114

12-
if !(outbound || inbound) {
15+
if inputRef == nil && outputRef == nil {
1316
continue
1417
}
1518

16-
a.removeOperation(name)
19+
if !a.KeepUnsupportedAPIs {
20+
fmt.Fprintf(os.Stderr,
21+
"removing unsupported eventstream operation, %s\n",
22+
opName)
23+
a.removeOperation(opName)
24+
continue
25+
}
26+
return UnsupportedAPIModelError{
27+
Err: fmt.Errorf("eventstream support not implemented, %s",
28+
op.ExportedName),
29+
}
1730
}
31+
32+
return nil
1833
}
1934

20-
func hasEventStream(topShape *Shape) bool {
35+
func getEventStreamMember(topShape *Shape) *ShapeRef {
2136
for _, ref := range topShape.MemberRefs {
22-
if ref.Shape.IsEventStream {
23-
return true
37+
if !ref.Shape.IsEventStream {
38+
continue
2439
}
40+
return ref
2541
}
2642

27-
return false
43+
return nil
2844
}

private/model/api/example.go

Lines changed: 57 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,41 @@ import (
1414
"github.com/aws/aws-sdk-go-v2/private/util"
1515
)
1616

17-
type Examples map[string][]Example
17+
// ExamplesGoCode will return a code representation of the entry within the
18+
// examples.json file.
19+
func (a *API) ExamplesGoCode() string {
20+
a.resetImports()
21+
a.AddImport("context")
22+
a.AddImport("fmt")
23+
24+
a.AddSDKImport("aws")
25+
a.AddSDKImport("aws/awserr")
26+
a.AddSDKImport("aws/external")
27+
a.AddImport(a.ImportPath())
28+
29+
var extra = `
30+
var _ aws.Config
31+
`
32+
33+
code := a.Examples.GoCode()
34+
if len(code) == 0 {
35+
return ""
36+
}
37+
if a.Examples.UsedTimestamp() {
38+
a.AddImport("time")
39+
extra += `
40+
func parseTime(layout, value string) time.Time {
41+
t, err := time.Parse(layout, value)
42+
if err != nil {
43+
panic(err)
44+
}
45+
return t
46+
}
47+
`
48+
}
49+
50+
return a.importsGoCode() + extra + code
51+
}
1852

1953
// ExamplesDefinition is the structural representation of the examples-1.json file
2054
type ExamplesDefinition struct {
@@ -28,7 +62,7 @@ type Example struct {
2862
Operation *Operation `json:"-"`
2963
OperationName string `json:"-"`
3064
Index string `json:"-"`
31-
Builder examplesBuilder `json:"-"`
65+
Builder *ExamplesBuilder `json:"-"`
3266
VisitedErrors map[string]struct{} `json:"-"`
3367
Title string `json:"title"`
3468
Description string `json:"description"`
@@ -91,6 +125,20 @@ func Example{{ .API.StructName }}_{{ .MethodName }}() {
91125
}
92126
`))
93127

128+
type Examples map[string][]Example
129+
130+
func (exs Examples) UsedTimestamp() bool {
131+
for _, es := range exs {
132+
for _, e := range es {
133+
if e.Builder.HasTimestamp {
134+
return true
135+
}
136+
}
137+
}
138+
139+
return false
140+
}
141+
94142
// Names will return the name of the example. This will also be the name of the operation
95143
// that is to be tested.
96144
func (exs Examples) Names() []string {
@@ -175,10 +223,6 @@ func correctType(memName string, t string, value interface{}, asValue bool) stri
175223
return convertToCorrectType(memName, t, v, asValue)
176224
}
177225

178-
func convertToCorrectType(memName, t, v string, asValue bool) string {
179-
return fmt.Sprintf("%s: %s,\n", memName, getValue(t, v, asValue))
180-
}
181-
182226
func getValue(t, v string, asValue bool) string {
183227
if t[0] == '*' {
184228
t = t[1:]
@@ -211,24 +255,24 @@ func getValue(t, v string, asValue bool) string {
211255

212256
// AttachExamples will create a new ExamplesDefinition from the examples file
213257
// and reference the API object.
214-
func (a *API) AttachExamples(filename string) {
258+
func (a *API) AttachExamples(filename string) error {
215259
p := ExamplesDefinition{API: a}
216260

217261
f, err := os.Open(filename)
218262
defer f.Close()
219263
if err != nil {
220-
panic(err)
264+
return err
221265
}
222266
err = json.NewDecoder(f).Decode(&p)
223267
if err != nil {
224-
panic(err)
268+
return fmt.Errorf("failed to decode %s, err: %v", filename, err)
225269
}
226270

227-
p.setup()
271+
return p.setup()
228272
}
229273

230-
func (p *ExamplesDefinition) setup() {
231-
builder := defaultExamplesBuilder{}
274+
func (p *ExamplesDefinition) setup() error {
275+
builder := NewExamplesBuilder()
232276
keys := p.Examples.Names()
233277
for _, n := range keys {
234278
examples := p.Examples[n]
@@ -249,74 +293,17 @@ func (p *ExamplesDefinition) setup() {
249293
}
250294

251295
p.API.Examples = p.Examples
252-
}
253296

254-
var exampleHeader = template.Must(template.New("exampleHeader").Parse(`
255-
import (
256-
{{ .Builder.Imports .API }}
257-
)
258-
259-
var _ time.Duration
260-
var _ strings.Reader
261-
var _ aws.Config
262-
263-
func parseTime(layout, value string) *time.Time {
264-
t, err := time.Parse(layout, value)
265-
if err != nil {
266-
panic(err)
267-
}
268-
return &t
269-
}
270-
271-
`))
272-
273-
type exHeader struct {
274-
Builder examplesBuilder
275-
API *API
276-
}
277-
278-
// ExamplesGoCode will return a code representation of the entry within the
279-
// examples.json file.
280-
func (a *API) ExamplesGoCode() string {
281-
var buf bytes.Buffer
282-
builder := defaultExamplesBuilder{}
283-
if err := exampleHeader.ExecuteTemplate(&buf, "exampleHeader", &exHeader{builder, a}); err != nil {
284-
panic(err)
285-
}
286-
287-
code := a.Examples.GoCode()
288-
if len(code) == 0 {
289-
return ""
290-
}
291-
292-
buf.WriteString(code)
293-
return buf.String()
297+
return nil
294298
}
295299

296-
// TODO: In the operation docuentation where we list errors, this needs to be done
297-
// there as well.
298300
func (ex *Example) HasVisitedError(errRef *ShapeRef) bool {
299301
errName := errRef.Shape.ErrorCodeName()
300302
_, ok := ex.VisitedErrors[errName]
301303
ex.VisitedErrors[errName] = struct{}{}
302304
return ok
303305
}
304306

305-
func parseTimeString(ref *ShapeRef, memName, v string) string {
306-
if ref.Location == "header" {
307-
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "Mon, 2 Jan 2006 15:04:05 GMT", v)
308-
} else {
309-
switch ref.API.Metadata.Protocol {
310-
case "json", "rest-json":
311-
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v)
312-
case "rest-xml", "ec2", "query":
313-
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v)
314-
default:
315-
panic("Unsupported time type: " + ref.API.Metadata.Protocol)
316-
}
317-
}
318-
}
319-
320307
func (ex *Example) MethodName() string {
321308
return fmt.Sprintf("%sRequest_%s", ex.OperationName, ex.Index)
322309
}

private/model/api/example_test.go

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ package api
44

55
import (
66
"encoding/json"
7-
"github.com/google/go-cmp/cmp"
87
"testing"
8+
9+
"github.com/google/go-cmp/cmp"
910
)
1011

1112
func buildAPI() (*API, error) {
@@ -126,32 +127,18 @@ func TestExampleGeneration(t *testing.T) {
126127
def.API = a
127128

128129
def.setup()
129-
expected := `
130-
import (
131-
"fmt"
130+
expected := `import (
132131
"context"
133-
"strings"
134-
"time"
132+
"fmt"
135133
136134
"github.com/aws/aws-sdk-go-v2/aws"
137135
"github.com/aws/aws-sdk-go-v2/aws/awserr"
138136
"github.com/aws/aws-sdk-go-v2/aws/external"
139137
"github.com/aws/aws-sdk-go-v2/service/fooservice"
140-
141138
)
142139
143-
var _ time.Duration
144-
var _ strings.Reader
145-
var _ aws.Config
146-
147-
func parseTime(layout, value string) *time.Time {
148-
t, err := time.Parse(layout, value)
149-
if err != nil {
150-
panic(err)
151-
}
152-
return &t
153-
}
154140
141+
var _ aws.Config
155142
// I pity the foo
156143
//
157144
// Foo bar baz qux
@@ -215,7 +202,7 @@ func TestBuildShape(t *testing.T) {
215202

216203
for _, c := range cases {
217204
ref := a.Operations["Foo"].InputRef
218-
shapeStr := defaultExamplesBuilder{}.BuildShape(&ref, c.defs, false, false)
205+
shapeStr := NewExamplesBuilder().BuildShape(&ref, c.defs, false, false)
219206
if c.expected != shapeStr {
220207
t.Errorf("Expected:\n%s\nReceived:\n%s", c.expected, shapeStr)
221208
}

0 commit comments

Comments
 (0)