From cb4410df30a5dab587a429f83c88dcdd982c3a05 Mon Sep 17 00:00:00 2001 From: zeromake Date: Thu, 27 Feb 2020 22:13:55 +0800 Subject: [PATCH 1/2] feat(error): support go 1.13 errors.Unwrap method --- .gitignore | 2 ++ error.go | 49 ++++++++++++++++++++++++++++++++++++++ error_test.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ go113.go | 22 ++++++++++++++++++ interface.go | 4 ---- pre_go113.go | 28 ++++++++++++++++++++++ wrapper.go | 23 ++++-------------- wrapper_test.go | 5 ++-- 8 files changed, 171 insertions(+), 24 deletions(-) create mode 100644 .gitignore create mode 100644 error.go create mode 100644 error_test.go create mode 100644 go113.go create mode 100644 pre_go113.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90ac674 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea +.DS_Store diff --git a/error.go b/error.go new file mode 100644 index 0000000..285045b --- /dev/null +++ b/error.go @@ -0,0 +1,49 @@ +// Copyright 2017 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package fn + +type statusCodeError struct { + err error + statusCode int +} + +type StatusCodeError interface { + StatusCode() int +} + +func (s *statusCodeError) StatusCode() int { + return s.statusCode +} + +func (s *statusCodeError) Unwrap() error { + return s.err +} + +func (s *statusCodeError) Error() string { + return s.err.Error() +} + +func UnwrapErrorStatusCode(err error) (int, bool) { + for err != nil { + if v, ok := err.(StatusCodeError); ok { + return v.StatusCode(), true + } + err = Unwrap(err) + } + return 0, false +} + +func ErrorWithStatusCode(err error, statusCode int) error { + return &statusCodeError{err, statusCode} +} diff --git a/error_test.go b/error_test.go new file mode 100644 index 0000000..1c9cf1b --- /dev/null +++ b/error_test.go @@ -0,0 +1,62 @@ +// Copyright 2017 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package fn + +import ( + "errors" + . "github.com/pingcap/check" + "net/http" + "testing" +) + +var ( + errTest = errors.New("test") +) + +type withError struct { + err error +} + +func (w *withError) Error() string { + return w.err.Error() +} + +func (w *withError) Unwrap() error { + return w.err +} + +type errSuite struct{} + +func TestError(t *testing.T) { + TestingT(t) +} + +var _ = Suite(&errSuite{}) + +// TestWithError test UnwrapErrorStatusCode method +func (e *errSuite) TestWithError(c *C) { + var err error = &withError{ + err: ErrorWithStatusCode(errTest, http.StatusInternalServerError), + } + code, ok := UnwrapErrorStatusCode(err) + c.Assert(ok, IsTrue) + c.Assert(code == http.StatusInternalServerError, IsTrue) +} + +// TestOriginError ErrorWithStatusCode Unwrap +func (e *errSuite) TestOriginError(c *C) { + err := ErrorWithStatusCode(errTest, http.StatusInternalServerError) + err = Unwrap(err) + c.Assert(err == errTest, IsTrue) +} diff --git a/go113.go b/go113.go new file mode 100644 index 0000000..83e0b92 --- /dev/null +++ b/go113.go @@ -0,0 +1,22 @@ +//+build go1.13 + +// Copyright 2017 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package fn + +import "errors" + +func Unwrap(err error) error { + return errors.Unwrap(err) +} diff --git a/interface.go b/interface.go index 7b08d0e..635e9de 100644 --- a/interface.go +++ b/interface.go @@ -109,7 +109,3 @@ func SetResponseEncoder(c ResponseEncoder) { func SetMultipartFormMaxMemory(m int64) { maxMemory = m } - -func ErrorWithStatusCode(err error, statusCode int) error { - return &statusCodeError{err, statusCode} -} diff --git a/pre_go113.go b/pre_go113.go new file mode 100644 index 0000000..98d6279 --- /dev/null +++ b/pre_go113.go @@ -0,0 +1,28 @@ +//+build !go1.13 + +// Copyright 2017 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package fn + +type wrapError interface { + Unwrap() error +} + +func Unwrap(err error) error { + u, ok := err.(wrapError) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/wrapper.go b/wrapper.go index 4689ab9..ada125f 100644 --- a/wrapper.go +++ b/wrapper.go @@ -15,9 +15,9 @@ package fn import ( "context" - "reflect" "encoding/json" "net/http" + "reflect" ) type ( @@ -32,15 +32,6 @@ type ( plugins []PluginFunc adapter adapter } - - statusCodeError struct { - error - statusCode int - } - - StatusCodeError interface { - StatusCode() int - } ) var ( @@ -48,24 +39,20 @@ var ( responseEncoder ResponseEncoder ) -func (s *statusCodeError) StatusCode() int { - return s.statusCode -} - func failure(ctx context.Context, w http.ResponseWriter, err error) { statusCode := http.StatusBadRequest - if v, ok := err.(StatusCodeError); ok { - statusCode = v.StatusCode() + if v, ok := UnwrapErrorStatusCode(err); ok { + statusCode = v } w.WriteHeader(statusCode) - json.NewEncoder(w).Encode(errorEncoder(ctx, err)) + _ = json.NewEncoder(w).Encode(errorEncoder(ctx, err)) } func success(ctx context.Context, w http.ResponseWriter, data interface{}) { if data == nil || (reflect.ValueOf(data).Kind() == reflect.Ptr && reflect.ValueOf(data).IsNil()) { w.WriteHeader(http.StatusNoContent) } else { - json.NewEncoder(w).Encode(responseEncoder(ctx, data)) + _ = json.NewEncoder(w).Encode(responseEncoder(ctx, data)) } } diff --git a/wrapper_test.go b/wrapper_test.go index e70348a..7b0ed48 100644 --- a/wrapper_test.go +++ b/wrapper_test.go @@ -172,7 +172,7 @@ func (s *fnSuite) TestSetResponseEncoder(c *C) { c.Assert(err, IsNil) handler.ServeHTTP(recorder, request) respMsg := &testResponse{} - json.Unmarshal(recorder.Body.Bytes(), &respMsg) + _ = json.Unmarshal(recorder.Body.Bytes(), &respMsg) c.Assert(reflect.DeepEqual(respMsg, testResp), IsTrue) } @@ -195,7 +195,7 @@ func (s *fnSuite) TestSetErrorEncoder(c *C) { handler.ServeHTTP(recorder, request) respMsg := &testErrorResponse{} - json.Unmarshal(recorder.Body.Bytes(), &respMsg) + _ = json.Unmarshal(recorder.Body.Bytes(), &respMsg) c.Assert(reflect.DeepEqual(respMsg, testErrorResp), IsTrue) } @@ -207,6 +207,7 @@ func (s *fnSuite) TestGenericAdapter_Invoke(c *C) { recorder := httptest.NewRecorder() request, err := http.NewRequest(http.MethodGet, "", nil) + c.Assert(err == nil, IsTrue) payload := []byte(`{"for":"hello", "bar":10000}`) request.Body = ioutil.NopCloser(bytes.NewBuffer(payload)) c.Assert(err, IsNil) From f7fc8fa0bffaf6d6a9b131d500176268874675de Mon Sep 17 00:00:00 2001 From: zeromake Date: Fri, 6 Mar 2020 11:27:21 +0800 Subject: [PATCH 2/2] fix: refactoring code by code review --- error.go | 2 +- error_test.go | 5 +++-- go113.go | 2 +- pre_go113.go | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/error.go b/error.go index 285045b..b9d1c9f 100644 --- a/error.go +++ b/error.go @@ -1,4 +1,4 @@ -// Copyright 2017 PingCAP, Inc. +// Copyright 2020 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/error_test.go b/error_test.go index 1c9cf1b..090dda8 100644 --- a/error_test.go +++ b/error_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 PingCAP, Inc. +// Copyright 2020 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,9 +15,10 @@ package fn import ( "errors" - . "github.com/pingcap/check" "net/http" "testing" + + . "github.com/pingcap/check" ) var ( diff --git a/go113.go b/go113.go index 83e0b92..957ac8c 100644 --- a/go113.go +++ b/go113.go @@ -1,6 +1,6 @@ //+build go1.13 -// Copyright 2017 PingCAP, Inc. +// Copyright 2020 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pre_go113.go b/pre_go113.go index 98d6279..291df71 100644 --- a/pre_go113.go +++ b/pre_go113.go @@ -1,6 +1,6 @@ //+build !go1.13 -// Copyright 2017 PingCAP, Inc. +// Copyright 2020 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.