diff --git a/cmd/grpcannon/main.go b/cmd/grpcannon/main.go index 9a0c0dd8..809e5f02 100644 --- a/cmd/grpcannon/main.go +++ b/cmd/grpcannon/main.go @@ -31,7 +31,8 @@ var ( n = flag.Int("n", 200, "Number of requests to run. Default is 200.") q = flag.Int("q", 0, "Rate limit, in queries per second (QPS). Default is no rate limit.") t = flag.Int("t", 20, "Timeout for each request in seconds.") - z = flag.Duration("z", 0, "") + z = flag.Duration("z", 0, "Duration of application to send requests.") + x = flag.Duration("x", 0, "Maximum duration of application to send requests.") data = flag.String("d", "", "The call data as stringified JSON.") dataPath = flag.String("D", "", "Path for call data JSON file.") @@ -70,6 +71,9 @@ Options: -z Duration of application to send requests. When duration is reached, application stops and exits. If duration is specified, n is ignored. Examples: -z 10s -z 3m. + -x Maximum duration of application to send requests with n setting respected. + If duration is reached before n requests are completed, application stops and exits. + Examples: -x 10s -x 3m. -d The call data as stringified JSON. -D Path for call data JSON file. For example, /home/user/file.json or ./file.json. @@ -133,7 +137,7 @@ func main() { iPaths = strings.Split(pathsTrimmed, ",") } - cfg, err = config.New(*proto, *protoset, *call, *cert, *cname, *n, *c, *q, *z, *t, + cfg, err = config.New(*proto, *protoset, *call, *cert, *cname, *n, *c, *q, *z, *x, *t, *data, *dataPath, *md, *mdPath, *output, *format, host, *ct, *kt, *cpus, iPaths) if err != nil { errAndExit(err.Error()) diff --git a/config/config.go b/config/config.go index 4f684799..4248f792 100644 --- a/config/config.go +++ b/config/config.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math" "path/filepath" "runtime" "strings" @@ -23,6 +24,7 @@ type Config struct { C int `json:"c"` QPS int `json:"q"` Z time.Duration `json:"z"` + X time.Duration `json:"x"` Timeout int `json:"t"` Data interface{} `json:"d,omitempty"` DataPath string `json:"D"` @@ -38,8 +40,8 @@ type Config struct { } // New creates a new config -func New(proto, protoset, call, cert, cName string, n, c, qps int, z time.Duration, timeout int, - data, dataPath, metadata, mdPath, output, format, host string, +func New(proto, protoset, call, cert, cName string, n, c, qps int, z time.Duration, x time.Duration, + timeout int, data, dataPath, metadata, mdPath, output, format, host string, dialTimout, keepaliveTime, cpus int, importPaths []string) (*Config, error) { cfg := &Config{ @@ -52,6 +54,7 @@ func New(proto, protoset, call, cert, cName string, n, c, qps int, z time.Durati C: c, QPS: qps, Z: z, + X: x, Timeout: timeout, DataPath: dataPath, MetadataPath: mdPath, @@ -174,6 +177,7 @@ func (c *Config) UnmarshalJSON(data []byte) error { type Alias Config aux := &struct { Z string `json:"z"` + X string `json:"x"` *Alias }{ Alias: (*Alias)(c), @@ -199,6 +203,7 @@ func (c Config) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { *Alias Z string `json:"z"` + X string `json:"x"` }{ Alias: (*Alias)(&c), Z: c.Z.String(), @@ -263,6 +268,14 @@ func (c *Config) initMetadata() error { return nil } +func (c *Config) initDurations() { + if c.X > 0 { + c.Z = c.X + } else if c.Z > 0 { + c.N = math.MaxInt32 + } +} + func (c *Config) init() error { err := c.initData() if err != nil { @@ -274,6 +287,8 @@ func (c *Config) init() error { return err } + c.initDurations() + c.Default() err = c.Validate() diff --git a/config/config_test.go b/config/config_test.go index 3ef39b5a..f9e85369 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -3,6 +3,7 @@ package config import ( "encoding/json" "io/ioutil" + "math" "os" "runtime" "testing" @@ -11,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" ) -const expected = `{"proto":"asdf","protoset":"","call":"","cert":"","cName":"","n":0,"c":0,"q":0,"t":0,"D":"","M":"","o":"","O":"oval","host":"","T":0,"L":0,"cpus":0,"z":"4h30m0s"}` +const expected = `{"proto":"asdf","protoset":"","call":"","cert":"","cName":"","n":0,"c":0,"q":0,"t":0,"D":"","M":"","o":"","O":"oval","host":"","T":0,"L":0,"cpus":0,"z":"4h30m0s","x":""}` func TestConfig_MarshalJSON(t *testing.T) { z, _ := time.ParseDuration("4h30m") @@ -418,3 +419,31 @@ func TestConfig_initData(t *testing.T) { assert.Equal(t, c.Data, data) }) } + +func TestConfig_initDurations(t *testing.T) { + t.Run("with Z specified should set N to max int", func(t *testing.T) { + dur, _ := time.ParseDuration("4h30m") + c := &Config{N: 500, Z: dur} + c.initDurations() + assert.Equal(t, c.N, math.MaxInt32) + }) + + t.Run("with X specified should set Z to X and keep N", func(t *testing.T) { + dur, _ := time.ParseDuration("4h30m") + c := &Config{N: 500, X: dur} + c.initDurations() + assert.Equal(t, c.N, 500) + assert.Equal(t, c.X, dur) + assert.Equal(t, c.Z, dur) + }) + + t.Run("with X and Z specified should set Z to X and keep N", func(t *testing.T) { + dur, _ := time.ParseDuration("4m") + dur2, _ := time.ParseDuration("5m") + c := &Config{N: 500, X: dur, Z: dur2} + c.initDurations() + assert.Equal(t, c.N, 500) + assert.Equal(t, c.X, dur) + assert.Equal(t, c.Z, dur) + }) +} diff --git a/testdata/localhost.crt b/testdata/localhost.crt index f339bf96..478d2248 100644 --- a/testdata/localhost.crt +++ b/testdata/localhost.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIJAOgYWLSklwI4MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV -BAMMCWxvY2FsaG9zdDAeFw0xODA1MTQxMjEwMThaFw0xOTA1MTQxMjEwMThaMBQx +MIIC5TCCAc2gAwIBAgIJAJFwlruqLNgaMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAeFw0xODA2MDExNjA1NDNaFw0xODA3MDExNjA1NDNaMBQx EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAMRmo16RCgaqwwkR4Aq9XvKcphMPynXepPspYxt/Yt+d1mPLf1JuoZITD9Qg -Rm9FMqyt06qAAuMfkRuaL6C9GSDWz3cHAQgZHwODieYc6BMZh1Bq+3XI0cYamBYk -KRtfgrJVOYNJFQGvcbp0A8N5SXty8C05staUhIqErqwYiOxEd7gCTnHhWcczQAjJ -kRNhoxOnih7xQUbFmh0rIgmANA6UDvugWYwPKuV+hZtM80gYUz3hGGh5s1NWttNl -UtoTgdOrwUDmGJxi6CYFeikwvxA2MbSe94g3JpHEC01y8PAANyOtfUtdI5gHmzFP -ZEZQjq657phbJfa6aR6TBzBbQ8kCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo +ggEBALQ1gPZBLD2D4HBveN4eRzal1r8lX4AQSq9h4ofcMo/0sqz7yEQ3zH41Ff+U +KyeBSpXQ6eHtQNiJAATFNPzmHtCbS/YsE18+Msab+Qz0Bgk3pCM97k7japl6Hzag +83C/c2U1Wr3i5otCUQhk+pY2zWjh07gRZWmkp10Ijapxf7mQwC3u2vguzfXEE9co +BS2wyRiJxbwN3DIhW7fTZfoOgfnEGktrTF+hlO8YPNfodZum0jwrlv0hAwYfDiIJ +yQmNMbBLAcZIeH/ZKXEKQkFFKYfxYVMM9Hf4B2XOJ8z7M5o0R+l059RHqric6/c1 +9XPvfDvWSIijI5HgymNAUZmFT+ECAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B -AQsFAAOCAQEAi06brp5sUGSN7EIz8isZ2wRrBXcMIrKOmzbTSNYNBb4B57/97RFY -Z4OA0WdCJHUhWJ89owPtikpVnS9NxJLdiZQrpsz8O6wWPS3+lbc5mVyfWLHMQhIB -V3MMhsI3qWpSXoN/xpjdzYsP4EzHbK5G1y5XX64TvfArogtCUIl+bIUt2N1jyH5+ -IcAAmppW85HMpyMflYNUMKTmzOyOg/ZCJDbq/24QLzdjQPFoFyww+1PI9R+hNduk -rBmbUEsDlUlamwICW+o2hbm97fDxE9AyQOUSu2/+xu1m2rMXzwtzEy56qx0COuZv -peEgi2sajoxeie3HuziU4tUbRYqQWeriHA== +AQsFAAOCAQEAK3MQsX8AN9x1FeOV79Qitk9Hzy0UoGDGcfn/so/2cAbU1mY1Uk6h +W9iCLiBKrKkoO8Ys6hR5Rx5f809pbe7hKmyQ4C0WdGxwUydAPloKj4kvf8oWcPRd +SYxuaeD7I/tGuet7A5krneUKJi2bZtB/8OiDg64PRHNbK3wU25yB9t14aQbeXEzF +qDlId9HZVZLVOb0G/XhcSX5kHiVVrk97x3hXsMh8iAt7zjbn2y8QitKsTpGpfsZ2 +j2a8OoV/shKt20Ea7zGMc/U/UDp3auKnD1RMA1Z11sht5cW+l8YTJ7UVLfZEdlnP +XQSacAbjHwZ/YxEdSCiKTc+8wHGTb28aeQ== -----END CERTIFICATE----- diff --git a/testdata/localhost.key b/testdata/localhost.key index 2d9e0eb8..898e7cd7 100644 --- a/testdata/localhost.key +++ b/testdata/localhost.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEZqNekQoGqsMJ -EeAKvV7ynKYTD8p13qT7KWMbf2LfndZjy39SbqGSEw/UIEZvRTKsrdOqgALjH5Eb -mi+gvRkg1s93BwEIGR8Dg4nmHOgTGYdQavt1yNHGGpgWJCkbX4KyVTmDSRUBr3G6 -dAPDeUl7cvAtObLWlISKhK6sGIjsRHe4Ak5x4VnHM0AIyZETYaMTp4oe8UFGxZod -KyIJgDQOlA77oFmMDyrlfoWbTPNIGFM94RhoebNTVrbTZVLaE4HTq8FA5hicYugm -BXopML8QNjG0nveINyaRxAtNcvDwADcjrX1LXSOYB5sxT2RGUI6uue6YWyX2umke -kwcwW0PJAgMBAAECggEAZUCw+uD1dUh18mgXxBGrMJLX/73FWA0nqyDEKnn7BGQA -EkToaBwHCiLvpyHYjibzoBihpiYG1wcALWXJJio3GToFjUy8GGuzFIGtB0hh0O75 -VtlAuJGGrIYrYEbWNnmADOZpFykHPm4vyLtk8VLHMnCoJ/i2HXBGAI+06Z5ggMVI -VkDsz/RwfzziVnIuu/V939FLXotmdnWVIYf/8ZvZiE0pUBpNAMPUCMxlu5YS/ylV -ILG1hi8k4zklufSXX8sVVG9HOM+lzcRWhG91hMcfZWTdvZ6yxOTGYMqc5ibFtLJK -Hv0/UiarUM9/eAaVTRnIXZxVvqMyAKu8QGs6pyehLQKBgQDmU9tW+ljB6V1Got6W -9ru1A6i8tmoo3s+uXO7BAFAAPAECq1LewiOo1VPDX5xAIJkDUP00BvianKhFl4yJ -xuPZTi8YZkCb2N2sec6NpzYglUhQQuQxS8fhH864RxRqZhf8rPY8l8ZdurOTbOM3 -XgXA9W9OVaLynKrlW8pqyML2ewKBgQDaSrjjp4A5lRJ6kuXaibkjeiVnuGHW+xaO -wF8KJ6BNINDJlQUyBwlNRyJOdWWvLqW7fIyPMeDn1wbfWQfR+ZC1p+OSREjFopFJ -J1i5g3d+BkYLT3avgi7rNTMKU5Zzmbw7FyspVsej5r9qUsbMzA1zOPq1waXaJIRM -Nq76UyKdiwKBgQCKCowUrunvHdvnb8mUFMAfFthUccdiQ1eZGt2FEpjf6xZ38RIz -q4sPrvsKxwywalkKYcm/GsZ4c5duTgvOr0LzhCY5q17hiLIiosYmo6aPFKlIYS6+ -VLqwtA2C6CbWNeX+a/MQEa6zkif6HXJ4RoOQSAiznCOS4E6UM9U29qfSbQKBgEK/ -5pl2drck5mmk0bRpuLsodpeowgJC9TrhiC5Kv7HV/wIlF1mc3TNMNSlYrKdM1FDo -XPLMhcFe9zMEvmdusNlbZTMsvjPw6gw8g9z2Xmui73g17EzuufoiYmEd/juLHwvS -odgaOSHdRVr1xOSK4PIC0mcRt+1kjS/g6NCS61rRAoGAO9Eku+4GI7AH36Sllvaq -xmBFKp/ivUYi7+xU/cX1W54y7vbz1BmM8u5k3o+tdudcnT85/VQvklcRFfcxkOc9 -qyCwsSd9TpwVvvCt3yd+L6n/FR2ha/I9wRKdphcBfOSpDOJeUZGI7s8bXiFEa2rf -CLm8Ltm3f3Vy+2FFoa1ejUc= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0NYD2QSw9g+Bw +b3jeHkc2pda/JV+AEEqvYeKH3DKP9LKs+8hEN8x+NRX/lCsngUqV0Onh7UDYiQAE +xTT85h7Qm0v2LBNfPjLGm/kM9AYJN6QjPe5O42qZeh82oPNwv3NlNVq94uaLQlEI +ZPqWNs1o4dO4EWVppKddCI2qcX+5kMAt7tr4Ls31xBPXKAUtsMkYicW8DdwyIVu3 +02X6DoH5xBpLa0xfoZTvGDzX6HWbptI8K5b9IQMGHw4iCckJjTGwSwHGSHh/2Slx +CkJBRSmH8WFTDPR3+AdlzifM+zOaNEfpdOfUR6q4nOv3NfVz73w71kiIoyOR4Mpj +QFGZhU/hAgMBAAECggEBAJFEqCbatq0IB/7a/VYglkuJOClyGSAFAg+LGq9mZCQD +n50ugmvrhx8d8BPM/1SjNtq6RC9pr+Jd3fP6fRJ49tI2ve897IfUfd34kbVNaSg5 +AEmgfOB/FsmN1meVK2jyDDXD4tg7dpk/5k6cCBzbJI6trJwu+c9FedzXLkv9nnaY +zNKkVfRFFgS9f0e48ASDSDERYzbPEsO6OXkZHZIFfXcE0I297LtwzeYQN0ScGQ98 +3CC/lAipClpMsENfhEH5SIbLT6I9IXSzT+yDiA+Q6PApzuXQd0d+Y3ADns7rn8Ie +QTGNRMOhFKSqciOdW/fL+gHlyoqcWU5XCP2wfTVnrqECgYEA26HzsdHgRKnBe4Cf +GwEw6t+nA2Mf04AXpfJDVy5UEMupiPOZjZi/jPO539BKl1sks/nYT2oFfL6f+1PP +vH1G/NMTJVRumWrmY+tu/VzdTd7cQTWBvbbfvRlQ7Jc84przUEyFRdmXhydgoHf1 +la/4D+IebZAZTeSwK2jdePIWZiUCgYEA0gxqnBPoR8EfxqXKYb/waV7b5XBwnmo9 +IIu9mEEHU7S1CEie67+T69Lx6NM6Sjx8mI679oYWMHbuWR3pOVgn4SYeQRLIprKd +ceUlyVIbvSWEbUBoNnQ7xp5x2/WpT8vtf30AHcsEOIMFxsqkzwmKshdBTqfpK4Up +m42wborvoA0CgYBYKJ+q5rWAmishqbUzn7zE6lUdlPI3cRkM8Tt6iQwRWc6JPE6M +eZ2ZtFMNtYvbSShoXYcoCUR+l/2bYj7mR9rwrMDooQVr627i+KOqa1YhZa0/N30G +a5tPShQjg2lbBBtaRfzQ1tBt3a55eu1G0kVeCsNv8wFVNNBJ/GO5omK/SQKBgCIS +n4yX8hsJqeToae73WsFNAPC0D6Cy7R2FbYjwK4cZjjA8z4LAffdILbOt6Au4yiFZ +LgZsc9cCw+Ey5+1EbpuoOkomCOR5nu6l1D5XEmbZWiT6yKzkp/mtJB0hOYjXNLx0 +g3tRvmqIXnyDzL5E9vmyqgZfWISVwk0Ya+FSqlJVAoGBAKY925otoT53TlFyT/6l +rZVeAfne5OR1HbcT+wsm4QMCKoewZaT9r8RCHMvQfnucJggbLxdY0/+WpN7v9nlg +QHVuJ9g2jJ7mHXXq31R1o6G/c0mmNKXqPmsPBWbkNF2MIfJmKh2FmsBREdt9xZ4V +uRge7upZZNUDy1HbZhAX8+du -----END PRIVATE KEY-----