From 9380b70ed54347aa6cf1ff4d7f59fbd32919030b Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 31 Mar 2022 09:02:53 -0700 Subject: [PATCH] fix http result errors by wrapping the upstream error, allowing for isNack (#764) * Add test for non-2XX response to Send Signed-off-by: Stephen Greene * fix http result errors by wrapping the upstream error, allowing for isNack Signed-off-by: Scott Nichols * special case http errors if the first error is not wrapped Signed-off-by: Scott Nichols * Update test/integration/http/tap_handler.go Signed-off-by: Scott Nichols * a receiver error will result in no event, the tap is returning an error before the handler Signed-off-by: Scott Nichols Co-authored-by: Greene --- test/integration/http/direct.go | 14 +++++++---- test/integration/http/direct_v1_test.go | 32 +++++++++++++++++++++++++ test/integration/http/tap_handler.go | 7 +++++- v2/protocol/http/protocol.go | 9 ++++++- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/test/integration/http/direct.go b/test/integration/http/direct.go index 48a35adab..15f3712d8 100644 --- a/test/integration/http/direct.go +++ b/test/integration/http/direct.go @@ -27,17 +27,20 @@ import ( // Client is a set to binary or type DirectTapTest struct { - now time.Time - event *cloudevents.Event - want *cloudevents.Event - wantResult cloudevents.Result - asSent *TapValidation + now time.Time + event *cloudevents.Event + serverReturnedStatusCode int + want *cloudevents.Event + wantResult cloudevents.Result + asSent *TapValidation } type DirectTapTestCases map[string]DirectTapTest func ClientDirect(t *testing.T, tc DirectTapTest, copts ...client.Option) { tap := NewTap() + tap.statusCode = tc.serverReturnedStatusCode + server := httptest.NewServer(tap) defer server.Close() @@ -83,6 +86,7 @@ func ClientDirect(t *testing.T, tc DirectTapTest, copts ...client.Option) { t.Errorf("expected ACK, got %s", result) } } else if !cloudevents.ResultIs(result, tc.wantResult) { + t.Errorf("result.IsUndelivered = %v", cloudevents.IsUndelivered(result)) t.Fatalf("expected %s, got %s", tc.wantResult, result) } } diff --git a/test/integration/http/direct_v1_test.go b/test/integration/http/direct_v1_test.go index 47a3a637b..9b8253ce0 100644 --- a/test/integration/http/direct_v1_test.go +++ b/test/integration/http/direct_v1_test.go @@ -8,6 +8,7 @@ package http import ( "fmt" "github.com/cloudevents/sdk-go/v2/client" + "net/http" "testing" "time" @@ -58,6 +59,37 @@ func TestSenderReceiver_binary_v1(t *testing.T) { ContentLength: 20, }, }, + "Binary v1.0 Sender Result Are NACK For Non-2XX": { + now: now, + event: &cloudevents.Event{ + Context: cloudevents.EventContextV1{ + ID: "ABC-123", + Type: "unit.test.client.sent", + Source: *cloudevents.ParseURIRef("/unit/test/client"), + Subject: strptr("resource"), + DataContentType: cloudevents.StringOfApplicationJSON(), + }.AsV1(), + DataEncoded: toBytes(map[string]interface{}{"hello": "unittest"}), + }, + serverReturnedStatusCode: http.StatusInternalServerError, + want: nil, + wantResult: cloudevents.ResultNACK, + asSent: &TapValidation{ + Method: "POST", + URI: "/", + Header: map[string][]string{ + "ce-specversion": {"1.0"}, + "ce-id": {"ABC-123"}, + "ce-time": {now.UTC().Format(time.RFC3339Nano)}, + "ce-type": {"unit.test.client.sent"}, + "ce-source": {"/unit/test/client"}, + "ce-subject": {"resource"}, + "content-type": {"application/json"}, + }, + Body: `{"hello":"unittest"}`, + ContentLength: 20, + }, + }, } for n, tc := range testCases { diff --git a/test/integration/http/tap_handler.go b/test/integration/http/tap_handler.go index 9d14ab0c1..5d69e8140 100644 --- a/test/integration/http/tap_handler.go +++ b/test/integration/http/tap_handler.go @@ -25,7 +25,8 @@ type TapValidation struct { } type tapHandler struct { - handler http.Handler + handler http.Handler + statusCode int req map[string]TapValidation resp map[string]TapValidation @@ -113,6 +114,10 @@ func (t *tapHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.WriteHeader(500) return } + if t.statusCode > 299 { + w.WriteHeader(t.statusCode) + return + } rec := httptest.NewRecorder() t.handler.ServeHTTP(rec, r) diff --git a/v2/protocol/http/protocol.go b/v2/protocol/http/protocol.go index 7ca5ad271..06204b2a1 100644 --- a/v2/protocol/http/protocol.go +++ b/v2/protocol/http/protocol.go @@ -157,7 +157,14 @@ func (p *Protocol) Send(ctx context.Context, m binding.Message, transformers ... buf := new(bytes.Buffer) buf.ReadFrom(message.BodyReader) errorStr := buf.String() - err = NewResult(res.StatusCode, "%s", errorStr) + // If the error is not wrapped, then append the original error string. + if og, ok := err.(*Result); ok { + og.Format = og.Format + "%s" + og.Args = append(og.Args, errorStr) + err = og + } else { + err = NewResult(res.StatusCode, "%w: %s", err, errorStr) + } } } }