diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..e859b96 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,75 @@ +run: +tests: false +skip-dirs: + - examples + - vendor + +linters: + enable: + - bodyclose + - deadcode + - depguard + - dogsled + - dupl + - errcheck + - exhaustive + - funlen + - gochecknoinits + - goconst + - gocritic + - gocyclo + - gofmt + - goimports + - golint + - gomnd + - goprintffuncname + - gosec + - gosimple + - govet + - ineffassign + - interfacer + - lll + - misspell + - nakedret + - noctx + - nolintlint + - rowserrcheck + - scopelint + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + - whitespace + - asciicheck + - gochecknoglobals + - gocognit + - godot + - godox + - goerr113 + - maligned + - nestif + - prealloc + - testpackage + - wsl + +linters-settings: + # see all options at https://github.com/bombsimon/wsl/blob/master/doc/configuration.md + # Even the default values have been copied here to give us control and fine tunning on them + wsl: + strict-append: false + allow-assign-and-call: true + allow-assign-and-anything: false + allow-multiline-assign: true + force-case-trailing-whitespace: 0 + allow-cuddle-declarations: false + allow-case-trailing-whitespace: false + allow-trailing-comment: false + enforce-err-cuddling: false + +issues: + exclude: + - '^singleCaseSwitch' \ No newline at end of file diff --git a/Makefile b/Makefile index d4b1203..5b9a524 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,12 @@ fmt: vet: go vet $(ALL_PACKAGES) +goimports: + goimports -w $(shell find . -type f -name '*.go' -not -path "./vendor/*") + +gofmts: + gofmt -s -w $(shell find . -type f -name '*.go' -not -path "./vendor/*") + lint: @for p in $(ALL_PACKAGES); do \ echo "==> Linting $$p"; \ diff --git a/bus/bus.go b/bus/bus.go index bc378c6..b9828aa 100644 --- a/bus/bus.go +++ b/bus/bus.go @@ -6,14 +6,14 @@ import ( "sync" ) -//The type of the function's first and only argument -//declares the msg to listen for. +// The type of the function's first and only argument. +// declares the msg to listen for. type HandlerFunc interface{} type Msg interface{} -//It is a simple but powerful publish-subscribe event system. It requires object to -//register themselves with the event bus to receive events. +// It is a simple but powerful publish-subscribe event system. It requires object to +// register themselves with the event bus to receive events. type Bus interface { Dispatch(msg Msg) error AddHandler(handler HandlerFunc) error @@ -34,14 +34,14 @@ func New() Bus { } } -//Dispatch sends an msg to registered handler that were declared -//to accept values of a msg +// Dispatch sends an msg to registered handler that were declared +// to accept values of a msg func (b *InProcBus) Dispatch(msg Msg) error { nameOfMsg := reflect.TypeOf(msg) handler, ok := b.handlers[nameOfMsg.String()] if !ok { - return fmt.Errorf("handler not found for %s", nameOfMsg) + return &HandlerNotFoundError{Name: nameOfMsg.Name()} } params := make([]reflect.Value, 0, 1) @@ -55,8 +55,8 @@ func (b *InProcBus) Dispatch(msg Msg) error { return nil } -//Publish sends an msg to all registered listeners that were declared -//to accept values of a msg +// Publish sends an msg to all registered listeners that were declared +// to accept values of a msg func (b *InProcBus) Publish(msg Msg) error { nameOfMsg := reflect.TypeOf(msg) listeners := b.listeners[nameOfMsg.String()] @@ -74,8 +74,8 @@ func (b *InProcBus) Publish(msg Msg) error { return nil } -//AddHandler registers a handler function that will be called when a matching -//msg is dispatched. +// AddHandler registers a handler function that will be called when a matching +// msg is dispatched. func (b *InProcBus) AddHandler(handler HandlerFunc) error { b.Mutex.Lock() defer b.Mutex.Unlock() @@ -85,15 +85,15 @@ func (b *InProcBus) AddHandler(handler HandlerFunc) error { typeOfMsg := handlerType.In(0) if _, ok := b.handlers[typeOfMsg.String()]; ok { - return fmt.Errorf("handler exists for %s", typeOfMsg) + return &OverwriteHandlerError{Name: typeOfMsg.Name()} } b.handlers[typeOfMsg.String()] = reflect.ValueOf(handler) return nil } -//AddListener registers a listener function that will be called when a matching -//msg is dispatched. +// AddListener registers a listener function that will be called when a matching +// msg is dispatched. func (b *InProcBus) AddEventListener(handler HandlerFunc) { b.Mutex.Lock() defer b.Mutex.Unlock() @@ -109,7 +109,7 @@ func (b *InProcBus) AddEventListener(handler HandlerFunc) { b.listeners[typOfMsg.String()] = append(b.listeners[typOfMsg.String()], reflect.ValueOf(handler)) } -//panic if conditions not met (this is a programming error) +// panic if conditions not met (this is a programming error) func validateHandlerFunc(handlerType reflect.Type) { switch { case handlerType.Kind() != reflect.Func: @@ -121,10 +121,22 @@ func validateHandlerFunc(handlerType reflect.Type) { } } -//BadFuncError is raised via panic() when AddEventListener or AddHandler is called with an -//invalid listener function. +// BadFuncError is raised via panic() when AddEventListener or AddHandler is called with an +// invalid listener function. type BadFuncError string func (bhf BadFuncError) Error() string { return fmt.Sprintf("bad handler func: %s", string(bhf)) } + +type HandlerNotFoundError struct { + Name string +} + +func (e *HandlerNotFoundError) Error() string { return e.Name + ": not found" } + +type OverwriteHandlerError struct { + Name string +} + +func (e *OverwriteHandlerError) Error() string { return e.Name + ": handler exists" } diff --git a/bus/bus_test.go b/bus/bus_test.go index 6ff3bf5..2fb2c52 100644 --- a/bus/bus_test.go +++ b/bus/bus_test.go @@ -3,8 +3,9 @@ package bus_test import ( "errors" "fmt" - "github.com/donutloop/toolkit/bus" "testing" + + "github.com/donutloop/toolkit/bus" ) type msg struct { @@ -15,27 +16,32 @@ type msg struct { func TestHandlerReturnsError(t *testing.T) { b := bus.New() - b.AddHandler(func(m *msg) error { + err := b.AddHandler(func(m *msg) error { return errors.New("handler error") }) + if err != nil { + t.Fatal(err) + } - err := b.Dispatch(new(msg)) + err = b.Dispatch(new(msg)) if err == nil { - t.Fatalf("dispatch msg failed (%s)", err.Error()) + t.Fatalf("dispatch msg failed (%v)", err) } } func TestHandlerReturn(t *testing.T) { b := bus.New() - b.AddHandler(func(m *msg) error { + err := b.AddHandler(func(m *msg) error { m.body = "Hello, world!" return nil }) + if err != nil { + t.Fatal(err) + } msg := new(msg) - err := b.Dispatch(msg) - + err = b.Dispatch(msg) if err != nil { t.Fatalf("dispatch msg failed (%s)", err.Error()) } @@ -80,9 +86,12 @@ func TestAddHandlerBadFunc(t *testing.T) { }() b := bus.New() - b.AddHandler(func(m *msg, s string) error { + err := b.AddHandler(func(m *msg, s string) error { return nil }) + if err != nil { + t.Fatal(err) + } } func TestAddListenerBadFunc(t *testing.T) { @@ -103,13 +112,13 @@ func TestAddListenerBadFunc(t *testing.T) { func BenchmarkHandlerRun(b *testing.B) { for n := 0; n < b.N; n++ { - bus := bus.New() + bs := bus.New() - bus.AddHandler(func(m *msg) error { + bs.AddHandler(func(m *msg) error { return nil }) - if err := bus.Dispatch(new(msg)); err != nil { + if err := bs.Dispatch(new(msg)); err != nil { b.Fatal(err) } } @@ -117,29 +126,29 @@ func BenchmarkHandlerRun(b *testing.B) { func BenchmarkListenerRun(b *testing.B) { for n := 0; n < b.N; n++ { - bus := bus.New() + bs := bus.New() - bus.AddEventListener(func(m *msg) error { + bs.AddEventListener(func(m *msg) error { return nil }) - bus.AddEventListener(func(m *msg) error { + bs.AddEventListener(func(m *msg) error { return nil }) - bus.AddEventListener(func(m *msg) error { + bs.AddEventListener(func(m *msg) error { return nil }) - bus.AddEventListener(func(m *msg) error { + bs.AddEventListener(func(m *msg) error { return nil }) - bus.AddEventListener(func(m *msg) error { + bs.AddEventListener(func(m *msg) error { return nil }) - if err := bus.Publish(new(msg)); err != nil { + if err := bs.Publish(new(msg)); err != nil { b.Fatal(err) } } diff --git a/bus/doc_test.go b/bus/doc_test.go index da13ab6..76686e3 100644 --- a/bus/doc_test.go +++ b/bus/doc_test.go @@ -2,14 +2,15 @@ package bus_test import ( "fmt" + "github.com/donutloop/toolkit/bus" ) -// Creates a bus and adds a listener to a message afterward it publishes a new message -func ExampleBusListener() { +// Creates a bus and adds a listener to a message afterward it publishes a new message. +func ExampleInProcBus_AddEventListener() { type msg struct { - Id int64 + ID int64 body string } @@ -21,29 +22,34 @@ func ExampleBusListener() { }) if err := b.Publish(new(msg)); err != nil { - fmt.Println(fmt.Sprintf("bus: %v", err)) + fmt.Printf("error: (%v) \n", err) } // Output: db insert listener } -// Creates a bus and adds a handler for a message afterward it dispatch a new message -func ExampleBusHandler() { +// Creates a bus and adds a handler for a message afterward it dispatch a new message. +func ExampleInProcBus_AddHandler() { type msg struct { - Id int64 + ID int64 body string } b := bus.New() - b.AddHandler(func(m *msg) error { + err := b.AddHandler(func(m *msg) error { fmt.Println("db insert listener") return nil }) + if err != nil { + fmt.Printf("error: (%v) \n", err) + return + } + if err := b.Dispatch(new(msg)); err != nil { - fmt.Println(fmt.Sprintf("bus: %v", err)) + fmt.Printf("error: (%v) \n", err) } // Output: db insert listener diff --git a/cmd/xcode/main.go b/cmd/xcode/main.go index fe1117c..dc0a30f 100644 --- a/cmd/xcode/main.go +++ b/cmd/xcode/main.go @@ -3,11 +3,12 @@ package main import ( "flag" "fmt" - "github.com/donutloop/toolkit/internal/ast" "io/ioutil" "log" "os" "text/tabwriter" + + "github.com/donutloop/toolkit/internal/ast" ) func main() { diff --git a/concurrent/doc_test.go b/concurrent/doc_test.go index 52f8531..d8f2a15 100644 --- a/concurrent/doc_test.go +++ b/concurrent/doc_test.go @@ -2,11 +2,12 @@ package concurrent_test import ( "fmt" - "github.com/donutloop/toolkit/concurrent" "sync/atomic" + + "github.com/donutloop/toolkit/concurrent" ) -// Run concurrently your func() error +// Run concurrently your func() error. func ExampleRun() { counter := int32(0) @@ -23,7 +24,7 @@ func ExampleRun() { if len(errs) > 0 { for _, err := range errs { - fmt.Println(fmt.Sprintf("error: %v", err)) + fmt.Printf("error: %v \n", err) } } diff --git a/concurrent/runner.go b/concurrent/runner.go index 0752c9a..5ac4a36 100644 --- a/concurrent/runner.go +++ b/concurrent/runner.go @@ -2,11 +2,19 @@ package concurrent import ( "fmt" + "runtime/debug" "sync" ) +type RecoverError struct { + Err interface{} + Stack []byte +} + +func (e *RecoverError) Error() string { return fmt.Sprintf("Do panicked: %v", e.Err) } + // Run executes the provided functions in concurrent and collects any errors they return. -// Be careful about your resource consumption +// Be careful about your resource consumption. func Run(fns ...func() error) []error { wg := sync.WaitGroup{} errc := make(chan error, len(fns)) @@ -16,7 +24,7 @@ func Run(fns ...func() error) []error { defer func() { if v := recover(); v != nil { - errc <- fmt.Errorf("do is panicked (%v)", v) + errc <- &RecoverError{Err: v, Stack: debug.Stack()} } wg.Done() diff --git a/concurrent/runner_test.go b/concurrent/runner_test.go index 71c6750..17f04dd 100644 --- a/concurrent/runner_test.go +++ b/concurrent/runner_test.go @@ -2,9 +2,10 @@ package concurrent_test import ( "errors" - "github.com/donutloop/toolkit/concurrent" "sync/atomic" "testing" + + "github.com/donutloop/toolkit/concurrent" ) func TestRun(t *testing.T) { diff --git a/debugutil/doc_test.go b/debugutil/doc_test.go index c51bd5f..2253af5 100644 --- a/debugutil/doc_test.go +++ b/debugutil/doc_test.go @@ -2,6 +2,7 @@ package debugutil_test import ( "fmt" + "github.com/donutloop/toolkit/debugutil" ) diff --git a/debugutil/http_dump.go b/debugutil/http_dump.go index eb8d81c..aeec318 100644 --- a/debugutil/http_dump.go +++ b/debugutil/http_dump.go @@ -8,12 +8,13 @@ import ( "strings" ) -// PrettyPrintResponse is pretty printing a http response +// PrettyPrintResponse is pretty printing a http response. func PrettySprintResponse(resp *http.Response) (string, error) { dump, err := PrettyDumpResponse(resp, true) if err != nil { return "", err } + return string(dump), nil } @@ -31,21 +32,24 @@ func PrettyDumpResponse(resp *http.Response, body bool) ([]byte, error) { jsonRaw := b[int64(len(b))-resp.ContentLength:] b = b[:int64(len(b))-resp.ContentLength] buffer.Write(b) + if err := json.Indent(buffer, jsonRaw, "", "\t"); err != nil { return nil, err } + return buffer.Bytes(), nil } return b, nil } -// PrettySprintRequest is pretty printing a http request +// PrettySprintRequest is pretty printing a http request. func PrettySprintRequest(resp *http.Request) (string, error) { dump, err := PrettyDumpRequest(resp, true) if err != nil { return "", err } + return string(dump), nil } @@ -63,9 +67,11 @@ func PrettyDumpRequest(req *http.Request, body bool) ([]byte, error) { jsonRaw := b[int64(len(b))-req.ContentLength:] b = b[:int64(len(b))-req.ContentLength] buffer.Write(b) + if err := json.Indent(buffer, jsonRaw, "", "\t"); err != nil { return nil, err } + return buffer.Bytes(), nil } diff --git a/debugutil/http_dump_test.go b/debugutil/http_dump_test.go index c6a7200..15bcc70 100644 --- a/debugutil/http_dump_test.go +++ b/debugutil/http_dump_test.go @@ -3,9 +3,11 @@ package debugutil_test import ( "bufio" "bytes" - "github.com/donutloop/toolkit/debugutil" + "context" "net/http" "testing" + + "github.com/donutloop/toolkit/debugutil" ) func TestPrettyDumpResponse(t *testing.T) { @@ -30,7 +32,8 @@ X-Xss-Protection: 1; mode=block {"data": {"partner": {"verified_data": {"people": [{"identity_document_checks": [{"status": "passed", "file_links": [{"file_type": "photo", "link": "https://static.iwoca.com/assets/iwoca.4c17fef7de62.png"}], "check_id": "REFERENCE_0001", "datetime": "2017-06-12T14:05:51.666Z", "identity_document_type": "passport", "document_issuing_country": "gb", "provider_name": "test"}], "uid": "6cf7319e-f9ec-4038-ba4f-3561a6097484"}]}}, "state_key": "8e4db383-2ead-4a47-87df-220432714c47", "schema_version": "v1", "application": {"company": {"last_12_months_turnover": {"amount": 700000, "datetime": "2016-10-12T14:05:51.666Z"}, "type": "gmbh", "company_number": "01111112", "bank_details": {"iban": "DE89370400440532013000"}}, "requested_products": {"credit_facility": {"approval": {"amount": 15000}}}, "people": [{"residential_addresses": [{"town": "Ely", "uid": "cf9aa203-4e0c-4d7f-b42b-90c7b3d193d3", "house_number": "286", "date_from": "2014-02-03", "street_line_1": "Idverifier St", "postcode": "CB62AG"}], "last_name": "Norton", "uid": "6cf7319e-f9ec-4038-ba4f-3561a6097484", "roles": ["applicant", "shareholder", "guarantor", "director"], "title": "herr", "first_name": "Ervin", "privacy_policy": {"agreed": true, "datetime": "2016-10-12T14:05:51.666Z"}, "date_of_birth": "1980-01-01"}]}}} `) reader := bufio.NewReader(bytes.NewReader(r)) - req, err := http.NewRequest(http.MethodGet, "/api/resource", nil) + + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "/api/resource", nil) if err != nil { t.Fatal(err) } @@ -40,6 +43,8 @@ X-Xss-Protection: 1; mode=block t.Fatal(err) } + defer resp.Body.Close() + s, err := debugutil.PrettySprintResponse(resp) if err != nil { t.Fatal(err) @@ -52,7 +57,7 @@ func TestPrettyDumpRequest(t *testing.T) { b := []byte(`{"data": {"partner": {"verified_data": {"people": [{"identity_document_checks": [{"status": "passed", "file_links": [{"file_type": "photo", "link": "https://static.iwoca.com/assets/iwoca.4c17fef7de62.png"}], "check_id": "REFERENCE_0001", "datetime": "2017-06-12T14:05:51.666Z", "identity_document_type": "passport", "document_issuing_country": "gb", "provider_name": "test"}], "uid": "6cf7319e-f9ec-4038-ba4f-3561a6097484"}]}}, "state_key": "8e4db383-2ead-4a47-87df-220432714c47", "schema_version": "v1", "application": {"company": {"last_12_months_turnover": {"amount": 700000, "datetime": "2016-10-12T14:05:51.666Z"}, "type": "gmbh", "company_number": "01111112", "bank_details": {"iban": "DE89370400440532013000"}}, "requested_products": {"credit_facility": {"approval": {"amount": 15000}}}, "people": [{"residential_addresses": [{"town": "Ely", "uid": "cf9aa203-4e0c-4d7f-b42b-90c7b3d193d3", "house_number": "286", "date_from": "2014-02-03", "street_line_1": "Idverifier St", "postcode": "CB62AG"}], "last_name": "Norton", "uid": "6cf7319e-f9ec-4038-ba4f-3561a6097484", "roles": ["applicant", "shareholder", "guarantor", "director"], "title": "herr", "first_name": "Ervin", "privacy_policy": {"agreed": true, "datetime": "2016-10-12T14:05:51.666Z"}, "date_of_birth": "1980-01-01"}]}}}`) - req, err := http.NewRequest(http.MethodGet, "/api/resource", bytes.NewReader(b)) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "/api/resource", bytes.NewReader(b)) if err != nil { t.Fatal(err) } diff --git a/debugutil/http_log_round_tripper.go b/debugutil/http_log_round_tripper.go index da8d46a..c39e00e 100644 --- a/debugutil/http_log_round_tripper.go +++ b/debugutil/http_log_round_tripper.go @@ -16,8 +16,8 @@ type LogRoundTripper struct { dumpBody bool } -// RoundTripper returns a new http.RoundTripper which logs all requests (request and response dump) -// Should only be used for none production envs +// RoundTripper returns a new http.RoundTripper which logs all requests (request and response dump). +// Should only be used for none production envs. func NewLogRoundTripper(roundTripper http.RoundTripper, logger logger, dumpBody bool) http.RoundTripper { return LogRoundTripper{roundTripper, logger, dumpBody} } diff --git a/debugutil/http_log_round_tripper_test.go b/debugutil/http_log_round_tripper_test.go index 902828e..64c0f10 100644 --- a/debugutil/http_log_round_tripper_test.go +++ b/debugutil/http_log_round_tripper_test.go @@ -1,12 +1,14 @@ package debugutil_test import ( + "context" "fmt" - "github.com/donutloop/toolkit/debugutil" "log" "net/http" "net/http/httptest" "testing" + + "github.com/donutloop/toolkit/debugutil" ) type logger struct{} @@ -25,13 +27,19 @@ func TestLogRoundTripper_RoundTrip(t *testing.T) { } testHandler := http.HandlerFunc(handler) + server := httptest.NewServer(testHandler) defer server.Close() httpClient := new(http.Client) httpClient.Transport = debugutil.NewLogRoundTripper(http.DefaultTransport, logger{}, true) - response, err := httpClient.Get(server.URL) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, server.URL, nil) + if err != nil { + t.Fatal(err) + } + + response, err := httpClient.Do(req) if err != nil { t.Fatalf("could not create request: %v", err) } diff --git a/debugutil/prettysprint.go b/debugutil/prettysprint.go index 707d297..5183d1e 100644 --- a/debugutil/prettysprint.go +++ b/debugutil/prettysprint.go @@ -32,35 +32,46 @@ func PrettySprint(v interface{}) string { } buff := bytes.Buffer{} + switch value.Kind() { case reflect.Struct: buff.WriteString(fullName(value.Type()) + bracketOpen) + for i := 0; i < value.NumField(); i++ { l := string(value.Type().Field(i).Name[0]) if strings.ToUpper(l) == l { buff.WriteString(fmt.Sprintf("%s: %s,\n", value.Type().Field(i).Name, PrettySprint(value.Field(i).Interface()))) } } + buff.WriteString(bracketClose) + return buff.String() case reflect.Map: buff.WriteString("map[" + fullName(value.Type().Key()) + "]" + fullName(value.Type().Elem()) + bracketOpen) + for _, k := range value.MapKeys() { buff.WriteString(fmt.Sprintf(`"%s":%s,\n`, k.String(), PrettySprint(value.MapIndex(k).Interface()))) } + buff.WriteString(bracketClose) + return buff.String() case reflect.Ptr: if e := value.Elem(); e.IsValid() { return fmt.Sprintf("%s%s", pointerSign, PrettySprint(e.Interface())) } + return nilSign case reflect.Slice: buff.WriteString("[]" + fullName(value.Type().Elem()) + bracketOpen) + for i := 0; i < value.Len(); i++ { buff.WriteString(fmt.Sprintf("%s,\n", PrettySprint(value.Index(i).Interface()))) } + buff.WriteString(bracketClose) + return buff.String() default: return fmt.Sprintf("%#v", v) @@ -70,6 +81,7 @@ func PrettySprint(v interface{}) string { func pkgName(t reflect.Type) string { pkg := t.PkgPath() c := strings.Split(pkg, "/") + return c[len(c)-1] } @@ -77,5 +89,6 @@ func fullName(t reflect.Type) string { if pkg := pkgName(t); pkg != "" { return pkg + "." + t.Name() } + return t.Name() } diff --git a/debugutil/prettysprint_test.go b/debugutil/prettysprint_test.go index 262da81..32df21c 100644 --- a/debugutil/prettysprint_test.go +++ b/debugutil/prettysprint_test.go @@ -55,6 +55,7 @@ func Test(t *testing.T) { }, } for _, test := range tests { + test := test t.Run(test.name, func(t *testing.T) { output := debugutil.PrettySprint(test.input) if output != test.output { diff --git a/event/doc_test.go b/event/doc_test.go index 2ae9416..4edc0cd 100644 --- a/event/doc_test.go +++ b/event/doc_test.go @@ -2,6 +2,7 @@ package event_test import ( "fmt" + "github.com/donutloop/toolkit/event" ) @@ -13,7 +14,7 @@ func ExampleHooks() { errs := hooks.Fire() if len(errs) > 0 { for _, err := range errs { - fmt.Println(fmt.Sprintf("error: %v", err)) + fmt.Printf("error: %v \n", err) } } diff --git a/event/hook_test.go b/event/hook_test.go index f8fbbb0..a8b8ad2 100644 --- a/event/hook_test.go +++ b/event/hook_test.go @@ -1,8 +1,9 @@ package event_test import ( - "github.com/donutloop/toolkit/event" "testing" + + "github.com/donutloop/toolkit/event" ) func TestHooksMultiFire(t *testing.T) { diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 698f1bb..eacd289 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -3,13 +3,14 @@ package ast import ( "bytes" "fmt" - "github.com/fatih/astrewrite" "go/ast" "go/format" "go/parser" "go/token" "log" "strings" + + "github.com/fatih/astrewrite" ) const ( diff --git a/lease/lease_test.go b/lease/lease_test.go index ea04f14..d452186 100644 --- a/lease/lease_test.go +++ b/lease/lease_test.go @@ -12,7 +12,7 @@ import ( func TestLeaser_Lease(t *testing.T) { var counter int32 leaser := lease.NewLeaser() - leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() { + leaser.Lease("cleanup-cache", 1*time.Second, func() { atomic.AddInt32(&counter, 1) }) @@ -26,11 +26,11 @@ func TestLeaser_Lease(t *testing.T) { func TestLeaser_OverwriteLease(t *testing.T) { var counter int32 leaser := lease.NewLeaser() - leaser.Lease("cleanup-cache", time.Duration(2*time.Second), func() { + leaser.Lease("cleanup-cache", 2*time.Second, func() { atomic.AddInt32(&counter, 1) }) - leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() { + leaser.Lease("cleanup-cache", 1*time.Second, func() { atomic.AddInt32(&counter, 2) }) @@ -44,7 +44,7 @@ func TestLeaser_OverwriteLease(t *testing.T) { func TestLeaser_Return(t *testing.T) { var counter int32 leaser := lease.NewLeaser() - leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() { + leaser.Lease("cleanup-cache", 1*time.Second, func() { atomic.AddInt32(&counter, 1) }) diff --git a/loop/doc_test.go b/loop/doc_test.go index e708daf..bfe0be5 100644 --- a/loop/doc_test.go +++ b/loop/doc_test.go @@ -2,8 +2,9 @@ package loop_test import ( "fmt" - "github.com/donutloop/toolkit/loop" "time" + + "github.com/donutloop/toolkit/loop" ) func ExampleLoop() { diff --git a/loop/loop_test.go b/loop/loop_test.go index 39886c4..138ae8b 100644 --- a/loop/loop_test.go +++ b/loop/loop_test.go @@ -7,9 +7,10 @@ package loop_test import ( "errors" "fmt" - "github.com/donutloop/toolkit/loop" "testing" "time" + + "github.com/donutloop/toolkit/loop" ) func TestLoop(t *testing.T) { diff --git a/multierror/doc_test.go b/multierror/doc_test.go index 41f1443..ffa85cb 100644 --- a/multierror/doc_test.go +++ b/multierror/doc_test.go @@ -8,7 +8,7 @@ import ( "github.com/donutloop/toolkit/multierror" ) -func ExampleMultiError() { +func Example() { errs := []error{ errors.New("error connect to db failed"), errors.New("error marschaling json"), diff --git a/multierror/muliterror_test.go b/multierror/muliterror_test.go index 74549ca..9b3ac65 100644 --- a/multierror/muliterror_test.go +++ b/multierror/muliterror_test.go @@ -12,15 +12,18 @@ import ( "github.com/donutloop/toolkit/multierror" ) +var marshalError error = errors.New("error marshal json") +var connectionError error = errors.New("error connect to db failed") + func TestMultiError_Error(t *testing.T) { errs := []error{ nil, - errors.New("error connect to db failed"), - errors.New("error marschaling json"), + connectionError, + marshalError, } - expectedValue := "multiple errors: error connect to db failed; error marschaling json" + expectedValue := "multiple errors: error connect to db failed; error marshal json" err := multierror.New(errs...) if err.Error() != expectedValue { - t.Errorf(`unexpected error message (actual:"%s", expected: "%s")`, err.Error(), expectedValue) + t.Errorf(`unexpected error message (actual:"%v", expected: "%s")`, err, expectedValue) } } diff --git a/promise/doc_test.go b/promise/doc_test.go index a65af83..2cdbe40 100644 --- a/promise/doc_test.go +++ b/promise/doc_test.go @@ -3,10 +3,11 @@ package promise_test import ( "context" "fmt" + "github.com/donutloop/toolkit/promise" ) -func ExamplePromise() { +func Example() { done, errc := promise.Do(context.Background(), func(ctx context.Context) error { fmt.Println("do things") @@ -16,7 +17,7 @@ func ExamplePromise() { select { case <-done: case err := <-errc: - fmt.Println(fmt.Sprintf("error: %v", err)) + fmt.Printf("error: %v \n", err) } // Output: do things diff --git a/promise/promise.go b/promise/promise.go index 201d08a..28bf636 100644 --- a/promise/promise.go +++ b/promise/promise.go @@ -7,21 +7,29 @@ package promise import ( "context" "fmt" + "runtime/debug" ) -//Do is a basic promise implementation: it wraps calls a function in a goroutine +type RecoverError struct { + Err interface{} + Stack []byte +} + +func (e *RecoverError) Error() string { return fmt.Sprintf("Do panicked: %v", e.Err) } + +// Do is a basic promise implementation: it wraps calls a function in a goroutine. func Do(ctx context.Context, f func(ctx context.Context) error) (<-chan struct{}, chan error) { done := make(chan struct{}, 1) errc := make(chan error) go func(done chan struct{}, error chan error, ctx context.Context) { defer func() { if v := recover(); v != nil { - errc <- fmt.Errorf("promise is panicked (%v)", v) + errc <- &RecoverError{Err: v, Stack: debug.Stack()} } }() if err := f(ctx); err != nil { - errc <- err + error <- err return } diff --git a/promise/promise_test.go b/promise/promise_test.go index 1b609e2..21cdc7b 100644 --- a/promise/promise_test.go +++ b/promise/promise_test.go @@ -6,13 +6,16 @@ package promise_test import ( "context" - "fmt" - "github.com/donutloop/toolkit/promise" + "errors" "strings" "testing" "time" + + "github.com/donutloop/toolkit/promise" ) +var stubError error = errors.New("stub") + func TestDoPanic(t *testing.T) { done, errc := promise.Do(context.Background(), func(ctx context.Context) error { @@ -26,7 +29,7 @@ func TestDoPanic(t *testing.T) { t.Fatal("unexpected nil error") } - if !strings.Contains(err.Error(), "promise is panicked") { + if !strings.Contains(err.Error(), "Do panicked") { t.Fatalf(`unexpected error message (actual: "%s", expected: "promise is panicked (*)")`, err.Error()) } } @@ -35,7 +38,7 @@ func TestDoPanic(t *testing.T) { func TestDoFail(t *testing.T) { done, errc := promise.Do(context.Background(), func(ctx context.Context) error { - return fmt.Errorf("stub") + return stubError }) select { diff --git a/retry/doc_test.go b/retry/doc_test.go index 1438436..ea082b6 100644 --- a/retry/doc_test.go +++ b/retry/doc_test.go @@ -3,6 +3,7 @@ package retry_test import ( "context" "fmt" + "github.com/donutloop/toolkit/retry" ) @@ -14,7 +15,7 @@ func ExampleRetrier() { }) if err != nil { - fmt.Println(fmt.Sprintf("error: (%v)", err)) + fmt.Printf("error: (%v) \n", err) } // Output: fire request diff --git a/retry/retry.go b/retry/retry.go index 66ce7cb..d011ad0 100644 --- a/retry/retry.go +++ b/retry/retry.go @@ -83,7 +83,9 @@ type Strategy interface { type Exp struct{} +const expCurve float64 = 2 + func (e *Exp) Policy(intervalInSeconds, maxIntervalInSeconds float64) float64 { time.Sleep(time.Duration(intervalInSeconds) * time.Second) - return math.Min(intervalInSeconds*2, maxIntervalInSeconds) + return math.Min(intervalInSeconds*expCurve, maxIntervalInSeconds) } diff --git a/retry/retry_test.go b/retry/retry_test.go index 45d4c26..f4b5364 100644 --- a/retry/retry_test.go +++ b/retry/retry_test.go @@ -7,8 +7,9 @@ package retry_test import ( "context" "errors" - "github.com/donutloop/toolkit/retry" "testing" + + "github.com/donutloop/toolkit/retry" ) func TestRetrierRetryContextDeadlineFail(t *testing.T) { diff --git a/retry/roundtripper.go b/retry/roundtripper.go index de7aa2f..846841a 100644 --- a/retry/roundtripper.go +++ b/retry/roundtripper.go @@ -11,7 +11,7 @@ type RoundTripper struct { blacklistStatusCodes []int } -// NewRoundTripper is constructing a new retry RoundTripper with given default values +// NewRoundTripper is constructing a new retry RoundTripper with given default values. func NewRoundTripper(next http.RoundTripper, maxInterval, initialInterval float64, tries uint, blacklistStatusCodes []int, strategy Strategy) *RoundTripper { retrier := NewRetrier(initialInterval, maxInterval, tries, strategy) return &RoundTripper{ @@ -21,8 +21,8 @@ func NewRoundTripper(next http.RoundTripper, maxInterval, initialInterval float6 } } -// RoundTrip is retrying a outgoing request in case of bad status code and not blacklisted status codes -// if rt.next.RoundTrip(req) is return an error then it will abort the process retrying a request +// RoundTrip is retrying a outgoing request in case of bad status code and not blacklisted status codes. +// if rt.next.RoundTrip(req) is return an error then it will abort the process retrying a request. func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { var resp *http.Response err := rt.retrier.Retry(context.Background(), func() (b bool, e error) { @@ -32,7 +32,8 @@ func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { return false, err } - if resp.StatusCode > 308 { + // handle all 4xx and 5xx status codes + if resp.StatusCode > http.StatusPermanentRedirect { if rt.isStatusCode(resp.StatusCode) { return true, nil } diff --git a/retry/roundtripper_test.go b/retry/roundtripper_test.go index d33c74a..f0e97d0 100644 --- a/retry/roundtripper_test.go +++ b/retry/roundtripper_test.go @@ -1,15 +1,18 @@ -package retry +package retry_test import ( "bytes" + "context" "io/ioutil" "net/http" "net/http/httptest" "sync/atomic" "testing" + + "github.com/donutloop/toolkit/retry" ) -func TestRoundTripper_RoundTripInternalServer(t *testing.T) { +func TestRoundTripper_InternalServer(t *testing.T) { var counter int32 testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -18,11 +21,11 @@ func TestRoundTripper_RoundTripInternalServer(t *testing.T) { w.WriteHeader(http.StatusInternalServerError) })) - retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(Exp)) + retryRoundTripper := retry.NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(retry.Exp)) httpClient := new(http.Client) httpClient.Transport = retryRoundTripper - req, err := http.NewRequest(http.MethodGet, testserver.URL, nil) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, testserver.URL, nil) if err != nil { t.Fatal(err) } @@ -31,6 +34,7 @@ func TestRoundTripper_RoundTripInternalServer(t *testing.T) { if err != nil { t.Fatal(err) } + defer resp.Body.Close() if resp.StatusCode != http.StatusInternalServerError { t.Errorf("response is bad, got=%v", resp.StatusCode) @@ -41,7 +45,7 @@ func TestRoundTripper_RoundTripInternalServer(t *testing.T) { } } -func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) { +func TestRoundTripper_InternalServerBlacklisted(t *testing.T) { var counter int32 testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -50,11 +54,11 @@ func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) { w.WriteHeader(http.StatusInternalServerError) })) - retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50, .15, 3, []int{http.StatusInternalServerError}, new(Exp)) + retryRoundTripper := retry.NewRoundTripper(http.DefaultTransport, .50, .15, 3, []int{http.StatusInternalServerError}, new(retry.Exp)) httpClient := new(http.Client) httpClient.Transport = retryRoundTripper - req, err := http.NewRequest(http.MethodGet, testserver.URL, nil) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, testserver.URL, nil) if err != nil { t.Fatal(err) } @@ -64,6 +68,8 @@ func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) { t.Fatal(err) } + defer resp.Body.Close() + if resp.StatusCode != http.StatusInternalServerError { t.Errorf("response is bad, got=%v", resp.StatusCode) } @@ -73,7 +79,7 @@ func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) { } } -func TestRoundTripper_RoundTripStatusOk(t *testing.T) { +func TestRoundTripper_StatusOk(t *testing.T) { var counter int32 testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -82,11 +88,11 @@ func TestRoundTripper_RoundTripStatusOk(t *testing.T) { w.WriteHeader(http.StatusOK) })) - retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(Exp)) + retryRoundTripper := retry.NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(retry.Exp)) httpClient := new(http.Client) httpClient.Transport = retryRoundTripper - req, err := http.NewRequest(http.MethodGet, testserver.URL, nil) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, testserver.URL, nil) if err != nil { t.Fatal(err) } @@ -96,6 +102,8 @@ func TestRoundTripper_RoundTripStatusOk(t *testing.T) { t.Fatal(err) } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { t.Errorf("response is bad, got=%v", resp.StatusCode) } @@ -105,7 +113,7 @@ func TestRoundTripper_RoundTripStatusOk(t *testing.T) { } } -func TestRoundTripper_RoundTripJsonStatusOk(t *testing.T) { +func TestRoundTripper_JsonStatusOk(t *testing.T) { json := `{"hello":"world"}` @@ -134,14 +142,17 @@ func TestRoundTripper_RoundTripJsonStatusOk(t *testing.T) { } w.WriteHeader(http.StatusOK) - w.Write([]byte(json)) + _, err = w.Write([]byte(json)) + if err != nil { + t.Fatal(err) + } })) - retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(Exp)) + retryRoundTripper := retry.NewRoundTripper(http.DefaultTransport, .50, .15, 3, nil, new(retry.Exp)) httpClient := new(http.Client) httpClient.Transport = retryRoundTripper - req, err := http.NewRequest(http.MethodGet, testserver.URL, bytes.NewBuffer([]byte(json))) + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, testserver.URL, bytes.NewBuffer([]byte(json))) if err != nil { t.Fatal(err) } diff --git a/schedule/doc_test.go b/schedule/doc_test.go index 4ca72ff..dbf6ecc 100644 --- a/schedule/doc_test.go +++ b/schedule/doc_test.go @@ -3,10 +3,11 @@ package schedule_test import ( "context" "fmt" + "github.com/donutloop/toolkit/schedule" ) -func ExampleFIFOScheduler() { +func Example() { s := schedule.NewFIFOScheduler() defer s.Stop() @@ -16,7 +17,7 @@ func ExampleFIFOScheduler() { } if err := s.Schedule(job); err != nil { - fmt.Println(fmt.Sprintf("error: (%v)", err)) + fmt.Printf("error: (%v) \n", err) } s.WaitFinish(1) diff --git a/schedule/schedule.go b/schedule/schedule.go index efe9579..6ba87d0 100644 --- a/schedule/schedule.go +++ b/schedule/schedule.go @@ -32,8 +32,7 @@ type Fifo struct { done chan struct{} } -// NewFIFOScheduler returns a Scheduler that schedules jobs in FIFO -// order sequentially +// NewFIFOScheduler returns a Scheduler that schedules jobs in FIFO order sequentially. func NewFIFOScheduler() *Fifo { f := &Fifo{ resume: make(chan struct{}, 1), diff --git a/schedule/schedule_test.go b/schedule/schedule_test.go index e155083..4b2a15e 100644 --- a/schedule/schedule_test.go +++ b/schedule/schedule_test.go @@ -32,7 +32,10 @@ func TestFIFOSchedule(t *testing.T) { } for _, j := range jobs { - s.Schedule(j) + err := s.Schedule(j) + if err != nil { + t.Fatal(err) + } } s.WaitFinish(100) @@ -45,7 +48,7 @@ func TestFIFOSchedule(t *testing.T) { func TestFIFOScheduleCtx(t *testing.T) { s := schedule.NewFIFOScheduler() - s.Schedule(func(ctx context.Context) { + err := s.Schedule(func(ctx context.Context) { <-time.After(250 * time.Millisecond) err := ctx.Err() if err == nil { @@ -58,6 +61,10 @@ func TestFIFOScheduleCtx(t *testing.T) { } }) + if err != nil { + t.Fatal(err) + } + s.Stop() expectedJobCount := 1 @@ -81,8 +88,8 @@ func BenchmarkFIFOSchedule(b *testing.B) { for _, j := range jobs { if err := s.Schedule(j); err != nil { - b.Fatal(err) s.Stop() + b.Fatal(err) } } @@ -90,8 +97,8 @@ func BenchmarkFIFOSchedule(b *testing.B) { expectedJobCount := 100 if s.Scheduled() != expectedJobCount { - b.Fatalf("scheduled (actual: %d, expected: %d)", s.Scheduled(), expectedJobCount) s.Stop() + b.Fatalf("scheduled (actual: %d, expected: %d)", s.Scheduled(), expectedJobCount) } s.Stop() } diff --git a/singleton/doc_test.go b/singleton/doc_test.go index 30b92c2..46aef32 100644 --- a/singleton/doc_test.go +++ b/singleton/doc_test.go @@ -2,6 +2,7 @@ package singleton_test import ( "fmt" + "github.com/donutloop/toolkit/singleton" ) @@ -23,14 +24,12 @@ func ExampleSingleton() { } return s.(*config), nil } - - configFunc() - + c, err := configFunc() if err != nil { - fmt.Println(fmt.Sprintf("error: (%v)", err)) + fmt.Printf("error: (%v) \n", err) } - fmt.Println(fmt.Sprintf("%#v", c)) + fmt.Printf("%#v \n", c) // Output: &singleton_test.config{Addr:"localhost", Port:80} } diff --git a/singleton/singleton.go b/singleton/singleton.go index da2cdf4..cbaca61 100644 --- a/singleton/singleton.go +++ b/singleton/singleton.go @@ -17,7 +17,7 @@ type Singleton interface { } // Call to create a new singleton that is instantiated with the given constructor function. -// constructor is not called until the first call of Get(). If constructor returns a error, it will be called again +// Constructor is not called until the first call of Get(). If constructor returns a error, it will be called again // on the next call of Get(). func NewSingleton(constructor ConstructorFunc) Singleton { return &singleton{ @@ -54,7 +54,7 @@ func (s *singleton) Get() (interface{}, error) { return s.object, nil } -// Reset indicates that the next call of Get should actually a create instance +// Reset indicates that the next call of Get should actually a create instance. func (s *singleton) Reset() { s.m.Lock() defer s.m.Unlock() diff --git a/singleton/singleton_test.go b/singleton/singleton_test.go index ad5eddd..a6c5922 100644 --- a/singleton/singleton_test.go +++ b/singleton/singleton_test.go @@ -1,13 +1,15 @@ -package singleton +package singleton_test import ( "testing" + + "github.com/donutloop/toolkit/singleton" ) func TestNewSingleton(t *testing.T) { var counter int - stubSingleton := NewSingleton(func() (interface{}, error) { + stubSingleton := singleton.NewSingleton(func() (interface{}, error) { counter++ return counter, nil }) @@ -36,7 +38,7 @@ func TestNewSingleton(t *testing.T) { func TestSingletonReset(t *testing.T) { var counter int - stubSingleton := NewSingleton(func() (interface{}, error) { + stubSingleton := singleton.NewSingleton(func() (interface{}, error) { counter++ return counter, nil }) @@ -85,11 +87,14 @@ func TestSingletonReset(t *testing.T) { } func BenchmarkSingleton_Get(b *testing.B) { - stubSingleton := NewSingleton(func() (interface{}, error) { + stubSingleton := singleton.NewSingleton(func() (interface{}, error) { return nil, nil }) for n := 0; n < b.N; n++ { - stubSingleton.Get() + _, err := stubSingleton.Get() + if err != nil { + b.Fatal(err) + } } } diff --git a/worker/doc_test.go b/worker/doc_test.go index 39cbad7..7f9fdd8 100644 --- a/worker/doc_test.go +++ b/worker/doc_test.go @@ -2,11 +2,12 @@ package worker_test import ( "fmt" - "github.com/donutloop/toolkit/worker" "time" + + "github.com/donutloop/toolkit/worker" ) -func ExampleWorker() { +func Example() { workerHandler := func(parameter interface{}) (interface{}, error) { v := parameter.(string) return v + " world", nil diff --git a/worker/worker.go b/worker/worker.go index fedf3b0..e27a107 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -21,9 +21,11 @@ type worker struct { // NewWorker starts n*Workers goroutines running func on incoming // parameters sent on the returned channel. func New(nWorkers uint, fn func(gt interface{}) (interface{}, error), buffer uint) (Request, Response, <-chan error) { + request := make(chan interface{}, buffer) response := make(chan interface{}, buffer) errs := make(chan error, buffer) + w := &worker{ errs: errs, request: request, @@ -33,28 +35,35 @@ func New(nWorkers uint, fn func(gt interface{}) (interface{}, error), buffer uin fn: fn, buf: list.New(), } + go w.listener() + for i := uint(0); i < nWorkers; i++ { go w.work() } + go func() { for i := uint(0); i < nWorkers; i++ { <-w.done } }() + return request, response, errs } func (w *worker) listener() { inc := w.request + for inc != nil || w.buf.Len() > 0 { outc := w.jobs + var frontNode interface{} if e := w.buf.Front(); e != nil { frontNode = e.Value } else { outc = nil } + select { case outc <- frontNode: w.buf.Remove(w.buf.Front()) @@ -63,9 +72,11 @@ func (w *worker) listener() { inc = nil continue } + w.buf.PushBack(el) } } + close(w.jobs) } @@ -77,11 +88,13 @@ func (w *worker) work() { w.done <- true return } + v, err := w.fn(genericType) if err != nil { w.errs <- err continue } + w.response <- v } } diff --git a/worker/worker_test.go b/worker/worker_test.go index 3234b86..eef8c25 100644 --- a/worker/worker_test.go +++ b/worker/worker_test.go @@ -2,15 +2,16 @@ package worker_test import ( "fmt" - "github.com/donutloop/toolkit/worker" "sync/atomic" "testing" "time" + + "github.com/donutloop/toolkit/worker" ) func TestWorker(t *testing.T) { - containes := func(ls []string, s string) bool { + contains := func(ls []string, s string) bool { for _, ss := range ls { if ss == s { return true @@ -26,7 +27,7 @@ func TestWorker(t *testing.T) { return false, fmt.Errorf("value is not a string got=%v", parameter) } - if !containes([]string{"hello", "golang", "world"}, v) { + if !contains([]string{"hello", "golang", "world"}, v) { t.Errorf("value is bad got=%v", parameter) } diff --git a/xhttp/xhttp.go b/xhttp/xhttp.go index 4abe93f..f2b3dbe 100644 --- a/xhttp/xhttp.go +++ b/xhttp/xhttp.go @@ -7,7 +7,7 @@ import ( type Middleware func(m http.RoundTripper) http.RoundTripper -// Use is wrapping up a RoundTripper with a set of middleware +// Use is wrapping up a RoundTripper with a set of middleware. func Use(client *http.Client, middlewares ...Middleware) *http.Client { if client == nil { panic(errors.New("client is nil")) diff --git a/xhttp/xhttp_test.go b/xhttp/xhttp_test.go index cd899b6..8291644 100644 --- a/xhttp/xhttp_test.go +++ b/xhttp/xhttp_test.go @@ -1,11 +1,12 @@ package xhttp_test import ( - "github.com/donutloop/toolkit/xhttp" "log" "net/http" "net/http/httptest" "testing" + + "github.com/donutloop/toolkit/xhttp" ) type TestMiddleware struct { diff --git a/xpanic/handlepanic.go b/xpanic/handlepanic.go index ac6ef21..475ccc3 100644 --- a/xpanic/handlepanic.go +++ b/xpanic/handlepanic.go @@ -15,7 +15,7 @@ const ( CrashOnErrorDeactivated = false ) -// BuildPanicHandler builds a panic handler and verifies a none nil logger got passed +// BuildPanicHandler builds a panic handler and verifies a none nil logger got passed. func BuildPanicHandler(errorf func(format string, args ...interface{}), crashOnError bool) func() { if errorf == nil { panic("errorf is not set") @@ -32,7 +32,10 @@ func BuildPanicHandler(errorf func(format string, args ...interface{}), crashOnE if crashOnError { signal.Reset(syscall.SIGABRT) errorf("finished capturing of panic infos") - syscall.Kill(0, syscall.SIGABRT) + err := syscall.Kill(0, syscall.SIGABRT) + if err != nil { + errorf("syscall.Kill failed: %v", err) + } } else { errorf("finished capturing of panic infos") } diff --git a/xpanic/handlepanic_test.go b/xpanic/handlepanic_test.go index e0625a8..c10cfe4 100644 --- a/xpanic/handlepanic_test.go +++ b/xpanic/handlepanic_test.go @@ -3,10 +3,11 @@ package xpanic_test import ( "bytes" "fmt" - "github.com/donutloop/toolkit/xpanic" "runtime" "sync" "testing" + + "github.com/donutloop/toolkit/xpanic" ) func TestHandlePanic(t *testing.T) {
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: