Switch to using the dep tool and update all the dependencies

This commit is contained in:
Nick Craig-Wood 2017-05-11 15:39:54 +01:00
parent 5135ff73cb
commit 98c2d2c41b
5321 changed files with 4483201 additions and 5922 deletions

View file

@ -0,0 +1,122 @@
// +build integration
package performance
import (
"errors"
"fmt"
"os"
"reflect"
"runtime"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting/mock"
"github.com/gucumber/gucumber"
)
// mapCreateClients allows for the creation of clients
func mapCreateClients() {
clientFns := []func(){}
for _, c := range clients {
clientFns = append(clientFns, func() { c.Call([]reflect.Value{reflect.ValueOf(mock.Session)}) })
}
gucumber.World["services"] = clientFns
}
func buildAnArrayOfClients() {
methods := []reflect.Value{}
params := [][]reflect.Value{}
for _, c := range clients {
method, param, err := findAndGetMethod(c.Call([]reflect.Value{reflect.ValueOf(mock.Session)}))
if err == nil {
methods = append(methods, method)
params = append(params, param)
}
}
fns := []func(){}
for i := 0; i < len(methods); i++ {
m := methods[i]
p := params[i]
f := func() {
reqs := m.Call(p)
resp := reqs[0].Interface().(*request.Request).Send()
fmt.Println(resp)
}
fns = append(fns, f)
}
gucumber.World["clientFns"] = fns
}
// findAndGetMethod will grab the method, params to be passed to the method, and an error.
// The method that is found, is a method that doesn't have any required input
func findAndGetMethod(client interface{}) (reflect.Value, []reflect.Value, error) {
v := reflect.ValueOf(client).Type()
n := v.NumMethod()
outer:
for i := 0; i < n; i++ {
method := v.Method(i)
if method.Type.NumIn() != 2 || strings.HasSuffix(method.Name, "Request") {
continue
}
param := reflect.New(method.Type.In(1).Elem())
for j := 0; j < param.Elem().NumField(); j++ {
field := param.Elem().Type().Field(j)
req := field.Tag.Get("required")
if req == "true" {
continue outer
}
}
params := []reflect.Value{reflect.ValueOf(client), param}
return method.Func, params, nil
}
return reflect.Value{}, nil, errors.New("No method found")
}
// benchmarkTask takes a unique key to write to the logger with the benchmark
// result's data
func benchmarkTask(key string, fns []func(), i1 int) error {
gucumber.World["error"] = nil
memStatStart := &runtime.MemStats{}
runtime.ReadMemStats(memStatStart)
results := testing.Benchmark(func(b *testing.B) {
for _, f := range fns {
for i := 0; i < i1; i++ {
f()
}
}
})
results.N = i1
memStatEnd := &runtime.MemStats{}
runtime.ReadMemStats(memStatEnd)
l, err := newBenchmarkLogger("stdout")
if err != nil {
return err
}
l.log(key, results)
toDynamodb := os.Getenv("AWS_TESTING_LOG_RESULTS") == "true"
if toDynamodb {
l, err := newBenchmarkLogger("dynamodb")
if err != nil {
return err
}
l.log(key+"_start_benchmarks", memStatStart)
l.log(key+"_end_benchmarks", memStatEnd)
}
if memStatStart.Alloc < memStatEnd.Alloc {
return errors.New("Leaked memory")
}
return nil
}

View file

@ -0,0 +1,13 @@
// +build integration
//Package performance provides gucumber integration tests support.
package performance
import (
"github.com/gucumber/gucumber"
)
func init() {
gucumber.Before("@performance", func() {
})
}

View file

@ -0,0 +1,17 @@
# language: en
@performance @clients
Feature: Client Performance
Background:
Given I have loaded my SDK and its dependencies
And I have a list of services
And I take a snapshot of my resources
Scenario: Creating and then cleaning up clients doesn't leak resources
When I create and discard 100 clients for each service
Then I should not have leaked any resources
Scenario: Sending requests doesn't leak resources
When I create a client for each service
And I execute 100 command(s) on each client
And I destroy all the clients
Then I should not have leaked any resources

