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) {