// Copyright © 2023 Roberto Hidalgo // SPDX-License-Identifier: Apache-2.0 package http_test import ( "bytes" "encoding/json" "fmt" "io" "net/http/httptest" "reflect" "strings" "testing" "time" "git.rob.mx/nidito/event-gateway/internal/config" "git.rob.mx/nidito/event-gateway/internal/payload" "git.rob.mx/nidito/event-gateway/internal/sink" "git.rob.mx/nidito/event-gateway/internal/sink/debug" "git.rob.mx/nidito/event-gateway/internal/source/http" "git.rob.mx/nidito/event-gateway/internal/source/types" "github.com/sirupsen/logrus" ) func TestHTTPPayload(t *testing.T) { logrus.SetLevel(logrus.DebugLevel) testCases := []struct { Name string Payload any Expect any ExpectKind payload.Kind ContentType string }{ { Name: "empty-payload", Payload: nil, Expect: nil, ExpectKind: "", }, { Name: "text-payload", Payload: "sup", Expect: "sup", ExpectKind: payload.KindText, }, { Name: "json-payload", Payload: map[string]any{"yo": "sup"}, ContentType: "application/json", Expect: map[string]any{"yo": "sup"}, ExpectKind: payload.KindJSON, }, { Name: "form-urlencoded-payload", Payload: "yo=sup&yo=quihubo&dude=sweet", ContentType: "application/x-www-form-urlencoded", Expect: map[string]any{"yo": []string{"sup", "quihubo"}, "dude": "sweet"}, ExpectKind: payload.KindForm, }, { Name: "form-data-payload", Payload: strings.ReplaceAll(` --424242 Content-Disposition: form-data; name="yo" sup --424242 Content-Disposition: form-data; name="yo" quihubo --424242 Content-Disposition: form-data; name="dude" sweet --424242 Content-Disposition: form-data; name="ignored"; filename="example.txt" Content-type: text/plain some ignored text --424242-- `, "\n", "\r\n"), ContentType: `multipart/form-data; boundary=424242`, Expect: map[string]any{"yo": []string{"sup", "quihubo"}, "dude": "sweet"}, ExpectKind: payload.KindForm, }, } for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { sink.Clear() server := http.New(nil) target := &debug.Event{} l := &config.Listener{ ID: tc.Name, Source: &config.RawSource{ Kind: types.HTTP, Config: []byte(fmt.Sprintf(`{"path": "%s"}`, tc.Name)), }, Event: target, } if err := server.Register(l); err != nil { t.Fatalf("failed to register %s", tc.Name) } outbound := &bytes.Buffer{} if tc.Payload != nil { if tc.ContentType == "application/json" { if serialized, err := json.Marshal(tc.Payload); err != nil { t.Fatalf("could not serialize %s payload: %s", tc.Name, err) } else { outbound = bytes.NewBuffer(serialized) } } else { outbound = bytes.NewBufferString(tc.Payload.(string)) } } res := httptest.NewRecorder() req := httptest.NewRequest("POST", "/-/"+tc.Name, outbound) if tc.ContentType != "" { req.Header["Content-Type"] = []string{tc.ContentType} } server.Router.ServeHTTP(res, req) defer req.Body.Close() if res.Code > 200 { body, _ := io.ReadAll(res.Body) logrus.Errorf("request headers: %+v", req.Header) t.Fatalf("Request ended with non 200 code: %d: %s", res.Code, body) } time.Sleep(15 * time.Millisecond) sI, err := sink.ForKind(target.Kind()) if err != nil { t.Fatalf("could not get debug sink %s", err) } s := sI.(*debug.Sink) if len(s.Calls) != 1 { t.Fatalf("unexpected number of triggers called: %+v", s.Calls) } payload, err := payload.FromContext(s.Calls[0]) if err != nil { t.Fatalf("Could not parse payload: %s", err) } var got any = nil if tc.Expect != nil { if payload == nil { t.Fatalf("no payload parsed!") } got = payload.Value } if !reflect.DeepEqual(got, tc.Expect) { t.Fatalf("%s: unexpected payload, wanted %v, got: %v", tc.Name, tc.Expect, got) } }) } }