View file

@ -0,0 +1,137 @@
// +build integration
package performance
import (
"reflect"
"github.com/aws/aws-sdk-go/service/acm"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/aws/aws-sdk-go/service/cloudhsm"
"github.com/aws/aws-sdk-go/service/cloudsearch"
"github.com/aws/aws-sdk-go/service/cloudsearchdomain"
"github.com/aws/aws-sdk-go/service/cloudtrail"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/cloudwatchevents"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/aws/aws-sdk-go/service/codecommit"
"github.com/aws/aws-sdk-go/service/codedeploy"
"github.com/aws/aws-sdk-go/service/codepipeline"
"github.com/aws/aws-sdk-go/service/cognitoidentity"
"github.com/aws/aws-sdk-go/service/cognitosync"
"github.com/aws/aws-sdk-go/service/configservice"
"github.com/aws/aws-sdk-go/service/datapipeline"
"github.com/aws/aws-sdk-go/service/devicefarm"
"github.com/aws/aws-sdk-go/service/directconnect"
"github.com/aws/aws-sdk-go/service/directoryservice"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodbstreams"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/aws/aws-sdk-go/service/elasticache"
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
"github.com/aws/aws-sdk-go/service/elasticsearchservice"
"github.com/aws/aws-sdk-go/service/elastictranscoder"
"github.com/aws/aws-sdk-go/service/elb"
"github.com/aws/aws-sdk-go/service/emr"
"github.com/aws/aws-sdk-go/service/firehose"
"github.com/aws/aws-sdk-go/service/glacier"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/inspector"
"github.com/aws/aws-sdk-go/service/iot"
"github.com/aws/aws-sdk-go/service/iotdataplane"
"github.com/aws/aws-sdk-go/service/kinesis"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/aws/aws-sdk-go/service/lambda"
"github.com/aws/aws-sdk-go/service/machinelearning"
"github.com/aws/aws-sdk-go/service/marketplacecommerceanalytics"
"github.com/aws/aws-sdk-go/service/mobileanalytics"
"github.com/aws/aws-sdk-go/service/opsworks"
"github.com/aws/aws-sdk-go/service/rds"
"github.com/aws/aws-sdk-go/service/redshift"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/aws/aws-sdk-go/service/route53domains"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/ses"
"github.com/aws/aws-sdk-go/service/simpledb"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go/service/storagegateway"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/aws/aws-sdk-go/service/support"
"github.com/aws/aws-sdk-go/service/swf"
"github.com/aws/aws-sdk-go/service/waf"
"github.com/aws/aws-sdk-go/service/workspaces"
)
var clients = []reflect.Value{
reflect.ValueOf(acm.New),
reflect.ValueOf(apigateway.New),
reflect.ValueOf(autoscaling.New),
reflect.ValueOf(cloudformation.New),
reflect.ValueOf(cloudfront.New),
reflect.ValueOf(cloudhsm.New),
reflect.ValueOf(cloudsearch.New),
reflect.ValueOf(cloudsearchdomain.New),
reflect.ValueOf(cloudtrail.New),
reflect.ValueOf(cloudwatch.New),
reflect.ValueOf(cloudwatchevents.New),
reflect.ValueOf(cloudwatchlogs.New),
reflect.ValueOf(codecommit.New),
reflect.ValueOf(codedeploy.New),
reflect.ValueOf(codepipeline.New),
reflect.ValueOf(cognitoidentity.New),
reflect.ValueOf(cognitosync.New),
reflect.ValueOf(configservice.New),
reflect.ValueOf(datapipeline.New),
reflect.ValueOf(devicefarm.New),
reflect.ValueOf(directconnect.New),
reflect.ValueOf(directoryservice.New),
reflect.ValueOf(dynamodb.New),
reflect.ValueOf(dynamodbstreams.New),
reflect.ValueOf(ec2.New),
reflect.ValueOf(ecr.New),
reflect.ValueOf(ecs.New),
reflect.ValueOf(efs.New),
reflect.ValueOf(elasticache.New),
reflect.ValueOf(elasticbeanstalk.New),
reflect.ValueOf(elasticsearchservice.New),
reflect.ValueOf(elastictranscoder.New),
reflect.ValueOf(elb.New),
reflect.ValueOf(emr.New),
reflect.ValueOf(firehose.New),
reflect.ValueOf(glacier.New),
reflect.ValueOf(iam.New),
reflect.ValueOf(inspector.New),
reflect.ValueOf(iot.New),
reflect.ValueOf(iotdataplane.New),
reflect.ValueOf(kinesis.New),
reflect.ValueOf(kms.New),
reflect.ValueOf(lambda.New),
reflect.ValueOf(machinelearning.New),
reflect.ValueOf(marketplacecommerceanalytics.New),
reflect.ValueOf(mobileanalytics.New),
reflect.ValueOf(opsworks.New),
reflect.ValueOf(rds.New),
reflect.ValueOf(redshift.New),
reflect.ValueOf(route53.New),
reflect.ValueOf(route53domains.New),
reflect.ValueOf(s3.New),
reflect.ValueOf(ses.New),
reflect.ValueOf(simpledb.New),
reflect.ValueOf(sns.New),
reflect.ValueOf(sqs.New),
reflect.ValueOf(ssm.New),
reflect.ValueOf(storagegateway.New),
reflect.ValueOf(sts.New),
reflect.ValueOf(support.New),
reflect.ValueOf(swf.New),
reflect.ValueOf(waf.New),
reflect.ValueOf(workspaces.New),
}

