Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 24 additions & 22 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ func init() {
}

type RunConfig struct {
Target string
ParsedTarget *url.URL
Requests int
Concurrency int
Timeout time.Duration
Duration time.Duration
Method string
Body string
BodyFile string
Headers []string
Verbose bool
DisableRedirects bool
Target string
ParsedTarget *url.URL
Requests int
Concurrency int
Timeout time.Duration
Duration time.Duration
Method string
Body string
BodyFile string
Headers []string
Verbose bool
DisableRedirects bool
DisableKeepAlives bool
}

var validMethods = map[string]bool{
Expand Down Expand Up @@ -100,15 +101,16 @@ func (c *RunConfig) Validate() error {

func (c *RunConfig) ToHTTPConfig() httpclient.Config {
return httpclient.Config{
Target: c.Target,
Requests: c.Requests,
Concurrency: c.Concurrency,
Timeout: c.Timeout,
Duration: c.Duration,
Method: c.Method,
Body: c.Body,
Headers: c.Headers,
Verbose: c.Verbose,
DisableRedirects: c.DisableRedirects,
Target: c.Target,
Requests: c.Requests,
Concurrency: c.Concurrency,
Timeout: c.Timeout,
Duration: c.Duration,
Method: c.Method,
Body: c.Body,
Headers: c.Headers,
Verbose: c.Verbose,
DisableRedirects: c.DisableRedirects,
DisableKeepAlives: c.DisableKeepAlives,
}
}
27 changes: 16 additions & 11 deletions cmd/configfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ import (
)

type fileConfig struct {
Target *string `json:"target" yaml:"target"`
Requests *int `json:"requests" yaml:"requests"`
Concurrency *int `json:"concurrency" yaml:"concurrency"`
Timeout *string `json:"timeout" yaml:"timeout"`
Duration *string `json:"duration" yaml:"duration"`
Method *string `json:"method" yaml:"method"`
Body *string `json:"body" yaml:"body"`
BodyFile *string `json:"body_file" yaml:"body_file"`
Headers []string `json:"headers" yaml:"headers"`
Verbose *bool `json:"verbose" yaml:"verbose"`
DisableRedirects *bool `json:"disable_redirects" yaml:"disable_redirects"`
Target *string `json:"target" yaml:"target"`
Requests *int `json:"requests" yaml:"requests"`
Concurrency *int `json:"concurrency" yaml:"concurrency"`
Timeout *string `json:"timeout" yaml:"timeout"`
Duration *string `json:"duration" yaml:"duration"`
Method *string `json:"method" yaml:"method"`
Body *string `json:"body" yaml:"body"`
BodyFile *string `json:"body_file" yaml:"body_file"`
Headers []string `json:"headers" yaml:"headers"`
Verbose *bool `json:"verbose" yaml:"verbose"`
DisableRedirects *bool `json:"disable_redirects" yaml:"disable_redirects"`
DisableKeepAlives *bool `json:"disable_keepalive" yaml:"disable_keepalive"`
}

func loadConfig(path string) (*fileConfig, error) {
Expand Down Expand Up @@ -135,5 +136,9 @@ func mergeConfig(file *fileConfig, cli RunConfig, changed map[string]bool) (RunC
merged.DisableRedirects = *file.DisableRedirects
}

if file.DisableKeepAlives != nil && !changed["disable-keepalive"] {
merged.DisableKeepAlives = *file.DisableKeepAlives
}

return merged, nil
}
25 changes: 14 additions & 11 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Latency Percentiles:
headers, _ := f.GetStringArray("header")
verbose, _ := f.GetBool("verbose")
disableRedirects, _ := f.GetBool("disable-redirects")
disableKeepAlives, _ := f.GetBool("disable-keepalive")
outputFormat, _ := f.GetString("output")

if outputFormat != "text" && outputFormat != "json" {
Expand All @@ -70,17 +71,18 @@ Latency Percentiles:
}

cliConfig := RunConfig{
Target: target,
Requests: requests,
Concurrency: concurrency,
Timeout: timeout,
Duration: duration,
Method: strings.ToUpper(method),
Body: body,
BodyFile: bodyFile,
Headers: headers,
Verbose: verbose,
DisableRedirects: disableRedirects,
Target: target,
Requests: requests,
Concurrency: concurrency,
Timeout: timeout,
Duration: duration,
Method: strings.ToUpper(method),
Body: body,
BodyFile: bodyFile,
Headers: headers,
Verbose: verbose,
DisableRedirects: disableRedirects,
DisableKeepAlives: disableKeepAlives,
}

changed := make(map[string]bool)
Expand Down Expand Up @@ -145,6 +147,7 @@ Latency Percentiles:
cmd.Flags().StringP("config", "f", "", "Path to configuration file (JSON/YAML)")
cmd.Flags().BoolP("verbose", "v", false, "Enable verbose output")
cmd.Flags().Bool("disable-redirects", false, "Do not follow HTTP redirects")
cmd.Flags().Bool("disable-keepalive", false, "Disable HTTP keep-alive, forcing a new connection per request")
cmd.Flags().StringP("output", "o", "text", "Output format (text or json)")

return cmd
Expand Down
1 change: 1 addition & 0 deletions cmd/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestFlagRegistration(t *testing.T) {
{"config", "f", ""},
{"verbose", "v", false},
{"disable-redirects", "", false},
{"disable-keepalive", "", false},
{"output", "o", "text"},
}

Expand Down
30 changes: 16 additions & 14 deletions internal/httpclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import (
"github.com/infraspecdev/goperf/internal/stats"
)

func NewHTTPClient(concurrency int, disableRedirects bool) *http.Client {
func NewHTTPClient(concurrency int, disableRedirects bool, disableKeepAlives bool) *http.Client {
client := &http.Client{
Transport: &http.Transport{
MaxIdleConnsPerHost: concurrency,
DisableCompression: true,
DisableKeepAlives: disableKeepAlives,
},
}
if disableRedirects {
Expand All @@ -32,18 +33,19 @@ func NewHTTPClient(concurrency int, disableRedirects bool) *http.Client {
}

type Config struct {
Target string
Requests int
Concurrency int
Timeout time.Duration
Duration time.Duration
Method string
Body string
Headers []string
Verbose bool
Version string
Stderr io.Writer
DisableRedirects bool
Target string
Requests int
Concurrency int
Timeout time.Duration
Duration time.Duration
Method string
Body string
Headers []string
Verbose bool
Version string
Stderr io.Writer
DisableRedirects bool
DisableKeepAlives bool
}

type HTTPDoer interface {
Expand Down Expand Up @@ -157,7 +159,7 @@ func recordResult(ctx context.Context, recorder *stats.HistogramRecorder, verbos
}

func Run(ctx context.Context, cfg Config) *stats.HistogramRecorder {
client := NewHTTPClient(cfg.Concurrency, cfg.DisableRedirects)
client := NewHTTPClient(cfg.Concurrency, cfg.DisableRedirects, cfg.DisableKeepAlives)
recorder := stats.NewHistogramRecorder(cfg.Timeout)

var verboseWriter io.Writer
Expand Down
7 changes: 5 additions & 2 deletions internal/httpclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
const testTimeout = 2 * time.Second

func TestNewHTTPClient(t *testing.T) {
client := NewHTTPClient(50, false)
client := NewHTTPClient(50, false, true)

tr, ok := client.Transport.(*http.Transport)
if !ok {
Expand All @@ -30,6 +30,9 @@ func TestNewHTTPClient(t *testing.T) {
if !tr.DisableCompression {
t.Error("expected DisableCompression=true")
}
if !tr.DisableKeepAlives {
t.Error("expected DisableKeepAlives=true")
}
}

func TestMakeRequestSuccess(t *testing.T) {
Expand Down Expand Up @@ -811,7 +814,7 @@ func TestNewHTTPClient_Redirects(t *testing.T) {
}))
defer server.Close()

client := NewHTTPClient(1, tt.disableRedirects)
client := NewHTTPClient(1, tt.disableRedirects, false)
cfg := Config{
Target: server.URL,
Timeout: testTimeout,
Expand Down