Skip to content

Commit

Permalink
Merge pull request #22 from rogerwelin/refactor-cli
Browse files Browse the repository at this point in the history
Refactor cli
  • Loading branch information
rogerwelin authored Jun 11, 2020
2 parents 88fbd9f + 1c2ef1f commit c85379c
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 165 deletions.
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
apa*
out.json
go-dist
.theia/
/.theia
.theia/settings.json
urls.txt
2 changes: 1 addition & 1 deletion README-ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Summary:
示例:访问外部文件指定的URL路径(外部文件也可以是http路径的)

```bash
$ ./cassowary run-file -u http://localhost:8000 -c 10 -f urlpath.txt
$ ./cassowary run -u http://localhost:8000 -c 10 -f urlpath.txt

Starting Load Test with 3925 requests using 10 concurrent users

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Installation

Grab a pre-built binary from the [GitHub Releases page](https://github.com/rogerwelin/cassowary/releases). You can optionally put the **cassowary** binary in your `PATH` so you can run cassowary from any location. Alternative you can:

### Homebrew on MAC OSX
### Homebrew on Mac OSX
You can install **cassowary** using the Homebrew package manager on Mac:

```bash
Expand Down Expand Up @@ -107,14 +107,14 @@ Summary:
Example running **cassowary** in file slurp mode where all URL paths are specified from an external file (which can also be fetched from http if specified). By default cassowary will, without the -n flag specified, make one request per path specified in the file. However with the -n flag you can also specify how many request you want cassowary to generate against those URL paths. Example:

```bash
$ ./cassowary run-file -u http://localhost:8000 -c 1 -f urlpath.txt
$ ./cassowary run -u http://localhost:8000 -c 1 -f urlpath.txt

Starting Load Test with 5 requests using 1 concurrent users

[ omitted ]


$ ./cassowary run-file -u http://localhost:8000 -c 10 -n 100 -f urlpath.txt
$ ./cassowary run -u http://localhost:8000 -c 10 -n 100 -f urlpath.txt

Starting Load Test with 100 requests using 10 concurrent users

Expand Down
221 changes: 65 additions & 156 deletions cmd/cassowary/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/fatih/color"
"github.com/rogerwelin/cassowary/pkg/client"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
)

var (
Expand Down Expand Up @@ -94,12 +94,13 @@ func runLoadTest(c *client.Cassowary) error {
}

func validateCLI(c *cli.Context) error {

prometheusEnabled := false
var header []string
var httpMethod string
var data []byte
duration := 0
var urlSuffixes []string
fileMode := false

if c.Int("concurrency") == 0 {
return errConcurrencyLevel
Expand Down Expand Up @@ -136,6 +137,15 @@ func validateCLI(c *cli.Context) error {
}
}

if c.String("file") != "" {
var err error
urlSuffixes, err = readLocalRemoteFile(c.String("file"))
if err != nil {
return nil
}
fileMode = true
}

if c.String("postfile") != "" {
httpMethod = "POST"
fileData, err := readFile(c.String("postfile"))
Expand Down Expand Up @@ -176,7 +186,7 @@ func validateCLI(c *cli.Context) error {
}

cass := &client.Cassowary{
FileMode: false,
FileMode: fileMode,
BaseURL: c.String("url"),
ConcurrencyLevel: c.Int("concurrency"),
Requests: c.Int("requests"),
Expand All @@ -191,56 +201,8 @@ func validateCLI(c *cli.Context) error {
DisableKeepAlive: c.Bool("disable-keep-alive"),
Timeout: c.Int("timeout"),
HTTPMethod: httpMethod,
Data: data,
}

return runLoadTest(cass)
}

func validateCLIFile(c *cli.Context) error {
prometheusEnabled := false
var header []string

if c.Int("concurrency") == 0 {
return errConcurrencyLevel
}

if client.IsValidURL(c.String("url")) == false {
return errNotValidURL
}

if c.String("prompushgwurl") != "" {
prometheusEnabled = true
}

if c.String("header") != "" {
length := 0
length, header = client.SplitHeader(c.String("header"))
if length != 2 {
return errNotValidHeader
}
}

urlSuffixes, err := readLocalRemoteFile(c.String("file"))
if err != nil {
return nil
}

cass := &client.Cassowary{
FileMode: true,
BaseURL: c.String("url"),
ConcurrencyLevel: c.Int("concurrency"),
RequestHeader: header,
PromExport: prometheusEnabled,
PromURL: c.String("prompushgwurl"),
Cloudwatch: c.Bool("cloudwatch"),
ExportMetrics: c.Bool("json-metrics"),
ExportMetricsFile: c.String("json-metrics-file"),
DisableKeepAlive: c.Bool("diable-keep-alive"),
Timeout: c.Int("timeout"),
Requests: c.Int("requests"),
URLPaths: urlSuffixes,
HTTPMethod: "GET",
Data: data,
}

return runLoadTest(cass)
Expand All @@ -254,143 +216,90 @@ func runCLI(args []string) {
app.EnableBashCompletion = true
app.Usage = ""
app.Version = version
app.Commands = []cli.Command{
{
Name: "run-file",
Usage: "start load test in spread mode",
Flags: []cli.Flag{
cli.StringFlag{
Name: "u, url",
Usage: "the base url (absoluteURI) to be used",
Required: true,
},
cli.IntFlag{
Name: "c, concurrency",
Usage: "number of concurrent users",
Required: true,
},
cli.IntFlag{
Name: "n, requests",
Usage: "number of requests to perform",
},
cli.IntFlag{
Name: "t, timeout",
Usage: "http client timeout",
Value: 5,
},
cli.StringFlag{
Name: "f, file",
Usage: "specify `FILE` path, local or www, containing the url suffixes",
Required: true,
},
cli.StringFlag{
Name: "p, prompushgwurl",
Usage: "specify prometheus push gateway url to send metrics (optional)",
},
cli.BoolFlag{
Name: "C, cloudwatch",
Usage: "enable to send metrics to AWS Cloudwatch",
},
cli.StringFlag{
Name: "H, header",
Usage: "add arbitrary header, eg. 'Host: www.example.com'",
},
cli.BoolFlag{
Name: "F, json-metrics",
Usage: "outputs metrics to a json file by setting flag to true",
},
cli.StringFlag{
Name: "json-metrics-file",
Usage: "outputs metrics to a custom json filepath, if json-metrics is set to true",
},
cli.BoolFlag{
Name: "disable-keep-alive",
Usage: "use this flag to disable http keep-alive",
},
cli.StringFlag{
Name: "ca",
Usage: "ca certificate to verify peer against",
},
cli.StringFlag{
Name: "cert",
Usage: "client authentication certificate",
},
cli.StringFlag{
Name: "key",
Usage: "client authentication key",
},
},
Action: validateCLIFile,
},
app.Commands = []*cli.Command{
{
Name: "run",
Usage: "start load-test",
Flags: []cli.Flag{
cli.StringFlag{
Name: "u, url",
&cli.StringFlag{
Name: "u",
Aliases: []string{"url"},
Usage: "the url (absoluteURI) to be used",
Required: true,
},
cli.IntFlag{
Name: "c, concurrency",
Usage: "number of concurrent users",
Required: true,
&cli.IntFlag{
Name: "c",
Aliases: []string{"concurrency"},
Usage: "number of concurrent users",
Value: 1,
},
cli.IntFlag{
Name: "n, requests",
Usage: "number of requests to perform",
Required: true,
&cli.IntFlag{
Name: "n",
Aliases: []string{"requests"},
Usage: "number of requests to perform",
Value: 1,
},
&cli.StringFlag{
Name: "f",
Aliases: []string{"file"},
Usage: "file-slurp mode: specify `FILE` path, local or www, containing the url suffixes",
},
cli.StringFlag{
Name: "d, duration",
Usage: "set the duration in seconds of the load test (example: do 100 requests in a duration of 30s)",
&cli.StringFlag{
Name: "d",
Aliases: []string{"duration"},
Usage: "set the duration in seconds of the load test (example: do 100 requests in a duration of 30s)",
},
cli.IntFlag{
Name: "t, timeout",
Usage: "http client timeout",
Value: 5,
&cli.IntFlag{
Name: "t",
Aliases: []string{"timeout"},
Usage: "http client timeout",
Value: 5,
},
cli.StringFlag{
Name: "p, prompushgwurl",
Usage: "specify prometheus push gateway url to send metrics (optional)",
&cli.StringFlag{
Name: "p",
Aliases: []string{"prompushgwurl"},
Usage: "specify prometheus push gateway url to send metrics (optional)",
},
cli.BoolFlag{
Name: "C, cloudwatch",
Usage: "enable to send metrics to AWS Cloudwatch",
&cli.BoolFlag{
Name: "C",
Aliases: []string{"cloudwatch"},
Usage: "enable to send metrics to AWS Cloudwatch",
},
cli.StringFlag{
Name: "H, header",
Usage: "add arbitrary header, eg. 'Host: www.example.com'",
&cli.StringFlag{
Name: "H",
Aliases: []string{"header"},
Usage: "add arbitrary header, eg. 'Host: www.example.com'",
},
cli.BoolFlag{
Name: "F, json-metrics",
Usage: "outputs metrics to a json file by setting flag to true",
&cli.BoolFlag{
Name: "F",
Aliases: []string{"json-metrics"},
Usage: "outputs metrics to a json file by setting flag to true",
},
cli.StringFlag{
&cli.StringFlag{
Name: "postfile",
Usage: "file containing data to POST (content type will default to application/json)",
},
cli.StringFlag{
&cli.StringFlag{
Name: "putfile",
Usage: "file containig data to PUT (content type will default to application/json)",
},
cli.StringFlag{
&cli.StringFlag{
Name: "json-metrics-file",
Usage: "outputs metrics to a custom json filepath, if json-metrics is set to true",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "disable-keep-alive",
Usage: "use this flag to disable http keep-alive",
},
cli.StringFlag{
&cli.StringFlag{
Name: "ca",
Usage: "ca certificate to verify peer against",
},
cli.StringFlag{
&cli.StringFlag{
Name: "cert",
Usage: "client authentication certificate",
},
cli.StringFlag{
&cli.StringFlag{
Name: "key",
Usage: "client authentication key",
},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ require (
github.com/mattn/go-isatty v0.0.10 // indirect
github.com/prometheus/client_golang v1.3.0
github.com/schollz/progressbar v1.0.0
github.com/urfave/cli v1.22.1
github.com/urfave/cli/v2 v2.2.0
)
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down
8 changes: 7 additions & 1 deletion pkg/client/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,20 @@ func (c *Cassowary) Coordinate() (ResultMetrics, error) {
nextTick := durationMS / c.Requests
ticker := time.NewTicker(time.Duration(nextTick) * time.Millisecond)
done := make(chan bool)
iter := 0

go func() {
for {
select {
case <-done:
return
case _ = <-ticker.C:
workerChan <- "a"
if c.FileMode {
workerChan <- c.URLPaths[iter]
iter++
} else {
workerChan <- "a"
}
}
}
}()
Expand Down

0 comments on commit c85379c

Please sign in to comment.