View file

@ -0,0 +1,93 @@
// +build integration
package performance
import (
"bytes"
"errors"
"fmt"
"runtime"
"github.com/gucumber/gucumber"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/awstesting/mock"
"github.com/aws/aws-sdk-go/service/s3"
)
func init() {
// Go loads all of its dependecies on compile
gucumber.Given(`^I have loaded my SDK and its dependencies$`, func() {
})
// Performance
gucumber.When(`^I create and discard (\d+) clients for each service$`, func(i1 int) {
services := gucumber.World["services"].([]func())
err := benchmarkTask(fmt.Sprintf("%d_create_and_discard_clients", i1), services, i1)
gucumber.World["error"] = err
})
gucumber.Then(`^I should not have leaked any resources$`, func() {
runtime.GC()
err, ok := gucumber.World["error"].(awserr.Error)
assert.False(gucumber.T, ok, "error returned")
assert.NoError(gucumber.T, err)
})
gucumber.And(`^I have a list of services$`, func() {
mapCreateClients()
})
gucumber.And(`^I take a snapshot of my resources$`, func() {
// Can't take a memory snapshot here, because gucumber does some
// allocation between each instruction leading to unreliable numbers
})
gucumber.When(`^I create a client for each service$`, func() {
buildAnArrayOfClients()
})
gucumber.And("^I execute (\\d+) command\\(s\\) on each client$", func(i1 int) {
clientFns := gucumber.World["clientFns"].([]func())
err := benchmarkTask(fmt.Sprintf("%d_commands_on_clients", i1), clientFns, i1)
gucumber.World["error"] = err
})
gucumber.And(`^I destroy all the clients$`, func() {
delete(gucumber.World, "clientFns")
runtime.GC()
})
gucumber.Given(`^I have a (\d+) byte file$`, func(i1 int) {
gucumber.World["file"] = make([]byte, i1)
})
gucumber.When(`^I upload the file$`, func() {
svc := s3.New(mock.Session)
memStatStart := &runtime.MemStats{}
runtime.ReadMemStats(memStatStart)
gucumber.World["start"] = memStatStart
svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("bucketmesilly"),
Key: aws.String("testKey"),
Body: bytes.NewReader(gucumber.World["file"].([]byte)),
})
})
gucumber.And(`then download the file$`, func() {
svc := s3.New(mock.Session)
svc.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String("bucketmesilly"),
Key: aws.String("testKey"),
})
memStatEnd := &runtime.MemStats{}
runtime.ReadMemStats(memStatEnd)
memStatStart := gucumber.World["start"].(*runtime.MemStats)
if memStatStart.Alloc < memStatEnd.Alloc {
gucumber.World["error"] = errors.New("Leaked memory")
}
})
}

