From 1d9529495e175e7b36d3636d4d5c8739774ef876 Mon Sep 17 00:00:00 2001 From: Yanwei Guo Date: Wed, 2 Feb 2022 21:52:20 -0800 Subject: [PATCH] Adds a flag to allow customized request headers in conformance tests (#12540) * add flag * add validation * add comment * check empty --- test/conformance/api/shared/util.go | 1 + test/conformance/api/v1/blue_green_test.go | 3 ++- test/conformance/api/v1/generatename_test.go | 3 ++- test/conformance/api/v1/resources_test.go | 4 ++- .../api/v1/revision_timeout_test.go | 4 ++- test/conformance/api/v1/route_test.go | 3 ++- test/conformance/api/v1/service_test.go | 14 ++++++++-- .../api/v1/single_threaded_test.go | 4 ++- test/conformance/api/v1/util.go | 4 ++- test/conformance/api/v1/volumes_test.go | 3 ++- .../api/v1alpha1/domain_mapping_test.go | 9 ++++--- .../api/v1beta1/domain_mapping_test.go | 9 ++++--- .../runtime/readiness_probe_test.go | 2 ++ test/conformance/runtime/util.go | 2 +- test/e2e_flags.go | 26 ++++++++++++++++++- test/prober.go | 22 +++++++++++++--- 16 files changed, 91 insertions(+), 22 deletions(-) diff --git a/test/conformance/api/shared/util.go b/test/conformance/api/shared/util.go index 497057b12d77..34a5aed9d439 100644 --- a/test/conformance/api/shared/util.go +++ b/test/conformance/api/shared/util.go @@ -103,6 +103,7 @@ func sendRequests(ctx context.Context, client *spoof.SpoofingClient, url *url.UR if err != nil { return err } + spoof.WithHeader(test.ServingFlags.RequestHeader())(req) resp, err := client.Do(req) if err != nil { diff --git a/test/conformance/api/v1/blue_green_test.go b/test/conformance/api/v1/blue_green_test.go index 9f709aafa9f7..fee68c5e02f6 100644 --- a/test/conformance/api/v1/blue_green_test.go +++ b/test/conformance/api/v1/blue_green_test.go @@ -138,7 +138,8 @@ func TestBlueGreenRoute(t *testing.T) { spoof.IsStatusOK, "CheckSuccessfulResponse", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", greenURL, err) } diff --git a/test/conformance/api/v1/generatename_test.go b/test/conformance/api/v1/generatename_test.go index a9de309568dc..9fae99658297 100644 --- a/test/conformance/api/v1/generatename_test.go +++ b/test/conformance/api/v1/generatename_test.go @@ -102,7 +102,8 @@ func canServeRequests(t *testing.T, clients *test.Clients, route *v1.Route) erro spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.HelloWorldText)), "CheckEndpointToServeText", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) if err != nil { return fmt.Errorf("the endpoint for Route %s at %s didn't serve the expected text %q: %w", route.Name, url, test.HelloWorldText, err) } diff --git a/test/conformance/api/v1/resources_test.go b/test/conformance/api/v1/resources_test.go index fa6ddfcb168f..af8107d35822 100644 --- a/test/conformance/api/v1/resources_test.go +++ b/test/conformance/api/v1/resources_test.go @@ -72,7 +72,8 @@ func TestCustomResourcesLimits(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK), "ResourceTestServesText", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) if err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } @@ -88,6 +89,7 @@ func TestCustomResourcesLimits(t *testing.T) { if err != nil { return nil, err } + spoof.WithHeader(test.ServingFlags.RequestHeader())(req) return client.Do(req) } diff --git a/test/conformance/api/v1/revision_timeout_test.go b/test/conformance/api/v1/revision_timeout_test.go index 8033c9ce8704..9f29bbfe28f6 100644 --- a/test/conformance/api/v1/revision_timeout_test.go +++ b/test/conformance/api/v1/revision_timeout_test.go @@ -57,6 +57,7 @@ func sendRequest(t *testing.T, clients *test.Clients, endpoint *url.URL, if err != nil { return fmt.Errorf("failed to create new HTTP request: %w", err) } + spoof.WithHeader(test.ServingFlags.RequestHeader())(req) resp, err := client.Do(req) if err != nil { @@ -130,7 +131,8 @@ func TestRevisionTimeout(t *testing.T) { spoof.IsOneOfStatusCodes(http.StatusOK, http.StatusGatewayTimeout), "CheckSuccessfulResponse", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", serviceURL, err) } diff --git a/test/conformance/api/v1/route_test.go b/test/conformance/api/v1/route_test.go index 36bdd9778602..d1d823365350 100644 --- a/test/conformance/api/v1/route_test.go +++ b/test/conformance/api/v1/route_test.go @@ -52,7 +52,8 @@ func assertResourcesUpdatedWhenRevisionIsReady(t *testing.T, clients *test.Clien spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(expectedText)), "CheckEndpointToServeText", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) if err != nil { t.Fatalf("The endpoint for Route %s at %s didn't serve the expected text %q: %v", names.Route, url, expectedText, err) } diff --git a/test/conformance/api/v1/service_test.go b/test/conformance/api/v1/service_test.go index 90bb0089f458..3a0d9787ecec 100644 --- a/test/conformance/api/v1/service_test.go +++ b/test/conformance/api/v1/service_test.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" pkgtest "knative.dev/pkg/test" + "knative.dev/pkg/test/spoof" v1 "knative.dev/serving/pkg/apis/serving/v1" "knative.dev/serving/test" v1test "knative.dev/serving/test/v1" @@ -130,7 +131,11 @@ func TestServiceCreateAndUpdate(t *testing.T) { } // We start a background prober to test if Route is always healthy even during Route update. - prober := test.RunRouteProber(t.Logf, clients, names.URL, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + prober := test.RunRouteProber( + t.Logf, + clients, names.URL, + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) defer test.AssertProberDefault(t, prober) // Update Container Image @@ -287,7 +292,12 @@ func TestServiceBYOName(t *testing.T) { } // We start a background prober to test if Route is always healthy even during Route update. - prober := test.RunRouteProber(t.Logf, clients, names.URL, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + prober := test.RunRouteProber( + t.Logf, + clients, + names.URL, + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) defer test.AssertProberDefault(t, prober) // Update Container Image diff --git a/test/conformance/api/v1/single_threaded_test.go b/test/conformance/api/v1/single_threaded_test.go index 04c68347f988..0a740ae067c6 100644 --- a/test/conformance/api/v1/single_threaded_test.go +++ b/test/conformance/api/v1/single_threaded_test.go @@ -71,7 +71,8 @@ func TestSingleConcurrency(t *testing.T) { spoof.IsStatusOK, "CheckSuccessfulResponse", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", url, err) } @@ -94,6 +95,7 @@ func TestSingleConcurrency(t *testing.T) { if err != nil { return fmt.Errorf("error creating http request: %w", err) } + spoof.WithHeader(test.ServingFlags.RequestHeader())(req) for { select { diff --git a/test/conformance/api/v1/util.go b/test/conformance/api/v1/util.go index 0ae094aa2c77..67891885aa6d 100644 --- a/test/conformance/api/v1/util.go +++ b/test/conformance/api/v1/util.go @@ -50,6 +50,7 @@ func checkForExpectedResponses(ctx context.Context, t testing.TB, clients *test. if err != nil { return err } + spoof.WithHeader(test.ServingFlags.RequestHeader())(req) _, err = client.Poll(req, spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesAllBodies(expectedResponses...))) return err } @@ -136,7 +137,8 @@ func validateDataPlane(t testing.TB, clients *test.Clients, names test.ResourceN spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(expectedText)), "WaitForEndpointToServeText", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())) if err != nil { return fmt.Errorf("the endpoint for Route %s at %s didn't serve the expected text %q: %w", names.Route, names.URL, expectedText, err) } diff --git a/test/conformance/api/v1/volumes_test.go b/test/conformance/api/v1/volumes_test.go index c0d37a3e0a00..db3f541b50f6 100644 --- a/test/conformance/api/v1/volumes_test.go +++ b/test/conformance/api/v1/volumes_test.go @@ -480,7 +480,8 @@ func TestProjectedServiceAccountToken(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, isJWT), "CheckEndpointToServeTheToken", test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Error(err) } } diff --git a/test/conformance/api/v1alpha1/domain_mapping_test.go b/test/conformance/api/v1alpha1/domain_mapping_test.go index 03d6f06bf9a2..a3645e596ee4 100644 --- a/test/conformance/api/v1alpha1/domain_mapping_test.go +++ b/test/conformance/api/v1alpha1/domain_mapping_test.go @@ -117,7 +117,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText1)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } @@ -184,7 +185,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText1)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } @@ -217,7 +219,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText2)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } } diff --git a/test/conformance/api/v1beta1/domain_mapping_test.go b/test/conformance/api/v1beta1/domain_mapping_test.go index 0d04ace65a16..f18b790c800f 100644 --- a/test/conformance/api/v1beta1/domain_mapping_test.go +++ b/test/conformance/api/v1beta1/domain_mapping_test.go @@ -117,7 +117,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText1)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } @@ -184,7 +185,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText1)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } @@ -217,7 +219,8 @@ func TestDomainMapping(t *testing.T) { spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(test.PizzaPlanetText2)), "CheckSuccessfulResponse", resolvableCustomDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)); err != nil { + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader())); err != nil { t.Fatalf("Error probing %s: %v", endpoint, err) } } diff --git a/test/conformance/runtime/readiness_probe_test.go b/test/conformance/runtime/readiness_probe_test.go index 6541681a4a71..70e243b214b9 100644 --- a/test/conformance/runtime/readiness_probe_test.go +++ b/test/conformance/runtime/readiness_probe_test.go @@ -135,6 +135,7 @@ func TestProbeRuntime(t *testing.T) { "readinessIsReady", test.ServingFlags.ResolvableDomain, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader()), ); err != nil { t.Fatalf("The endpoint for Route %s at %s didn't return success: %v", names.Route, url, err) } @@ -240,6 +241,7 @@ func waitReadyThenStartFailing(t *testing.T, clients *test.Clients, names test.R "readinessIsReady", test.ServingFlags.ResolvableDomain, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + spoof.WithHeader(test.ServingFlags.RequestHeader()), ); err != nil { t.Fatalf("The endpoint for Route %s at %s didn't return success: %v", names.Route, url, err) } diff --git a/test/conformance/runtime/util.go b/test/conformance/runtime/util.go index 1b1d3923a571..0dcdbba3c47f 100644 --- a/test/conformance/runtime/util.go +++ b/test/conformance/runtime/util.go @@ -63,7 +63,7 @@ func fetchRuntimeInfo( spoof.IsStatusOK, "RuntimeInfo", test.ServingFlags.ResolvableDomain, - append(reqOpts, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))...) + append(reqOpts, spoof.WithHeader(test.ServingFlags.RequestHeader()), test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS))...) if err != nil { return nil, nil, err } diff --git a/test/e2e_flags.go b/test/e2e_flags.go index 1885373fe982..a0cc8e6eb202 100644 --- a/test/e2e_flags.go +++ b/test/e2e_flags.go @@ -21,6 +21,8 @@ package test import ( "flag" + "net/http" + "strings" // Load the generic flags of knative.dev/pkg too. _ "knative.dev/pkg/test" @@ -45,7 +47,7 @@ type ServingEnvironmentFlags struct { AltTestNamespace string // Alternative namespace for running cross-namespace tests in TLSTestNamespace string // Namespace for Serving TLS tests ExceedingMemoryLimitSize int // Memory size used to trigger a non-200 response when the service is set with 300MB memory limit. - + RequestHeaders string // Extra HTTP request headers sent to the testing deployed KServices. } func initializeServingFlags() *ServingEnvironmentFlags { @@ -93,5 +95,27 @@ func initializeServingFlags() *ServingEnvironmentFlags { "Set this flag to the MB of memory consumed by your service in resource limit tests. "+ "You service is set with 300 MB memory limit and shoud return a non-200 response when consuming such amount of memory.") + flag.StringVar(&f.RequestHeaders, "request-headers", "", + "Set this flag to add extra HTTP request headers sent to the testing deployed KServices. "+ + "Format: -request-headers=key1,value1,key2,value2") + return &f } + +// RequestHeader returns a http.Header object including key-value header pairs passed via testing flag. +func (f *ServingEnvironmentFlags) RequestHeader() http.Header { + header := make(http.Header) + + if f.RequestHeaders != "" { + headers := strings.Split(f.RequestHeaders, ",") + if len(headers)%2 != 0 { + panic("incorrect input of request headers: " + f.RequestHeaders) + } + + for i := 0; i < len(headers); i += 2 { + header.Add(headers[i], headers[i+1]) + } + } + + return header +} diff --git a/test/prober.go b/test/prober.go index 226c5a59b3e8..b70e77ce2b59 100644 --- a/test/prober.go +++ b/test/prober.go @@ -108,6 +108,7 @@ type manager struct { m sync.RWMutex probes map[*url.URL]Prober transportOptions []spoof.TransportOption + requestOptions []spoof.RequestOption } var _ ProberManager = (*manager)(nil) @@ -149,6 +150,9 @@ func (m *manager) Spawn(url *url.URL) Prober { if err != nil { return fmt.Errorf("failed to generate request: %w", err) } + for _, o := range m.requestOptions { + o(req) + } // We keep polling the domain and accumulate success rates // to ultimately establish the SLI and compare to the SLO. @@ -212,18 +216,28 @@ func (m *manager) Foreach(f func(url *url.URL, p Prober)) { } // NewProberManager creates a new manager for probes. -func NewProberManager(logf logging.FormatLogger, clients *Clients, minProbes int64, opts ...spoof.TransportOption) ProberManager { - return &manager{ +func NewProberManager(logf logging.FormatLogger, clients *Clients, minProbes int64, opts ...interface{}) ProberManager { + m := manager{ logf: logf, clients: clients, minProbes: minProbes, probes: make(map[*url.URL]Prober), - transportOptions: opts, + transportOptions: []spoof.TransportOption{}, + requestOptions: []spoof.RequestOption{}, + } + for _, opt := range opts { + switch o := opt.(type) { + case spoof.RequestOption: + m.requestOptions = append(m.requestOptions, o) + case spoof.TransportOption: + m.transportOptions = append(m.transportOptions, o) + } } + return &m } // RunRouteProber starts a single Prober of the given domain. -func RunRouteProber(logf logging.FormatLogger, clients *Clients, url *url.URL, opts ...spoof.TransportOption) Prober { +func RunRouteProber(logf logging.FormatLogger, clients *Clients, url *url.URL, opts ...interface{}) Prober { // Default to 10 probes pm := NewProberManager(logf, clients, 10, opts...) pm.Spawn(url)