diff options
| author | Shulhan <ms@kilabit.info> | 2021-03-21 15:38:14 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2021-03-21 15:45:33 +0700 |
| commit | 04ea6f8bb0aea5fcb40c2720d45aa6bc0570a967 (patch) | |
| tree | 56471c7d42894c924e296d02c92608072ec0c145 | |
| parent | 524962c1c8e26cec26fa356719ed990a4a4c82f1 (diff) | |
| download | gorankusu-04ea6f8bb0aea5fcb40c2720d45aa6bc0570a967.tar.xz | |
all: rename loadTestingResult to AttackResult
| -rw-r--r-- | attack_result.go | 202 | ||||
| -rw-r--r-- | environment.go | 8 | ||||
| -rw-r--r-- | errors.go | 4 | ||||
| -rw-r--r-- | http_target.go | 10 | ||||
| -rw-r--r-- | load_testing_result.go | 203 | ||||
| -rw-r--r-- | run_request.go | 2 | ||||
| -rw-r--r-- | trunks.go | 2 |
7 files changed, 215 insertions, 216 deletions
diff --git a/attack_result.go b/attack_result.go new file mode 100644 index 0000000..972ef31 --- /dev/null +++ b/attack_result.go @@ -0,0 +1,202 @@ +// Copyright 2021, Shulhan <ms@kilabit.info>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package trunks + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" + + vegeta "github.com/tsenart/vegeta/v12/lib" + + libbytes "github.com/shuLhan/share/lib/bytes" + "github.com/shuLhan/share/lib/mlog" +) + +const ( + histogramBuckets = "[0,1ms,5ms,10ms,20ms,30ms,40ms,50ms,100ms,500ms,1s,5s,10s,20s,30s,40s]" + outputSuffixDate = "20060102_150405" +) + +// +// AttackResult represent the output from load testing. +// +type AttackResult struct { + mtx sync.Mutex + + TargetID string // TargetID the ID of HTTP target which own the result. + Name string // Name of output file without path. + IsRunning bool + TextReport []byte // TextReport the result reported as text. + HistReport []byte // HistReport the result reported as histogram text. + + fullpath string + fout *os.File + encoder vegeta.Encoder + metrics *vegeta.Metrics + hist *vegeta.Histogram +} + +// +// newAttackResult create new load testing result from request. +// +func newAttackResult(env *Environment, rr *RunRequest) ( + ar *AttackResult, err error, +) { + ar = &AttackResult{ + TargetID: rr.HttpTarget.ID, + metrics: &vegeta.Metrics{}, + hist: &vegeta.Histogram{}, + } + + ar.Name = fmt.Sprintf("%s.%s.%dx%s.%s.bin", ar.TargetID, + time.Now().Format(outputSuffixDate), + rr.Target.Opts.RatePerSecond, rr.Target.Opts.Duration, + env.ResultsSuffix) + + err = ar.hist.Buckets.UnmarshalText([]byte(histogramBuckets)) + if err != nil { + return nil, fmt.Errorf("newAttackResult: %w", err) + } + + ar.fullpath = filepath.Join(env.ResultsDir, ar.Name) + + ar.fout, err = os.Create(ar.fullpath) + if err != nil { + return nil, fmt.Errorf("newAttackResult: %w", err) + } + + ar.encoder = vegeta.NewEncoder(ar.fout) + + return ar, nil +} + +func (ar *AttackResult) add(res *vegeta.Result) (err error) { + err = ar.encoder.Encode(res) + if err != nil { + return fmt.Errorf("AttackResult.add: %w", err) + } + ar.metrics.Add(res) + ar.hist.Add(res) + + return nil +} + +func (ar *AttackResult) cancel() { + ar.mtx.Lock() + defer ar.mtx.Unlock() + + ar.IsRunning = false + + if ar.metrics != nil { + ar.metrics.Close() + } + + if ar.fout != nil { + err := ar.fout.Close() + if err != nil { + mlog.Errf("AttackResult.cancel %s: %s\n", ar.TargetID, err) + } + ar.fout = nil + + if len(ar.fullpath) > 0 { + err = os.Remove(ar.fullpath) + if err != nil { + mlog.Errf("AttackResult.cancel %s: %s\n", ar.TargetID, err) + } + } + } + + ar.metrics = nil + ar.hist = nil +} + +func (ar *AttackResult) finish() (err error) { + var buf bytes.Buffer + + ar.mtx.Lock() + defer ar.mtx.Unlock() + + ar.IsRunning = false + ar.metrics.Close() + + if ar.fout != nil { + err = ar.fout.Close() + if err != nil { + return fmt.Errorf("%s: %w", ar.TargetID, err) + } + ar.fout = nil + } + + text := vegeta.NewTextReporter(ar.metrics) + err = text.Report(&buf) + if err != nil { + return err + } + + ar.TextReport = libbytes.Copy(buf.Bytes()) + + buf.Reset() + histWriter := vegeta.NewHistogramReporter(ar.hist) + err = histWriter.Report(&buf) + if err != nil { + return err + } + + ar.HistReport = libbytes.Copy(buf.Bytes()) + + ar.metrics = nil + ar.hist = nil + + return nil +} + +func (ar *AttackResult) init(path string) (err error) { + ar.fullpath = filepath.Join(path, ar.Name) + + result, err := ioutil.ReadFile(ar.fullpath) + if err != nil { + return err + } + + dec := vegeta.NewDecoder(bytes.NewReader(result)) + + ar.metrics = &vegeta.Metrics{} + ar.hist = &vegeta.Histogram{} + + err = ar.hist.Buckets.UnmarshalText([]byte(histogramBuckets)) + if err != nil { + return err + } + + for { + var res vegeta.Result + err = dec.Decode(&res) + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return err + } + ar.metrics.Add(&res) + ar.hist.Add(&res) + } + + return ar.finish() +} + +func (ar *AttackResult) pack() (b []byte, err error) { + ar.mtx.Lock() + b, err = json.Marshal(ar) + ar.mtx.Unlock() + return b, err +} diff --git a/environment.go b/environment.go index 393741f..ced921a 100644 --- a/environment.go +++ b/environment.go @@ -46,7 +46,7 @@ type Environment struct { // AttackRunning will be set to non-nil if there is a load // testing currently running. - AttackRunning *loadTestingResult + AttackRunning *AttackResult mtx sync.Mutex } @@ -71,11 +71,11 @@ func (env *Environment) init() (err error) { return nil } -func (env *Environment) getRunningAttack() (ltr *loadTestingResult) { +func (env *Environment) getRunningAttack() (ar *AttackResult) { env.mtx.Lock() - ltr = env.AttackRunning + ar = env.AttackRunning env.mtx.Unlock() - return ltr + return ar } func (env *Environment) isAttackRunning() (yorn bool) { @@ -12,14 +12,14 @@ import ( libhttp "github.com/shuLhan/share/lib/http" ) -func errAttackConflict(ltr *loadTestingResult) error { +func errAttackConflict(ar *AttackResult) error { res := &libhttp.EndpointResponse{ E: liberrors.E{ Code: http.StatusConflict, Message: "another attack is already running", Name: "ERR_ATTACK_CONFLICT", }, - Data: ltr, + Data: ar, } return res } diff --git a/http_target.go b/http_target.go index 8bff477..732d4ec 100644 --- a/http_target.go +++ b/http_target.go @@ -49,7 +49,7 @@ type HttpTarget struct { Status string // Results contains list of load testing output. - Results []*loadTestingResult + Results []*AttackResult // AllowAttack if its true the "Attack" button will be showed on user // interface to allow client to run load testing on this HttpTarget. @@ -71,7 +71,7 @@ func (ht *HttpTarget) init() { } } -func (ht *HttpTarget) deleteResult(result *loadTestingResult) { +func (ht *HttpTarget) deleteResult(result *AttackResult) { var x int for ; x < len(ht.Results); x++ { if ht.Results[x].Name == result.Name { @@ -90,17 +90,17 @@ func (ht *HttpTarget) deleteResult(result *loadTestingResult) { } func (ht *HttpTarget) addResult(path, name string) (err error) { - ltr := &loadTestingResult{ + ar := &AttackResult{ TargetID: ht.ID, Name: name, } - err = ltr.init(path) + err = ar.init(path) if err != nil { return fmt.Errorf("HttpTarget.addResult: %s %s: %w", path, name, err) } - ht.Results = append(ht.Results, ltr) + ht.Results = append(ht.Results, ar) return nil } diff --git a/load_testing_result.go b/load_testing_result.go deleted file mode 100644 index 1c0e0cd..0000000 --- a/load_testing_result.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2021, Shulhan <ms@kilabit.info>. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package trunks - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "sync" - "time" - - vegeta "github.com/tsenart/vegeta/v12/lib" - - libbytes "github.com/shuLhan/share/lib/bytes" - "github.com/shuLhan/share/lib/mlog" -) - -const ( - histogramBuckets = "[0,1ms,5ms,10ms,20ms,30ms,40ms,50ms,100ms,500ms,1s,5s,10s,20s,30s,40s]" - outputSuffixDate = "20060102_150405" -) - -// -// loadTestingResult represent the output from load testing. -// -type loadTestingResult struct { - sync.Mutex - - TargetID string // TargetID the ID of HTTP target which own the result. - Name string // Name of output file without path. - IsRunning bool - TextReport []byte // TextReport the result reported as text. - HistReport []byte // HistReport the result reported as histogram text. - - fullpath string - fout *os.File - encoder vegeta.Encoder - metrics *vegeta.Metrics - hist *vegeta.Histogram -} - -// -// newLoadTestingResult create new load testing result from request. -// -func newLoadTestingResult(env *Environment, rr *RunRequest) ( - ltr *loadTestingResult, err error, -) { - ltr = &loadTestingResult{ - TargetID: rr.HttpTarget.ID, - metrics: &vegeta.Metrics{}, - hist: &vegeta.Histogram{}, - } - - ltr.Name = fmt.Sprintf("%s.%s.%dx%s.%s.bin", ltr.TargetID, - time.Now().Format(outputSuffixDate), - rr.Target.Opts.RatePerSecond, rr.Target.Opts.Duration, - env.ResultsSuffix) - - err = ltr.hist.Buckets.UnmarshalText([]byte(histogramBuckets)) - if err != nil { - return nil, fmt.Errorf("newLoadTestingResult: %w", err) - } - - ltr.fullpath = filepath.Join(env.ResultsDir, ltr.Name) - - ltr.fout, err = os.Create(ltr.fullpath) - if err != nil { - return nil, fmt.Errorf("newLoadTestingResult: %w", err) - } - - ltr.encoder = vegeta.NewEncoder(ltr.fout) - - return ltr, nil -} - -func (ltr *loadTestingResult) add(res *vegeta.Result) (err error) { - err = ltr.encoder.Encode(res) - if err != nil { - return fmt.Errorf("loadTestingResult.add: %w", err) - } - - ltr.metrics.Add(res) - ltr.hist.Add(res) - - return nil -} - -func (ltr *loadTestingResult) cancel() { - ltr.Lock() - defer ltr.Unlock() - - ltr.IsRunning = false - - if ltr.metrics != nil { - ltr.metrics.Close() - } - - if ltr.fout != nil { - err := ltr.fout.Close() - if err != nil { - mlog.Errf("loadTestingResult.cancel %s: %s\n", ltr.TargetID, err) - } - ltr.fout = nil - - if len(ltr.fullpath) > 0 { - err = os.Remove(ltr.fullpath) - if err != nil { - mlog.Errf("loadTestingResult.cancel %s: %s\n", ltr.TargetID, err) - } - } - } - - ltr.metrics = nil - ltr.hist = nil -} - -func (ltr *loadTestingResult) finish() (err error) { - var buf bytes.Buffer - - ltr.Lock() - defer ltr.Unlock() - - ltr.IsRunning = false - ltr.metrics.Close() - - if ltr.fout != nil { - err = ltr.fout.Close() - if err != nil { - return fmt.Errorf("%s: %w", ltr.TargetID, err) - } - ltr.fout = nil - } - - text := vegeta.NewTextReporter(ltr.metrics) - err = text.Report(&buf) - if err != nil { - return err - } - - ltr.TextReport = libbytes.Copy(buf.Bytes()) - - buf.Reset() - histWriter := vegeta.NewHistogramReporter(ltr.hist) - err = histWriter.Report(&buf) - if err != nil { - return err - } - - ltr.HistReport = libbytes.Copy(buf.Bytes()) - - ltr.metrics = nil - ltr.hist = nil - - return nil -} - -func (ltr *loadTestingResult) init(path string) (err error) { - ltr.fullpath = filepath.Join(path, ltr.Name) - - result, err := ioutil.ReadFile(ltr.fullpath) - if err != nil { - return err - } - - dec := vegeta.NewDecoder(bytes.NewReader(result)) - - ltr.metrics = &vegeta.Metrics{} - ltr.hist = &vegeta.Histogram{} - - err = ltr.hist.Buckets.UnmarshalText([]byte(histogramBuckets)) - if err != nil { - return err - } - - for { - var res vegeta.Result - err = dec.Decode(&res) - if err != nil { - if errors.Is(err, io.EOF) { - break - } - return err - } - ltr.metrics.Add(&res) - ltr.hist.Add(&res) - } - - return ltr.finish() -} - -func (ltr *loadTestingResult) pack() (b []byte, err error) { - ltr.Lock() - b, err = json.Marshal(ltr) - ltr.Unlock() - return b, err -} diff --git a/run_request.go b/run_request.go index 1f72b96..27fe5fc 100644 --- a/run_request.go +++ b/run_request.go @@ -16,7 +16,7 @@ type RunRequest struct { Locker sync.Mutex Target *Target HttpTarget *HttpTarget - result *loadTestingResult + result *AttackResult } func (rr *RunRequest) String() string { @@ -274,7 +274,7 @@ func (trunks *Trunks) apiTargetAttack(epr *libhttp.EndpointRequest) (resbody []b req.merge(trunks.Env, origTarget, origHttpTarget) - req.result, err = newLoadTestingResult(trunks.Env, req) + req.result, err = newAttackResult(trunks.Env, req) if err != nil { return nil, err } |