View file

@ -0,0 +1,122 @@
// +build integration
// Package performance contains shared step definitions that are used for performance testing
package performance
import (
"errors"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
// benchmarkLogger handles all benchmark logging
type benchmarkLogger struct {
outputer
}
// logger interface that handles any logging to an output
type logger interface {
log(key string, data map[string]interface{}) error
}
// init initializes the logger and uses dependency injection for the
// outputer
func newBenchmarkLogger(output string) (*benchmarkLogger, error) {
b := &benchmarkLogger{}
switch output {
case "dynamodb":
region := os.Getenv("AWS_TESTING_REGION")
if region == "" {
return b, errors.New("No region specified. Please export AWS_TESTING_REGION")
}
table := os.Getenv("AWS_TESTING_DB_TABLE")
if table == "" {
return b, errors.New("No table specified. Please export AWS_TESTING_DB_TABLE")
}
b.outputer = newDynamodbOut(table, region)
case "stdout":
b.outputer = stdout{}
default:
return b, errors.New("Unsupported outputer")
}
return b, nil
}
type record struct {
Key string
Data interface{}
}
// log calls the output command and building a data structure
// to pass into its output formatter
func (b benchmarkLogger) log(key, data interface{}) error {
formatData := record{
Key: fmt.Sprintf("%d-%v", time.Now().Unix(), key.(string)),
Data: data,
}
return b.output(formatData)
}
// outputer is a simple interface that'll handle output
// to whatever system like dynamodb or stdout
type outputer interface {
output(record) error
}
// dyanmodbOut handles simple writes to dynamodb
type dynamodbOut struct {
table string // table to write to in dynamodb
region string
db *dynamodb.DynamoDB // the dynamodb
}
// init initializes dynamodbOut
func newDynamodbOut(table, region string) *dynamodbOut {
out := dynamodbOut{
table: table,
region: region,
}
out.db = dynamodb.New(
unit.Session,
&aws.Config{Region: &out.region},
)
return &out
}
// output just writes to dynamodb
func (out dynamodbOut) output(data record) error {
input := &dynamodb.PutItemInput{
TableName: aws.String(out.table),
}
item, err := dynamodbattribute.ConvertToMap(data)
if err != nil {
return err
}
input.Item = item
_, err = out.db.PutItem(input)
return err
}
// stdout handles writes to stdout
type stdout struct{}
// output expects key value data to print to stdout
func (out stdout) output(data record) error {
item, err := dynamodbattribute.ConvertToMap(data.Data)
if err != nil {
return err
}
fmt.Println(item)
return nil
}

View file

@ -0,0 +1,26 @@
# language: en
@performance @streaming
Feature: Streaming transfers consume a fixed amount of memory
Scenario Outline: Streaming uploads are O(1) in memory usage
Given I have a <bytes> byte file
And I take a snapshot of my resources
When I upload the file
Then I should not have leaked any resources
Examples:
| bytes |
| 2097152 |
| 209715200 |
Scenario Outline: Streaming download are O(1) in memory usage
Given I have a <bytes> byte file
And I take a snapshot of my resources
When I upload the file
And then download the file
Then I should not have leaked any resources
Examples:
| bytes |
| 2097152 |
| 209715200 |