diff --git a/conformance/echo-basic/echo-basic.go b/conformance/echo-basic/echo-basic.go index 98f8de5a7a..7ae8c2dfad 100644 --- a/conformance/echo-basic/echo-basic.go +++ b/conformance/echo-basic/echo-basic.go @@ -39,11 +39,12 @@ import ( // RequestAssertions contains information about the request and the Ingress type RequestAssertions struct { - Path string `json:"path"` - Host string `json:"host"` - Method string `json:"method"` - Proto string `json:"proto"` - Headers map[string][]string `json:"headers"` + Path string `json:"path"` + Host string `json:"host"` + Method string `json:"method"` + Proto string `json:"proto"` + Headers map[string][]string `json:"headers"` + HTTPPort string `json:"httpPort"` Context `json:",inline"` @@ -76,7 +77,10 @@ type Context struct { Pod string `json:"pod"` } -var context Context +var ( + context Context + httpPort string +) func main() { if os.Getenv("GRPC_ECHO_SERVER") != "" { @@ -84,7 +88,7 @@ func main() { return } - httpPort := os.Getenv("HTTP_PORT") + httpPort = os.Getenv("HTTP_PORT") if httpPort == "" { httpPort = "3000" } @@ -216,6 +220,7 @@ func echoHandler(w http.ResponseWriter, r *http.Request) { r.Method, r.Proto, r.Header, + httpPort, context, diff --git a/conformance/echo-basic/echo-basic_test.go b/conformance/echo-basic/echo-basic_test.go index 5cbe4b31d6..aec399b1b3 100644 --- a/conformance/echo-basic/echo-basic_test.go +++ b/conformance/echo-basic/echo-basic_test.go @@ -228,6 +228,70 @@ func TestWriteEchoResponseHeaders(t *testing.T) { } } +func TestEchoHandler_IncludesHTTPPort(t *testing.T) { + // Preserve global across tests. + prevHTTPPort := httpPort + defer func() { httpPort = prevHTTPPort }() + + httpPort = "3002" + + // Minimal context to satisfy marshaling (values don’t matter for this check). + context = Context{ + Namespace: "testNamespace", + Ingress: "testIngress", + Service: "testService", + Pod: "testPod", + } + + req := httptest.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + + echoHandler(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Fatalf("expected status %d, got %d", http.StatusOK, status) + } + + var resp RequestAssertions + if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil { + t.Fatalf("failed to unmarshal echo response: %v", err) + } + if resp.HTTPPort != "3002" { + t.Errorf("expected HTTPPort %q, got %q", "3002", resp.HTTPPort) + } +} + +func TestEchoHandler_HTTPPortReflectsChange(t *testing.T) { + // Preserve global across tests. + prevHTTPPort := httpPort + defer func() { httpPort = prevHTTPPort }() + + httpPort = "3004" + context = Context{ + Namespace: "ns", + Ingress: "ing", + Service: "svc", + Pod: "pod", + } + + req := httptest.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + + echoHandler(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Fatalf("expected status %d, got %d", http.StatusOK, status) + } + + var resp RequestAssertions + if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil { + t.Fatalf("failed to unmarshal echo response: %v", err) + } + if resp.HTTPPort != "3004" { + t.Errorf("expected HTTPPort %q, got %q", "3004", resp.HTTPPort) + } +} + func TestProcessError(t *testing.T) { // Create a response recorder to capture the response rr := httptest.NewRecorder() diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go index 2d116423c1..4f50eb566a 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -87,6 +87,8 @@ type ExpectedRequest struct { // AbsentHeaders are names of headers that are expected // *not* to be present on the request. AbsentHeaders []string + // If set, CompareRoundTrip asserts the echoed httpPort equals this value. + HTTPPort string } // Response defines expected properties of a response from a backend. @@ -362,6 +364,10 @@ func CompareRoundTrip(t *testing.T, req *roundtripper.Request, cReq *roundtrippe } } + if expected.ExpectedRequest.HTTPPort != "" && expected.ExpectedRequest.HTTPPort != cReq.HTTPPort { + return fmt.Errorf("expected httpPort %q, got %q", expected.ExpectedRequest.HTTPPort, cReq.HTTPPort) + } + if expected.Response.Headers != nil { if cRes.Headers == nil { return fmt.Errorf("no headers captured, expected %v", len(expected.ExpectedRequest.Headers)) diff --git a/conformance/utils/roundtripper/roundtripper.go b/conformance/utils/roundtripper/roundtripper.go index 9490b648e2..27c3bb79c7 100644 --- a/conformance/utils/roundtripper/roundtripper.go +++ b/conformance/utils/roundtripper/roundtripper.go @@ -85,6 +85,7 @@ type CapturedRequest struct { Method string `json:"method"` Protocol string `json:"proto"` Headers map[string][]string `json:"headers"` + HTTPPort string `json:"httpPort,omitempty"` Namespace string `json:"namespace"` Pod string `json:"pod"`