diff --git a/cmd/grpcannon/main.go b/cmd/grpcannon/main.go index 25dd5391..3aeadd50 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. @@ -132,7 +136,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 27eff570..478d2248 100644 --- a/testdata/localhost.crt +++ b/testdata/localhost.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIJALLvqFlCiW3VMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV -BAMMCWxvY2FsaG9zdDAeFw0xODA0MDcxNjU0MjRaFw0xODA1MDcxNjU0MjRaMBQx +MIIC5TCCAc2gAwIBAgIJAJFwlruqLNgaMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAeFw0xODA2MDExNjA1NDNaFw0xODA3MDExNjA1NDNaMBQx EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBANzmciFhitqzmsHLHKCx/yMHFYOAXHBFnWras+NcW/5iDym1Oe1QgXn0y1cX -1b9cINcL5xHiNjI3iFW2/FPQ8TZ2OpFx3MA/HW0raOyZqofubfSiyQXJV2pi+5ps -jP/9/ogPlXuWjtmAsn923XhexKOLxDk3n5khgD74txrcOtX8VGPGnMHLDtUWCdiZ -wSKocWNqU2+rMw3fivuyzPKVx5uMB3FDjqIHTTyrLRSR8WtRZQaI+XsIXiYC31tV -nEnve2LoPRboNgdVDb7rXp/x2SUOQHN2menLy3P6kkUiAG787oxdxl2v0dcgPGWD -TWvrwbE2nckZ+wQlruVkQ5JQWH8CAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo +ggEBALQ1gPZBLD2D4HBveN4eRzal1r8lX4AQSq9h4ofcMo/0sqz7yEQ3zH41Ff+U +KyeBSpXQ6eHtQNiJAATFNPzmHtCbS/YsE18+Msab+Qz0Bgk3pCM97k7japl6Hzag +83C/c2U1Wr3i5otCUQhk+pY2zWjh07gRZWmkp10Ijapxf7mQwC3u2vguzfXEE9co +BS2wyRiJxbwN3DIhW7fTZfoOgfnEGktrTF+hlO8YPNfodZum0jwrlv0hAwYfDiIJ +yQmNMbBLAcZIeH/ZKXEKQkFFKYfxYVMM9Hf4B2XOJ8z7M5o0R+l059RHqric6/c1 +9XPvfDvWSIijI5HgymNAUZmFT+ECAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B -AQsFAAOCAQEAO+9sIEkbZl5ssOgc027hYhhsUe+0FxQp5GxOshZMFvLlgDzJxMF2 -UwLgNjJHaK8kkEtGSQy8Qg02vF+iuZMYGknGHyjCSOyriDhsynh7085cRPq91d+9 -Rj2egomZYCQlOaWyqB7jA6pZM5JHBQOGPJttuASFZC8IdhNrI25Ki8JBibpT3DqK -BJP4PccK8gGT5yxtv7fYf3Tp4Spsiqk0yyRawAIKXCbIpSTY7MrjYJ9iqzTT7WiY -NXMRASmS7yTP4NK8Um1X6GP4+gAuh5UeNnYAGFCqqYznxrohoNbqEnp3E4Oqy/EQ -6qe8HePlE+oho7TecaZRvuLXcHMCVatJMA== +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 e024c723..898e7cd7 100644 --- a/testdata/localhost.key +++ b/testdata/localhost.key @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEA3OZyIWGK2rOawcscoLH/IwcVg4BccEWdatqz41xb/mIPKbU5 -7VCBefTLVxfVv1wg1wvnEeI2MjeIVbb8U9DxNnY6kXHcwD8dbSto7Jmqh+5t9KLJ -BclXamL7mmyM//3+iA+Ve5aO2YCyf3bdeF7Eo4vEOTefmSGAPvi3Gtw61fxUY8ac -wcsO1RYJ2JnBIqhxY2pTb6szDd+K+7LM8pXHm4wHcUOOogdNPKstFJHxa1FlBoj5 -ewheJgLfW1WcSe97Yug9Fug2B1UNvuten/HZJQ5Ac3aZ6cvLc/qSRSIAbvzujF3G -Xa/R1yA8ZYNNa+vBsTadyRn7BCWu5WRDklBYfwIDAQABAoIBAQDMdjBlXVecnmk7 -vrg8tQQmc8Qh94mYEZdm9A9U/oPXrQPD4w4+7ikprL8ZWeJqQOfUpBu4ndz0FhqG -29wp6FebxUronK9q8gBWr7tqY8FIGBSGPrY6OOZEfmHLyXWo7HvPjD0cK3sFLu4I -tQjBBVaU2iVBoI6EulFt99/jaLy8mhyqF6vvXKmDQ3/h4SavRK2NXWg8JxEL5UVk -53qLjy8e5bosbld9X6zMWAVpJnrMm6L20mPnx7Cd4aDwuRmW1HbeO6pmOWTbJYB/ -EPNaXZ4fuVJ8Ge6s33+iYb9ig3PdDqXkktN/Mx9w6APOQy1nzTcQv5SGl8PE6DFy -vWMpVzahAoGBAPyvoyBy9Oozfrg1NEOB4CC2FauF/cVMBBffurzJbL9f/TCGm9B/ -4vKzBgVzFdWX0fig9qUtopqGkS5qNOuCYV7D5iiiS6t9+C6ZeO4AtEyDyH08GBPe -Li1by2wP7jM2kCiklMl8thmILRwM4IB/x7v6jh7flkLF+vwnCr6bcnQFAoGBAN/M -F1+UowYYBhQeQHfnVK1Pre7Bc/pLtuFIPn4tnAw91VR33Mh3OcQ2Zs5TU4s+lJO8 -ZtDGA4g2SHS3sKRJsuNmbeViJQLHCTG1b4a0ikV0QNdDzwpdDqaCmJSTFRXKIYFW -kmlL+RE8vMiSir8Z6S4VouLJqK3XYPGYjt9EGqWzAoGBAOKrF3UTShoQ6XqK14A7 -L/eH/zZnMvbaMs3Lt3KEaZXeoHv4NCu7nLTD3QHkc9CvqP4UPkx7/GILlo6BXUlq -IrhkmMEYnTKQBKKgr3cokJQWnzGgR6UC6H9t2bPtMmskZfrfcEyyH5QVsQl5j6YV -efFpWDXfsaXifTvWNfA391qVAoGBAKYe8c6iH2zbkk+GsSYP0hwfxCUw9iz53NNW -9ARnSKkRkPP1US6AyaFrHF7VHXODzXfoZo1cHq0SVjBFVdptVltT4gleE8j/A0Uh -v5pHE0hA5gykKeAweTqCQE4w63rUIpDGOUHuAgCYjC16EYGO8zahGtqrBAmekThk -nND/1aPfAoGAMMCkYRHRwEoJBa4LoRg2kJw76s6MGeVQ1FhC5R1S1HQMm/ODP2ul -jlk+ZXM+r/rnQXCyVG8i/mAH44A1fiL/vDUiHDwOjQYLNz/dVH3fHbWA/sCf68tm -8Tuv6mGqQUSW13H9jIueY8RwKgIFPcGVCY9ThtXsf8WpQROPmiZSwbg= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +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-----