Skip to content

Commit

Permalink
Review updates
Browse files Browse the repository at this point in the history
* Expanded test for NewEventsFromHTTPRequest
* Implemented NewHTTPRequestFromEvent as well
  • Loading branch information
markmandel committed Jan 9, 2023
1 parent 5361386 commit 3da778d
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 8 deletions.
20 changes: 19 additions & 1 deletion v2/protocol/http/utility.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,25 @@ func NewEventsFromHTTPResponse(resp *nethttp.Response) ([]event.Event, error) {
return binding.ToEvents(context.Background(), msg, msg.BodyReader)
}

// NewHTTPRequestFromEvents creates a http.Request object that can be used with any http.Client.
// NewHTTPRequestFromEvent creates a http.Request object that can be used with any http.Client for a singular event.
func NewHTTPRequestFromEvent(ctx context.Context, url string, event event.Event) (*nethttp.Request, error) {
if err := event.Validate(); err != nil {
return nil, err
}

req, err := nethttp.NewRequestWithContext(ctx, nethttp.MethodPost, url, nil)
if err != nil {
return nil, err
}
if err := WriteRequest(ctx, (*binding.EventMessage)(&event), req); err != nil {
return nil, err
}

return req, nil
}

// NewHTTPRequestFromEvents creates a http.Request object that can be used with any http.Client for sending
// a batched set of events.
func NewHTTPRequestFromEvents(ctx context.Context, url string, events []event.Event) (*nethttp.Request, error) {
// Sending batch events is quite straightforward, as there is only JSON format, so a simple implementation.
for _, e := range events {
Expand Down
95 changes: 88 additions & 7 deletions v2/protocol/http/utility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/cloudevents/sdk-go/v2/binding"
Expand Down Expand Up @@ -92,13 +93,58 @@ func TestNewEventFromHttpResponse(t *testing.T) {
}

func TestNewEventsFromHTTPRequest(t *testing.T) {
req := httptest.NewRequest("POST", "http://localhost", bytes.NewReader([]byte(`[{"data":"foo","datacontenttype":"application/json","id":"id","source":"source","specversion":"1.0","type":"type"}]`)))
req.Header.Set(ContentType, event.ApplicationCloudEventsBatchJSON)
type expected struct {
len int
ids []string
}

events, err := NewEventsFromHTTPRequest(req)
require.NoError(t, err)
require.Len(t, events, 1)
test.AssertEvent(t, events[0], test.IsValid())
fixtures := map[string]struct {
jsn string
expected expected
}{
"single": {
jsn: `[{"data":"foo","datacontenttype":"application/json","id":"id","source":"source","specversion":"1.0","type":"type"}]`,
expected: expected{
len: 1,
ids: []string{"id"},
},
},
"triple": {
jsn: `[{"data":"foo","datacontenttype":"application/json","id":"id1","source":"source","specversion":"1.0","type":"type"},{"data":"foo","datacontenttype":"application/json","id":"id2","source":"source","specversion":"1.0","type":"type"},{"data":"foo","datacontenttype":"application/json","id":"id3","source":"source","specversion":"1.0","type":"type"}]`,
expected: expected{
len: 3,
ids: []string{"id1", "id2", "id3"},
},
},
}

for k, v := range fixtures {
t.Run(k, func(t *testing.T) {
req := httptest.NewRequest("POST", "http://localhost", bytes.NewReader([]byte(v.jsn)))
req.Header.Set(ContentType, event.ApplicationCloudEventsBatchJSON)

events, err := NewEventsFromHTTPRequest(req)
require.NoError(t, err)
require.Len(t, events, v.expected.len)
for i, e := range events {
test.AssertEvent(t, e, test.IsValid())
require.Equal(t, v.expected.ids[i], events[i].ID())
}
})
}

t.Run("bad request", func(t *testing.T) {
e := event.New()
e.SetID(uuid.New().String())
e.SetSource("example/uri")
e.SetType("example.type")
require.NoError(t, e.SetData(event.ApplicationJSON, map[string]string{"hello": "world"}))
req, err := NewHTTPRequestFromEvent(context.Background(), "http://localhost", e)
require.NoError(t, err)

_, err = NewEventsFromHTTPRequest(req)
require.ErrorContainsf(t, err, "cannot convert message to batched events", "error should include message")
})
}

func TestNewEventsFromHTTPResponse(t *testing.T) {
Expand All @@ -116,6 +162,42 @@ func TestNewEventsFromHTTPResponse(t *testing.T) {
test.AssertEvent(t, events[0], test.IsValid())
}

func TestNewHTTPRequestFromEvent(t *testing.T) {
e := event.New()
e.SetID(uuid.New().String())
e.SetSource("example/uri")
e.SetType("example.type")
require.NoError(t, e.SetData(event.ApplicationJSON, map[string]string{"hello": "world"}))

// echo back what we get, so we can compare events at either side.
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(ContentType, r.Header.Get(ContentType))
// copy across structured headers
for k, v := range r.Header {
if strings.HasPrefix(k, "Ce-") {
w.Header()[k] = v
}
}

b, err := io.ReadAll(r.Body)
require.NoError(t, err)
require.NoError(t, r.Body.Close())
_, err = w.Write(b)
require.NoError(t, err)
}))
defer ts.Close()

req, err := NewHTTPRequestFromEvent(context.Background(), ts.URL, e)
require.NoError(t, err)

resp, err := ts.Client().Do(req)
require.NoError(t, err)

result, err := NewEventFromHTTPResponse(resp)
require.NoError(t, err)
require.Equal(t, &e, result)
}

func TestNewHTTPRequestFromEvents(t *testing.T) {
var events []event.Event
e := event.New()
Expand Down Expand Up @@ -151,6 +233,5 @@ func TestNewHTTPRequestFromEvents(t *testing.T) {

result, err := NewEventsFromHTTPResponse(resp)
require.NoError(t, err)

require.Equal(t, events, result)
}

0 comments on commit 3da778d

Please sign in to comment.