diff --git a/core/transport/headers_test.go b/core/transport/headers_test.go new file mode 100644 index 0000000..e84ac73 --- /dev/null +++ b/core/transport/headers_test.go @@ -0,0 +1,55 @@ +package transport + +import ( + "net/http" + "reflect" + "testing" +) + +func TestNewHeaders_NormalInput(t *testing.T) { + input := []string{"Content-Type=application/json", "Accept=*/*"} + want := http.Header{ + "Content-Type": {"application/json"}, + "Accept": {"*/*"}, + } + got := NewHeaders(input) + if !reflect.DeepEqual(got, want) { + t.Errorf("NewHeaders() = %v, want %v", got, want) + } +} + +func TestNewHeaders_InvalidFormat(t *testing.T) { + input := []string{"invalid-header", "AnotherOne"} + want := http.Header{} + got := NewHeaders(input) + if !reflect.DeepEqual(got, want) { + t.Errorf("NewHeaders() = %v, want %v", got, want) + } +} + +func TestNewHeaders_DuplicateKeys(t *testing.T) { + input := []string{"X-Test=1", "X-Test=2"} + want := http.Header{ + "X-Test": {"1", "2"}, + } + got := NewHeaders(input) + if !reflect.DeepEqual(got, want) { + t.Errorf("NewHeaders() = %v, want %v", got, want) + } +} + +func TestNewHeaders_EmptyOrNilInput(t *testing.T) { + var inputNil []string + inputEmpty := []string{} + want := http.Header{} + + gotNil := NewHeaders(inputNil) + if !reflect.DeepEqual(gotNil, want) { + t.Errorf("NewHeaders(nil) = %v, want %v", gotNil, want) + } + + gotEmpty := NewHeaders(inputEmpty) + if !reflect.DeepEqual(gotEmpty, want) { + t.Errorf("NewHeaders(empty) = %v, want %v", gotEmpty, want) + } +} diff --git a/core/transport/transport_test.go b/core/transport/transport_test.go new file mode 100644 index 0000000..7451699 --- /dev/null +++ b/core/transport/transport_test.go @@ -0,0 +1,128 @@ +package transport + +import ( + "context" + "errors" + "net/http" + "reflect" + "testing" +) + +// mockRoundTripper is used to intercept requests and record headers +type mockRoundTripper struct { + lastReq *http.Request + resp *http.Response + err error +} + +func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + m.lastReq = req + if m.resp != nil || m.err != nil { + return m.resp, m.err + } + return &http.Response{StatusCode: 200, Body: http.NoBody, Request: req}, nil +} + +func TestDefaultHeaderTransport_CustomHeaders(t *testing.T) { + mock := &mockRoundTripper{} + tr := &DefaultHeaderTransport{ + Origin: mock, + Header: http.Header{ + "X-Test": {"abc"}, + "Foo": {"bar"}, + }, + AppName: "myapp", + AppVersion: "1.2.3", + } + req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil) + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatalf("RoundTrip error: %v", err) + } + if resp != nil && resp.Body != nil { + resp.Body.Close() + } + + want := http.Header{ + "X-Test": {"abc"}, + "Foo": {"bar"}, + "X-App-Name": {"myapp"}, + "X-App-Version": {"1.2.3"}, + } + for k, v := range want { + got := req.Header.Values(k) + if !reflect.DeepEqual(got, v) { + t.Errorf("Header %q = %v, want %v", k, got, v) + } + } +} + +func TestDefaultHeaderTransport_EmptyHeadersAndAppInfo(t *testing.T) { + mock := &mockRoundTripper{} + tr := &DefaultHeaderTransport{ + Origin: mock, + Header: http.Header{}, + AppName: "", + AppVersion: "", + } + req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil) + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatalf("RoundTrip error: %v", err) + } + if resp != nil && resp.Body != nil { + resp.Body.Close() + } + + // x-app-name/version should not be present + if req.Header.Get("x-app-name") != "" { + t.Errorf("x-app-name should be empty") + } + if req.Header.Get("x-app-version") != "" { + t.Errorf("x-app-version should be empty") + } +} + +func TestDefaultHeaderTransport_OriginErrorPropagation(t *testing.T) { + mock := &mockRoundTripper{err: errors.New("mock error")} + tr := &DefaultHeaderTransport{ + Origin: mock, + Header: http.Header{}, + AppName: "", + AppVersion: "", + } + req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil) + resp, err := tr.RoundTrip(req) + if resp != nil && resp.Body != nil { + resp.Body.Close() + } + if err == nil || err.Error() != "mock error" { + t.Errorf("Expected error 'mock error', got %v", err) + } +} + +func TestDefaultHeaderTransport_MultipleHeaderValues(t *testing.T) { + mock := &mockRoundTripper{} + tr := &DefaultHeaderTransport{ + Origin: mock, + Header: http.Header{ + "X-Multi": {"a", "b"}, + }, + AppName: "app", + AppVersion: "v", + } + req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil) + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatalf("RoundTrip error: %v", err) + } + if resp != nil && resp.Body != nil { + resp.Body.Close() + } + + got := req.Header.Values("X-Multi") + want := []string{"a", "b"} + if !reflect.DeepEqual(got, want) { + t.Errorf("X-Multi header = %v, want %v", got, want) + } +}