Merge pull request #131704 from karlkfi/karl-watch-subtests

test: Use sub-tests in watch tests

Kubernetes-commit: 4e80b05087cf26188208f1c80d133566be4eae18
This commit is contained in:
Kubernetes Publisher 2025-05-19 12:45:14 -07:00
commit df39bcd7dd
2 changed files with 644 additions and 604 deletions

View File

@ -808,9 +808,10 @@ func TestNotFound(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
client := http.Client{}
for k, v := range cases {
for testName, test := range cases {
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
request, err := http.NewRequestWithContext(ctx, v.Method, server.URL+v.Path, nil)
request, err := http.NewRequestWithContext(ctx, test.Method, server.URL+test.Path, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -820,9 +821,10 @@ func TestNotFound(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
defer apitesting.Close(t, response.Body)
if response.StatusCode != v.Status {
t.Errorf("Expected %d for %s (%s), Got %#v", v.Status, v.Method, k, response)
if response.StatusCode != test.Status {
t.Errorf("Expected %d for %s, Got %#v", test.Status, test.Method, response)
}
})
}
}
@ -879,9 +881,10 @@ func TestUnimplementedRESTStorage(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
client := http.Client{}
for k, v := range cases {
for testName, test := range cases {
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
request, err := http.NewRequestWithContext(ctx, v.Method, server.URL+v.Path, bytes.NewReader([]byte(`{"kind":"Simple","apiVersion":"version"}`)))
request, err := http.NewRequestWithContext(ctx, test.Method, server.URL+test.Path, bytes.NewReader([]byte(`{"kind":"Simple","apiVersion":"version"}`)))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -895,10 +898,10 @@ func TestUnimplementedRESTStorage(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if response.StatusCode != v.ErrCode {
t.Errorf("%s: expected %d for %s, Got %s", k, v.ErrCode, v.Method, string(data))
continue
if response.StatusCode != test.ErrCode {
t.Fatalf("expected %d for %s, Got %s", test.ErrCode, test.Method, string(data))
}
})
}
}
@ -949,9 +952,10 @@ func TestSomeUnimplementedRESTStorage(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
client := http.Client{}
for k, v := range cases {
for testName, test := range cases {
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
request, err := http.NewRequestWithContext(ctx, v.Method, server.URL+v.Path, bytes.NewReader([]byte(`{"kind":"Simple","apiVersion":"version"}`)))
request, err := http.NewRequestWithContext(ctx, test.Method, server.URL+test.Path, bytes.NewReader([]byte(`{"kind":"Simple","apiVersion":"version"}`)))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -965,15 +969,15 @@ func TestSomeUnimplementedRESTStorage(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if response.StatusCode != v.ErrCode {
t.Errorf("%s: expected %d for %s, Got %s", k, v.ErrCode, v.Method, string(data))
continue
if response.StatusCode != test.ErrCode {
t.Fatalf("expected %d for %s, Got %s", test.ErrCode, test.Method, string(data))
}
})
}
}
func TestList(t *testing.T) {
testCases := []struct {
cases := []struct {
url string
namespace string
legacy bool
@ -1110,45 +1114,46 @@ func TestList(t *testing.T) {
namespace: "",
},
}
for i, testCase := range testCases {
for testIndex, test := range cases {
testName := fmt.Sprintf("%d", testIndex)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{expectedResourceNamespace: testCase.namespace}
simpleStorage := SimpleRESTStorage{expectedResourceNamespace: test.namespace}
storage["simple"] = &simpleStorage
var handler = handleInternal(storage, admissionControl, nil)
server := httptest.NewServer(handler)
defer server.Close()
url := server.URL + testCase.url
url := server.URL + test.url
req, err := http.NewRequestWithContext(ctx, request.MethodGet, url, nil)
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
defer apitesting.Close(t, resp.Body)
if resp.StatusCode != http.StatusOK {
t.Errorf("%d: unexpected status: %d from url %s, Expected: %d, %#v", i, resp.StatusCode, testCase.url, http.StatusOK, resp)
t.Errorf("unexpected status: %d from url %s, Expected: %d, %#v", resp.StatusCode, test.url, http.StatusOK, resp)
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
t.Logf("%d: body: %s", i, string(body))
continue
t.Logf("body: %s", string(body))
return
}
if !simpleStorage.namespacePresent {
t.Errorf("%d: namespace not set", i)
} else if simpleStorage.actualNamespace != testCase.namespace {
t.Errorf("%d: %q unexpected resource namespace: %s", i, testCase.url, simpleStorage.actualNamespace)
t.Error("namespace not set")
} else if simpleStorage.actualNamespace != test.namespace {
t.Errorf("%q unexpected resource namespace: %s", test.url, simpleStorage.actualNamespace)
}
if simpleStorage.requestedLabelSelector == nil || simpleStorage.requestedLabelSelector.String() != testCase.label {
t.Errorf("%d: unexpected label selector: expected=%v got=%v", i, testCase.label, simpleStorage.requestedLabelSelector)
if simpleStorage.requestedLabelSelector == nil || simpleStorage.requestedLabelSelector.String() != test.label {
t.Errorf("unexpected label selector: expected=%v got=%v", test.label, simpleStorage.requestedLabelSelector)
}
if simpleStorage.requestedFieldSelector == nil || simpleStorage.requestedFieldSelector.String() != testCase.field {
t.Errorf("%d: unexpected field selector: expected=%v got=%v", i, testCase.field, simpleStorage.requestedFieldSelector)
if simpleStorage.requestedFieldSelector == nil || simpleStorage.requestedFieldSelector.String() != test.field {
t.Errorf("unexpected field selector: expected=%v got=%v", test.field, simpleStorage.requestedFieldSelector)
}
})
}
}
@ -1162,7 +1167,7 @@ func TestRequestsWithInvalidQuery(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
for i, test := range []struct {
for _, test := range []struct {
postfix string
method string
}{
@ -1173,34 +1178,34 @@ func TestRequestsWithInvalidQuery(t *testing.T) {
// {"/simple/foo?resourceVersion=<invalid>", request.MethodGet}, TODO: there is no invalid resourceVersion. Should we be more strict?
// {"/withoptions?labelSelector=<invalid>", request.MethodGet}, TODO: SimpleGetOptions is always valid. Add more validation that can fail.
} {
testName := fmt.Sprintf("%s:%s", test.method, test.postfix)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
baseURL := server.URL + "/" + grouplessPrefix + "/" + grouplessGroupVersion.Version + "/namespaces/default"
url := baseURL + test.postfix
r, err := http.NewRequestWithContext(ctx, test.method, url, nil)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
resp, err := http.DefaultClient.Do(r)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
defer apitesting.Close(t, resp.Body)
if resp.StatusCode != http.StatusBadRequest {
t.Errorf("%d: unexpected status: %d from url %s, Expected: %d, %#v", i, resp.StatusCode, url, http.StatusBadRequest, resp)
t.Errorf("unexpected status: %d from url %s, Expected: %d, %#v", resp.StatusCode, url, http.StatusBadRequest, resp)
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
t.Logf("%d: body: %s", i, string(body))
t.Logf("body: %s", string(body))
}
})
}
}
func TestListCompression(t *testing.T) {
testCases := []struct {
cases := []struct {
url string
namespace string
legacy bool
@ -1220,11 +1225,12 @@ func TestListCompression(t *testing.T) {
acceptEncoding: "gzip",
},
}
for i, testCase := range testCases {
for testIndex, test := range cases {
t.Run(test.acceptEncoding, func(t *testing.T) {
ctx := t.Context()
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{
expectedResourceNamespace: testCase.namespace,
expectedResourceNamespace: test.namespace,
list: []genericapitesting.Simple{
{Other: strings.Repeat("0123456789abcdef", (128*1024/16)+1)},
},
@ -1238,45 +1244,42 @@ func TestListCompression(t *testing.T) {
defer server.Close()
req, err := http.NewRequestWithContext(ctx, request.MethodGet, server.URL+testCase.url, nil)
req, err := http.NewRequestWithContext(ctx, request.MethodGet, server.URL+test.url, nil)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("%d: unexpected error: %v", testIndex, err)
}
// It's necessary to manually set Accept-Encoding here
// to prevent http.DefaultClient from automatically
// decoding responses
req.Header.Set("Accept-Encoding", testCase.acceptEncoding)
req.Header.Set("Accept-Encoding", test.acceptEncoding)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("%d: unexpected error: %v", testIndex, err)
}
defer apitesting.Close(t, resp.Body)
if resp.StatusCode != http.StatusOK {
t.Errorf("%d: unexpected status: %d from url %s, Expected: %d, %#v", i, resp.StatusCode, testCase.url, http.StatusOK, resp)
t.Errorf("unexpected status: %d from url %s, Expected: %d, %#v", resp.StatusCode, test.url, http.StatusOK, resp)
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
t.Fatalf("unexpected error: %v", err)
}
t.Logf("%d: body: %s", i, string(body))
continue
t.Logf("body: %s", string(body))
return
}
if !simpleStorage.namespacePresent {
t.Errorf("%d: namespace not set", i)
} else if simpleStorage.actualNamespace != testCase.namespace {
t.Errorf("%d: %q unexpected resource namespace: %s", i, testCase.url, simpleStorage.actualNamespace)
t.Error("namespace not set")
} else if simpleStorage.actualNamespace != test.namespace {
t.Errorf("%q unexpected resource namespace: %s", test.url, simpleStorage.actualNamespace)
}
if simpleStorage.requestedLabelSelector == nil || simpleStorage.requestedLabelSelector.String() != testCase.label {
t.Errorf("%d: unexpected label selector: %v", i, simpleStorage.requestedLabelSelector)
if simpleStorage.requestedLabelSelector == nil || simpleStorage.requestedLabelSelector.String() != test.label {
t.Errorf("unexpected label selector: %v", simpleStorage.requestedLabelSelector)
}
if simpleStorage.requestedFieldSelector == nil || simpleStorage.requestedFieldSelector.String() != testCase.field {
t.Errorf("%d: unexpected field selector: %v", i, simpleStorage.requestedFieldSelector)
if simpleStorage.requestedFieldSelector == nil || simpleStorage.requestedFieldSelector.String() != test.field {
t.Errorf("unexpected field selector: %v", simpleStorage.requestedFieldSelector)
}
var decoder *json.Decoder
if testCase.acceptEncoding == "gzip" {
if test.acceptEncoding == "gzip" {
gzipReader, err := gzip.NewReader(resp.Body)
if err != nil {
t.Fatalf("unexpected error creating gzip reader: %v", err)
@ -1290,6 +1293,7 @@ func TestListCompression(t *testing.T) {
if err != nil {
t.Errorf("failed to read response body as SimpleList: %v", err)
}
})
}
}
@ -1482,6 +1486,8 @@ func BenchmarkGet(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Use a closure to execute defers before continuing
func() {
req, err := http.NewRequestWithContext(ctx, request.MethodGet, url, nil)
require.NoError(b, err)
resp, err := http.DefaultClient.Do(req)
@ -1495,11 +1501,13 @@ func BenchmarkGet(b *testing.B) {
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
b.Fatalf("unable to read body")
}
}()
}
b.StopTimer()
}
func BenchmarkGetNoCompression(b *testing.B) {
ctx := b.Context()
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{
item: genericapitesting.Simple{
@ -1517,11 +1525,19 @@ func BenchmarkGetNoCompression(b *testing.B) {
},
}
u := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id"
url := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id"
b.ResetTimer()
for i := 0; i < b.N; i++ {
resp, err := client.Get(u)
// Use a closure to execute defers before continuing
func() {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
req, err := http.NewRequestWithContext(ctx, request.MethodGet, url, nil)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
resp, err := client.Do(req)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
@ -1532,6 +1548,7 @@ func BenchmarkGetNoCompression(b *testing.B) {
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
b.Fatalf("unable to read body")
}
}()
}
b.StopTimer()
}
@ -1550,14 +1567,16 @@ func TestGetCompression(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
tests := []struct {
cases := []struct {
acceptEncoding string
}{
{acceptEncoding: ""},
{acceptEncoding: "gzip"},
}
for _, test := range tests {
for _, test := range cases {
testName := fmt.Sprintf("Accept-Encoding:%s", test.acceptEncoding)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
req, err := http.NewRequestWithContext(ctx, request.MethodGet, server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/id", nil)
if err != nil {
@ -1598,6 +1617,7 @@ func TestGetCompression(t *testing.T) {
if itemOut.Name != simpleStorage.item.Name {
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body))
}
})
}
}
@ -1613,7 +1633,7 @@ func TestGetPretty(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
tests := []struct {
cases := []struct {
accept string
userAgent string
params url.Values
@ -1631,7 +1651,15 @@ func TestGetPretty(t *testing.T) {
{pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"1"}}},
{pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"true"}}},
}
for i, test := range tests {
for _, test := range cases {
testName := fmt.Sprintf("Accept:%s", test.accept)
if test.userAgent != "" {
testName += fmt.Sprintf(" User-Agent:%s", test.userAgent)
}
if len(test.params) > 0 {
testName += fmt.Sprintf(" Params:%s", test.params.Encode())
}
t.Run(testName, func(t *testing.T) {
u, err := url.Parse(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id")
if err != nil {
t.Fatal(err)
@ -1673,8 +1701,9 @@ func TestGetPretty(t *testing.T) {
expect = string(out) + "\n"
}
if expect != body {
t.Errorf("%d: body did not match expected:\n%s\n%s", i, body, expect)
t.Errorf("body did not match expected:\n%s\n%s", body, expect)
}
})
}
}
@ -1714,7 +1743,7 @@ func TestGetTable(t *testing.T) {
metaDoc := metav1.ObjectMeta{}.SwaggerDoc()
tests := []struct {
cases := []struct {
accept string
params url.Values
pretty bool
@ -1815,8 +1844,9 @@ func TestGetTable(t *testing.T) {
},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
for testIndex, test := range cases {
testName := fmt.Sprintf("%d", testIndex)
t.Run(testName, func(t *testing.T) {
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{
item: obj,
@ -1845,20 +1875,20 @@ func TestGetTable(t *testing.T) {
}
if test.statusCode != 0 {
if resp.StatusCode != test.statusCode {
t.Errorf("%d: unexpected response: %#v", i, resp)
t.Errorf("unexpected response: %#v", resp)
}
obj, _, err := extractBodyObject(resp, unstructured.UnstructuredJSONScheme)
if err != nil {
t.Fatalf("%d: unexpected body read error: %v", i, err)
t.Fatalf("unexpected body read error: %v", err)
}
gvk := schema.GroupVersionKind{Version: "v1", Kind: "Status"}
if obj.GetObjectKind().GroupVersionKind() != gvk {
t.Fatalf("%d: unexpected error body: %#v", i, obj)
t.Fatalf("unexpected error body: %#v", obj)
}
return
}
if resp.StatusCode != http.StatusOK {
t.Errorf("%d: unexpected response: %#v", i, resp)
t.Errorf("unexpected response: %#v", resp)
}
var itemOut metav1.Table
body, err := extractBody(resp, &itemOut)
@ -1867,7 +1897,7 @@ func TestGetTable(t *testing.T) {
}
if !reflect.DeepEqual(test.expected, &itemOut) {
t.Log(body)
t.Errorf("%d: did not match: %s", i, cmp.Diff(test.expected, &itemOut))
t.Errorf("did not match: %s", cmp.Diff(test.expected, &itemOut))
}
})
}
@ -1903,7 +1933,7 @@ func TestWatchTable(t *testing.T) {
s := metainternalversionscheme.Codecs.SupportedMediaTypes()[0].Serializer
tests := []struct {
cases := []struct {
accept string
params url.Values
send func(w *watch.FakeWatcher)
@ -2016,8 +2046,9 @@ func TestWatchTable(t *testing.T) {
},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
for testIndex, test := range cases {
testName := fmt.Sprintf("%d", testIndex)
t.Run(testName, func(t *testing.T) {
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{
item: obj,
@ -2056,20 +2087,20 @@ func TestWatchTable(t *testing.T) {
defer apitesting.Close(t, resp.Body)
if test.statusCode != 0 {
if resp.StatusCode != test.statusCode {
t.Fatalf("%d: unexpected response: %#v", i, resp)
t.Fatalf("unexpected response: %#v", resp)
}
obj, _, err := extractBodyObject(resp, unstructured.UnstructuredJSONScheme)
if err != nil {
t.Fatalf("%d: unexpected body read error: %v", i, err)
t.Fatalf("unexpected body read error: %v", err)
}
gvk := schema.GroupVersionKind{Version: "v1", Kind: "Status"}
if obj.GetObjectKind().GroupVersionKind() != gvk {
t.Fatalf("%d: unexpected error body: %#v", i, obj)
t.Fatalf("unexpected error body: %#v", obj)
}
return
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("%d: unexpected response: %#v", i, resp)
t.Fatalf("unexpected response: %#v", resp)
}
go func() {
@ -2137,7 +2168,7 @@ func TestGetPartialObjectMetadata(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
tests := []struct {
cases := []struct {
accept string
params url.Values
pretty bool
@ -2231,7 +2262,9 @@ func TestGetPartialObjectMetadata(t *testing.T) {
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadataList", Group: "meta.k8s.io", Version: "v1beta1"},
},
}
for i, test := range tests {
for testIndex, test := range cases {
testName := fmt.Sprintf("%d", testIndex)
t.Run(testName, func(t *testing.T) {
suffix := "/namespaces/default/simple/id"
if test.list {
suffix = "/namespaces/default/simple"
@ -2251,22 +2284,20 @@ func TestGetPartialObjectMetadata(t *testing.T) {
defer apitesting.Close(t, resp.Body)
if test.statusCode != 0 {
if resp.StatusCode != test.statusCode {
t.Errorf("%d: unexpected response: %#v", i, resp)
t.Errorf("unexpected response: %#v", resp)
}
obj, _, err := extractBodyObject(resp, unstructured.UnstructuredJSONScheme)
if err != nil {
t.Errorf("%d: unexpected body read error: %v", i, err)
continue
t.Fatalf("unexpected body read error: %v", err)
}
gvk := schema.GroupVersionKind{Version: "v1", Kind: "Status"}
if obj.GetObjectKind().GroupVersionKind() != gvk {
t.Errorf("%d: unexpected error body: %#v", i, obj)
t.Errorf("unexpected error body: %#v", obj)
}
continue
return
}
if resp.StatusCode != http.StatusOK {
t.Errorf("%d: invalid status: %#v\n%s", i, resp, bodyOrDie(resp))
continue
t.Fatalf("invalid status: %#v\n%s", resp, bodyOrDie(resp))
}
body := ""
if test.expected != nil {
@ -2275,7 +2306,7 @@ func TestGetPartialObjectMetadata(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(test.expected, itemOut) {
t.Errorf("%d: did not match: %s", i, cmp.Diff(test.expected, itemOut))
t.Errorf("did not match: %s", cmp.Diff(test.expected, itemOut))
}
body = d
} else {
@ -2290,8 +2321,9 @@ func TestGetPartialObjectMetadata(t *testing.T) {
t.Fatal(err)
}
if obj.GetObjectKind().GroupVersionKind() != test.expectKind {
t.Errorf("%d: unexpected kind: %#v", i, obj.GetObjectKind().GroupVersionKind())
t.Errorf("unexpected kind: %#v", obj.GetObjectKind().GroupVersionKind())
}
})
}
}
@ -2373,7 +2405,7 @@ func TestGetWithOptionsRouteParams(t *testing.T) {
func TestGetWithOptions(t *testing.T) {
tests := []struct {
cases := []struct {
name string
rootScoped bool
requestURL string
@ -2424,7 +2456,8 @@ func TestGetWithOptions(t *testing.T) {
},
}
for _, test := range tests {
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
ctx := t.Context()
simpleStorage := GetWithOptionsRESTStorage{
SimpleRESTStorage: &SimpleRESTStorage{
@ -2461,13 +2494,11 @@ func TestGetWithOptions(t *testing.T) {
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Errorf("%s: %v", test.name, err)
continue
t.Fatalf("%s: %v", test.name, err)
}
defer apitesting.Close(t, resp.Body)
if resp.StatusCode != http.StatusOK {
t.Errorf("%s: unexpected response: %#v", test.name, resp)
continue
t.Fatalf("%s: unexpected response: %#v", test.name, resp)
}
var itemOut runtime.Object
@ -2478,16 +2509,14 @@ func TestGetWithOptions(t *testing.T) {
}
body, err := extractBody(resp, itemOut)
if err != nil {
t.Errorf("%s: %v", test.name, err)
continue
t.Fatalf("%s: %v", test.name, err)
}
if metadata, err := meta.Accessor(itemOut); err == nil {
if metadata.GetName() != simpleStorage.item.Name {
t.Errorf("%s: Unexpected data: %#v, expected %#v (%s)", test.name, itemOut, simpleStorage.item, string(body))
continue
t.Fatalf("%s: Unexpected data: %#v, expected %#v (%s)", test.name, itemOut, simpleStorage.item, string(body))
}
} else {
t.Errorf("%s: Couldn't get name from %#v: %v", test.name, itemOut, err)
t.Errorf("Couldn't get name from %#v: %v", itemOut, err)
}
var opts *genericapitesting.SimpleGetOptions
@ -2499,17 +2528,15 @@ func TestGetWithOptions(t *testing.T) {
}
if !ok {
t.Errorf("%s: Unexpected options object received: %#v", test.name, simpleStorage.optionsReceived)
continue
t.Fatalf("Unexpected options object received: %#v", simpleStorage.optionsReceived)
}
if opts.Param1 != "test1" || opts.Param2 != "test2" {
t.Errorf("%s: Did not receive expected options: %#v", test.name, opts)
continue
t.Fatalf("Did not receive expected options: %#v", opts)
}
if opts.Path != test.expectedPath {
t.Errorf("%s: Unexpected path value. Expected: %s. Actual: %s.", test.name, test.expectedPath, opts.Path)
continue
t.Fatalf("Unexpected path value. Expected: %s. Actual: %s.", test.expectedPath, opts.Path)
}
})
}
}
@ -2988,9 +3015,9 @@ func TestDeleteWithOptionsQueryAndBody(t *testing.T) {
func TestDeleteInvokesAdmissionControl(t *testing.T) {
// TODO: remove mutating deny when we removed it from the endpoint implementation and ported all plugins
for _, admit := range []admission.Interface{alwaysMutatingDeny{}, alwaysValidatingDeny{}} {
t.Logf("Testing %T", admit)
testName := fmt.Sprintf("%T", admit)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{}
ID := "id"
@ -3012,6 +3039,7 @@ func TestDeleteInvokesAdmissionControl(t *testing.T) {
if response.StatusCode != http.StatusForbidden {
t.Errorf("Unexpected response %#v", response)
}
})
}
}
@ -3085,7 +3113,8 @@ func TestUpdate(t *testing.T) {
func TestUpdateInvokesAdmissionControl(t *testing.T) {
for _, admit := range []admission.Interface{alwaysMutatingDeny{}, alwaysValidatingDeny{}} {
t.Logf("Testing %T", admit)
testName := fmt.Sprintf("%T", admit)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
storage := map[string]rest.Storage{}
@ -3125,6 +3154,7 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) {
if response.StatusCode != http.StatusForbidden {
t.Errorf("Unexpected response %#v", response)
}
})
}
}
@ -3855,9 +3885,9 @@ func TestCreateInNamespace(t *testing.T) {
func TestCreateInvokeAdmissionControl(t *testing.T) {
for _, admit := range []admission.Interface{alwaysMutatingDeny{}, alwaysValidatingDeny{}} {
t.Logf("Testing %T", admit)
testName := fmt.Sprintf("%T", admit)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
storage := SimpleRESTStorage{
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
time.Sleep(5 * time.Millisecond)
@ -3890,6 +3920,7 @@ func TestCreateInvokeAdmissionControl(t *testing.T) {
if response.StatusCode != http.StatusForbidden {
t.Errorf("Unexpected status: %d, Expected: %d, %#v", response.StatusCode, http.StatusForbidden, response)
}
})
}
}
@ -4201,7 +4232,7 @@ unknown: baz`)
invalidSMP = []byte(`{"unknown": "foo", "other":"foo", "other": "bar"}`)
fieldValidationTests = []struct {
cases = []struct {
name string
path string
verb string
@ -4268,7 +4299,7 @@ unknown: baz`)
},
}))
defer server.Close()
for _, test := range fieldValidationTests {
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
baseURL := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version
response := runRequest(t, baseURL+test.path+test.queryParams, test.verb, test.data, test.contentType)
@ -4548,6 +4579,8 @@ func BenchmarkUpdateProtobuf(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Use a closure to execute defers before continuing
func() {
request, err := http.NewRequestWithContext(ctx, request.MethodPut, dest.String(), bytes.NewReader(data))
if err != nil {
b.Fatalf("unexpected error: %v", err)
@ -4564,7 +4597,7 @@ func BenchmarkUpdateProtobuf(b *testing.B) {
b.Fatalf("Unexpected response %#v\n%s", response, body)
}
_, _ = io.ReadAll(response.Body)
response.Body.Close()
}()
}
b.StopTimer()
}

View File

@ -18,6 +18,7 @@ package endpoints
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
@ -268,7 +269,6 @@ func TestWatchClientClose(t *testing.T) {
}
func TestWatchRead(t *testing.T) {
ctx := t.Context()
simpleStorage := &SimpleRESTStorage{}
_ = rest.Watcher(simpleStorage) // Give compile error if this doesn't work.
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
@ -279,7 +279,7 @@ func TestWatchRead(t *testing.T) {
dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simples"
dest.RawQuery = "watch=1"
connectHTTP := func(accept string) (io.ReadCloser, string) {
connectHTTP := func(ctx context.Context, accept string) (io.ReadCloser, string) {
client := http.Client{}
request, err := http.NewRequestWithContext(ctx, request.MethodGet, dest.String(), nil)
if err != nil {
@ -299,7 +299,7 @@ func TestWatchRead(t *testing.T) {
return response.Body, response.Header.Get("Content-Type")
}
connectWebSocket := func(accept string) (io.ReadCloser, string) {
connectWebSocket := func(ctx context.Context, accept string) (io.ReadCloser, string) {
dest := *dest
dest.Scheme = "ws" // Required by websocket, though the server never sees it.
config, err := websocket.NewConfig(dest.String(), "http://localhost")
@ -307,14 +307,14 @@ func TestWatchRead(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
config.Header.Add("Accept", accept)
ws, err := websocket.DialConfig(config)
ws, err := config.DialContext(ctx)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
return ws, "__default__"
}
testCases := []struct {
cases := []struct {
Accept string
ExpectedContentType string
MediaType string
@ -351,22 +351,24 @@ func TestWatchRead(t *testing.T) {
protocols := []struct {
name string
selfFraming bool
fn func(string) (io.ReadCloser, string)
fn func(context.Context, string) (io.ReadCloser, string)
}{
{name: "http", fn: connectHTTP},
{name: "websocket", selfFraming: true, fn: connectWebSocket},
}
for _, protocol := range protocols {
for _, test := range testCases {
func() {
for textIndex, test := range cases {
testName := fmt.Sprintf("%s-%d", protocol.name, textIndex)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), test.MediaType)
if !ok || info.StreamSerializer == nil {
t.Fatal(info)
}
streamSerializer := info.StreamSerializer
r, contentType := protocol.fn(test.Accept)
r, contentType := protocol.fn(ctx, test.Accept)
closeBody := apitesting.Close
defer func() {
closeBody(t, r)
@ -424,7 +426,7 @@ func TestWatchRead(t *testing.T) {
if err == nil {
t.Errorf("Unexpected non-error")
}
}()
})
}
}
}
@ -472,7 +474,7 @@ func TestWatchParamParsing(t *testing.T) {
rootPath := "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples"
namespacedPath := "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/namespaces/other/simpleroots"
table := []struct {
cases := []struct {
path string
rawQuery string
resourceVersion string
@ -540,35 +542,37 @@ func TestWatchParamParsing(t *testing.T) {
},
}
for _, item := range table {
for testIndex, test := range cases {
testName := fmt.Sprintf("%d", testIndex)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
simpleStorage.requestedLabelSelector = labels.Everything()
simpleStorage.requestedFieldSelector = fields.Everything()
simpleStorage.requestedResourceVersion = "5" // Prove this is set in all cases
simpleStorage.requestedResourceNamespace = ""
dest.Path = item.path
dest.RawQuery = item.rawQuery
dest.Path = test.path
dest.RawQuery = test.rawQuery
req, err := http.NewRequestWithContext(ctx, request.MethodGet, dest.String(), nil)
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Errorf("%v: unexpected error: %v", item.rawQuery, err)
continue
t.Fatalf("%v: unexpected error: %v", test.rawQuery, err)
}
defer apitesting.Close(t, resp.Body)
if e, a := item.namespace, simpleStorage.requestedResourceNamespace; e != a {
t.Errorf("%v: expected %v, got %v", item.rawQuery, e, a)
if e, a := test.namespace, simpleStorage.requestedResourceNamespace; e != a {
t.Errorf("%v: expected %v, got %v", test.rawQuery, e, a)
}
if e, a := item.resourceVersion, simpleStorage.requestedResourceVersion; e != a {
t.Errorf("%v: expected %v, got %v", item.rawQuery, e, a)
if e, a := test.resourceVersion, simpleStorage.requestedResourceVersion; e != a {
t.Errorf("%v: expected %v, got %v", test.rawQuery, e, a)
}
if e, a := item.labelSelector, simpleStorage.requestedLabelSelector.String(); e != a {
t.Errorf("%v: expected %v, got %v", item.rawQuery, e, a)
if e, a := test.labelSelector, simpleStorage.requestedLabelSelector.String(); e != a {
t.Errorf("%v: expected %v, got %v", test.rawQuery, e, a)
}
if e, a := item.fieldSelector, simpleStorage.requestedFieldSelector.String(); e != a {
t.Errorf("%v: expected %v, got %v", item.rawQuery, e, a)
if e, a := test.fieldSelector, simpleStorage.requestedFieldSelector.String(); e != a {
t.Errorf("%v: expected %v, got %v", test.rawQuery, e, a)
}
})
}
}
@ -584,7 +588,7 @@ func TestWatchProtocolSelection(t *testing.T) {
dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/watch/simples"
dest.RawQuery = ""
table := []struct {
cases := []struct {
isWebsocket bool
connHeader string
}{
@ -594,13 +598,15 @@ func TestWatchProtocolSelection(t *testing.T) {
{false, "keep-alive"},
}
for _, item := range table {
for _, test := range cases {
testName := fmt.Sprintf("websocket:%v header:%s", test.isWebsocket, test.connHeader)
t.Run(testName, func(t *testing.T) {
ctx := t.Context()
request, err := http.NewRequestWithContext(ctx, request.MethodGet, dest.String(), nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
request.Header.Set("Connection", item.connHeader)
request.Header.Set("Connection", test.connHeader)
request.Header.Set("Upgrade", "websocket")
response, err := client.Do(request)
@ -611,13 +617,14 @@ func TestWatchProtocolSelection(t *testing.T) {
// The requests recognized as websocket requests based on connection
// and upgrade headers will not also have the necessary Sec-Websocket-*
// headers so it is expected to throw a 400
if item.isWebsocket && response.StatusCode != http.StatusBadRequest {
if test.isWebsocket && response.StatusCode != http.StatusBadRequest {
t.Errorf("Unexpected response %#v", response)
}
if !item.isWebsocket && response.StatusCode != http.StatusOK {
if !test.isWebsocket && response.StatusCode != http.StatusOK {
t.Errorf("Unexpected response %#v", response)
}
})
}
}