Skip to content

Commit 2ea622b

Browse files
authored
Merge pull request goadapp#169 from cwaltken-edrans/improve-messaging
Improve SQS messaging and overall infrastructure code
2 parents 153ba5f + e3d803f commit 2ea622b

File tree

5,637 files changed

+2483223
-10289
lines changed

Some content is hidden

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

5,637 files changed

+2483223
-10289
lines changed

Gopkg.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/cli.go

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/dustin/go-humanize"
2222
"github.com/goadapp/goad/goad"
23+
"github.com/goadapp/goad/goad/types"
2324
"github.com/goadapp/goad/result"
2425
"github.com/goadapp/goad/version"
2526
"github.com/nsf/termbox-go"
@@ -79,12 +80,13 @@ func Run() {
7980
app.VersionFlag.Short('V')
8081

8182
config := aggregateConfiguration()
82-
test := createGoadTest(config)
83+
err := config.Check()
84+
goad.HandleErr(err)
8385

8486
sigChan := make(chan os.Signal, 1)
8587
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // but interrupts from kbd are blocked by termbox
8688

87-
result := start(test, sigChan)
89+
result := start(config, sigChan)
8890
defer printSummary(result)
8991
if config.Output != "" {
9092
defer saveJSONSummary(*outputFile, result)
@@ -102,15 +104,15 @@ func writeConfigStream(writer io.Writer) {
102104
stream.WriteTo(writer)
103105
}
104106

105-
func aggregateConfiguration() *goad.TestConfig {
107+
func aggregateConfiguration() *types.TestConfig {
106108
config := parseSettings()
107109
applyDefaultsFromConfig(config)
108110
config = parseCommandline()
109111
applyExtendedConfiguration(config)
110112
return config
111113
}
112114

113-
func applyDefaultsFromConfig(config *goad.TestConfig) {
115+
func applyDefaultsFromConfig(config *types.TestConfig) {
114116
applyDefaultIfNotZero(bodyFlag, config.Body)
115117
applyDefaultIfNotZero(concurrencyFlag, prepareInt(config.Concurrency))
116118
applyDefaultIfNotZero(headersFlag, config.Headers)
@@ -191,8 +193,8 @@ func loadIni() *ini.File {
191193
return cfg
192194
}
193195

194-
func parseSettings() *goad.TestConfig {
195-
config := &goad.TestConfig{}
196+
func parseSettings() *types.TestConfig {
197+
config := &types.TestConfig{}
196198
cfg := loadIni()
197199
if cfg == nil {
198200
return config
@@ -219,7 +221,7 @@ func parseSettings() *goad.TestConfig {
219221
return config
220222
}
221223

222-
func applyExtendedConfiguration(config *goad.TestConfig) {
224+
func applyExtendedConfiguration(config *types.TestConfig) {
223225
cfg := loadIni()
224226
if cfg == nil {
225227
return
@@ -229,11 +231,7 @@ func applyExtendedConfiguration(config *goad.TestConfig) {
229231
if err != nil {
230232
return
231233
}
232-
task := goad.CustomTask{
233-
// Name: taskSection.Name(),
234-
RunnerPath: runnerPathKey.String(),
235-
}
236-
config.Task = task
234+
config.RunnerPath = runnerPathKey.String()
237235
}
238236

239237
func foldHeaders(hash map[string]string) []string {
@@ -244,7 +242,7 @@ func foldHeaders(hash map[string]string) []string {
244242
return headersList
245243
}
246244

247-
func parseCommandline() *goad.TestConfig {
245+
func parseCommandline() *types.TestConfig {
248246
args := os.Args[1:]
249247

250248
kingpin.MustParse(app.Parse(args))
@@ -262,7 +260,7 @@ func parseCommandline() *goad.TestConfig {
262260

263261
regionsArray := parseRegionsForBackwardsCompatibility(*regions)
264262

265-
config := &goad.TestConfig{}
263+
config := &types.TestConfig{}
266264
config.URL = *url
267265
config.Concurrency = *concurrency
268266
config.Requests = *requests
@@ -285,22 +283,13 @@ func parseRegionsForBackwardsCompatibility(regions []string) []string {
285283
return parsedRegions
286284
}
287285

288-
func createGoadTest(config *goad.TestConfig) *goad.Test {
289-
test, err := goad.NewTest(config)
290-
if err != nil {
291-
fmt.Println(err)
292-
os.Exit(1)
293-
}
294-
return test
295-
}
296-
297-
func start(test *goad.Test, sigChan chan os.Signal) result.LambdaResults {
286+
func start(test *types.TestConfig, sigChan chan os.Signal) result.LambdaResults {
298287
var currentResult result.LambdaResults
299-
resultChan, teardown := test.Start()
288+
resultChan, teardown := goad.Start(test)
300289
defer teardown()
301290

302291
platform := "AWS"
303-
if test.Config.RunDocker {
292+
if test.RunDocker {
304293
platform = "Docker"
305294
}
306295
launchingOn := fmt.Sprintf("Launching on %s... (be patient)", platform)
@@ -351,10 +340,10 @@ outer:
351340

352341
y = 0
353342
var percentDone float64
354-
if test.Config.Requests > 0 {
355-
percentDone = float64(totalReqs) / float64(test.Config.Requests)
343+
if test.Requests > 0 {
344+
percentDone = float64(totalReqs) / float64(test.Requests)
356345
} else {
357-
percentDone = math.Min(float64(time.Since(startTime).Seconds())/float64(test.Config.Timelimit), 1.0)
346+
percentDone = math.Min(float64(time.Since(startTime).Seconds())/float64(test.Timelimit), 1.0)
358347
}
359348
drawProgressBar(percentDone, y)
360349

cli/ini_parser_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ import (
77
"sort"
88
"testing"
99

10-
"github.com/goadapp/goad/goad"
10+
"github.com/goadapp/goad/goad/types"
1111
"github.com/stretchr/testify/assert"
1212
)
1313

1414
const testDataFile = "testdata/test-config.ini"
1515

1616
var expectedRegions = []string{"us-east-1", "eu-west-1"}
1717
var expectedHeader = []string{"cache-control: no-cache", "auth-token: YOUR-SECRET-AUTH-TOKEN", "base64-header: dGV4dG8gZGUgcHJ1ZWJhIA=="}
18-
var expectedTask = goad.CustomTask{RunnerPath: "default-runner"}
1918

2019
func TestLoadStandardConfig(t *testing.T) {
2120
iniFile = testDataFile
@@ -24,7 +23,7 @@ func TestLoadStandardConfig(t *testing.T) {
2423
assertConfigContent(config, t)
2524
}
2625

27-
func assertConfigContent(config *goad.TestConfig, t *testing.T) {
26+
func assertConfigContent(config *types.TestConfig, t *testing.T) {
2827
assert := assert.New(t)
2928
assert.Equal("http://file-config.com/", config.URL, "Should load the URL")
3029
assert.Equal("GET", config.Method, "Should load the request method")
@@ -38,7 +37,7 @@ func assertConfigContent(config *goad.TestConfig, t *testing.T) {
3837
sort.Strings(expectedHeader)
3938
sort.Strings(config.Headers)
4039
assert.Equal(expectedHeader, config.Headers, "Should load the output file")
41-
assert.Equal(expectedTask, config.Task, "Should load tasks configuration")
40+
assert.Equal("default-runner", config.RunnerPath, "Should load runner path configuration")
4241
}
4342

4443
func TestSaveConfig(t *testing.T) {

goad/goad.go

Lines changed: 12 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,31 @@
11
package goad
22

33
import (
4-
"errors"
5-
"fmt"
6-
"math"
7-
"strconv"
8-
"strings"
9-
"time"
10-
11-
"github.com/aws/aws-sdk-go/aws"
4+
"github.com/goadapp/goad/goad/types"
125
"github.com/goadapp/goad/infrastructure"
136
"github.com/goadapp/goad/infrastructure/aws"
147
"github.com/goadapp/goad/infrastructure/docker"
158
"github.com/goadapp/goad/result"
169
)
1710

18-
// TestConfig type
19-
type TestConfig struct {
20-
URL string
21-
Concurrency int
22-
Requests int
23-
Timelimit int
24-
Timeout int
25-
Regions []string
26-
Method string
27-
Body string
28-
Headers []string
29-
Output string
30-
Settings string
31-
RunDocker bool
32-
Task CustomTask
33-
}
34-
35-
type CustomTask struct {
36-
RunnerPath string
37-
}
38-
39-
const (
40-
MAX_REQUEST_COUNT = math.MaxInt32
41-
nano = 1000000000
42-
)
43-
44-
var supportedRegions = []string{
45-
"us-east-1", // N. Virginia
46-
"us-east-2", // Ohio
47-
"us-west-1", // N.California
48-
"us-west-2", // Oregon
49-
"eu-west-1", // Ireland
50-
"eu-central-1", // Frankfurt
51-
"ap-northeast-1", // Sydney
52-
"ap-northeast-2", // Seoul
53-
"ap-southeast-1", // Singapore
54-
"ap-southeast-2", // Tokio
55-
"sa-east-1", // Sao Paulo
56-
}
57-
58-
// Test type
59-
type Test struct {
60-
Config *TestConfig
61-
infra infrastructure.Infrastructure
62-
lambdas int
63-
currentID int
64-
}
65-
66-
// NewTest returns a configured Test
67-
func NewTest(config *TestConfig) (*Test, error) {
68-
err := config.check()
69-
if err != nil {
70-
return nil, err
71-
}
72-
return &Test{Config: config, infra: nil}, nil
73-
}
74-
7511
// Start a test
76-
func (t *Test) Start() (<-chan *result.LambdaResults, func()) {
77-
awsConfig := aws.NewConfig().WithRegion(t.Config.Regions[0])
12+
func Start(t *types.TestConfig) (<-chan *result.LambdaResults, func()) {
7813

79-
if t.Config.RunDocker {
80-
t.infra = dockerinfra.NewDockerInfrastructure()
14+
var infra infrastructure.Infrastructure
15+
if t.RunDocker {
16+
infra = dockerinfra.New(t)
8117
} else {
82-
t.infra = awsinfra.New(t.Config.Regions, awsConfig)
18+
infra = awsinfra.New(t)
8319
}
84-
teardown, err := t.infra.Setup(infrastructure.Settings{
85-
RunnerPath: t.Config.Task.RunnerPath,
86-
})
87-
handleErr(err)
88-
t.lambdas = numberOfLambdas(t.Config.Concurrency, len(t.Config.Regions))
89-
t.invokeLambdas()
20+
teardown, err := infra.Setup()
21+
HandleErr(err)
22+
t.Lambdas = numberOfLambdas(t.Concurrency, len(t.Regions))
23+
infrastructure.InvokeLambdas(infra)
9024

9125
results := make(chan *result.LambdaResults)
9226

9327
go func() {
94-
for result := range result.Aggregate(awsConfig, t.infra.GetQueueURL(), t.Config.Requests, t.lambdas) {
28+
for result := range infrastructure.Aggregate(infra) {
9529
results <- result
9630
}
9731
close(results)
@@ -100,47 +34,7 @@ func (t *Test) Start() (<-chan *result.LambdaResults, func()) {
10034
return results, teardown
10135
}
10236

103-
func (t *Test) invokeLambdas() {
104-
for i := 0; i < t.lambdas; i++ {
105-
region := t.Config.Regions[i%len(t.Config.Regions)]
106-
requests, requestsRemainder := divide(t.Config.Requests, t.lambdas)
107-
concurrency, _ := divide(t.Config.Concurrency, t.lambdas)
108-
execTimeout := t.Config.Timelimit
109-
110-
if requestsRemainder > 0 && i == t.lambdas-1 {
111-
requests += requestsRemainder
112-
}
113-
114-
c := t.Config
115-
args := []string{
116-
fmt.Sprintf("--concurrency=%s", strconv.Itoa(int(concurrency))),
117-
fmt.Sprintf("--requests=%s", strconv.Itoa(int(requests))),
118-
fmt.Sprintf("--execution-time=%s", strconv.Itoa(int(execTimeout))),
119-
fmt.Sprintf("--sqsurl=%s", t.infra.GetQueueURL()),
120-
fmt.Sprintf("--queue-region=%s", c.Regions[0]),
121-
fmt.Sprintf("--client-timeout=%s", time.Duration(c.Timeout)*time.Second),
122-
fmt.Sprintf("--frequency=%s", reportingFrequency(t.lambdas).String()),
123-
fmt.Sprintf("--aws-region=%s", region),
124-
fmt.Sprintf("--method=%s", c.Method),
125-
fmt.Sprintf("--runner-id=%d", t.currentID),
126-
fmt.Sprintf("--body=%s", c.Body),
127-
}
128-
t.currentID++
129-
for _, v := range t.Config.Headers {
130-
args = append(args, fmt.Sprintf("--header=%s", v))
131-
}
132-
args = append(args, fmt.Sprintf("%s", c.URL))
133-
134-
invokeargs := infrastructure.InvokeArgs{
135-
File: "./goad-lambda",
136-
Args: args,
137-
}
138-
139-
go t.infra.Run(invokeargs)
140-
}
141-
}
142-
143-
func handleErr(err error) {
37+
func HandleErr(err error) {
14438
if err != nil {
14539
panic(err)
14640
}
@@ -162,45 +56,3 @@ func numberOfLambdas(concurrency int, numRegions int) int {
16256
}
16357
return int(concurrency-1)/10 + 1
16458
}
165-
166-
func divide(dividend int, divisor int) (quotient, remainder int) {
167-
return dividend / divisor, dividend % divisor
168-
}
169-
170-
func reportingFrequency(numberOfLambdas int) time.Duration {
171-
return time.Duration((math.Log2(float64(numberOfLambdas)) + 1)) * time.Second
172-
}
173-
174-
func (c TestConfig) check() error {
175-
concurrencyLimit := 25000 * len(c.Regions)
176-
if c.Concurrency < 1 || c.Concurrency > concurrencyLimit {
177-
return fmt.Errorf("Invalid concurrency (use 1 - %d)", concurrencyLimit)
178-
}
179-
if (c.Requests < 1 && c.Timelimit <= 0) || c.Requests > MAX_REQUEST_COUNT {
180-
return errors.New(fmt.Sprintf("Invalid total requests (use 1 - %d)", MAX_REQUEST_COUNT))
181-
}
182-
if c.Timelimit > 3600 {
183-
return errors.New("Invalid maximum execution time in seconds (use 0 - 3600)")
184-
}
185-
if c.Timeout < 1 || c.Timeout > 100 {
186-
return errors.New("Invalid timeout (1s - 100s)")
187-
}
188-
for _, region := range c.Regions {
189-
supportedRegionFound := false
190-
for _, supported := range supportedRegions {
191-
if region == supported {
192-
supportedRegionFound = true
193-
}
194-
}
195-
if !supportedRegionFound {
196-
return fmt.Errorf("Unsupported region: %s. Supported regions are: %s.", region, strings.Join(supportedRegions, ", "))
197-
}
198-
}
199-
for _, v := range c.Headers {
200-
header := strings.Split(v, ":")
201-
if len(header) < 2 {
202-
return fmt.Errorf("Header %s not valid. Make sure your header is of the form \"Header: value\"", v)
203-
}
204-
}
205-
return nil
206-
}

0 commit comments

Comments
 (0)