From f350a976c61cf1b2d2a633d96245e3cf20814bb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 06:50:52 +0000 Subject: [PATCH 1/7] refactor: centralize shared test suite helpers in lib package Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- test/suites/connector/helpers_auth.go | 22 ++ test/suites/connector/helpers_config.go | 19 + test/suites/connector/helpers_http.go | 25 ++ test/suites/connector/helpers_shared.go | 46 +++ test/suites/connector/lib.go | 157 -------- test/suites/integration/helpers_auth.go | 51 +++ test/suites/integration/helpers_http.go | 181 +++++++++ test/suites/integration/helpers_shared.go | 58 +++ test/suites/integration/helpers_state.go | 68 ++++ test/suites/integration/lib.go | 426 ---------------------- test/suites/lib/assertions.go | 35 ++ test/suites/lib/cookies.go | 47 +++ test/suites/lib/environment.go | 94 +++++ test/suites/security/helpers_config.go | 21 ++ test/suites/security/helpers_shared.go | 46 +++ test/suites/security/helpers_tls.go | 80 ++++ test/suites/security/lib.go | 204 ----------- 17 files changed, 793 insertions(+), 787 deletions(-) create mode 100644 test/suites/connector/helpers_auth.go create mode 100644 test/suites/connector/helpers_config.go create mode 100644 test/suites/connector/helpers_http.go create mode 100644 test/suites/connector/helpers_shared.go delete mode 100644 test/suites/connector/lib.go create mode 100644 test/suites/integration/helpers_auth.go create mode 100644 test/suites/integration/helpers_http.go create mode 100644 test/suites/integration/helpers_shared.go create mode 100644 test/suites/integration/helpers_state.go delete mode 100644 test/suites/integration/lib.go create mode 100644 test/suites/lib/assertions.go create mode 100644 test/suites/lib/cookies.go create mode 100644 test/suites/lib/environment.go create mode 100644 test/suites/security/helpers_config.go create mode 100644 test/suites/security/helpers_shared.go create mode 100644 test/suites/security/helpers_tls.go delete mode 100644 test/suites/security/lib.go diff --git a/test/suites/connector/helpers_auth.go b/test/suites/connector/helpers_auth.go new file mode 100644 index 0000000..30d2d2d --- /dev/null +++ b/test/suites/connector/helpers_auth.go @@ -0,0 +1,22 @@ +package connector + +import ( + "net/http" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +func loginAndGetSessionCookie(t *testing.T) *http.Cookie { + loginResponse, err := adminClient.LoginWithResponse(t.Context(), adminapi.LoginJSONRequestBody{ + Username: adminUser, + Password: adminUserPassword, + }) + checkErr(err, t) + verifyStatusCode(loginResponse.StatusCode(), http.StatusNoContent, t) + + sessionCookie, err := extractSessionCookie(loginResponse.HTTPResponse) + checkErr(err, t) + + return sessionCookie +} diff --git a/test/suites/connector/helpers_config.go b/test/suites/connector/helpers_config.go new file mode 100644 index 0000000..1486801 --- /dev/null +++ b/test/suites/connector/helpers_config.go @@ -0,0 +1,19 @@ +package connector + +import ( + "fmt" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +const ( + adminUser = "connector-admin" + adminUserPassword = "connector-admin-password" + + superUserClientID = "admin" + superUserClientSecret = "secret" +) + +var adminClient, _ = adminapi.NewClientWithResponses( + fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), +) diff --git a/test/suites/connector/helpers_http.go b/test/suites/connector/helpers_http.go new file mode 100644 index 0000000..9fc81c9 --- /dev/null +++ b/test/suites/connector/helpers_http.go @@ -0,0 +1,25 @@ +package connector + +import ( + "net/http" + "testing" +) + +func options(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodOptions, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + for _, h := range headers { + for key, values := range h { + req.Header[key] = values + } + } + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + t.Fatalf("failed to send request: %v", err) + } + return resp +} diff --git a/test/suites/connector/helpers_shared.go b/test/suites/connector/helpers_shared.go new file mode 100644 index 0000000..2443321 --- /dev/null +++ b/test/suites/connector/helpers_shared.go @@ -0,0 +1,46 @@ +package connector + +import ( + "net/http" + "testing" + + testlib "github.com/trebent/kerberos/test/lib" +) + +type RequestEditorFn = testlib.RequestEditorFn + +func checkErr(err error, t *testing.T) { + testlib.CheckErr(err, t) +} + +func verifyStatusCode(in int, expected int, t *testing.T) { + testlib.VerifyStatusCode(in, expected, t) +} + +func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { + testlib.VerifyHeader(headers, key, expectedValue, t) +} + +func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { + testlib.VerifyHeaderMissing(headers, key, t) +} + +func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { + return testlib.ExtractSessionCookie(resp) +} + +func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { + return testlib.MakeRequestEditorFromCookie(cookie) +} + +func getHost() string { + return testlib.GetHost() +} + +func getAdminPort() int { + return testlib.GetAdminPort() +} + +func getConnectorPort() int { + return testlib.GetConnectorPort() +} diff --git a/test/suites/connector/lib.go b/test/suites/connector/lib.go deleted file mode 100644 index f857f20..0000000 --- a/test/suites/connector/lib.go +++ /dev/null @@ -1,157 +0,0 @@ -package connector - -import ( - "context" - "fmt" - "net/http" - "os" - "strconv" - "testing" - - adminapi "github.com/trebent/kerberos/test/client/admin" -) - -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -const ( - adminUser = "connector-admin" - adminUserPassword = "connector-admin-password" - - superUserClientID = "admin" - superUserClientSecret = "secret" - - defaultHost = "localhost" - defaultAdminPort = 30001 - defaultConnectorPort = 30100 -) - -var adminClient, _ = adminapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), -) - -func loginAndGetSessionCookie(t *testing.T) *http.Cookie { - loginResponse, err := adminClient.LoginWithResponse(t.Context(), adminapi.LoginJSONRequestBody{ - Username: adminUser, - Password: adminUserPassword, - }) - checkErr(err, t) - verifyStatusCode(loginResponse.StatusCode(), http.StatusNoContent, t) - - sessionCookie, err := extractSessionCookie(loginResponse.HTTPResponse) - checkErr(err, t) - - return sessionCookie -} - -func getHost() string { - hostVal, found := os.LookupEnv("KRB_FT_HOST") - if !found { - return defaultHost - } else { - return hostVal - } -} - -func getAdminPort() int { - val, found := os.LookupEnv("KRB_FT_ADMIN_PORT") - if !found { - return defaultAdminPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultAdminPort - } else { - return decoded - } -} - -func getConnectorPort() int { - val, found := os.LookupEnv("KRB_FT_CONNECTOR_PORT") - if !found { - return defaultConnectorPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultConnectorPort - } else { - return decoded - } -} - -func checkErr(err error, t *testing.T) { - t.Helper() - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - t.Helper() - if in != expected { - t.Fatalf("Expected status code %d, got %d", expected, in) - } -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - t.Helper() - actualValue := headers.Get(key) - if actualValue != expectedValue { - t.Fatalf("Expected header %s to have value %s, got %s", key, expectedValue, actualValue) - } -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - t.Helper() - if headers.Get(key) != "" { - t.Fatalf("Expected header %s to be missing, but it was present", key) - } -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - cookies := resp.Cookies() - if len(cookies) == 0 { - return nil, fmt.Errorf("no cookies found in response") - } - - var sessionCookie *http.Cookie - for _, cookie := range cookies { - if cookie.Name == "session" { - sessionCookie = cookie - break - } - } - - if sessionCookie == nil { - return nil, fmt.Errorf("session cookie not found in response") - } - - return sessionCookie, nil -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return func(ctx context.Context, req *http.Request) error { - req.AddCookie(cookie) - return nil - } -} - -func options(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodOptions, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - for _, h := range headers { - for key, values := range h { - req.Header[key] = values - } - } - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - t.Fatalf("failed to send request: %v", err) - } - return resp -} diff --git a/test/suites/integration/helpers_auth.go b/test/suites/integration/helpers_auth.go new file mode 100644 index 0000000..1649f9d --- /dev/null +++ b/test/suites/integration/helpers_auth.go @@ -0,0 +1,51 @@ +package integration + +import ( + "net/http" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +func refreshCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { + t.Helper() + refreshCookie, err := extractRefreshCookie(response) + if err != nil { + t.Fatalf("failed to extract refresh cookie: %v", err) + } + + return makeRequestEditorFromCookie(refreshCookie) +} + +func sessionCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { + sessionCookie, err := extractSessionCookie(response) + if err != nil { + t.Fatalf("failed to extract session cookie: %v", err) + } + + return makeRequestEditorFromCookie(sessionCookie) +} + +// superLogin logs in as the superuser and returns a request editor to use. +func superLogin(t *testing.T) RequestEditorFn { + t.Helper() + resp, err := adminClient.LoginSuperuserWithResponse( + t.Context(), + adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, + ) + checkErr(err, t) + verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) + return sessionCookieRequestEditor(resp.HTTPResponse, t) +} + +// adminUserLogin logs in as a non-superuser admin and returns the request editor to use. +func adminUserLogin(t *testing.T, name, pass string) RequestEditorFn { + t.Helper() + resp, err := adminClient.LoginWithResponse( + t.Context(), + adminapi.LoginJSONRequestBody{Username: name, Password: pass}, + ) + checkErr(err, t) + verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) + return sessionCookieRequestEditor(resp.HTTPResponse, t) +} diff --git a/test/suites/integration/helpers_http.go b/test/suites/integration/helpers_http.go new file mode 100644 index 0000000..799411b --- /dev/null +++ b/test/suites/integration/helpers_http.go @@ -0,0 +1,181 @@ +package integration + +import ( + "bytes" + "encoding/json" + "net/http" + "slices" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +type EchoResponse struct { + Method string `json:"method"` + URL string `json:"url"` + Headers map[string][]string `json:"headers"` + Body json.RawMessage `json:"body,omitempty"` +} + +func get(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func protectedGet(url string, t *testing.T, session *http.Cookie) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + req.AddCookie(session) + + return do(req, t) +} + +func post(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func put(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body)) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func delete(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodDelete, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func patch(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodPatch, url, bytes.NewBuffer(body)) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func trace(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodTrace, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func head(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodHead, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func options(url string, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodOptions, url, nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + return do(req, t, headers...) +} + +func do(req *http.Request, t *testing.T, headers ...http.Header) *http.Response { + t.Helper() + for _, headers := range headers { + for key, values := range headers { + req.Header[key] = values + } + } + + resp, err := client.Do(req) + if err != nil { + t.Fatalf("failed to send request: %v", err) + } + + return resp +} + +func verifyGWResponse(resp *http.Response, expectedCode int, t *testing.T) *EchoResponse { + t.Helper() + defer resp.Body.Close() + + if resp.StatusCode != expectedCode { + t.Fatalf("unexpected status code: got %d, want %d", resp.StatusCode, expectedCode) + } + + response := &EchoResponse{} + if err := json.NewDecoder(resp.Body).Decode(response); err != nil { + t.Fatalf("failed to decode response body: %v", err) + } + + return response +} + +func verifyAdminAPIErrorResponse(er *adminapi.APIErrorResponse, t *testing.T) { + t.Helper() + if er != nil { + if len(er.Errors) == 0 { + t.Fatalf("Expected errors in response body, but got empty errors array") + } + } else { + t.Fatalf("Expected error response but got nil") + } +} + +func verifyAuthBasicAPIErrorResponse(er *authbasicapi.APIErrorResponse, t *testing.T) { + t.Helper() + if er != nil { + if len(er.Errors) == 0 { + t.Fatalf("Expected errors in response body, but got empty errors array") + } + } else { + t.Fatalf("Expected error response but got nil") + } +} + +func matches[T comparable](one, two T, t *testing.T) { + t.Helper() + if one != two { + t.Fatalf("%v is not equal to %v", one, two) + } +} + +func containsAll[T comparable](source, reference []T, t *testing.T) { + t.Helper() + for _, item := range source { + if !slices.Contains(reference, item) { + t.Fatalf("Reference slice does not contain %v", item) + } + } +} diff --git a/test/suites/integration/helpers_shared.go b/test/suites/integration/helpers_shared.go new file mode 100644 index 0000000..03160d6 --- /dev/null +++ b/test/suites/integration/helpers_shared.go @@ -0,0 +1,58 @@ +package integration + +import ( + "net/http" + "testing" + + testlib "github.com/trebent/kerberos/test/lib" +) + +type RequestEditorFn = testlib.RequestEditorFn + +func checkErr(err error, t *testing.T) { + testlib.CheckErr(err, t) +} + +func verifyStatusCode(in int, expected int, t *testing.T) { + testlib.VerifyStatusCode(in, expected, t) +} + +func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { + testlib.VerifyHeader(headers, key, expectedValue, t) +} + +func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { + testlib.VerifyHeaderMissing(headers, key, t) +} + +func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { + return testlib.ExtractSessionCookie(resp) +} + +func extractRefreshCookie(resp *http.Response) (*http.Cookie, error) { + return testlib.ExtractRefreshCookie(resp) +} + +func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { + return testlib.MakeRequestEditorFromCookie(cookie) +} + +func getAdminPort() int { + return testlib.GetAdminPort() +} + +func getPort() int { + return testlib.GetPort() +} + +func getHost() string { + return testlib.GetHost() +} + +func getMetricsPort() int { + return testlib.GetMetricsPort() +} + +func getJaegerAPIPort() int { + return testlib.GetJaegerAPIPort() +} diff --git a/test/suites/integration/helpers_state.go b/test/suites/integration/helpers_state.go new file mode 100644 index 0000000..3318c64 --- /dev/null +++ b/test/suites/integration/helpers_state.go @@ -0,0 +1,68 @@ +package integration + +import ( + "fmt" + "net/http" + "sync/atomic" + "time" + + adminapi "github.com/trebent/kerberos/test/client/admin" + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +var ( + client = &http.Client{Timeout: 4 * time.Second} + + basicAuthClient, _ = authbasicapi.NewClientWithResponses( + fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), + ) + adminClient, _ = adminapi.NewClientWithResponses( + fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), + ) + + alwaysOrgID = 0 + alwaysUserID = 0 + alwaysGroupStaffID = 0 + alwaysGroupPlebID = 0 + alwaysGroupDevID = 0 + + // Used to generate unique names. + // This is initialised with a random int32 in TestMain. + a = atomic.Int32{} +) + +const ( + superUserClientID = "admin" + superUserClientSecret = "secret" +) + +const ( + orgNameBase = "Org" + usernameBase = "Smith" + groupNameBase = "Group" + + // Always resource names, used to denote resource that all tests can expect to be present. + // Always resource must never be altered or deleted by test cases, and are set up by test main. + alwaysOrg = "always" + alwaysUser = "always" + alwaysAdminUser = "always" + alwaysUserPassword = "password123" + alwaysGroupStaff = "staff" + alwaysGroupPleb = "pleb" + alwaysGroupDev = "dev" +) + +// Returns a guaranteed unique username. +func username() string { + return fmt.Sprintf("%s-%d", usernameBase, a.Add(1)) +} + +// Returns a guaranteed unique org name. +func orgName() string { + return fmt.Sprintf("%s-%d", orgNameBase, a.Add(1)) +} + +// Returns a guaranteed unique group name. +func groupName() string { + return fmt.Sprintf("%s-%d", groupNameBase, a.Add(1)) +} diff --git a/test/suites/integration/lib.go b/test/suites/integration/lib.go deleted file mode 100644 index 48e1dc1..0000000 --- a/test/suites/integration/lib.go +++ /dev/null @@ -1,426 +0,0 @@ -package integration - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "net/http" - "os" - "slices" - "strconv" - "sync/atomic" - "testing" - "time" - - adminapi "github.com/trebent/kerberos/test/client/admin" - authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" -) - -type ( - EchoResponse struct { - Method string `json:"method"` - URL string `json:"url"` - Headers map[string][]string `json:"headers"` - Body json.RawMessage `json:"body,omitempty"` - } - RequestEditorFn func(ctx context.Context, req *http.Request) error -) - -var ( - client = &http.Client{Timeout: 4 * time.Second} - - basicAuthClient, _ = authbasicapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), - ) - adminClient, _ = adminapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), - ) - - alwaysOrgID = 0 - alwaysUserID = 0 - alwaysGroupStaffID = 0 - alwaysGroupPlebID = 0 - alwaysGroupDevID = 0 - - // Used to generate unique names. - // This is initialised with a random int32 in TestMain. - a = atomic.Int32{} -) - -const ( - superUserClientID = "admin" - superUserClientSecret = "secret" -) - -// Returns a guaranteed unique username. -func username() string { - return fmt.Sprintf("%s-%d", usernameBase, a.Add(1)) -} - -// Returns a guaranteed unique org name. -func orgName() string { - return fmt.Sprintf("%s-%d", orgNameBase, a.Add(1)) -} - -// Returns a guaranteed unique group name. -func groupName() string { - return fmt.Sprintf("%s-%d", groupNameBase, a.Add(1)) -} - -const ( - orgNameBase = "Org" - usernameBase = "Smith" - groupNameBase = "Group" - - // Always resource names, used to denote resource that all tests can expect to be present. - // Always resource must never be altered or deleted by test cases, and are set up by test main. - alwaysOrg = "always" - alwaysUser = "always" - alwaysAdminUser = "always" - alwaysUserPassword = "password123" - alwaysGroupStaff = "staff" - alwaysGroupPleb = "pleb" - alwaysGroupDev = "dev" - - defaultHost = "localhost" - defaultKerberosPort = 30000 - defaultAdminPort = 30001 - defaultMetricsPort = 9464 - defaultJaegerReadAPIPort = 16685 -) - -func get(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func protectedGet(url string, t *testing.T, session *http.Cookie) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - req.AddCookie(session) - - return do(req, t) -} - -func post(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func put(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body)) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func delete(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodDelete, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func patch(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodPatch, url, bytes.NewBuffer(body)) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func trace(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodTrace, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func head(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodHead, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func options(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodOptions, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - - return do(req, t, headers...) -} - -func do(req *http.Request, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - for _, headers := range headers { - for key, values := range headers { - req.Header[key] = values - } - } - - resp, err := client.Do(req) - if err != nil { - t.Fatalf("failed to send request: %v", err) - } - - return resp -} - -func checkErr(err error, t *testing.T) { - t.Helper() - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - t.Helper() - if in != expected { - t.Fatalf("Expected status code %d, got %d", expected, in) - } -} - -func verifyGWResponse(resp *http.Response, expectedCode int, t *testing.T) *EchoResponse { - t.Helper() - defer resp.Body.Close() - - if resp.StatusCode != expectedCode { - t.Fatalf("unexpected status code: got %d, want %d", resp.StatusCode, expectedCode) - } - - response := &EchoResponse{} - if err := json.NewDecoder(resp.Body).Decode(response); err != nil { - t.Fatalf("failed to decode response body: %v", err) - } - - return response -} - -func verifyAdminAPIErrorResponse(er *adminapi.APIErrorResponse, t *testing.T) { - t.Helper() - if er != nil { - if len(er.Errors) == 0 { - t.Fatalf("Expected errors in response body, but got empty errors array") - } - } else { - t.Fatalf("Expected error response but got nil") - } -} - -func verifyAuthBasicAPIErrorResponse(er *authbasicapi.APIErrorResponse, t *testing.T) { - t.Helper() - if er != nil { - if len(er.Errors) == 0 { - t.Fatalf("Expected errors in response body, but got empty errors array") - } - } else { - t.Fatalf("Expected error response but got nil") - } -} - -func matches[T comparable](one, two T, t *testing.T) { - t.Helper() - if one != two { - t.Fatalf("%v is not equal to %v", one, two) - } -} - -func containsAll[T comparable](source, reference []T, t *testing.T) { - t.Helper() - for _, item := range source { - if !slices.Contains(reference, item) { - t.Fatalf("Reference slice does not contain %v", item) - } - } -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - cookies := resp.Cookies() - if len(cookies) == 0 { - return nil, fmt.Errorf("no cookies found in response") - } - - var sessionCookie *http.Cookie - for _, cookie := range cookies { - if cookie.Name == "session" { - sessionCookie = cookie - break - } - } - - if sessionCookie == nil { - return nil, fmt.Errorf("session cookie not found in response") - } - - return sessionCookie, nil -} - -func extractRefreshCookie(resp *http.Response) (*http.Cookie, error) { - for _, cookie := range resp.Cookies() { - if cookie.Name == "refresh" { - return cookie, nil - } - } - return nil, fmt.Errorf("refresh cookie not found in response") -} - -func refreshCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { - t.Helper() - refreshCookie, err := extractRefreshCookie(response) - if err != nil { - t.Fatalf("failed to extract refresh cookie: %v", err) - } - return makeRequestEditorFromCookie(refreshCookie) -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return func(ctx context.Context, req *http.Request) error { - req.AddCookie(cookie) - return nil - } -} - -func sessionCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { - sessionCookie, err := extractSessionCookie(response) - if err != nil { - t.Fatalf("failed to extract session cookie: %v", err) - } - - return makeRequestEditorFromCookie(sessionCookie) -} - -func getAdminPort() int { - val, found := os.LookupEnv("KRB_FT_ADMIN_PORT") - if !found { - return defaultAdminPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultAdminPort - } else { - return decoded - } -} - -func getPort() int { - val, found := os.LookupEnv("KRB_FT_PORT") - if !found { - return defaultKerberosPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultKerberosPort - } else { - return decoded - } -} - -func getHost() string { - hostVal, found := os.LookupEnv("KRB_FT_HOST") - if !found { - return defaultHost - } else { - return hostVal - } -} - -func getMetricsPort() int { - metricsPortVal, found := os.LookupEnv("KRB_FT_METRICS_PORT") - if !found { - return defaultMetricsPort - } - - decodedMetricsPort, err := strconv.Atoi(metricsPortVal) - if err != nil { - return defaultMetricsPort - } else { - return decodedMetricsPort - } -} - -func getJaegerAPIPort() int { - jaegerPortVal, found := os.LookupEnv("KRB_FT_JAEGER_PORT") - if !found { - return defaultJaegerReadAPIPort - } - - decodedJaegerPort, err := strconv.Atoi(jaegerPortVal) - if err != nil { - return defaultJaegerReadAPIPort - } else { - return decodedJaegerPort - } -} - -// superLogin logs in as the superuser and returns a request editor to use. -func superLogin(t *testing.T) RequestEditorFn { - t.Helper() - resp, err := adminClient.LoginSuperuserWithResponse( - t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) - return sessionCookieRequestEditor(resp.HTTPResponse, t) -} - -// adminUserLogin logs in as a non-superuser admin and returns the request editor to use. -func adminUserLogin(t *testing.T, name, pass string) RequestEditorFn { - t.Helper() - resp, err := adminClient.LoginWithResponse( - t.Context(), - adminapi.LoginJSONRequestBody{Username: name, Password: pass}, - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) - return sessionCookieRequestEditor(resp.HTTPResponse, t) -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - t.Helper() - actualValue := headers.Get(key) - if actualValue != expectedValue { - t.Fatalf("Expected header %s to have value %s, got %s", key, expectedValue, actualValue) - } -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - t.Helper() - if headers.Get(key) != "" { - t.Fatalf("Expected header %s to be missing, but it was present", key) - } -} diff --git a/test/suites/lib/assertions.go b/test/suites/lib/assertions.go new file mode 100644 index 0000000..1d1e888 --- /dev/null +++ b/test/suites/lib/assertions.go @@ -0,0 +1,35 @@ +package lib + +import ( + "net/http" + "testing" +) + +func CheckErr(err error, t testing.TB) { + t.Helper() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func VerifyStatusCode(in int, expected int, t testing.TB) { + t.Helper() + if in != expected { + t.Fatalf("Expected status code %d, got %d", expected, in) + } +} + +func VerifyHeader(headers http.Header, key string, expectedValue string, t testing.TB) { + t.Helper() + actualValue := headers.Get(key) + if actualValue != expectedValue { + t.Fatalf("Expected header %s to have value %s, got %s", key, expectedValue, actualValue) + } +} + +func VerifyHeaderMissing(headers http.Header, key string, t testing.TB) { + t.Helper() + if headers.Get(key) != "" { + t.Fatalf("Expected header %s to be missing, but it was present", key) + } +} diff --git a/test/suites/lib/cookies.go b/test/suites/lib/cookies.go new file mode 100644 index 0000000..2093544 --- /dev/null +++ b/test/suites/lib/cookies.go @@ -0,0 +1,47 @@ +package lib + +import ( + "context" + "fmt" + "net/http" +) + +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +func ExtractSessionCookie(resp *http.Response) (*http.Cookie, error) { + cookies := resp.Cookies() + if len(cookies) == 0 { + return nil, fmt.Errorf("no cookies found in response") + } + + var sessionCookie *http.Cookie + for _, cookie := range cookies { + if cookie.Name == "session" { + sessionCookie = cookie + break + } + } + + if sessionCookie == nil { + return nil, fmt.Errorf("session cookie not found in response") + } + + return sessionCookie, nil +} + +func ExtractRefreshCookie(resp *http.Response) (*http.Cookie, error) { + for _, cookie := range resp.Cookies() { + if cookie.Name == "refresh" { + return cookie, nil + } + } + + return nil, fmt.Errorf("refresh cookie not found in response") +} + +func MakeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { + return func(ctx context.Context, req *http.Request) error { + req.AddCookie(cookie) + return nil + } +} diff --git a/test/suites/lib/environment.go b/test/suites/lib/environment.go new file mode 100644 index 0000000..cf3149c --- /dev/null +++ b/test/suites/lib/environment.go @@ -0,0 +1,94 @@ +package lib + +import ( + "os" + "strconv" +) + +const ( + defaultHost = "localhost" + defaultKerberosPort = 30000 + defaultAdminPort = 30001 + defaultMetricsPort = 9464 + defaultJaegerReadAPIPort = 16685 + defaultConnectorPort = 30100 +) + +func GetHost() string { + hostVal, found := os.LookupEnv("KRB_FT_HOST") + if !found { + return defaultHost + } + + return hostVal +} + +func GetPort() int { + val, found := os.LookupEnv("KRB_FT_PORT") + if !found { + return defaultKerberosPort + } + + decoded, err := strconv.Atoi(val) + if err != nil { + return defaultKerberosPort + } + + return decoded +} + +func GetAdminPort() int { + val, found := os.LookupEnv("KRB_FT_ADMIN_PORT") + if !found { + return defaultAdminPort + } + + decoded, err := strconv.Atoi(val) + if err != nil { + return defaultAdminPort + } + + return decoded +} + +func GetMetricsPort() int { + metricsPortVal, found := os.LookupEnv("KRB_FT_METRICS_PORT") + if !found { + return defaultMetricsPort + } + + decodedMetricsPort, err := strconv.Atoi(metricsPortVal) + if err != nil { + return defaultMetricsPort + } + + return decodedMetricsPort +} + +func GetJaegerAPIPort() int { + jaegerPortVal, found := os.LookupEnv("KRB_FT_JAEGER_PORT") + if !found { + return defaultJaegerReadAPIPort + } + + decodedJaegerPort, err := strconv.Atoi(jaegerPortVal) + if err != nil { + return defaultJaegerReadAPIPort + } + + return decodedJaegerPort +} + +func GetConnectorPort() int { + val, found := os.LookupEnv("KRB_FT_CONNECTOR_PORT") + if !found { + return defaultConnectorPort + } + + decoded, err := strconv.Atoi(val) + if err != nil { + return defaultConnectorPort + } + + return decoded +} diff --git a/test/suites/security/helpers_config.go b/test/suites/security/helpers_config.go new file mode 100644 index 0000000..a639125 --- /dev/null +++ b/test/suites/security/helpers_config.go @@ -0,0 +1,21 @@ +package security + +const ( + // certDir is relative to the test working directory (test/suites/security/). + certDir = "../../certs" + + kerberosPort = 30000 + adminPort = 30001 + echoPort = 15000 + + superUserClientID = "admin" + superUserClientSecret = "secret" + + adminUser = "security-admin" + adminUserPassword = "security-admin-password" + + basicAuthUser = "security-basic-auth-user" + basicAuthPassword = "security-basic-auth-password" +) + +var orgID int64 diff --git a/test/suites/security/helpers_shared.go b/test/suites/security/helpers_shared.go new file mode 100644 index 0000000..6ce59a0 --- /dev/null +++ b/test/suites/security/helpers_shared.go @@ -0,0 +1,46 @@ +package security + +import ( + "net/http" + "testing" + + testlib "github.com/trebent/kerberos/test/lib" +) + +type RequestEditorFn = testlib.RequestEditorFn + +func checkErr(err error, t *testing.T) { + testlib.CheckErr(err, t) +} + +func verifyStatusCode(in int, expected int, t *testing.T) { + testlib.VerifyStatusCode(in, expected, t) +} + +func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { + testlib.VerifyHeader(headers, key, expectedValue, t) +} + +func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { + testlib.VerifyHeaderMissing(headers, key, t) +} + +func getHost() string { + return testlib.GetHost() +} + +func getPort() int { + return testlib.GetPort() +} + +func getAdminPort() int { + return testlib.GetAdminPort() +} + +func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { + return testlib.ExtractSessionCookie(resp) +} + +func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { + return testlib.MakeRequestEditorFromCookie(cookie) +} diff --git a/test/suites/security/helpers_tls.go b/test/suites/security/helpers_tls.go new file mode 100644 index 0000000..7938782 --- /dev/null +++ b/test/suites/security/helpers_tls.go @@ -0,0 +1,80 @@ +package security + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "net/http" + "os" + "testing" + "time" + + adminapi "github.com/trebent/kerberos/test/client/admin" + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +// adminResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against +// the test CA but sends no client certificate. +func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { + t.Helper() + client, err := adminapi.NewClientWithResponses( + fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + adminapi.WithHTTPClient(tlsClient(t)), + ) + checkErr(err, t) + return client +} + +// basicAuthResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against +// the test CA but sends no client certificate. +func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { + t.Helper() + client, err := authbasicapi.NewClientWithResponses( + fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + authbasicapi.WithHTTPClient(tlsClient(t)), + ) + checkErr(err, t) + return client +} + +// tlsClient returns an http.Client that verifies the server cert against the +// test CA but sends no client certificate. +func tlsClient(t *testing.T) *http.Client { + t.Helper() + return &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caPool(t), + }, + }, + } +} + +// plainClient returns an http.Client that uses plain HTTP (no TLS). +func plainClient() *http.Client { + return &http.Client{Timeout: 5 * time.Second} +} + +// caPool loads the test CA certificate into a new cert pool. +func caPool(t *testing.T) *x509.CertPool { + t.Helper() + pool, err := getCAPool() + if err != nil { + t.Fatalf("Failed to load CA pool: %v", err) + } + + return pool +} + +func getCAPool() (*x509.CertPool, error) { + pem, err := os.ReadFile(certDir + "/ca.crt") + if err != nil { + return nil, fmt.Errorf("read CA cert: %w", err) + } + pool := x509.NewCertPool() + if !pool.AppendCertsFromPEM(pem) { + return nil, fmt.Errorf("no certificates found in ca.crt") + } + return pool, nil +} diff --git a/test/suites/security/lib.go b/test/suites/security/lib.go deleted file mode 100644 index c8e6d93..0000000 --- a/test/suites/security/lib.go +++ /dev/null @@ -1,204 +0,0 @@ -package security - -import ( - "context" - "crypto/tls" - "crypto/x509" - "fmt" - "net/http" - "os" - "strconv" - "testing" - "time" - - adminapi "github.com/trebent/kerberos/test/client/admin" - authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" -) - -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -const ( - defaultHost = "localhost" - defaultKerberosPort = 30000 - defaultAdminPort = 30001 - defaultMetricsPort = 9464 - defaultJaegerReadAPIPort = 16685 - - // certDir is relative to the test working directory (test/suites/security/). - certDir = "../../certs" - - kerberosPort = 30000 - adminPort = 30001 - echoPort = 15000 - - superUserClientID = "admin" - superUserClientSecret = "secret" - - adminUser = "security-admin" - adminUserPassword = "security-admin-password" - - basicAuthUser = "security-basic-auth-user" - basicAuthPassword = "security-basic-auth-password" -) - -var orgID int64 - -func checkErr(err error, t *testing.T) { - t.Helper() - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - t.Helper() - if in != expected { - t.Fatalf("Expected status code %d, got %d", expected, in) - } -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - t.Helper() - actualValue := headers.Get(key) - if actualValue != expectedValue { - t.Fatalf("Expected header %s to have value %s, got %s", key, expectedValue, actualValue) - } -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - t.Helper() - if headers.Get(key) != "" { - t.Fatalf("Expected header %s to be missing, but it was present", key) - } -} - -// adminResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against -// the test CA but sends no client certificate. -func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { - t.Helper() - client, err := adminapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), - adminapi.WithHTTPClient(tlsClient(t)), - ) - checkErr(err, t) - return client -} - -// basicAuthResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against -// the test CA but sends no client certificate. -func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { - t.Helper() - client, err := authbasicapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), - authbasicapi.WithHTTPClient(tlsClient(t)), - ) - checkErr(err, t) - return client -} - -// tlsClient returns an http.Client that verifies the server cert against the -// test CA but sends no client certificate. -func tlsClient(t *testing.T) *http.Client { - t.Helper() - return &http.Client{ - Timeout: 5 * time.Second, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: caPool(t), - }, - }, - } -} - -// plainClient returns an http.Client that uses plain HTTP (no TLS). -func plainClient() *http.Client { - return &http.Client{Timeout: 5 * time.Second} -} - -// caPool loads the test CA certificate into a new cert pool. -func caPool(t *testing.T) *x509.CertPool { - t.Helper() - pool, err := getCAPool() - if err != nil { - t.Fatalf("Failed to load CA pool: %v", err) - } - - return pool -} - -func getCAPool() (*x509.CertPool, error) { - pem, err := os.ReadFile(certDir + "/ca.crt") - if err != nil { - return nil, fmt.Errorf("read CA cert: %w", err) - } - pool := x509.NewCertPool() - if !pool.AppendCertsFromPEM(pem) { - return nil, fmt.Errorf("no certificates found in ca.crt") - } - return pool, nil -} - -func getHost() string { - hostVal, found := os.LookupEnv("KRB_FT_HOST") - if !found { - return defaultHost - } else { - return hostVal - } -} - -func getPort() int { - val, found := os.LookupEnv("KRB_FT_PORT") - if !found { - return defaultKerberosPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultKerberosPort - } else { - return decoded - } -} - -func getAdminPort() int { - val, found := os.LookupEnv("KRB_FT_ADMIN_PORT") - if !found { - return defaultAdminPort - } - - decoded, err := strconv.Atoi(val) - if err != nil { - return defaultAdminPort - } else { - return decoded - } -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - cookies := resp.Cookies() - if len(cookies) == 0 { - return nil, fmt.Errorf("no cookies found in response") - } - - var sessionCookie *http.Cookie - for _, cookie := range cookies { - if cookie.Name == "session" { - sessionCookie = cookie - break - } - } - - if sessionCookie == nil { - return nil, fmt.Errorf("session cookie not found in response") - } - - return sessionCookie, nil -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return func(ctx context.Context, req *http.Request) error { - req.AddCookie(cookie) - return nil - } -} From 314a66baad3d16981386dbe5d4ca67d2c89a6c3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:05:26 +0000 Subject: [PATCH 2/7] refactor: rename suite helper files and streamline lib bindings Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- .../connector/{helpers_auth.go => auth.go} | 0 .../{helpers_config.go => config.go} | 0 test/suites/connector/helpers_shared.go | 46 --------------- .../{helpers_http.go => http_requests.go} | 0 test/suites/connector/shared_bindings.go | 17 ++++++ .../{lib_admin_user.go => admin_user.go} | 0 .../{helpers_auth.go => auth_sessions.go} | 0 .../{lib_basic_auth.go => basic_auth.go} | 0 .../integration/{lib_debug.go => debug.go} | 0 test/suites/integration/helpers_shared.go | 58 ------------------- .../{helpers_http.go => http_requests.go} | 0 test/suites/integration/shared_bindings.go | 20 +++++++ .../{helpers_state.go => state.go} | 0 .../security/{helpers_config.go => config.go} | 0 test/suites/security/helpers_shared.go | 46 --------------- test/suites/security/shared_bindings.go | 17 ++++++ .../{helpers_tls.go => tls_clients.go} | 0 17 files changed, 54 insertions(+), 150 deletions(-) rename test/suites/connector/{helpers_auth.go => auth.go} (100%) rename test/suites/connector/{helpers_config.go => config.go} (100%) delete mode 100644 test/suites/connector/helpers_shared.go rename test/suites/connector/{helpers_http.go => http_requests.go} (100%) create mode 100644 test/suites/connector/shared_bindings.go rename test/suites/integration/{lib_admin_user.go => admin_user.go} (100%) rename test/suites/integration/{helpers_auth.go => auth_sessions.go} (100%) rename test/suites/integration/{lib_basic_auth.go => basic_auth.go} (100%) rename test/suites/integration/{lib_debug.go => debug.go} (100%) delete mode 100644 test/suites/integration/helpers_shared.go rename test/suites/integration/{helpers_http.go => http_requests.go} (100%) create mode 100644 test/suites/integration/shared_bindings.go rename test/suites/integration/{helpers_state.go => state.go} (100%) rename test/suites/security/{helpers_config.go => config.go} (100%) delete mode 100644 test/suites/security/helpers_shared.go create mode 100644 test/suites/security/shared_bindings.go rename test/suites/security/{helpers_tls.go => tls_clients.go} (100%) diff --git a/test/suites/connector/helpers_auth.go b/test/suites/connector/auth.go similarity index 100% rename from test/suites/connector/helpers_auth.go rename to test/suites/connector/auth.go diff --git a/test/suites/connector/helpers_config.go b/test/suites/connector/config.go similarity index 100% rename from test/suites/connector/helpers_config.go rename to test/suites/connector/config.go diff --git a/test/suites/connector/helpers_shared.go b/test/suites/connector/helpers_shared.go deleted file mode 100644 index 2443321..0000000 --- a/test/suites/connector/helpers_shared.go +++ /dev/null @@ -1,46 +0,0 @@ -package connector - -import ( - "net/http" - "testing" - - testlib "github.com/trebent/kerberos/test/lib" -) - -type RequestEditorFn = testlib.RequestEditorFn - -func checkErr(err error, t *testing.T) { - testlib.CheckErr(err, t) -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - testlib.VerifyStatusCode(in, expected, t) -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - testlib.VerifyHeader(headers, key, expectedValue, t) -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - testlib.VerifyHeaderMissing(headers, key, t) -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - return testlib.ExtractSessionCookie(resp) -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return testlib.MakeRequestEditorFromCookie(cookie) -} - -func getHost() string { - return testlib.GetHost() -} - -func getAdminPort() int { - return testlib.GetAdminPort() -} - -func getConnectorPort() int { - return testlib.GetConnectorPort() -} diff --git a/test/suites/connector/helpers_http.go b/test/suites/connector/http_requests.go similarity index 100% rename from test/suites/connector/helpers_http.go rename to test/suites/connector/http_requests.go diff --git a/test/suites/connector/shared_bindings.go b/test/suites/connector/shared_bindings.go new file mode 100644 index 0000000..6316ebb --- /dev/null +++ b/test/suites/connector/shared_bindings.go @@ -0,0 +1,17 @@ +package connector + +import testlib "github.com/trebent/kerberos/test/lib" + +type RequestEditorFn = testlib.RequestEditorFn + +var ( + checkErr = testlib.CheckErr + verifyStatusCode = testlib.VerifyStatusCode + verifyHeader = testlib.VerifyHeader + verifyHeaderMissing = testlib.VerifyHeaderMissing + extractSessionCookie = testlib.ExtractSessionCookie + makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie + getHost = testlib.GetHost + getAdminPort = testlib.GetAdminPort + getConnectorPort = testlib.GetConnectorPort +) diff --git a/test/suites/integration/lib_admin_user.go b/test/suites/integration/admin_user.go similarity index 100% rename from test/suites/integration/lib_admin_user.go rename to test/suites/integration/admin_user.go diff --git a/test/suites/integration/helpers_auth.go b/test/suites/integration/auth_sessions.go similarity index 100% rename from test/suites/integration/helpers_auth.go rename to test/suites/integration/auth_sessions.go diff --git a/test/suites/integration/lib_basic_auth.go b/test/suites/integration/basic_auth.go similarity index 100% rename from test/suites/integration/lib_basic_auth.go rename to test/suites/integration/basic_auth.go diff --git a/test/suites/integration/lib_debug.go b/test/suites/integration/debug.go similarity index 100% rename from test/suites/integration/lib_debug.go rename to test/suites/integration/debug.go diff --git a/test/suites/integration/helpers_shared.go b/test/suites/integration/helpers_shared.go deleted file mode 100644 index 03160d6..0000000 --- a/test/suites/integration/helpers_shared.go +++ /dev/null @@ -1,58 +0,0 @@ -package integration - -import ( - "net/http" - "testing" - - testlib "github.com/trebent/kerberos/test/lib" -) - -type RequestEditorFn = testlib.RequestEditorFn - -func checkErr(err error, t *testing.T) { - testlib.CheckErr(err, t) -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - testlib.VerifyStatusCode(in, expected, t) -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - testlib.VerifyHeader(headers, key, expectedValue, t) -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - testlib.VerifyHeaderMissing(headers, key, t) -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - return testlib.ExtractSessionCookie(resp) -} - -func extractRefreshCookie(resp *http.Response) (*http.Cookie, error) { - return testlib.ExtractRefreshCookie(resp) -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return testlib.MakeRequestEditorFromCookie(cookie) -} - -func getAdminPort() int { - return testlib.GetAdminPort() -} - -func getPort() int { - return testlib.GetPort() -} - -func getHost() string { - return testlib.GetHost() -} - -func getMetricsPort() int { - return testlib.GetMetricsPort() -} - -func getJaegerAPIPort() int { - return testlib.GetJaegerAPIPort() -} diff --git a/test/suites/integration/helpers_http.go b/test/suites/integration/http_requests.go similarity index 100% rename from test/suites/integration/helpers_http.go rename to test/suites/integration/http_requests.go diff --git a/test/suites/integration/shared_bindings.go b/test/suites/integration/shared_bindings.go new file mode 100644 index 0000000..8dfc998 --- /dev/null +++ b/test/suites/integration/shared_bindings.go @@ -0,0 +1,20 @@ +package integration + +import testlib "github.com/trebent/kerberos/test/lib" + +type RequestEditorFn = testlib.RequestEditorFn + +var ( + checkErr = testlib.CheckErr + verifyStatusCode = testlib.VerifyStatusCode + verifyHeader = testlib.VerifyHeader + verifyHeaderMissing = testlib.VerifyHeaderMissing + extractSessionCookie = testlib.ExtractSessionCookie + extractRefreshCookie = testlib.ExtractRefreshCookie + makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie + getAdminPort = testlib.GetAdminPort + getPort = testlib.GetPort + getHost = testlib.GetHost + getMetricsPort = testlib.GetMetricsPort + getJaegerAPIPort = testlib.GetJaegerAPIPort +) diff --git a/test/suites/integration/helpers_state.go b/test/suites/integration/state.go similarity index 100% rename from test/suites/integration/helpers_state.go rename to test/suites/integration/state.go diff --git a/test/suites/security/helpers_config.go b/test/suites/security/config.go similarity index 100% rename from test/suites/security/helpers_config.go rename to test/suites/security/config.go diff --git a/test/suites/security/helpers_shared.go b/test/suites/security/helpers_shared.go deleted file mode 100644 index 6ce59a0..0000000 --- a/test/suites/security/helpers_shared.go +++ /dev/null @@ -1,46 +0,0 @@ -package security - -import ( - "net/http" - "testing" - - testlib "github.com/trebent/kerberos/test/lib" -) - -type RequestEditorFn = testlib.RequestEditorFn - -func checkErr(err error, t *testing.T) { - testlib.CheckErr(err, t) -} - -func verifyStatusCode(in int, expected int, t *testing.T) { - testlib.VerifyStatusCode(in, expected, t) -} - -func verifyHeader(headers http.Header, key string, expectedValue string, t *testing.T) { - testlib.VerifyHeader(headers, key, expectedValue, t) -} - -func verifyHeaderMissing(headers http.Header, key string, t *testing.T) { - testlib.VerifyHeaderMissing(headers, key, t) -} - -func getHost() string { - return testlib.GetHost() -} - -func getPort() int { - return testlib.GetPort() -} - -func getAdminPort() int { - return testlib.GetAdminPort() -} - -func extractSessionCookie(resp *http.Response) (*http.Cookie, error) { - return testlib.ExtractSessionCookie(resp) -} - -func makeRequestEditorFromCookie(cookie *http.Cookie) RequestEditorFn { - return testlib.MakeRequestEditorFromCookie(cookie) -} diff --git a/test/suites/security/shared_bindings.go b/test/suites/security/shared_bindings.go new file mode 100644 index 0000000..382d1f5 --- /dev/null +++ b/test/suites/security/shared_bindings.go @@ -0,0 +1,17 @@ +package security + +import testlib "github.com/trebent/kerberos/test/lib" + +type RequestEditorFn = testlib.RequestEditorFn + +var ( + checkErr = testlib.CheckErr + verifyStatusCode = testlib.VerifyStatusCode + verifyHeader = testlib.VerifyHeader + verifyHeaderMissing = testlib.VerifyHeaderMissing + getHost = testlib.GetHost + getPort = testlib.GetPort + getAdminPort = testlib.GetAdminPort + extractSessionCookie = testlib.ExtractSessionCookie + makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie +) diff --git a/test/suites/security/helpers_tls.go b/test/suites/security/tls_clients.go similarity index 100% rename from test/suites/security/helpers_tls.go rename to test/suites/security/tls_clients.go From a609419e8e67e6e9c0066f68acef71f64f8b47b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:19:44 +0000 Subject: [PATCH 3/7] Migrate suite helpers to lib package; remove wiring aliases Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- test/suites/connector/auth.go | 20 +- test/suites/connector/config.go | 13 - test/suites/connector/cors_test.go | 25 +- test/suites/connector/http_requests.go | 25 - test/suites/connector/main_test.go | 13 +- test/suites/connector/session_test.go | 19 +- test/suites/connector/shared_bindings.go | 17 - test/suites/connector/whitelist_test.go | 9 +- .../integration/admin_api_debug_test.go | 301 ++++++------ .../admin_api_group_bindings_test.go | 147 +++--- .../integration/admin_api_groups_test.go | 163 +++---- .../integration/admin_api_permissions_test.go | 443 +++++++++--------- .../integration/admin_api_session_test.go | 85 ++-- test/suites/integration/admin_api_test.go | 127 ++--- .../integration/admin_api_users_test.go | 275 +++++------ test/suites/integration/admin_user.go | 64 --- .../auth_basic_api_bindings_test.go | 165 +++---- .../integration/auth_basic_api_groups_test.go | 315 ++++++------- .../auth_basic_api_organisations_test.go | 375 +++++++-------- .../suites/integration/auth_basic_api_test.go | 369 +++++++-------- .../integration/auth_basic_api_users_test.go | 401 ++++++++-------- test/suites/integration/auth_basic_test.go | 57 +-- test/suites/integration/auth_sessions.go | 51 -- test/suites/integration/basic_auth.go | 35 -- test/suites/integration/cookies_test.go | 23 +- test/suites/integration/cors_test.go | 97 ++-- test/suites/integration/debug.go | 31 -- test/suites/integration/gateway_test.go | 21 +- test/suites/integration/main_test.go | 29 +- test/suites/integration/metrics_test.go | 19 +- test/suites/integration/shared_bindings.go | 20 - test/suites/integration/state.go | 47 -- test/suites/integration/tracing_test.go | 7 +- test/suites/lib/admin_user.go | 64 +++ test/suites/lib/auth.go | 50 ++ test/suites/lib/basic_auth.go | 34 ++ test/suites/lib/clients.go | 26 + test/suites/lib/debug.go | 31 ++ .../{integration => lib}/http_requests.go | 71 ++- test/suites/lib/names.go | 29 ++ test/suites/security/config.go | 3 - test/suites/security/cookies_test.go | 17 +- test/suites/security/cors_test.go | 79 ++-- test/suites/security/main_test.go | 13 +- test/suites/security/shared_bindings.go | 17 - test/suites/security/tls_clients.go | 9 +- 46 files changed, 2087 insertions(+), 2164 deletions(-) delete mode 100644 test/suites/connector/http_requests.go delete mode 100644 test/suites/connector/shared_bindings.go delete mode 100644 test/suites/integration/admin_user.go delete mode 100644 test/suites/integration/auth_sessions.go delete mode 100644 test/suites/integration/basic_auth.go delete mode 100644 test/suites/integration/debug.go delete mode 100644 test/suites/integration/shared_bindings.go create mode 100644 test/suites/lib/admin_user.go create mode 100644 test/suites/lib/auth.go create mode 100644 test/suites/lib/basic_auth.go create mode 100644 test/suites/lib/clients.go create mode 100644 test/suites/lib/debug.go rename test/suites/{integration => lib}/http_requests.go (69%) create mode 100644 test/suites/lib/names.go delete mode 100644 test/suites/security/shared_bindings.go diff --git a/test/suites/connector/auth.go b/test/suites/connector/auth.go index 30d2d2d..2365790 100644 --- a/test/suites/connector/auth.go +++ b/test/suites/connector/auth.go @@ -5,18 +5,18 @@ import ( "testing" adminapi "github.com/trebent/kerberos/test/client/admin" + lib "github.com/trebent/kerberos/test/lib" ) func loginAndGetSessionCookie(t *testing.T) *http.Cookie { - loginResponse, err := adminClient.LoginWithResponse(t.Context(), adminapi.LoginJSONRequestBody{ - Username: adminUser, - Password: adminUserPassword, - }) - checkErr(err, t) - verifyStatusCode(loginResponse.StatusCode(), http.StatusNoContent, t) - - sessionCookie, err := extractSessionCookie(loginResponse.HTTPResponse) - checkErr(err, t) - + t.Helper() + loginResponse, err := lib.AdminClient.LoginWithResponse( + t.Context(), + adminapi.LoginJSONRequestBody{Username: adminUser, Password: adminUserPassword}, + ) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResponse.StatusCode(), http.StatusNoContent, t) + sessionCookie, err := lib.ExtractSessionCookie(loginResponse.HTTPResponse) + lib.CheckErr(err, t) return sessionCookie } diff --git a/test/suites/connector/config.go b/test/suites/connector/config.go index 1486801..ca1a0e0 100644 --- a/test/suites/connector/config.go +++ b/test/suites/connector/config.go @@ -1,19 +1,6 @@ package connector -import ( - "fmt" - - adminapi "github.com/trebent/kerberos/test/client/admin" -) - const ( adminUser = "connector-admin" adminUserPassword = "connector-admin-password" - - superUserClientID = "admin" - superUserClientSecret = "secret" -) - -var adminClient, _ = adminapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), ) diff --git a/test/suites/connector/cors_test.go b/test/suites/connector/cors_test.go index 2492dd5..9931d54 100644 --- a/test/suites/connector/cors_test.go +++ b/test/suites/connector/cors_test.go @@ -2,6 +2,7 @@ package connector import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "net/url" "testing" @@ -18,12 +19,12 @@ func TestCORS(t *testing.T) { t.Run("allowed origin, OPTIONS preflight", func(t *testing.T) { t.Parallel() - url := fmt.Sprintf("http://%s:%d", getHost(), getConnectorPort()) - resp := options(url, t, http.Header{"Origin": []string{"https://admin.trebent.test:30001"}}) + url := fmt.Sprintf("http://%s:%d", lib.GetHost(), lib.GetConnectorPort()) + resp := lib.Options(url, t, http.Header{"Origin": []string{"https://admin.trebent.test:30001"}}) defer resp.Body.Close() - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "https://admin.trebent.test:30001", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "https://admin.trebent.test:30001", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) if resp.Header.Get("Access-Control-Allow-Methods") == "" { t.Fatal("Expected Access-Control-Allow-Methods to be set") } @@ -38,7 +39,7 @@ func testCORS(t *testing.T, origin string, expectCORSHeaders bool) { Method: "GET", URL: &url.URL{ Scheme: "http", - Host: fmt.Sprintf("%s:%d", getHost(), getConnectorPort()), + Host: fmt.Sprintf("%s:%d", lib.GetHost(), lib.GetConnectorPort()), }, Header: make(http.Header), } @@ -48,15 +49,15 @@ func testCORS(t *testing.T, origin string, expectCORSHeaders bool) { } response, err := httpClient.Do(req) - checkErr(err, t) + lib.CheckErr(err, t) defer response.Body.Close() if expectCORSHeaders { - verifyStatusCode(response.StatusCode, http.StatusOK, t) - verifyHeader(response.Header, "Access-Control-Allow-Origin", origin, t) - verifyHeader(response.Header, "Access-Control-Allow-Credentials", "true", t) + lib.VerifyStatusCode(response.StatusCode, http.StatusOK, t) + lib.VerifyHeader(response.Header, "Access-Control-Allow-Origin", origin, t) + lib.VerifyHeader(response.Header, "Access-Control-Allow-Credentials", "true", t) } else { - verifyStatusCode(response.StatusCode, http.StatusOK, t) - verifyHeaderMissing(response.Header, "Access-Control-Allow-Origin", t) + lib.VerifyStatusCode(response.StatusCode, http.StatusOK, t) + lib.VerifyHeaderMissing(response.Header, "Access-Control-Allow-Origin", t) } } diff --git a/test/suites/connector/http_requests.go b/test/suites/connector/http_requests.go deleted file mode 100644 index 9fc81c9..0000000 --- a/test/suites/connector/http_requests.go +++ /dev/null @@ -1,25 +0,0 @@ -package connector - -import ( - "net/http" - "testing" -) - -func options(url string, t *testing.T, headers ...http.Header) *http.Response { - t.Helper() - req, err := http.NewRequest(http.MethodOptions, url, nil) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - for _, h := range headers { - for key, values := range h { - req.Header[key] = values - } - } - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - t.Fatalf("failed to send request: %v", err) - } - return resp -} diff --git a/test/suites/connector/main_test.go b/test/suites/connector/main_test.go index 3bc5de2..ce4918b 100644 --- a/test/suites/connector/main_test.go +++ b/test/suites/connector/main_test.go @@ -2,6 +2,7 @@ package connector import ( "context" + lib "github.com/trebent/kerberos/test/lib" "net/http" "os" "testing" @@ -12,10 +13,10 @@ import ( func TestMain(m *testing.M) { println("Running TestMain, setting up test foundation...") - loginResp, err := adminClient.LoginSuperuserWithResponse( + loginResp, err := lib.AdminClient.LoginSuperuserWithResponse( context.Background(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, ) if err != nil { @@ -24,13 +25,13 @@ func TestMain(m *testing.M) { if loginResp.StatusCode() != http.StatusNoContent { panic("superuser login response did not indicate success: " + loginResp.Status()) } - cookie, err := extractSessionCookie(loginResp.HTTPResponse) + cookie, err := lib.ExtractSessionCookie(loginResp.HTTPResponse) if err != nil { panic(err) } - requestEditorSuper := makeRequestEditorFromCookie(cookie) + requestEditorSuper := lib.MakeRequestEditorFromCookie(cookie) - createAdminUserResp, err := adminClient.CreateUserWithResponse( + createAdminUserResp, err := lib.AdminClient.CreateUserWithResponse( context.Background(), adminapi.CreateUserJSONRequestBody{ Username: adminUser, diff --git a/test/suites/connector/session_test.go b/test/suites/connector/session_test.go index 1b976b8..f41e3c6 100644 --- a/test/suites/connector/session_test.go +++ b/test/suites/connector/session_test.go @@ -2,6 +2,7 @@ package connector import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "net/url" "testing" @@ -15,16 +16,16 @@ func TestSession(t *testing.T) { Method: "GET", URL: &url.URL{ Scheme: "http", - Host: fmt.Sprintf("%s:%d", getHost(), getConnectorPort()), + Host: fmt.Sprintf("%s:%d", lib.GetHost(), lib.GetConnectorPort()), }, Header: make(http.Header), } response, err := httpClient.Do(req) - checkErr(err, t) + lib.CheckErr(err, t) defer response.Body.Close() - verifyStatusCode(response.StatusCode, http.StatusUnauthorized, t) + lib.VerifyStatusCode(response.StatusCode, http.StatusUnauthorized, t) }) t.Run("invalid session cookie, unauthorized", func(t *testing.T) { @@ -34,7 +35,7 @@ func TestSession(t *testing.T) { Method: "GET", URL: &url.URL{ Scheme: "http", - Host: fmt.Sprintf("%s:%d", getHost(), getConnectorPort()), + Host: fmt.Sprintf("%s:%d", lib.GetHost(), lib.GetConnectorPort()), }, Header: make(http.Header), } @@ -44,10 +45,10 @@ func TestSession(t *testing.T) { }) response, err := httpClient.Do(req) - checkErr(err, t) + lib.CheckErr(err, t) defer response.Body.Close() - verifyStatusCode(response.StatusCode, http.StatusUnauthorized, t) + lib.VerifyStatusCode(response.StatusCode, http.StatusUnauthorized, t) }) t.Run("session cookie is valid", func(t *testing.T) { @@ -62,16 +63,16 @@ func TestSession(t *testing.T) { Method: "GET", URL: &url.URL{ Scheme: "http", - Host: fmt.Sprintf("%s:%d", getHost(), getConnectorPort()), + Host: fmt.Sprintf("%s:%d", lib.GetHost(), lib.GetConnectorPort()), }, Header: make(http.Header), } req.AddCookie(cookie) response, err := httpClient.Do(req) - checkErr(err, t) + lib.CheckErr(err, t) defer response.Body.Close() - verifyStatusCode(response.StatusCode, http.StatusOK, t) + lib.VerifyStatusCode(response.StatusCode, http.StatusOK, t) }) } diff --git a/test/suites/connector/shared_bindings.go b/test/suites/connector/shared_bindings.go deleted file mode 100644 index 6316ebb..0000000 --- a/test/suites/connector/shared_bindings.go +++ /dev/null @@ -1,17 +0,0 @@ -package connector - -import testlib "github.com/trebent/kerberos/test/lib" - -type RequestEditorFn = testlib.RequestEditorFn - -var ( - checkErr = testlib.CheckErr - verifyStatusCode = testlib.VerifyStatusCode - verifyHeader = testlib.VerifyHeader - verifyHeaderMissing = testlib.VerifyHeaderMissing - extractSessionCookie = testlib.ExtractSessionCookie - makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie - getHost = testlib.GetHost - getAdminPort = testlib.GetAdminPort - getConnectorPort = testlib.GetConnectorPort -) diff --git a/test/suites/connector/whitelist_test.go b/test/suites/connector/whitelist_test.go index e3f27a8..dfd8761 100644 --- a/test/suites/connector/whitelist_test.go +++ b/test/suites/connector/whitelist_test.go @@ -2,6 +2,7 @@ package connector import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "net/url" "testing" @@ -33,7 +34,7 @@ func testWhitelist(t *testing.T, origin string, expectAllowed bool) { Method: http.MethodGet, URL: &url.URL{ Scheme: "http", - Host: fmt.Sprintf("%s:%d", getHost(), getConnectorPort()), + Host: fmt.Sprintf("%s:%d", lib.GetHost(), lib.GetConnectorPort()), }, Header: make(http.Header), } @@ -43,12 +44,12 @@ func testWhitelist(t *testing.T, origin string, expectAllowed bool) { } response, err := httpClient.Do(req) - checkErr(err, t) + lib.CheckErr(err, t) _ = response.Body.Close() if expectAllowed { - verifyStatusCode(response.StatusCode, http.StatusOK, t) + lib.VerifyStatusCode(response.StatusCode, http.StatusOK, t) } else { - verifyStatusCode(response.StatusCode, http.StatusForbidden, t) + lib.VerifyStatusCode(response.StatusCode, http.StatusForbidden, t) } } diff --git a/test/suites/integration/admin_api_debug_test.go b/test/suites/integration/admin_api_debug_test.go index 5ced123..b65c99a 100644 --- a/test/suites/integration/admin_api_debug_test.go +++ b/test/suites/integration/admin_api_debug_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -12,16 +13,16 @@ import ( // TestDebugStartSession verifies that a superuser can start a debug session and // the response body contains the correct fields. func TestDebugStartSession(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.StartDebugSessionWithResponse( + resp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), "echo", adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) session := resp.JSON200 if session == nil { @@ -44,47 +45,47 @@ func TestDebugStartSession(t *testing.T) { } // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", session.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestDebugStartSessionConflict verifies that starting a second debug session for a // backend that already has an active session returns 409 conflict. func TestDebugStartSessionConflict(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Use a backend name unique to this test to avoid conflicts with parallel tests. const conflictBackend = "echo-conflict-test" - sessionID := startDebugSession(t, superRequestEditor, conflictBackend) + sessionID := lib.StartDebugSession(t, superRequestEditor, conflictBackend) // Attempt to start a second session for the same backend. - resp, err := adminClient.StartDebugSessionWithResponse( + resp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), conflictBackend, adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusConflict, t) - verifyAdminAPIErrorResponse(resp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusConflict, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON409, t) // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), conflictBackend, sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // --- ListDebugSessions --- @@ -93,18 +94,18 @@ func TestDebugStartSessionConflict(t *testing.T) { // sessions returns 200 with an empty list. func TestDebugListSessionsEmpty(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Use a backend name that no other test will use. const unusedBackend = "no-such-backend-for-list-test" - resp, err := adminClient.ListDebugSessionsWithResponse( + resp, err := lib.AdminClient.ListDebugSessionsWithResponse( t.Context(), unusedBackend, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) if resp.JSON200 == nil { t.Fatal("expected non-nil sessions list") @@ -116,17 +117,17 @@ func TestDebugListSessionsEmpty(t *testing.T) { // TestDebugListSessionsContainsCreated verifies that a created session appears in the list. func TestDebugListSessionsContainsCreated(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") - listResp, err := adminClient.ListDebugSessionsWithResponse( + listResp, err := lib.AdminClient.ListDebugSessionsWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) found := false for _, s := range *listResp.JSON200 { @@ -140,32 +141,32 @@ func TestDebugListSessionsContainsCreated(t *testing.T) { } // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // --- GetDebugSession --- // TestDebugGetSession verifies that an existing session can be retrieved by ID. func TestDebugGetSession(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") - getResp, err := adminClient.GetDebugSessionWithResponse( + getResp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200 == nil { t.Fatal("expected non-nil debug session in response body") @@ -178,61 +179,61 @@ func TestDebugGetSession(t *testing.T) { } // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestDebugGetSessionNotFound verifies that requesting a non-existent session returns 404. func TestDebugGetSessionNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.GetDebugSessionWithResponse( + resp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } // --- ExtendDebugSession --- // TestDebugExtendSession verifies that extending a session updates ExpiresAt. func TestDebugExtendSession(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") // Read original expiry. - getResp, err := adminClient.GetDebugSessionWithResponse( + getResp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) originalExpiry := getResp.JSON200.ExpiresAt // Extend by 60 seconds. - extResp, err := adminClient.ExtendDebugSessionWithResponse( + extResp, err := lib.AdminClient.ExtendDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.ExtendDebugSessionJSONRequestBody{AdditionalDurationSeconds: 60}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(extResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(extResp.StatusCode(), http.StatusOK, t) if extResp.JSON200 == nil { t.Fatal("expected non-nil debug session in extend response body") @@ -242,31 +243,31 @@ func TestDebugExtendSession(t *testing.T) { } // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestDebugExtendSessionNotFound verifies that extending a non-existent session returns 404. func TestDebugExtendSessionNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.ExtendDebugSessionWithResponse( + resp, err := lib.AdminClient.ExtendDebugSessionWithResponse( t.Context(), "echo", 999999999, adminapi.ExtendDebugSessionJSONRequestBody{AdditionalDurationSeconds: 60}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } // --- StopDebugSession --- @@ -274,57 +275,57 @@ func TestDebugExtendSessionNotFound(t *testing.T) { // TestDebugStopSession verifies that stopping an active session returns 204 and marks // the session as stopped. func TestDebugStopSession(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") - stopResp, err := adminClient.StopDebugSessionWithResponse( + stopResp, err := lib.AdminClient.StopDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(stopResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(stopResp.StatusCode(), http.StatusNoContent, t) // Verify StoppedAt is set. - getResp, err := adminClient.GetDebugSessionWithResponse( + getResp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200.StoppedAt == nil { t.Error("expected non-nil StoppedAt after stopping the session") } // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestDebugStopSessionNotFound verifies that stopping a non-existent session returns 404. func TestDebugStopSessionNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.StopDebugSessionWithResponse( + resp, err := lib.AdminClient.StopDebugSessionWithResponse( t.Context(), "echo", 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } // --- DeleteDebugSession --- @@ -332,44 +333,44 @@ func TestDebugStopSessionNotFound(t *testing.T) { // TestDebugDeleteSession verifies that deleting a session returns 204 and the session // is no longer retrievable. func TestDebugDeleteSession(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Verify the session is gone. - getResp, err := adminClient.GetDebugSessionWithResponse( + getResp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestDebugDeleteSessionNotFound verifies that deleting a non-existent session returns 404. func TestDebugDeleteSessionNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.DeleteDebugSessionWithResponse( + resp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } // --- ListDebugSessionCalls & GetDebugSessionCall --- @@ -378,31 +379,31 @@ func TestDebugDeleteSessionNotFound(t *testing.T) { // during an active debug session, the call is recorded and flow transitions are populated // when includeTransitions=true. func TestDebugListSessionCallsWithTransitions(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") defer func() { - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) }() - makeGatewayRequest(t, "echo", "/hi") + lib.MakeGatewayRequest(t, "echo", "/hi") - listResp, err := adminClient.ListDebugSessionCallsWithResponse( + listResp, err := lib.AdminClient.ListDebugSessionCallsWithResponse( t.Context(), "echo", sessionID, &adminapi.ListDebugSessionCallsParams{IncludeTransitions: true}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) if listResp.JSON200 == nil { t.Fatal("expected non-nil calls list") @@ -419,31 +420,31 @@ func TestDebugListSessionCallsWithTransitions(t *testing.T) { // TestDebugListSessionCallsWithoutTransitions verifies that when includeTransitions=false, // FlowTransitions are not included in the response. func TestDebugListSessionCallsWithoutTransitions(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") defer func() { - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) }() - makeGatewayRequest(t, "echo", "/hi") + lib.MakeGatewayRequest(t, "echo", "/hi") - listResp, err := adminClient.ListDebugSessionCallsWithResponse( + listResp, err := lib.AdminClient.ListDebugSessionCallsWithResponse( t.Context(), "echo", sessionID, &adminapi.ListDebugSessionCallsParams{IncludeTransitions: false}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) if listResp.JSON200 == nil { t.Fatal("expected non-nil calls list") @@ -460,46 +461,46 @@ func TestDebugListSessionCallsWithoutTransitions(t *testing.T) { // TestDebugGetSessionCall verifies that a specific recorded call can be retrieved by ID. func TestDebugGetSessionCall(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") defer func() { - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) }() - makeGatewayRequest(t, "echo", "/hi") + lib.MakeGatewayRequest(t, "echo", "/hi") - listResp, err := adminClient.ListDebugSessionCallsWithResponse( + listResp, err := lib.AdminClient.ListDebugSessionCallsWithResponse( t.Context(), "echo", sessionID, &adminapi.ListDebugSessionCallsParams{IncludeTransitions: false}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) if listResp.JSON200 == nil || len(*listResp.JSON200) == 0 { t.Fatal("expected at least one recorded call") } callID := (*listResp.JSON200)[0].Id - getCallResp, err := adminClient.GetDebugSessionCallWithResponse( + getCallResp, err := lib.AdminClient.GetDebugSessionCallWithResponse( t.Context(), "echo", sessionID, callID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getCallResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getCallResp.StatusCode(), http.StatusOK, t) if getCallResp.JSON200 == nil { t.Fatal("expected non-nil call in response body") @@ -517,30 +518,30 @@ func TestDebugGetSessionCall(t *testing.T) { // TestDebugGetSessionCallNotFound verifies that requesting a non-existent call returns 404. func TestDebugGetSessionCallNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - sessionID := startDebugSession(t, superRequestEditor, "echo") + sessionID := lib.StartDebugSession(t, superRequestEditor, "echo") defer func() { - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) }() - resp, err := adminClient.GetDebugSessionCallWithResponse( + resp, err := lib.AdminClient.GetDebugSessionCallWithResponse( t.Context(), "echo", sessionID, 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } // --- Full lifecycle --- @@ -548,80 +549,80 @@ func TestDebugGetSessionCallNotFound(t *testing.T) { // TestDebugFullFlow exercises the complete debug session lifecycle end-to-end: // start → get → hit gateway (records a call) → list calls → get call → stop → delete. func TestDebugFullFlow(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Start. - startResp, err := adminClient.StartDebugSessionWithResponse( + startResp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), "echo", adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(startResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(startResp.StatusCode(), http.StatusOK, t) sessionID := startResp.JSON200.Id // Get. - getResp, err := adminClient.GetDebugSessionWithResponse( + getResp, err := lib.AdminClient.GetDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Id, sessionID, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Id, sessionID, t) // Make a gateway request so a call gets recorded. - makeGatewayRequest(t, "echo", "/hi") + lib.MakeGatewayRequest(t, "echo", "/hi") // List calls with transitions. - listCallsResp, err := adminClient.ListDebugSessionCallsWithResponse( + listCallsResp, err := lib.AdminClient.ListDebugSessionCallsWithResponse( t.Context(), "echo", sessionID, &adminapi.ListDebugSessionCallsParams{IncludeTransitions: false}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listCallsResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listCallsResp.StatusCode(), http.StatusOK, t) if len(*listCallsResp.JSON200) == 0 { t.Fatal("expected at least one recorded call after gateway request") } callID := (*listCallsResp.JSON200)[0].Id // Get specific call. - getCallResp, err := adminClient.GetDebugSessionCallWithResponse( + getCallResp, err := lib.AdminClient.GetDebugSessionCallWithResponse( t.Context(), "echo", sessionID, callID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getCallResp.StatusCode(), http.StatusOK, t) - matches(getCallResp.JSON200.Id, callID, t) - matches(false, len(getCallResp.JSON200.FlowTransitions) == 0, t) - matches(http.MethodGet, getCallResp.JSON200.Method, t) - matches("/gw/backend/echo/hi", getCallResp.JSON200.Url, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getCallResp.StatusCode(), http.StatusOK, t) + lib.Matches(getCallResp.JSON200.Id, callID, t) + lib.Matches(false, len(getCallResp.JSON200.FlowTransitions) == 0, t) + lib.Matches(http.MethodGet, getCallResp.JSON200.Method, t) + lib.Matches("/gw/backend/echo/hi", getCallResp.JSON200.Url, t) // Stop. - stopResp, err := adminClient.StopDebugSessionWithResponse( + stopResp, err := lib.AdminClient.StopDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(stopResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(stopResp.StatusCode(), http.StatusNoContent, t) // Delete. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", sessionID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } diff --git a/test/suites/integration/admin_api_group_bindings_test.go b/test/suites/integration/admin_api_group_bindings_test.go index aa6a6fd..57dab3a 100644 --- a/test/suites/integration/admin_api_group_bindings_test.go +++ b/test/suites/integration/admin_api_group_bindings_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -11,52 +12,52 @@ import ( // and that those groups are reflected in the GetUser response. func TestAdminUserGroupBindingsAssign(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createUserResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) - userID := mustGetAdminUserID(t, superRequestEditor, name) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + userID := lib.MustGetAdminUserID(t, superRequestEditor, name) - grp1Resp, err := adminClient.CreateGroupWithResponse( + grp1Resp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grp1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grp1Resp.StatusCode(), http.StatusCreated, t) grp1ID := grp1Resp.JSON201.Id - grp2Resp, err := adminClient.CreateGroupWithResponse( + grp2Resp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grp2Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grp2Resp.StatusCode(), http.StatusCreated, t) grp2ID := grp2Resp.JSON201.Id - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grp1ID, grp2ID}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), userID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200.Groups == nil { t.Fatal("expected non-nil groups on user") } @@ -67,79 +68,79 @@ func TestAdminUserGroupBindingsAssign(t *testing.T) { for _, g := range *getResp.JSON200.Groups { groupIDs = append(groupIDs, g.Id) } - containsAll([]int{grp1ID, grp2ID}, groupIDs, t) + lib.ContainsAll([]int{grp1ID, grp2ID}, groupIDs, t) } // TestAdminUserGroupBindingsUpdate verifies that a user's group membership can be partially updated // (groups removed and added). func TestAdminUserGroupBindingsUpdate(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createUserResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) - userID := mustGetAdminUserID(t, superRequestEditor, name) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + userID := lib.MustGetAdminUserID(t, superRequestEditor, name) - grp1Resp, err := adminClient.CreateGroupWithResponse( + grp1Resp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grp1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grp1Resp.StatusCode(), http.StatusCreated, t) grp1ID := grp1Resp.JSON201.Id - grp2Resp, err := adminClient.CreateGroupWithResponse( + grp2Resp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grp2Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grp2Resp.StatusCode(), http.StatusCreated, t) grp2ID := grp2Resp.JSON201.Id - grp3Resp, err := adminClient.CreateGroupWithResponse( + grp3Resp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grp3Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grp3Resp.StatusCode(), http.StatusCreated, t) grp3ID := grp3Resp.JSON201.Id // Assign to grp1 and grp2. - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grp1ID, grp2ID}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) // Update: remove grp1, add grp3. - updateResp, err = adminClient.UpdateUserGroupsWithResponse( + updateResp, err = lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grp2ID, grp3ID}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), userID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200.Groups == nil { t.Fatal("expected non-nil groups on user") } @@ -150,7 +151,7 @@ func TestAdminUserGroupBindingsUpdate(t *testing.T) { for _, g := range *getResp.JSON200.Groups { groupIDs = append(groupIDs, g.Id) } - containsAll([]int{grp2ID, grp3ID}, groupIDs, t) + lib.ContainsAll([]int{grp2ID, grp3ID}, groupIDs, t) for _, id := range groupIDs { if id == grp1ID { t.Fatalf("grp1 should have been removed from user groups") @@ -161,54 +162,54 @@ func TestAdminUserGroupBindingsUpdate(t *testing.T) { // TestAdminUserGroupBindingsClear verifies that a user's group memberships can be cleared. func TestAdminUserGroupBindingsClear(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createUserResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) - userID := mustGetAdminUserID(t, superRequestEditor, name) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + userID := lib.MustGetAdminUserID(t, superRequestEditor, name) - grpResp, err := adminClient.CreateGroupWithResponse( + grpResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) grpID := grpResp.JSON201.Id // Assign to the group. - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grpID}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) // Clear all groups. - updateResp, err = adminClient.UpdateUserGroupsWithResponse( + updateResp, err = lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), userID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200.Groups != nil && len(*getResp.JSON200.Groups) != 0 { t.Fatalf("expected 0 groups after clear, got %d", len(*getResp.JSON200.Groups)) } @@ -217,15 +218,15 @@ func TestAdminUserGroupBindingsClear(t *testing.T) { // TestAdminUserGroupBindingsNotFoundUser verifies that updating groups for a non-existent user returns 404. func TestAdminUserGroupBindingsNotFoundUser(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), 999999999, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(updateResp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(updateResp.JSON404, t) } diff --git a/test/suites/integration/admin_api_groups_test.go b/test/suites/integration/admin_api_groups_test.go index 7ccad89..b295584 100644 --- a/test/suites/integration/admin_api_groups_test.go +++ b/test/suites/integration/admin_api_groups_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,17 +11,17 @@ import ( // TestAdminGroupCreate verifies that a new admin group can be created. func TestAdminGroupCreate(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - matches(createResp.JSON201.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.Matches(createResp.JSON201.Name, name, t) if createResp.JSON201.Id == 0 { t.Fatal("expected non-zero group ID in create response") } @@ -38,51 +39,51 @@ func TestAdminGroupCreate(t *testing.T) { // TestAdminGroupCreateConflict verifies that creating a duplicate admin group name is rejected. func TestAdminGroupCreateConflict(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - dupResp, err := adminClient.CreateGroupWithResponse( + dupResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(dupResp.StatusCode(), http.StatusConflict, t) - verifyAdminAPIErrorResponse(dupResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(dupResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAdminAPIErrorResponse(dupResp.JSON409, t) } // TestAdminGroupList verifies that a newly created admin group appears in the list response. func TestAdminGroupList(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) createdID := createResp.JSON201.Id - listResp, err := adminClient.GetGroupsWithResponse( + listResp, err := lib.AdminClient.GetGroupsWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) for _, g := range *listResp.JSON200 { if g.Id == createdID { - matches(g.Name, name, t) + lib.Matches(g.Name, name, t) return } } @@ -92,158 +93,158 @@ func TestAdminGroupList(t *testing.T) { // TestAdminGroupGet verifies that a created admin group can be fetched by ID. func TestAdminGroupGet(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) groupID := createResp.JSON201.Id - getResp, err := adminClient.GetGroupWithResponse( + getResp, err := lib.AdminClient.GetGroupWithResponse( t.Context(), groupID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Id, groupID, t) - matches(getResp.JSON200.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Id, groupID, t) + lib.Matches(getResp.JSON200.Name, name, t) } // TestAdminGroupGetNotFound verifies that fetching a non-existent admin group returns 404. func TestAdminGroupGetNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - getResp, err := adminClient.GetGroupWithResponse( + getResp, err := lib.AdminClient.GetGroupWithResponse( t.Context(), 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(getResp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(getResp.JSON404, t) } // TestAdminGroupUpdate verifies that an admin group's name can be updated. func TestAdminGroupUpdate(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) groupID := createResp.JSON201.Id - newName := groupName() - updateResp, err := adminClient.UpdateGroupWithResponse( + newName := lib.GroupName() + updateResp, err := lib.AdminClient.UpdateGroupWithResponse( t.Context(), groupID, adminapi.UpdateGroupJSONRequestBody{Name: newName, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetGroupWithResponse( + getResp, err := lib.AdminClient.GetGroupWithResponse( t.Context(), groupID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Name, newName, t) } // TestAdminGroupUpdateConflict verifies that updating an admin group's name to an existing name returns a conflict. func TestAdminGroupUpdateConflict(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - name2 := groupName() - createResp2, err := adminClient.CreateGroupWithResponse( + name2 := lib.GroupName() + createResp2, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name2, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) groupID := createResp.JSON201.Id - updateResp, err := adminClient.UpdateGroupWithResponse( + updateResp, err := lib.AdminClient.UpdateGroupWithResponse( t.Context(), groupID, adminapi.UpdateGroupJSONRequestBody{Name: name2, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) - verifyAdminAPIErrorResponse(updateResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAdminAPIErrorResponse(updateResp.JSON409, t) } // TestAdminGroupDelete verifies that an admin group can be deleted and is no longer retrievable. func TestAdminGroupDelete(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := adminClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), adminapi.CreateGroupJSONRequestBody{Name: name, PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) groupID := createResp.JSON201.Id - deleteResp, err := adminClient.DeleteGroupWithResponse( + deleteResp, err := lib.AdminClient.DeleteGroupWithResponse( t.Context(), groupID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetGroupWithResponse( + getResp, err := lib.AdminClient.GetGroupWithResponse( t.Context(), groupID, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestAdminGroupDeleteNotFound verifies that deleting a non-existent admin group returns 404. func TestAdminGroupDeleteNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - deleteResp, err := adminClient.DeleteGroupWithResponse( + deleteResp, err := lib.AdminClient.DeleteGroupWithResponse( t.Context(), 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(deleteResp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(deleteResp.JSON404, t) } diff --git a/test/suites/integration/admin_api_permissions_test.go b/test/suites/integration/admin_api_permissions_test.go index e0f50a8..0f21fba 100644 --- a/test/suites/integration/admin_api_permissions_test.go +++ b/test/suites/integration/admin_api_permissions_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -35,14 +36,14 @@ const ( // available permissions. func TestPermissionsGetPermissions(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.GetPermissionsWithResponse( + resp, err := lib.AdminClient.GetPermissionsWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) if resp.JSON200 == nil || len(*resp.JSON200) == 0 { t.Fatal("expected non-empty permissions list") @@ -76,89 +77,89 @@ func TestPermissionsGetPermissions(t *testing.T) { // permission-gated endpoint without being a member of any group. func TestPermissionsSuperuserAccessAll(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // GetFlow — requires flowviewer. - getFlowResp, err := adminClient.GetFlowWithResponse( + getFlowResp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) // GetBackendOAS — requires oasviewer. - getOASResp, err := adminClient.GetBackendOASWithResponse( + getOASResp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getOASResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getOASResp.StatusCode(), http.StatusOK, t) // Basic auth endpoint (GET) — requires basicauthorgadmin or basicauthorgviewer. - orgID, _ := orgWithSession(t, superRequestEditor) - listUsersResp, err := basicAuthClient.ListUsersWithResponse( + orgID, _ := lib.OrgWithSession(t, superRequestEditor) + listUsersResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) // Basic auth endpoint (non-GET) — requires basicauthorgadmin. - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) // Admin user mgmt (GET) — requires adminusermgmtadmin or adminusermgmtviewer. - getUsersResp, err := adminClient.GetUsersWithResponse( + getUsersResp, err := lib.AdminClient.GetUsersWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUsersResp.StatusCode(), http.StatusOK, t) // Admin user mgmt (non-GET) — requires adminusermgmtadmin. - createUserResp, err := adminClient.CreateUserWithResponse( + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), - adminapi.CreateUserJSONRequestBody{Username: username(), Password: "password123"}, + adminapi.CreateUserJSONRequestBody{Username: lib.Username(), Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) // Debug (GET) — requires debugger. - listDebugResp, err := adminClient.ListDebugSessionsWithResponse( + listDebugResp, err := lib.AdminClient.ListDebugSessionsWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listDebugResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listDebugResp.StatusCode(), http.StatusOK, t) // Debug (POST) — requires debugger. - startDebugResp, err := adminClient.StartDebugSessionWithResponse( + startDebugResp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), "echo", adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(startDebugResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(startDebugResp.StatusCode(), http.StatusOK, t) // Clean up the debug session started above. - deleteDebugResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteDebugResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", startDebugResp.JSON200.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteDebugResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteDebugResp.StatusCode(), http.StatusNoContent, t) } // --- flowviewer permission --- @@ -167,57 +168,57 @@ func TestPermissionsSuperuserAccessAll(t *testing.T) { // permission can call GetFlow. func TestPermissionsFlowViewerAllowed(t *testing.T) { t.Parallel() - superSession := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superSession, []int{PermissionIDFlowViewer}) + superSession := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superSession, []int{PermissionIDFlowViewer}) - resp, err := adminClient.GetFlowWithResponse( + resp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) } // TestPermissionsFlowViewerDeniedWithoutPermission verifies that an admin user without // the flowviewer permission receives 403 when calling GetFlow. func TestPermissionsFlowViewerDeniedWithoutPermission(t *testing.T) { t.Parallel() - superSession := superLogin(t) + superSession := lib.SuperLogin(t) // Give only oasviewer — no flowviewer. - adminRequestEditor := createAdminUserInGroup(t, superSession, []int{PermissionIDOASViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superSession, []int{PermissionIDOASViewer}) - resp, err := adminClient.GetFlowWithResponse( + resp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) } // TestPermissionsFlowViewerDeniedNoGroup verifies that an admin user in no group at all // receives 403 when calling GetFlow. func TestPermissionsFlowViewerDeniedNoGroup(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) const pass = "testpassword1" - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - adminRequestEditor := adminUserLogin(t, name, pass) + adminRequestEditor := lib.AdminUserLogin(t, name, pass) - resp, err := adminClient.GetFlowWithResponse( + resp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) } // --- oasviewer permission --- @@ -226,33 +227,33 @@ func TestPermissionsFlowViewerDeniedNoGroup(t *testing.T) { // permission can call GetBackendOAS. func TestPermissionsOASViewerAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDOASViewer}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDOASViewer}) - resp, err := adminClient.GetBackendOASWithResponse( + resp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) } // TestPermissionsOASViewerDeniedWithoutPermission verifies that an admin user without // the oasviewer permission receives 403 when calling GetBackendOAS. func TestPermissionsOASViewerDeniedWithoutPermission(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Give only flowviewer — no oasviewer. - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) - resp, err := adminClient.GetBackendOASWithResponse( + resp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) } // --- basicauthorgadmin permission --- @@ -262,38 +263,38 @@ func TestPermissionsOASViewerDeniedWithoutPermission(t *testing.T) { // basic auth API. func TestPermissionsBasicAuthOrgAdminAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgAdmin}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgAdmin}) // basicauthorgadmin must be able to create an organisation (write). - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id // basicauthorgadmin must be able to list users (read). - listUsersResp, err := basicAuthClient.ListUsersWithResponse( + listUsersResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) // basicauthorgadmin must be able to create a user (write). - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) } // TestPermissionsBasicAuthOrgAdminDeniedWithoutPermission verifies that an admin user @@ -301,18 +302,18 @@ func TestPermissionsBasicAuthOrgAdminAllowed(t *testing.T) { // through to session lookup (which does not recognise an admin session), returning 401. func TestPermissionsBasicAuthOrgAdminDeniedWithoutPermission(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Give only flowviewer — no basic auth permission. - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) // The admin session is not a valid basic auth session, so the middleware returns 401. - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusUnauthorized, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusUnauthorized, t) } // --- basicauthorgviewer permission --- @@ -321,30 +322,30 @@ func TestPermissionsBasicAuthOrgAdminDeniedWithoutPermission(t *testing.T) { // basicauthorgviewer permission can call GET endpoints on the basic auth API. func TestPermissionsBasicAuthOrgViewerReadAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Create an org via the superuser first so there is something to read. - orgID, _ := orgWithSession(t, superRequestEditor) + orgID, _ := lib.OrgWithSession(t, superRequestEditor) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgViewer}) // basicauthorgviewer must be able to list users (GET). - listUsersResp, err := basicAuthClient.ListUsersWithResponse( + listUsersResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) // basicauthorgviewer must be able to list groups (GET). - listGroupsResp, err := basicAuthClient.ListGroupsWithResponse( + listGroupsResp, err := lib.BasicAuthClient.ListGroupsWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) } // TestPermissionsBasicAuthOrgViewerWriteDenied verifies that an admin user with the @@ -352,28 +353,28 @@ func TestPermissionsBasicAuthOrgViewerReadAllowed(t *testing.T) { // auth API. func TestPermissionsBasicAuthOrgViewerWriteDenied(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgViewer}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDBasicAuthOrgViewer}) // basicauthorgviewer must NOT be able to create an organisation (POST). - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusForbidden, t) - orgID, _ := orgWithSession(t, superRequestEditor) + orgID, _ := lib.OrgWithSession(t, superRequestEditor) // Also verify that a user-creation call (POST) is denied. - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusForbidden, t) } // TestPermissionsBasicAuthOrgViewerDeniedWithoutPermission verifies that an admin user @@ -382,19 +383,19 @@ func TestPermissionsBasicAuthOrgViewerWriteDenied(t *testing.T) { // returning 401. func TestPermissionsBasicAuthOrgViewerDeniedWithoutPermission(t *testing.T) { t.Parallel() - superSession := superLogin(t) - orgID, _ := orgWithSession(t, superSession) + superSession := lib.SuperLogin(t) + orgID, _ := lib.OrgWithSession(t, superSession) // Give only flowviewer — no basic auth permission. - adminRequestEditor := createAdminUserInGroup(t, superSession, []int{PermissionIDFlowViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superSession, []int{PermissionIDFlowViewer}) - listUsersResp, err := basicAuthClient.ListUsersWithResponse( + listUsersResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusUnauthorized, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusUnauthorized, t) } // --- Group response includes permissions --- @@ -403,16 +404,16 @@ func TestPermissionsBasicAuthOrgViewerDeniedWithoutPermission(t *testing.T) { // present and accurate in the group create/get responses. func TestPermissionsGroupResponseIncludesPermissions(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) permIDs := []int{PermissionIDFlowViewer, PermissionIDOASViewer} - createResp, err := adminClient.CreateGroupWithResponse( + createResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: permIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: permIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) if createResp.JSON201.Permissions == nil || len(*createResp.JSON201.Permissions) == 0 { t.Fatal("expected permissions in create group response, got empty slice") @@ -422,17 +423,17 @@ func TestPermissionsGroupResponseIncludesPermissions(t *testing.T) { for _, p := range *createResp.JSON201.Permissions { returnedIDs = append(returnedIDs, p.Id) } - containsAll(permIDs, returnedIDs, t) - containsAll(returnedIDs, permIDs, t) + lib.ContainsAll(permIDs, returnedIDs, t) + lib.ContainsAll(returnedIDs, permIDs, t) // Verify the same data is returned by GetGroup. - getResp, err := adminClient.GetGroupWithResponse( + getResp, err := lib.AdminClient.GetGroupWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if getResp.JSON200.Permissions == nil || len(*getResp.JSON200.Permissions) == 0 { t.Fatal("expected permissions in get group response, got empty slice") @@ -442,8 +443,8 @@ func TestPermissionsGroupResponseIncludesPermissions(t *testing.T) { for _, p := range *getResp.JSON200.Permissions { getReturnedIDs = append(getReturnedIDs, p.Id) } - containsAll(permIDs, getReturnedIDs, t) - containsAll(getReturnedIDs, permIDs, t) + lib.ContainsAll(permIDs, getReturnedIDs, t) + lib.ContainsAll(getReturnedIDs, permIDs, t) } // --- adminusermgmtadmin permission --- @@ -453,97 +454,97 @@ func TestPermissionsGroupResponseIncludesPermissions(t *testing.T) { // admin user and group management endpoints. func TestPermissionsAdminUserMgmtAdminAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtAdmin}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtAdmin}) // adminusermgmtadmin must be able to list users (GET). - listUsersResp, err := adminClient.GetUsersWithResponse( + listUsersResp, err := lib.AdminClient.GetUsersWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) // adminusermgmtadmin must be able to create a user (POST). - name := username() + name := lib.Username() const pass = "testpassword1" - createUserResp, err := adminClient.CreateUserWithResponse( + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) // adminusermgmtadmin must be able to list users (GET). - userID := mustGetAdminUserID(t, adminRequestEditor, name) + userID := lib.MustGetAdminUserID(t, adminRequestEditor, name) // adminusermgmtadmin must be able to get a user (GET). - getUserResp, err := adminClient.GetUserWithResponse( + getUserResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), userID, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserResp.StatusCode(), http.StatusOK, t) // adminusermgmtadmin must be able to list groups (GET). - listGroupsResp, err := adminClient.GetGroupsWithResponse( + listGroupsResp, err := lib.AdminClient.GetGroupsWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) // adminusermgmtadmin must be able to create a group (POST). - createGroupResp, err := adminClient.CreateGroupWithResponse( + createGroupResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: []int{}}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: []int{}}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id // adminusermgmtadmin must be able to update user–group bindings (PUT). - updateGroupsResp, err := adminClient.UpdateUserGroupsWithResponse( + updateGroupsResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{groupID}}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateGroupsResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateGroupsResp.StatusCode(), http.StatusNoContent, t) // adminusermgmtadmin must be able to update a group (PUT). - newGroupName := groupName() - updateGroupResp, err := adminClient.UpdateGroupWithResponse( + newGroupName := lib.GroupName() + updateGroupResp, err := lib.AdminClient.UpdateGroupWithResponse( t.Context(), groupID, adminapi.UpdateGroupJSONRequestBody{Name: newGroupName, PermissionIDs: []int{}}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateGroupResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateGroupResp.StatusCode(), http.StatusNoContent, t) // adminusermgmtadmin must be able to delete a user (DELETE). - deleteUserResp, err := adminClient.DeleteUserWithResponse( + deleteUserResp, err := lib.AdminClient.DeleteUserWithResponse( t.Context(), userID, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteUserResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteUserResp.StatusCode(), http.StatusNoContent, t) // adminusermgmtadmin must be able to delete a group (DELETE). - deleteGroupResp, err := adminClient.DeleteGroupWithResponse( + deleteGroupResp, err := lib.AdminClient.DeleteGroupWithResponse( t.Context(), groupID, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteGroupResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteGroupResp.StatusCode(), http.StatusNoContent, t) } // --- adminusermgmtviewer permission --- @@ -552,24 +553,24 @@ func TestPermissionsAdminUserMgmtAdminAllowed(t *testing.T) { // adminusermgmtviewer permission can call GET endpoints on the admin user/group mgmt API. func TestPermissionsAdminUserMgmtViewerReadAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) // adminusermgmtviewer must be able to list users (GET). - listUsersResp, err := adminClient.GetUsersWithResponse( + listUsersResp, err := lib.AdminClient.GetUsersWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) // adminusermgmtviewer must be able to list groups (GET). - listGroupsResp, err := adminClient.GetGroupsWithResponse( + listGroupsResp, err := lib.AdminClient.GetGroupsWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listGroupsResp.StatusCode(), http.StatusOK, t) } // TestPermissionsAdminUserMgmtViewerWriteDenied verifies that an admin user with the @@ -577,124 +578,124 @@ func TestPermissionsAdminUserMgmtViewerReadAllowed(t *testing.T) { // user/group mgmt API. func TestPermissionsAdminUserMgmtViewerWriteDenied(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) // adminusermgmtviewer must NOT be able to create a user (POST). - createUserResp, err := adminClient.CreateUserWithResponse( + createUserResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), - adminapi.CreateUserJSONRequestBody{Username: username(), Password: "testpassword1"}, + adminapi.CreateUserJSONRequestBody{Username: lib.Username(), Password: "testpassword1"}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusForbidden, t) // adminusermgmtviewer must NOT be able to create a group (POST). - createGroupResp, err := adminClient.CreateGroupWithResponse( + createGroupResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: []int{}}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: []int{}}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusForbidden, t) } // TestPermissionsAdminUserMgmtViewerDeniedWithoutPermission verifies that an admin user // with no user mgmt permission receives 403 when calling even GET user mgmt endpoints. func TestPermissionsAdminUserMgmtViewerDeniedWithoutPermission(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Give only flowviewer — no user mgmt permission. - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) - listUsersResp, err := adminClient.GetUsersWithResponse( + listUsersResp, err := lib.AdminClient.GetUsersWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusForbidden, t) } // TestPermissionsAdminUserMgmtViewerGetSelf verifies that an admin user // with no user mgmt permission can still get their own user information. func TestPermissionsAdminUserMgmtViewerGetSelf(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "pass"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - userRequestEditor := adminUserLogin(t, name, "pass") + userRequestEditor := lib.AdminUserLogin(t, name, "pass") - listUsersResp, err := adminClient.GetUserWithResponse( + listUsersResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(userRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) - matches(listUsersResp.JSON200.Username, name, t) - matches(listUsersResp.JSON200.Id, createResp.JSON201.Id, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusOK, t) + lib.Matches(listUsersResp.JSON200.Username, name, t) + lib.Matches(listUsersResp.JSON200.Id, createResp.JSON201.Id, t) } // TestPermissionsNormalUserLogoutSuper verifies that a normal admin user, even with permissions to call the logout // endpoint, cannot log out the superuser. func TestPermissionsNormalUserLogoutSuper(t *testing.T) { - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDAdminUserMgmtViewer}) // Normal admin users should not be able to log out the superuser, even if they // have permissions to call the logout endpoint. - logoutResp, err := adminClient.LogoutSuperuserWithResponse( + logoutResp, err := lib.AdminClient.LogoutSuperuserWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(logoutResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(logoutResp.StatusCode(), http.StatusForbidden, t) } // TestPermissionsAdminUserChangePasswordWrongUser verifies that an admin user cannot change another user's // password without the appropriate permission. func TestPermissionsAdminUserChangePasswordWrongUser(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "correctpassword123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - name2 := username() - createResp2, err := adminClient.CreateUserWithResponse( + name2 := lib.Username() + createResp2, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name2, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) - userRequestEditor := adminUserLogin(t, name2, pass) + userRequestEditor := lib.AdminUserLogin(t, name2, pass) - changeResp, err := adminClient.ChangeUserPasswordWithResponse( + changeResp, err := lib.AdminClient.ChangeUserPasswordWithResponse( t.Context(), createResp.JSON201.Id, adminapi.ChangeUserPasswordJSONRequestBody{OldPassword: pass, NewPassword: "newpass"}, adminapi.RequestEditorFn(userRequestEditor), ) - checkErr(err, t) - verifyStatusCode(changeResp.StatusCode(), http.StatusForbidden, t) - verifyAdminAPIErrorResponse(changeResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changeResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAdminAPIErrorResponse(changeResp.JSON403, t) } // --- debugger permission --- @@ -703,44 +704,44 @@ func TestPermissionsAdminUserChangePasswordWrongUser(t *testing.T) { // can call StartDebugSession. func TestPermissionsDebuggerAllowed(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDDebugger}) + superRequestEditor := lib.SuperLogin(t) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDDebugger}) - resp, err := adminClient.StartDebugSessionWithResponse( + resp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), "echo", adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) // Clean up. - deleteResp, err := adminClient.DeleteDebugSessionWithResponse( + deleteResp, err := lib.AdminClient.DeleteDebugSessionWithResponse( t.Context(), "echo", resp.JSON200.Id, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestPermissionsDebuggerDenied verifies that an admin user without the debugger permission // receives 403 when calling StartDebugSession. func TestPermissionsDebuggerDenied(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Give only flowviewer — no debugger. - adminRequestEditor := createAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) + adminRequestEditor := lib.CreateAdminUserInGroup(t, superRequestEditor, []int{PermissionIDFlowViewer}) - resp, err := adminClient.StartDebugSessionWithResponse( + resp, err := lib.AdminClient.StartDebugSessionWithResponse( t.Context(), "echo", adminapi.StartDebugSessionJSONRequestBody{}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) - verifyAdminAPIErrorResponse(resp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON403, t) } diff --git a/test/suites/integration/admin_api_session_test.go b/test/suites/integration/admin_api_session_test.go index e92604a..bb8ed68 100644 --- a/test/suites/integration/admin_api_session_test.go +++ b/test/suites/integration/admin_api_session_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -12,113 +13,113 @@ import ( // to trigger an error — only the missing refresh cookie matters here. func TestAdminRefreshSuperuserSessionNoRefreshCookie(t *testing.T) { t.Parallel() - resp, err := adminClient.RefreshSuperuserSessionWithResponse(t.Context()) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) - verifyAdminAPIErrorResponse(resp.JSON401, t) + resp, err := lib.AdminClient.RefreshSuperuserSessionWithResponse(t.Context()) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON401, t) } // TestAdminRefreshSuperuserSession verifies that the superuser refresh endpoint issues a new // session when called with only the refresh cookie (no session cookie required). func TestAdminRefreshSuperuserSession(t *testing.T) { t.Parallel() - loginResp, err := adminClient.LoginSuperuserWithResponse( + loginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) // Use only the refresh cookie — deliberately omit the session cookie to prove it is not required. - refreshEditor := refreshCookieRequestEditor(loginResp.HTTPResponse, t) + refreshEditor := lib.RefreshCookieRequestEditor(loginResp.HTTPResponse, t) - refreshResp, err := adminClient.RefreshSuperuserSessionWithResponse( + refreshResp, err := lib.AdminClient.RefreshSuperuserSessionWithResponse( t.Context(), adminapi.RequestEditorFn(refreshEditor), ) - checkErr(err, t) - verifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) } // TestAdminRefreshSuperuserSessionForbidden verifies that a non-superuser admin refresh token // is rejected by the superuser refresh endpoint with 403. func TestAdminRefreshSuperuserSessionForbidden(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "password123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) // Login as the regular admin user to get a non-superuser refresh token. - loginResp, err := adminClient.LoginWithResponse( + loginResp, err := lib.AdminClient.LoginWithResponse( t.Context(), adminapi.LoginJSONRequestBody{Username: name, Password: pass}, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) // Use only the refresh cookie from the regular user session. - userRefreshEditor := refreshCookieRequestEditor(loginResp.HTTPResponse, t) + userRefreshEditor := lib.RefreshCookieRequestEditor(loginResp.HTTPResponse, t) - refreshResp, err := adminClient.RefreshSuperuserSessionWithResponse( + refreshResp, err := lib.AdminClient.RefreshSuperuserSessionWithResponse( t.Context(), adminapi.RequestEditorFn(userRefreshEditor), ) - checkErr(err, t) - verifyStatusCode(refreshResp.StatusCode(), http.StatusForbidden, t) - verifyAdminAPIErrorResponse(refreshResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(refreshResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAdminAPIErrorResponse(refreshResp.JSON403, t) } // TestAdminRefreshUserSessionNoRefreshCookie verifies that calling the admin user refresh // endpoint without a refresh cookie returns 401. func TestAdminRefreshUserSessionNoRefreshCookie(t *testing.T) { t.Parallel() - resp, err := adminClient.RefreshUserSessionWithResponse(t.Context()) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) - verifyAdminAPIErrorResponse(resp.JSON401, t) + resp, err := lib.AdminClient.RefreshUserSessionWithResponse(t.Context()) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON401, t) } // TestAdminRefreshUserSession verifies that the admin user refresh endpoint issues a new // session when called with only the refresh cookie (no session cookie required). func TestAdminRefreshUserSession(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "password123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - loginResp, err := adminClient.LoginWithResponse( + loginResp, err := lib.AdminClient.LoginWithResponse( t.Context(), adminapi.LoginJSONRequestBody{Username: name, Password: pass}, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) // Use only the refresh cookie — deliberately omit the session cookie. - refreshEditor := refreshCookieRequestEditor(loginResp.HTTPResponse, t) + refreshEditor := lib.RefreshCookieRequestEditor(loginResp.HTTPResponse, t) - refreshResp, err := adminClient.RefreshUserSessionWithResponse( + refreshResp, err := lib.AdminClient.RefreshUserSessionWithResponse( t.Context(), adminapi.RequestEditorFn(refreshEditor), ) - checkErr(err, t) - verifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) } diff --git a/test/suites/integration/admin_api_test.go b/test/suites/integration/admin_api_test.go index 8441ad7..00b20f7 100644 --- a/test/suites/integration/admin_api_test.go +++ b/test/suites/integration/admin_api_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -12,55 +13,55 @@ import ( var allPermissionIDs = []int{1, 2, 3, 4, 5, 6, 7} func TestAdminLoginSuperuser(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) t.Log("Logging the superuser out") - superLogoutResp, err := adminClient.LogoutSuperuserWithResponse( + superLogoutResp, err := lib.AdminClient.LogoutSuperuserWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(superLogoutResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(superLogoutResp.StatusCode(), http.StatusNoContent, t) t.Log("Running a GET flow request with the old session to verify it is invalidated") // Verify the old session is truly invalidated by attempting to access a protected endpoint with it. - getFlowResp, err := adminClient.GetFlowWithResponse( + getFlowResp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getFlowResp.StatusCode(), http.StatusUnauthorized, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getFlowResp.StatusCode(), http.StatusUnauthorized, t) } func TestAdminLoginSuperuserFailure(t *testing.T) { t.Parallel() - superLoginResp, err := adminClient.LoginSuperuserWithResponse( + superLoginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: "not-correct"}, + adminapi.LoginSuperuserJSONRequestBody{ClientId: lib.SuperUserClientID, ClientSecret: "not-correct"}, ) - checkErr(err, t) - verifyStatusCode(superLoginResp.StatusCode(), http.StatusUnauthorized, t) - verifyAdminAPIErrorResponse(superLoginResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(superLoginResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAdminAPIErrorResponse(superLoginResp.JSON401, t) } func TestAdminOASFailure(t *testing.T) { t.Parallel() - badSuperLoginResp, err := adminClient.LoginSuperuserWithResponse(t.Context(), adminapi.LoginSuperuserJSONRequestBody{}) - checkErr(err, t) - verifyStatusCode(badSuperLoginResp.StatusCode(), http.StatusBadRequest, t) - verifyAdminAPIErrorResponse(badSuperLoginResp.JSON400, t) + badSuperLoginResp, err := lib.AdminClient.LoginSuperuserWithResponse(t.Context(), adminapi.LoginSuperuserJSONRequestBody{}) + lib.CheckErr(err, t) + lib.VerifyStatusCode(badSuperLoginResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAdminAPIErrorResponse(badSuperLoginResp.JSON400, t) } func TestAdminGetFlow(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - getFlowResp, err := adminClient.GetFlowWithResponse( + getFlowResp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) for i, component := range *getFlowResp.JSON200 { t.Logf("Flow component index: %d name: %s", i, component.Name) @@ -114,116 +115,116 @@ func TestAdminGetFlow(t *testing.T) { func TestAdminGetBackendOASNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - resp, err := adminClient.GetBackendOASWithResponse( + resp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "nonexistent-backend", adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(resp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(resp.JSON404, t) } func TestAdminGetBackendOAS(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - getBackendOASResp, err := adminClient.GetBackendOASWithResponse( + getBackendOASResp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getBackendOASResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getBackendOASResp.StatusCode(), http.StatusOK, t) } // TestAdminGetFlowAsAdminUser verifies that a non-superuser admin user can also access the GetFlow endpoint. func TestAdminGetFlowAsAdminUser(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "password123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - userID := mustGetAdminUserID(t, superRequestEditor, name) + userID := lib.MustGetAdminUserID(t, superRequestEditor, name) // Create a group with the flowviewer permission and assign the user to it. - grpResp, err := adminClient.CreateGroupWithResponse( + grpResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grpResp.JSON201.Id}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - adminRequestEditor := adminUserLogin(t, name, pass) + adminRequestEditor := lib.AdminUserLogin(t, name, pass) - getFlowResp, err := adminClient.GetFlowWithResponse( + getFlowResp, err := lib.AdminClient.GetFlowWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getFlowResp.StatusCode(), http.StatusOK, t) } // TestAdminGetBackendOASAsAdminUser verifies that a non-superuser admin user can also access the GetBackendOAS endpoint. func TestAdminGetBackendOASAsAdminUser(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "password123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - userID := mustGetAdminUserID(t, superRequestEditor, name) + userID := lib.MustGetAdminUserID(t, superRequestEditor, name) // Create a group with the oasviewer permission and assign the user to it. - grpResp, err := adminClient.CreateGroupWithResponse( + grpResp, err := lib.AdminClient.CreateGroupWithResponse( t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: allPermissionIDs}, + adminapi.CreateGroupJSONRequestBody{Name: lib.GroupName(), PermissionIDs: allPermissionIDs}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) - updateResp, err := adminClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.AdminClient.UpdateUserGroupsWithResponse( t.Context(), userID, adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grpResp.JSON201.Id}}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - adminRequestEditor := adminUserLogin(t, name, pass) + adminRequestEditor := lib.AdminUserLogin(t, name, pass) - getBackendOASResp, err := adminClient.GetBackendOASWithResponse( + getBackendOASResp, err := lib.AdminClient.GetBackendOASWithResponse( t.Context(), "echo", adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getBackendOASResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getBackendOASResp.StatusCode(), http.StatusOK, t) } diff --git a/test/suites/integration/admin_api_users_test.go b/test/suites/integration/admin_api_users_test.go index 793ea7e..2cb2a57 100644 --- a/test/suites/integration/admin_api_users_test.go +++ b/test/suites/integration/admin_api_users_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,61 +11,61 @@ import ( // TestAdminUserCreate verifies that a new admin user can be created via a superuser session. func TestAdminUserCreate(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), - adminapi.CreateUserJSONRequestBody{Username: username(), Password: "password123"}, + adminapi.CreateUserJSONRequestBody{Username: lib.Username(), Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) } // TestAdminUserCreateConflict verifies that creating a duplicate admin username is rejected. func TestAdminUserCreateConflict(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - dupResp, err := adminClient.CreateUserWithResponse( + dupResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "other-password"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(dupResp.StatusCode(), http.StatusConflict, t) - verifyAdminAPIErrorResponse(dupResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(dupResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAdminAPIErrorResponse(dupResp.JSON409, t) } // TestAdminUserList verifies that a newly created admin user appears in the list response. func TestAdminUserList(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - listResp, err := adminClient.GetUsersWithResponse( + listResp, err := lib.AdminClient.GetUsersWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) for _, u := range *listResp.JSON200 { if u.Username == name { return @@ -76,297 +77,297 @@ func TestAdminUserList(t *testing.T) { // TestAdminUserGet verifies that a created admin user can be fetched by ID. func TestAdminUserGet(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Username, name, t) - matches(getResp.JSON200.Id, createResp.JSON201.Id, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Username, name, t) + lib.Matches(getResp.JSON200.Id, createResp.JSON201.Id, t) } // TestAdminUserGetNotFound verifies that fetching a non-existent admin user returns 404. func TestAdminUserGetNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(getResp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(getResp.JSON404, t) } // TestAdminUserUpdate verifies that an admin user's username can be updated. func TestAdminUserUpdate(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - newName := username() - updateResp, err := adminClient.UpdateUserWithResponse( + newName := lib.Username() + updateResp, err := lib.AdminClient.UpdateUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.UpdateUserJSONRequestBody{Username: newName}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Username, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Username, newName, t) } // TestAdminUserUpdateConflict verifies that updating an admin user's username to an existing username returns a conflict. func TestAdminUserUpdateConflict(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - name2 := username() - createResp2, err := adminClient.CreateUserWithResponse( + name2 := lib.Username() + createResp2, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name2, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp2.StatusCode(), http.StatusCreated, t) - updateResp, err := adminClient.UpdateUserWithResponse( + updateResp, err := lib.AdminClient.UpdateUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.UpdateUserJSONRequestBody{Username: name2}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) } // TestAdminUserDelete verifies that an admin user can be deleted and is no longer retrievable. func TestAdminUserDelete(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := adminClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: "password123"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - deleteResp, err := adminClient.DeleteUserWithResponse( + deleteResp, err := lib.AdminClient.DeleteUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := adminClient.GetUserWithResponse( + getResp, err := lib.AdminClient.GetUserWithResponse( t.Context(), createResp.JSON201.Id, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestAdminUserDeleteNotFound verifies that deleting a non-existent admin user returns 404. func TestAdminUserDeleteNotFound(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - deleteResp, err := adminClient.DeleteUserWithResponse( + deleteResp, err := lib.AdminClient.DeleteUserWithResponse( t.Context(), 999999999, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNotFound, t) - verifyAdminAPIErrorResponse(deleteResp.JSON404, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNotFound, t) + lib.VerifyAdminAPIErrorResponse(deleteResp.JSON404, t) } // TestAdminUserLoginLogout verifies that an admin user can log in, access protected endpoints, // log out, and that their session is invalidated afterwards. func TestAdminUserLoginLogout(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "loginpassword123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - adminRequestEditor := adminUserLogin(t, name, pass) + adminRequestEditor := lib.AdminUserLogin(t, name, pass) // GetPermissions is accessible to any authenticated admin user (no specific permission required). - getPermsResp, err := adminClient.GetPermissionsWithResponse( + getPermsResp, err := lib.AdminClient.GetPermissionsWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getPermsResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getPermsResp.StatusCode(), http.StatusOK, t) - logoutResp, err := adminClient.LogoutWithResponse( + logoutResp, err := lib.AdminClient.LogoutWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(logoutResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(logoutResp.StatusCode(), http.StatusNoContent, t) - getPermsResp, err = adminClient.GetPermissionsWithResponse( + getPermsResp, err = lib.AdminClient.GetPermissionsWithResponse( t.Context(), adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getPermsResp.StatusCode(), http.StatusUnauthorized, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getPermsResp.StatusCode(), http.StatusUnauthorized, t) } // TestAdminUserLoginFailure verifies that login with incorrect credentials returns 401. func TestAdminUserLoginFailure(t *testing.T) { t.Parallel() - loginResp, err := adminClient.LoginWithResponse( + loginResp, err := lib.AdminClient.LoginWithResponse( t.Context(), adminapi.LoginJSONRequestBody{Username: "no-such-user", Password: "wrong"}, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusUnauthorized, t) - verifyAdminAPIErrorResponse(loginResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAdminAPIErrorResponse(loginResp.JSON401, t) } // TestAdminUserChangePassword verifies that an admin user can change their password, // that the old credentials are rejected, and that the new credentials work. func TestAdminUserChangePassword(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const oldPass = "oldpassword123" const newPass = "newpassword456" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: oldPass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - adminRequestEditor := adminUserLogin(t, name, oldPass) + adminRequestEditor := lib.AdminUserLogin(t, name, oldPass) - changeResp, err := adminClient.ChangeUserPasswordWithResponse( + changeResp, err := lib.AdminClient.ChangeUserPasswordWithResponse( t.Context(), createResp.JSON201.Id, adminapi.ChangeUserPasswordJSONRequestBody{OldPassword: oldPass, NewPassword: newPass}, adminapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(changeResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changeResp.StatusCode(), http.StatusNoContent, t) - oldLoginResp, err := adminClient.LoginWithResponse( + oldLoginResp, err := lib.AdminClient.LoginWithResponse( t.Context(), adminapi.LoginJSONRequestBody{Username: name, Password: oldPass}, ) - checkErr(err, t) - verifyStatusCode(oldLoginResp.StatusCode(), http.StatusUnauthorized, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(oldLoginResp.StatusCode(), http.StatusUnauthorized, t) - _ = adminUserLogin(t, name, newPass) + _ = lib.AdminUserLogin(t, name, newPass) } // TestAdminUserChangePasswordWrongOld verifies that providing the wrong old password is rejected. func TestAdminUserChangePasswordWrongOld(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "correctpassword123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - changeResp, err := adminClient.ChangeUserPasswordWithResponse( + changeResp, err := lib.AdminClient.ChangeUserPasswordWithResponse( t.Context(), createResp.JSON201.Id, adminapi.ChangeUserPasswordJSONRequestBody{OldPassword: "wrong-old-pass", NewPassword: "newpass"}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(changeResp.StatusCode(), http.StatusBadRequest, t) - verifyAdminAPIErrorResponse(changeResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changeResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAdminAPIErrorResponse(changeResp.JSON400, t) } // TestAdminMeNormalUser verifies that a normal admin user receives their own user info from /me. func TestAdminMeNormalUser(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() + name := lib.Username() const pass = "mepassword123" - createResp, err := adminClient.CreateUserWithResponse( + createResp, err := lib.AdminClient.CreateUserWithResponse( t.Context(), adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - userRequestEditor := adminUserLogin(t, name, pass) + userRequestEditor := lib.AdminUserLogin(t, name, pass) - meResp, err := adminClient.GetMeWithResponse( + meResp, err := lib.AdminClient.GetMeWithResponse( t.Context(), adminapi.RequestEditorFn(userRequestEditor), ) - checkErr(err, t) - verifyStatusCode(meResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(meResp.StatusCode(), http.StatusOK, t) if meResp.JSON200 == nil { t.Fatal("Expected non-nil JSON200 body") @@ -377,21 +378,21 @@ func TestAdminMeNormalUser(t *testing.T) { if meResp.JSON200.User == nil { t.Fatal("Expected non-nil user field for normal admin user") } - matches(meResp.JSON200.User.Username, name, t) - matches(meResp.JSON200.User.Id, createResp.JSON201.Id, t) + lib.Matches(meResp.JSON200.User.Username, name, t) + lib.Matches(meResp.JSON200.User.Id, createResp.JSON201.Id, t) } // TestAdminMeSuperuser verifies that the superuser receives isSuperuser=true and no user field from /me. func TestAdminMeSuperuser(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - meResp, err := adminClient.GetMeWithResponse( + meResp, err := lib.AdminClient.GetMeWithResponse( t.Context(), adminapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(meResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(meResp.StatusCode(), http.StatusOK, t) if meResp.JSON200 == nil { t.Fatal("Expected non-nil JSON200 body") @@ -407,7 +408,7 @@ func TestAdminMeSuperuser(t *testing.T) { // TestAdminMeUnauthenticated verifies that calling /me without a session returns 401. func TestAdminMeUnauthenticated(t *testing.T) { t.Parallel() - meResp, err := adminClient.GetMeWithResponse(t.Context()) - checkErr(err, t) - verifyStatusCode(meResp.StatusCode(), http.StatusUnauthorized, t) + meResp, err := lib.AdminClient.GetMeWithResponse(t.Context()) + lib.CheckErr(err, t) + lib.VerifyStatusCode(meResp.StatusCode(), http.StatusUnauthorized, t) } diff --git a/test/suites/integration/admin_user.go b/test/suites/integration/admin_user.go deleted file mode 100644 index fd8f083..0000000 --- a/test/suites/integration/admin_user.go +++ /dev/null @@ -1,64 +0,0 @@ -package integration - -import ( - "net/http" - "testing" - - adminapi "github.com/trebent/kerberos/test/client/admin" -) - -// mustGetAdminUserID fetches the admin user list and returns the ID of the user with the given username. -func mustGetAdminUserID(t *testing.T, requestEditor RequestEditorFn, name string) int { - t.Helper() - resp, err := adminClient.GetUsersWithResponse( - t.Context(), - adminapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) - for _, u := range *resp.JSON200 { - if u.Username == name { - return u.Id - } - } - t.Fatalf("admin user %q not found in list", name) - return 0 -} - -// createAdminUserInGroup creates a fresh admin user, creates a group with the specified -// permissionIDs, adds the user to that group, and returns the user's session. -func createAdminUserInGroup(t *testing.T, requestEditor RequestEditorFn, permissionIDs []int) RequestEditorFn { - t.Helper() - - const pass = "testpassword1" - name := username() - - createUserResp, err := adminClient.CreateUserWithResponse( - t.Context(), - adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, - adminapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) - - userID := mustGetAdminUserID(t, requestEditor, name) - - grpResp, err := adminClient.CreateGroupWithResponse( - t.Context(), - adminapi.CreateGroupJSONRequestBody{Name: groupName(), PermissionIDs: permissionIDs}, - adminapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) - - updateResp, err := adminClient.UpdateUserGroupsWithResponse( - t.Context(), - userID, - adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grpResp.JSON201.Id}}, - adminapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) - - return adminUserLogin(t, name, pass) -} diff --git a/test/suites/integration/auth_basic_api_bindings_test.go b/test/suites/integration/auth_basic_api_bindings_test.go index 04cb9ba..4ee059d 100644 --- a/test/suites/integration/auth_basic_api_bindings_test.go +++ b/test/suites/integration/auth_basic_api_bindings_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "slices" "testing" @@ -12,47 +13,47 @@ import ( // TestUserGroupBindingAssign verifies that groups can be assigned to a user and are returned // by GetUserGroups. func TestUserGroupBindingAssign(t *testing.T) { - superLoginResp, err := adminClient.LoginSuperuserWithResponse( + superLoginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, + adminapi.LoginSuperuserJSONRequestBody{ClientId: lib.SuperUserClientID, ClientSecret: lib.SuperUserClientSecret}, ) - checkErr(err, t) - verifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) - superRequestEditor := sessionCookieRequestEditor(superLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) + superRequestEditor := lib.SessionCookieRequestEditor(superLoginResp.HTTPResponse, t) - orgID, adminRequestEditor := orgWithSession(t, superRequestEditor) + orgID, adminRequestEditor := lib.OrgWithSession(t, superRequestEditor) - groupAName := groupName() - createGroupA, err := basicAuthClient.CreateGroupWithResponse( + groupAName := lib.GroupName() + createGroupA, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, authbasicapi.CreateGroupJSONRequestBody{Name: groupAName}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupA.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupA.StatusCode(), http.StatusCreated, t) - groupBName := groupName() - createGroupB, err := basicAuthClient.CreateGroupWithResponse( + groupBName := lib.GroupName() + createGroupB, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, authbasicapi.CreateGroupJSONRequestBody{Name: groupBName}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupB.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupB.StatusCode(), http.StatusCreated, t) - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id - updateResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, userID, @@ -62,17 +63,17 @@ func TestUserGroupBindingAssign(t *testing.T) { }, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) - getResp, err := basicAuthClient.GetUserGroupsWithResponse( + getResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) groups := *getResp.JSON200 if !slices.ContainsFunc(groups, func(g authbasicapi.Group) bool { return g.Name == groupAName }) { t.Fatalf("expected group %q in user groups, got %v", groupAName, groups) @@ -85,48 +86,48 @@ func TestUserGroupBindingAssign(t *testing.T) { // TestUserGroupBindingReplace verifies that updating a user's groups replaces the previous // set entirely — groups removed from the request are no longer returned. func TestUserGroupBindingReplace(t *testing.T) { - superLoginResp, err := adminClient.LoginSuperuserWithResponse( + superLoginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, + adminapi.LoginSuperuserJSONRequestBody{ClientId: lib.SuperUserClientID, ClientSecret: lib.SuperUserClientSecret}, ) - checkErr(err, t) - verifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) - superRequestEditor := sessionCookieRequestEditor(superLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) + superRequestEditor := lib.SessionCookieRequestEditor(superLoginResp.HTTPResponse, t) - orgID, adminRequestEditor := orgWithSession(t, superRequestEditor) + orgID, adminRequestEditor := lib.OrgWithSession(t, superRequestEditor) - groupAName := groupName() - createGroupA, err := basicAuthClient.CreateGroupWithResponse( + groupAName := lib.GroupName() + createGroupA, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, authbasicapi.CreateGroupJSONRequestBody{Name: groupAName}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupA.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupA.StatusCode(), http.StatusCreated, t) - groupBName := groupName() - createGroupB, err := basicAuthClient.CreateGroupWithResponse( + groupBName := lib.GroupName() + createGroupB, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, authbasicapi.CreateGroupJSONRequestBody{Name: groupBName}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupB.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupB.StatusCode(), http.StatusCreated, t) - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id // Assign both groups initially. - initialUpdateResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + initialUpdateResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, userID, @@ -136,11 +137,11 @@ func TestUserGroupBindingReplace(t *testing.T) { }, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(initialUpdateResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(initialUpdateResp.StatusCode(), http.StatusOK, t) // Replace with only group B — group A should be removed. - replaceResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + replaceResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, userID, @@ -149,17 +150,17 @@ func TestUserGroupBindingReplace(t *testing.T) { }, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(replaceResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(replaceResp.StatusCode(), http.StatusOK, t) - getResp, err := basicAuthClient.GetUserGroupsWithResponse( + getResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) groups := *getResp.JSON200 if slices.ContainsFunc(groups, func(g authbasicapi.Group) bool { return g.Name == groupAName }) { t.Fatalf("group %q should have been removed after replace, got %v", groupAName, groups) @@ -172,38 +173,38 @@ func TestUserGroupBindingReplace(t *testing.T) { // TestUserGroupBindingClear verifies that assigning an empty group list removes all group // memberships from the user. func TestUserGroupBindingClear(t *testing.T) { - superLoginResp, err := adminClient.LoginSuperuserWithResponse( + superLoginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, + adminapi.LoginSuperuserJSONRequestBody{ClientId: lib.SuperUserClientID, ClientSecret: lib.SuperUserClientSecret}, ) - checkErr(err, t) - verifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) - superRequestEditor := sessionCookieRequestEditor(superLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(superLoginResp.StatusCode(), http.StatusNoContent, t) + superRequestEditor := lib.SessionCookieRequestEditor(superLoginResp.HTTPResponse, t) - orgID, adminRequestEditor := orgWithSession(t, superRequestEditor) + orgID, adminRequestEditor := lib.OrgWithSession(t, superRequestEditor) - gName := groupName() - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + gName := lib.GroupName() + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, authbasicapi.CreateGroupJSONRequestBody{Name: gName}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id // Assign the group first. - assignResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + assignResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, userID, @@ -212,28 +213,28 @@ func TestUserGroupBindingClear(t *testing.T) { }, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(assignResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(assignResp.StatusCode(), http.StatusOK, t) // Clear all groups. - clearResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + clearResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, userID, authbasicapi.UpdateUserGroupsJSONRequestBody{}, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(clearResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(clearResp.StatusCode(), http.StatusOK, t) - getResp, err := basicAuthClient.GetUserGroupsWithResponse( + getResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(adminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) if len(*getResp.JSON200) != 0 { t.Fatalf("expected empty groups after clear, got %v", *getResp.JSON200) } @@ -242,22 +243,22 @@ func TestUserGroupBindingClear(t *testing.T) { // TestUserGroupBindingGet verifies that GetUserGroups returns the expected groups for a user // that was set up with known group memberships in TestMain. func TestUserGroupBindingGet(t *testing.T) { - loginResp, err := adminClient.LoginSuperuserWithResponse( + loginResp, err := lib.AdminClient.LoginSuperuserWithResponse( t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, + adminapi.LoginSuperuserJSONRequestBody{ClientId: lib.SuperUserClientID, ClientSecret: lib.SuperUserClientSecret}, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - superRequestEditor := sessionCookieRequestEditor(loginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + superRequestEditor := lib.SessionCookieRequestEditor(loginResp.HTTPResponse, t) - getResp, err := basicAuthClient.GetUserGroupsWithResponse( + getResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) groups := *getResp.JSON200 for _, expected := range []string{alwaysGroupStaff, alwaysGroupPleb, alwaysGroupDev} { if !slices.ContainsFunc(groups, func(g authbasicapi.Group) bool { return g.Name == expected }) { diff --git a/test/suites/integration/auth_basic_api_groups_test.go b/test/suites/integration/auth_basic_api_groups_test.go index d00791c..b753693 100644 --- a/test/suites/integration/auth_basic_api_groups_test.go +++ b/test/suites/integration/auth_basic_api_groups_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,18 +11,18 @@ import ( // TestGroupCreate verifies that a new group can be created within an organisation and that // the response contains the expected name and a valid ID. func TestGroupCreate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := basicAuthClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - matches(createResp.JSON201.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.Matches(createResp.JSON201.Name, name, t) if createResp.JSON201.Id == 0 { t.Fatal("expected non-zero group ID in create response") } @@ -29,25 +30,25 @@ func TestGroupCreate(t *testing.T) { // TestGroupList verifies that a newly created group appears in the list response for its organisation. func TestGroupList(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateGroupWithResponse( + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) createdID := createResp.JSON201.Id - listResp, err := basicAuthClient.ListGroupsWithResponse( + listResp, err := lib.BasicAuthClient.ListGroupsWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) for _, group := range *listResp.JSON200 { if group.Id == createdID { return @@ -58,397 +59,397 @@ func TestGroupList(t *testing.T) { // TestGroupGet verifies that a created group can be fetched by ID. func TestGroupGet(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := basicAuthClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - getResp, err := basicAuthClient.GetGroupWithResponse( + getResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), createResp.JSON201.Id, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Id, createResp.JSON201.Id, t) - matches(getResp.JSON200.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Id, createResp.JSON201.Id, t) + lib.Matches(getResp.JSON200.Name, name, t) } // TestGroupGetNotFound verifies that fetching a deleted group returns 404. func TestGroupGetNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := basicAuthClient.GetGroupWithResponse( + getResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestGroupUpdate verifies that a group's name can be changed and the updated value is // reflected in a subsequent get. func TestGroupUpdate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateGroupWithResponse( + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) groupID := createResp.JSON201.Id - newName := groupName() - updateResp, err := basicAuthClient.UpdateGroupWithResponse( + newName := lib.GroupName() + updateResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), groupID, authbasicapi.UpdateGroupJSONRequestBody{Name: newName}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) - matches(updateResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) + lib.Matches(updateResp.JSON200.Name, newName, t) - getResp, err := basicAuthClient.GetGroupWithResponse( + getResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Name, newName, t) } // TestGroupUpdateConflict verifies that renaming a group to an already-taken name within the // same organisation returns a conflict error. func TestGroupUpdateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - create1Resp, err := basicAuthClient.CreateGroupWithResponse( + create1Resp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) - create2Resp, err := basicAuthClient.CreateGroupWithResponse( + create2Resp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) - updateResp, err := basicAuthClient.UpdateGroupWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), create2Resp.JSON201.Id, authbasicapi.UpdateGroupJSONRequestBody{Name: create1Resp.JSON201.Name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) } // TestGroupCreateConflict verifies that creating a group whose name already exists within the // same organisation returns a conflict error. func TestGroupCreateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := groupName() - createResp, err := basicAuthClient.CreateGroupWithResponse( + name := lib.GroupName() + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - conflictResp, err := basicAuthClient.CreateGroupWithResponse( + conflictResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) } // TestGroupDelete verifies that a deleted group is no longer accessible. func TestGroupDelete(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := basicAuthClient.GetGroupWithResponse( + getResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestGroupCreateOASValidation verifies that creating a group with an empty name is // rejected with 400 by the OAS validator (name has minLength: 1). func TestGroupCreateOASValidation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Name below minLength: 1 — must be rejected. - createResp, err := basicAuthClient.CreateGroupWithResponse( + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: ""}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON400, t) } // TestGroupUpdateOASValidation verifies that updating a group with an empty name is // rejected with 400 by the OAS validator (Group.name has minLength: 1). func TestGroupUpdateOASValidation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateGroupWithResponse( + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) // Name below minLength: 1 — must be rejected. - updateResp, err := basicAuthClient.UpdateGroupWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), createResp.JSON201.Id, authbasicapi.UpdateGroupJSONRequestBody{Name: ""}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON400, t) } // TestGroupNoSession verifies that every group-scoped endpoint returns 401 with a // populated error body when called without a session header. func TestGroupNoSession(t *testing.T) { // CreateGroup — no session. - createResp, err := basicAuthClient.CreateGroupWithResponse( + createResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON401, t) // ListGroups — no session. - listResp, err := basicAuthClient.ListGroupsWithResponse( + listResp, err := lib.BasicAuthClient.ListGroupsWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(listResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(listResp.JSON401, t) // GetGroup — no session. - getResp, err := basicAuthClient.GetGroupWithResponse( + getResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Groupid(alwaysGroupStaffID), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(getResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(getResp.JSON401, t) // UpdateGroup — no session. - updateResp, err := basicAuthClient.UpdateGroupWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Groupid(alwaysGroupStaffID), - authbasicapi.UpdateGroupJSONRequestBody{Id: int64(alwaysGroupStaffID), Name: groupName()}, + authbasicapi.UpdateGroupJSONRequestBody{Id: int64(alwaysGroupStaffID), Name: lib.GroupName()}, ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) // DeleteGroup — no session. - deleteResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Groupid(alwaysGroupStaffID), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) } // TestGroupDeleteNotFound verifies deleting an already-deleted group. func TestGroupDeleteNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id // First delete succeeds. - deleteResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Second delete must return 404 (no body defined in spec). - deleteAgainResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteAgainResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) } // TestGroupUpdateNotFound verifies that attempting to update a deleted group returns 404 // (no body defined in spec). func TestGroupUpdateNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id // Delete the group first. - deleteResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Update the deleted group must return 404 (no body defined in spec). - updateResp, err := basicAuthClient.UpdateGroupWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), orgID, groupID, - authbasicapi.UpdateGroupJSONRequestBody{Id: groupID, Name: groupName()}, + authbasicapi.UpdateGroupJSONRequestBody{Id: groupID, Name: lib.GroupName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) } diff --git a/test/suites/integration/auth_basic_api_organisations_test.go b/test/suites/integration/auth_basic_api_organisations_test.go index 7d4e2df..fe1a787 100644 --- a/test/suites/integration/auth_basic_api_organisations_test.go +++ b/test/suites/integration/auth_basic_api_organisations_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,17 +11,17 @@ import ( // TestOrganisationCreate verifies that a superuser can create an organisation and // that the response includes the generated admin credentials. func TestOrganisationCreate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := orgName() - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + name := lib.OrgName() + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), authbasicapi.CreateOrganisationJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - matches(createResp.JSON201.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.Matches(createResp.JSON201.Name, name, t) if createResp.JSON201.AdminUsername == "" { t.Fatal("expected non-empty admin username in create response") } @@ -34,23 +35,23 @@ func TestOrganisationCreate(t *testing.T) { // TestOrganisationList verifies that a newly created organisation appears in the list response. func TestOrganisationList(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) createdID := createResp.JSON201.Id - listResp, err := basicAuthClient.ListOrganisationsWithResponse( + listResp, err := lib.BasicAuthClient.ListOrganisationsWithResponse( t.Context(), authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) for _, org := range *listResp.JSON200 { if org.Id == createdID { return @@ -61,185 +62,185 @@ func TestOrganisationList(t *testing.T) { // TestOrganisationGet verifies that a created organisation can be fetched by ID. func TestOrganisationGet(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := orgName() - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + name := lib.OrgName() + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), authbasicapi.CreateOrganisationJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - getResp, err := basicAuthClient.GetOrganisationWithResponse( + getResp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), createResp.JSON201.Id, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Id, createResp.JSON201.Id, t) - matches(getResp.JSON200.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Id, createResp.JSON201.Id, t) + lib.Matches(getResp.JSON200.Name, name, t) } // TestOrganisationGetNotFound verifies that fetching a deleted organisation returns 404. func TestOrganisationGetNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) orgID := createResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := basicAuthClient.GetOrganisationWithResponse( + getResp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestOrganisationUpdate verifies that an organisation's name can be changed and the // updated value is reflected in a subsequent get. func TestOrganisationUpdate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) orgID := createResp.JSON201.Id - newName := orgName() - updateResp, err := basicAuthClient.UpdateOrganisationWithResponse( + newName := lib.OrgName() + updateResp, err := lib.BasicAuthClient.UpdateOrganisationWithResponse( t.Context(), orgID, authbasicapi.UpdateOrganisationJSONRequestBody{Name: newName}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) - matches(updateResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) + lib.Matches(updateResp.JSON200.Name, newName, t) - getResp, err := basicAuthClient.GetOrganisationWithResponse( + getResp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Name, newName, t) } // TestOrganisationUpdateConflict verifies that renaming an organisation to an already-taken // name returns a conflict error. func TestOrganisationUpdateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - create1Resp, err := basicAuthClient.CreateOrganisationWithResponse( + create1Resp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) - create2Resp, err := basicAuthClient.CreateOrganisationWithResponse( + create2Resp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) - updateResp, err := basicAuthClient.UpdateOrganisationWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateOrganisationWithResponse( t.Context(), create2Resp.JSON201.Id, authbasicapi.UpdateOrganisationJSONRequestBody{Name: create1Resp.JSON201.Name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) } // TestOrganisationCreateConflict verifies that creating an organisation whose name is already // taken returns a conflict error. func TestOrganisationCreateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := orgName() - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + name := lib.OrgName() + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), authbasicapi.CreateOrganisationJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - conflictResp, err := basicAuthClient.CreateOrganisationWithResponse( + conflictResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), authbasicapi.CreateOrganisationJSONRequestBody{Name: name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) } // TestOrganisationDelete verifies that a deleted organisation is no longer accessible. func TestOrganisationDelete(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) orgID := createResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) } // TestOrganisationCreateDenied verifies that an organisation-scoped session cannot create // new organisations. func TestOrganisationCreateDenied(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) - orgLoginResp, err := basicAuthClient.LoginWithResponse( + orgLoginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrgResp.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -247,49 +248,49 @@ func TestOrganisationCreateDenied(t *testing.T) { Password: createOrgResp.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(orgLoginResp.StatusCode(), http.StatusNoContent, t) - orgAdminRequestEditor := sessionCookieRequestEditor(orgLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(orgLoginResp.StatusCode(), http.StatusNoContent, t) + orgAdminRequestEditor := lib.SessionCookieRequestEditor(orgLoginResp.HTTPResponse, t) - denyResp, err := basicAuthClient.CreateOrganisationWithResponse( + denyResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(denyResp.StatusCode(), http.StatusForbidden, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(denyResp.StatusCode(), http.StatusForbidden, t) } // TestOrganisationCreateOASValidation verifies that creating an organisation with an empty // name is rejected with 400 by the OAS validator. func TestOrganisationCreateOASValidation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Name below minLength: 1 — must be rejected. - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), authbasicapi.CreateOrganisationJSONRequestBody{Name: ""}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON400, t) } // TestOrganisationLogin verifies that a user can log in to their organisation and receives // a session token in the response header. func TestOrganisationLogin(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrgResp.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -297,25 +298,25 @@ func TestOrganisationLogin(t *testing.T) { Password: createOrgResp.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - _ = sessionCookieRequestEditor(loginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + _ = lib.SessionCookieRequestEditor(loginResp.HTTPResponse, t) } // TestOrganisationLoginInvalidCredentials verifies that a login attempt with the wrong // password returns 401. func TestOrganisationLoginInvalidCredentials(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrgResp.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -323,15 +324,15 @@ func TestOrganisationLoginInvalidCredentials(t *testing.T) { Password: "wrongpassword1", }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(loginResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(loginResp.JSON401, t) } // TestOrganisationLogout verifies that logging out invalidates the session token so that // subsequent authenticated requests are rejected with 401. func TestOrganisationLogout(t *testing.T) { - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ @@ -339,120 +340,120 @@ func TestOrganisationLogout(t *testing.T) { Password: alwaysUserPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - basicRequestEditor := sessionCookieRequestEditor(loginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + basicRequestEditor := lib.SessionCookieRequestEditor(loginResp.HTTPResponse, t) // Verify the session is valid before logging out. - getUserResp, err := basicAuthClient.GetUserWithResponse( + getUserResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.RequestEditorFn(basicRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserResp.StatusCode(), http.StatusOK, t) - logoutResp, err := basicAuthClient.LogoutWithResponse( + logoutResp, err := lib.BasicAuthClient.LogoutWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.RequestEditorFn(basicRequestEditor), ) - checkErr(err, t) - verifyStatusCode(logoutResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(logoutResp.StatusCode(), http.StatusNoContent, t) // The old session must now be rejected. - getUserAfterLogoutResp, err := basicAuthClient.GetUserWithResponse( + getUserAfterLogoutResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.RequestEditorFn(basicRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserAfterLogoutResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(getUserAfterLogoutResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserAfterLogoutResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(getUserAfterLogoutResp.JSON401, t) } // TestOrganisationNoSession verifies that every organisation-scoped endpoint returns 401 // with a populated error body when called without a session header. func TestOrganisationNoSession(t *testing.T) { // CreateOrganisation — no session. - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON401, t) // ListOrganisations — no session. - listResp, err := basicAuthClient.ListOrganisationsWithResponse(t.Context()) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(listResp.JSON401, t) + listResp, err := lib.BasicAuthClient.ListOrganisationsWithResponse(t.Context()) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(listResp.JSON401, t) // GetOrganisation — no session. - getResp, err := basicAuthClient.GetOrganisationWithResponse( + getResp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(getResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(getResp.JSON401, t) // UpdateOrganisation — no session. - updateResp, err := basicAuthClient.UpdateOrganisationWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateOrganisationWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.UpdateOrganisationJSONRequestBody{Id: int64(alwaysOrgID), Name: orgName()}, + authbasicapi.UpdateOrganisationJSONRequestBody{Id: int64(alwaysOrgID), Name: lib.OrgName()}, ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) // DeleteOrganisation — no session. - deleteResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) // Logout — no session. - logoutResp, err := basicAuthClient.LogoutWithResponse( + logoutResp, err := lib.BasicAuthClient.LogoutWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(logoutResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(logoutResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(logoutResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(logoutResp.JSON401, t) } // TestOrganisationCrossOrgForbidden verifies that GetOrganisation and DeleteOrganisation // return 403 with a populated error body when called with a session from a different // organisation. func TestOrganisationCrossOrgForbidden(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Create two organisations; each login produces a session scoped to that org. - createOrg1, err := basicAuthClient.CreateOrganisationWithResponse( + createOrg1, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrg1.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrg1.StatusCode(), http.StatusCreated, t) - createOrg2, err := basicAuthClient.CreateOrganisationWithResponse( + createOrg2, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrg2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrg2.StatusCode(), http.StatusCreated, t) - loginOrg2, err := basicAuthClient.LoginWithResponse( + loginOrg2, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrg2.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -460,59 +461,59 @@ func TestOrganisationCrossOrgForbidden(t *testing.T) { Password: createOrg2.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginOrg2.StatusCode(), http.StatusNoContent, t) - orgAdminRequestEditor := sessionCookieRequestEditor(loginOrg2.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginOrg2.StatusCode(), http.StatusNoContent, t) + orgAdminRequestEditor := lib.SessionCookieRequestEditor(loginOrg2.HTTPResponse, t) // GetOrganisation for org1 using org2 session — must be 403. - getOrg1Resp, err := basicAuthClient.GetOrganisationWithResponse( + getOrg1Resp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), createOrg1.JSON201.Id, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getOrg1Resp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getOrg1Resp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getOrg1Resp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getOrg1Resp.JSON403, t) // DeleteOrganisation for org1 using org2 session — must be 403. - deleteOrg1Resp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteOrg1Resp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), createOrg1.JSON201.Id, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteOrg1Resp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(deleteOrg1Resp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteOrg1Resp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteOrg1Resp.JSON403, t) } // TestOrganisationDeleteNotFound verifies deleting an already-deleted organisation. func TestOrganisationDeleteNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) orgID := createResp.JSON201.Id // First delete succeeds. - deleteResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Second delete must return 404 (no body defined in spec). - deleteAgainResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteAgainResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) } diff --git a/test/suites/integration/auth_basic_api_test.go b/test/suites/integration/auth_basic_api_test.go index 68f1235..1419a9c 100644 --- a/test/suites/integration/auth_basic_api_test.go +++ b/test/suites/integration/auth_basic_api_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,17 +11,17 @@ import ( // TestAuthBasicAPIOrganisationIsolation verifies that a session from one organisation // cannot read or mutate any resource that belongs to a different organisation. func TestAuthBasicAPIOrganisationIsolation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrg1, err := basicAuthClient.CreateOrganisationWithResponse( + createOrg1, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrg1.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrg1.StatusCode(), http.StatusCreated, t) - loginResp1, err := basicAuthClient.LoginWithResponse( + loginResp1, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrg1.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -28,19 +29,19 @@ func TestAuthBasicAPIOrganisationIsolation(t *testing.T) { Password: createOrg1.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp1.StatusCode(), http.StatusNoContent, t) - orgAdmin1RequestEditor := sessionCookieRequestEditor(loginResp1.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp1.StatusCode(), http.StatusNoContent, t) + orgAdmin1RequestEditor := lib.SessionCookieRequestEditor(loginResp1.HTTPResponse, t) - createOrg2, err := basicAuthClient.CreateOrganisationWithResponse( + createOrg2, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrg2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrg2.StatusCode(), http.StatusCreated, t) - loginResp2, err := basicAuthClient.LoginWithResponse( + loginResp2, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrg2.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -48,154 +49,154 @@ func TestAuthBasicAPIOrganisationIsolation(t *testing.T) { Password: createOrg2.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp2.StatusCode(), http.StatusNoContent, t) - orgAdmin2RequestEditor := sessionCookieRequestEditor(loginResp2.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp2.StatusCode(), http.StatusNoContent, t) + orgAdmin2RequestEditor := lib.SessionCookieRequestEditor(loginResp2.HTTPResponse, t) // All read operations below target org1 but use session2 (org2) — all must be 403. - listGroupsResp, err := basicAuthClient.ListGroupsWithResponse( + listGroupsResp, err := lib.BasicAuthClient.ListGroupsWithResponse( t.Context(), createOrg1.JSON201.Id, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(listGroupsResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(listGroupsResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listGroupsResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(listGroupsResp.JSON403, t) - listUsersResp, err := basicAuthClient.ListUsersWithResponse( + listUsersResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), createOrg1.JSON201.Id, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(listUsersResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(listUsersResp.JSON403, t) - getUserResp, err := basicAuthClient.GetUserWithResponse( + getUserResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), createOrg1.JSON201.Id, createOrg1.JSON201.AdminUserId, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getUserResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getUserResp.JSON403, t) // Create a group in org1 using session1, then verify session2 cannot access it. - createGroup1Resp, err := basicAuthClient.CreateGroupWithResponse( + createGroup1Resp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), createOrg1.JSON201.Id, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgAdmin1RequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroup1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroup1Resp.StatusCode(), http.StatusCreated, t) - getGroupResp, err := basicAuthClient.GetGroupWithResponse( + getGroupResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), createOrg1.JSON201.Id, createGroup1Resp.JSON201.Id, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(getGroupResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getGroupResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getGroupResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getGroupResp.JSON403, t) // Create a user in org1 using session1; all write operations via session2 must be 403. - createUser1Resp, err := basicAuthClient.CreateUserWithResponse( + createUser1Resp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), createOrg1.JSON201.Id, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(orgAdmin1RequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUser1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUser1Resp.StatusCode(), http.StatusCreated, t) user1ID := createUser1Resp.JSON201.Id - createUserCrossResp, err := basicAuthClient.CreateUserWithResponse( + createUserCrossResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), createOrg1.JSON201.Id, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(createUserCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(createUserCrossResp.JSON403, t) - createGroupCrossResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupCrossResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), createOrg1.JSON201.Id, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(createGroupCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(createGroupCrossResp.JSON403, t) - updateUserCrossResp, err := basicAuthClient.UpdateUserWithResponse( + updateUserCrossResp, err := lib.BasicAuthClient.UpdateUserWithResponse( t.Context(), createOrg1.JSON201.Id, user1ID, - authbasicapi.UpdateUserJSONRequestBody{Name: username()}, + authbasicapi.UpdateUserJSONRequestBody{Name: lib.Username()}, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateUserCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(updateUserCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateUserCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(updateUserCrossResp.JSON403, t) - updateGroupCrossResp, err := basicAuthClient.UpdateGroupWithResponse( + updateGroupCrossResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), createOrg1.JSON201.Id, createGroup1Resp.JSON201.Id, - authbasicapi.UpdateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.UpdateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateGroupCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(updateGroupCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateGroupCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(updateGroupCrossResp.JSON403, t) - deleteUserCrossResp, err := basicAuthClient.DeleteUserWithResponse( + deleteUserCrossResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), createOrg1.JSON201.Id, user1ID, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteUserCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(deleteUserCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteUserCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteUserCrossResp.JSON403, t) - deleteGroupCrossResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteGroupCrossResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), createOrg1.JSON201.Id, createGroup1Resp.JSON201.Id, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteGroupCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(deleteGroupCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteGroupCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteGroupCrossResp.JSON403, t) - updateUserGroupsCrossResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + updateUserGroupsCrossResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), createOrg1.JSON201.Id, user1ID, authbasicapi.UpdateUserGroupsJSONRequestBody{}, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateUserGroupsCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(updateUserGroupsCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateUserGroupsCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(updateUserGroupsCrossResp.JSON403, t) - getUserGroupsCrossResp, err := basicAuthClient.GetUserGroupsWithResponse( + getUserGroupsCrossResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), createOrg1.JSON201.Id, user1ID, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserGroupsCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getUserGroupsCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserGroupsCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getUserGroupsCrossResp.JSON403, t) - changePasswordCrossResp, err := basicAuthClient.ChangePasswordWithResponse( + changePasswordCrossResp, err := lib.BasicAuthClient.ChangePasswordWithResponse( t.Context(), createOrg1.JSON201.Id, user1ID, @@ -205,26 +206,26 @@ func TestAuthBasicAPIOrganisationIsolation(t *testing.T) { }, authbasicapi.RequestEditorFn(orgAdmin2RequestEditor), ) - checkErr(err, t) - verifyStatusCode(changePasswordCrossResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(changePasswordCrossResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changePasswordCrossResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(changePasswordCrossResp.JSON403, t) } // TestAuthBasicAPIOrgAdminListOrganisationsForbidden verifies that a session scoped to an // organisation cannot list organisations (superuser-only operation). // The spec does not define a 403 body for ListOrganisations, so only the status is checked. func TestAuthBasicAPIOrgAdminListOrganisationsForbidden(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) - orgLoginResp, err := basicAuthClient.LoginWithResponse( + orgLoginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), createOrgResp.JSON201.Id, authbasicapi.LoginJSONRequestBody{ @@ -232,215 +233,215 @@ func TestAuthBasicAPIOrgAdminListOrganisationsForbidden(t *testing.T) { Password: createOrgResp.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(orgLoginResp.StatusCode(), http.StatusNoContent, t) - orgAdminRequestEditor := sessionCookieRequestEditor(orgLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(orgLoginResp.StatusCode(), http.StatusNoContent, t) + orgAdminRequestEditor := lib.SessionCookieRequestEditor(orgLoginResp.HTTPResponse, t) - listResp, err := basicAuthClient.ListOrganisationsWithResponse( + listResp, err := lib.BasicAuthClient.ListOrganisationsWithResponse( t.Context(), authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(listResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(listResp.JSON403, t) - createResp, err := basicAuthClient.CreateOrganisationWithResponse( + createResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON403, t) } // TestAuthBasicAPINormalUserAccessControl verifies that a non-administrator user receives // 403 (with populated error body) for all admin-only operations, and can still successfully // retrieve their own user record. func TestAuthBasicAPINormalUserAccessControl(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Create a dedicated org for this test. - orgID, orgAdminRequestEditor := orgWithSession(t, superRequestEditor) + orgID, orgAdminRequestEditor := lib.OrgWithSession(t, superRequestEditor) // Create a group to use in group-level checks. - createGroupResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupResp.StatusCode(), http.StatusCreated, t) groupID := createGroupResp.JSON201.Id // Create a regular (non-admin) user. - regularUserName := username() + regularUserName := lib.Username() regularPassword := "regularpass1" - createRegularResp, err := basicAuthClient.CreateUserWithResponse( + createRegularResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, authbasicapi.CreateUserJSONRequestBody{Name: regularUserName, Password: regularPassword}, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createRegularResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createRegularResp.StatusCode(), http.StatusCreated, t) regularUserID := createRegularResp.JSON201.Id // Create another user to test that the regular user cannot access a different user. - createOtherResp, err := basicAuthClient.CreateUserWithResponse( + createOtherResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "otherpass123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "otherpass123"}, authbasicapi.RequestEditorFn(orgAdminRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOtherResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOtherResp.StatusCode(), http.StatusCreated, t) otherUserID := createOtherResp.JSON201.Id // Log in as the regular user. - regularLoginResp, err := basicAuthClient.LoginWithResponse( + regularLoginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), orgID, authbasicapi.LoginJSONRequestBody{Username: regularUserName, Password: regularPassword}, ) - checkErr(err, t) - verifyStatusCode(regularLoginResp.StatusCode(), http.StatusNoContent, t) - orgUserRequestEditor := sessionCookieRequestEditor(regularLoginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(regularLoginResp.StatusCode(), http.StatusNoContent, t) + orgUserRequestEditor := lib.SessionCookieRequestEditor(regularLoginResp.HTTPResponse, t) // --- Admin-only operations that must be denied (403 + body) --- // CreateUser. - createUserDenyResp, err := basicAuthClient.CreateUserWithResponse( + createUserDenyResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(createUserDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(createUserDenyResp.JSON403, t) // ListUsers. - listUsersDenyResp, err := basicAuthClient.ListUsersWithResponse( + listUsersDenyResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listUsersDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(listUsersDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listUsersDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(listUsersDenyResp.JSON403, t) // GetUser for a different user in the same org. - getUserOtherDenyResp, err := basicAuthClient.GetUserWithResponse( + getUserOtherDenyResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), orgID, otherUserID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserOtherDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getUserOtherDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserOtherDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getUserOtherDenyResp.JSON403, t) // GetOrganisation. - getOrgDenyResp, err := basicAuthClient.GetOrganisationWithResponse( + getOrgDenyResp, err := lib.BasicAuthClient.GetOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getOrgDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getOrgDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getOrgDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getOrgDenyResp.JSON403, t) // DeleteOrganisation. - deleteOrgDenyResp, err := basicAuthClient.DeleteOrganisationWithResponse( + deleteOrgDenyResp, err := lib.BasicAuthClient.DeleteOrganisationWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteOrgDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(deleteOrgDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteOrgDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteOrgDenyResp.JSON403, t) // CreateGroup. - createGroupDenyResp, err := basicAuthClient.CreateGroupWithResponse( + createGroupDenyResp, err := lib.BasicAuthClient.CreateGroupWithResponse( t.Context(), orgID, - authbasicapi.CreateGroupJSONRequestBody{Name: groupName()}, + authbasicapi.CreateGroupJSONRequestBody{Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createGroupDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(createGroupDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createGroupDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(createGroupDenyResp.JSON403, t) // ListGroups. - listGroupsDenyResp, err := basicAuthClient.ListGroupsWithResponse( + listGroupsDenyResp, err := lib.BasicAuthClient.ListGroupsWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listGroupsDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(listGroupsDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listGroupsDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(listGroupsDenyResp.JSON403, t) // GetGroup. - getGroupDenyResp, err := basicAuthClient.GetGroupWithResponse( + getGroupDenyResp, err := lib.BasicAuthClient.GetGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getGroupDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(getGroupDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getGroupDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(getGroupDenyResp.JSON403, t) // UpdateGroup. - updateGroupDenyResp, err := basicAuthClient.UpdateGroupWithResponse( + updateGroupDenyResp, err := lib.BasicAuthClient.UpdateGroupWithResponse( t.Context(), orgID, groupID, - authbasicapi.UpdateGroupJSONRequestBody{Id: groupID, Name: groupName()}, + authbasicapi.UpdateGroupJSONRequestBody{Id: groupID, Name: lib.GroupName()}, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateGroupDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(updateGroupDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateGroupDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(updateGroupDenyResp.JSON403, t) // DeleteGroup. - deleteGroupDenyResp, err := basicAuthClient.DeleteGroupWithResponse( + deleteGroupDenyResp, err := lib.BasicAuthClient.DeleteGroupWithResponse( t.Context(), orgID, groupID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteGroupDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(deleteGroupDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteGroupDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteGroupDenyResp.JSON403, t) // UpdateUserGroups. - updateUserGroupsDenyResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + updateUserGroupsDenyResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), orgID, regularUserID, authbasicapi.UpdateUserGroupsJSONRequestBody{}, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateUserGroupsDenyResp.StatusCode(), http.StatusForbidden, t) - verifyAuthBasicAPIErrorResponse(updateUserGroupsDenyResp.JSON403, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateUserGroupsDenyResp.StatusCode(), http.StatusForbidden, t) + lib.VerifyAuthBasicAPIErrorResponse(updateUserGroupsDenyResp.JSON403, t) // --- Operations the regular user IS allowed to perform on themselves --- // GetUser for own record must succeed. - getUserSelfResp, err := basicAuthClient.GetUserWithResponse( + getUserSelfResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), orgID, regularUserID, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getUserSelfResp.StatusCode(), http.StatusOK, t) - matches(getUserSelfResp.JSON200.Id, regularUserID, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getUserSelfResp.StatusCode(), http.StatusOK, t) + lib.Matches(getUserSelfResp.JSON200.Id, regularUserID, t) } // TestAuthBasicRefreshNoRefreshCookie verifies that calling the refresh endpoint without a @@ -448,32 +449,32 @@ func TestAuthBasicAPINormalUserAccessControl(t *testing.T) { // missing refresh cookie matters here. func TestAuthBasicRefreshNoRefreshCookie(t *testing.T) { t.Parallel() - resp, err := basicAuthClient.RefreshWithResponse( + resp, err := lib.BasicAuthClient.RefreshWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(resp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(resp.JSON401, t) } // TestAuthBasicRefresh verifies that the refresh endpoint issues a new session when called // with only the refresh cookie (no session cookie required). func TestAuthBasicRefresh(t *testing.T) { t.Parallel() - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), orgID, authbasicapi.LoginJSONRequestBody{ @@ -481,17 +482,17 @@ func TestAuthBasicRefresh(t *testing.T) { Password: createOrgResp.JSON201.AdminPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) // Use only the refresh cookie — deliberately omit the session cookie to prove it is not required. - refreshEditor := refreshCookieRequestEditor(loginResp.HTTPResponse, t) + refreshEditor := lib.RefreshCookieRequestEditor(loginResp.HTTPResponse, t) - refreshResp, err := basicAuthClient.RefreshWithResponse( + refreshResp, err := lib.BasicAuthClient.RefreshWithResponse( t.Context(), orgID, authbasicapi.RequestEditorFn(refreshEditor), ) - checkErr(err, t) - verifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(refreshResp.StatusCode(), http.StatusNoContent, t) } diff --git a/test/suites/integration/auth_basic_api_users_test.go b/test/suites/integration/auth_basic_api_users_test.go index 32bd67b..21533a4 100644 --- a/test/suites/integration/auth_basic_api_users_test.go +++ b/test/suites/integration/auth_basic_api_users_test.go @@ -1,6 +1,7 @@ package integration import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -10,18 +11,18 @@ import ( // TestUserCreate verifies that a new user can be created within an organisation and that // the response contains the expected name and a valid ID. func TestUserCreate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := basicAuthClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: name, Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - matches(createResp.JSON201.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.Matches(createResp.JSON201.Name, name, t) if createResp.JSON201.Id == 0 { t.Fatal("expected non-zero user ID in create response") } @@ -29,25 +30,25 @@ func TestUserCreate(t *testing.T) { // TestUserList verifies that a newly created user appears in the list response for its organisation. func TestUserList(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateUserWithResponse( + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) createdID := createResp.JSON201.Id - listResp, err := basicAuthClient.ListUsersWithResponse( + listResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusOK, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusOK, t) for _, user := range *listResp.JSON200 { if user.Id == createdID { return @@ -58,317 +59,317 @@ func TestUserList(t *testing.T) { // TestUserGet verifies that a created user can be fetched by ID. func TestUserGet(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := basicAuthClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: name, Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - getResp, err := basicAuthClient.GetUserWithResponse( + getResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), createResp.JSON201.Id, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Id, createResp.JSON201.Id, t) - matches(getResp.JSON200.Name, name, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Id, createResp.JSON201.Id, t) + lib.Matches(getResp.JSON200.Name, name, t) } // TestUserGetNotFound verifies that fetching a deleted user returns 404. func TestUserGetNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteUserWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := basicAuthClient.GetUserWithResponse( + getResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestUserUpdate verifies that a user's name can be changed and the updated value is // reflected in a subsequent get. func TestUserUpdate(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createResp, err := basicAuthClient.CreateUserWithResponse( + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) userID := createResp.JSON201.Id - newName := username() - updateResp, err := basicAuthClient.UpdateUserWithResponse( + newName := lib.Username() + updateResp, err := lib.BasicAuthClient.UpdateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), userID, authbasicapi.UpdateUserJSONRequestBody{Name: newName}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) - matches(updateResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusOK, t) + lib.Matches(updateResp.JSON200.Name, newName, t) - getResp, err := basicAuthClient.GetUserWithResponse( + getResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusOK, t) - matches(getResp.JSON200.Name, newName, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusOK, t) + lib.Matches(getResp.JSON200.Name, newName, t) } // TestUserUpdateConflict verifies that renaming a user to an already-taken name within the // same organisation returns a conflict error. func TestUserUpdateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - create1Resp, err := basicAuthClient.CreateUserWithResponse( + create1Resp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create1Resp.StatusCode(), http.StatusCreated, t) - create2Resp, err := basicAuthClient.CreateUserWithResponse( + create2Resp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(create2Resp.StatusCode(), http.StatusCreated, t) - updateResp, err := basicAuthClient.UpdateUserWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), create2Resp.JSON201.Id, authbasicapi.UpdateUserJSONRequestBody{Name: create1Resp.JSON201.Name}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON409, t) } // TestUserCreateConflict verifies that creating a user whose name already exists within the // same organisation returns a conflict error. func TestUserCreateConflict(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - name := username() - createResp, err := basicAuthClient.CreateUserWithResponse( + name := lib.Username() + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: name, Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusCreated, t) - conflictResp, err := basicAuthClient.CreateUserWithResponse( + conflictResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: name, Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) - verifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(conflictResp.StatusCode(), http.StatusConflict, t) + lib.VerifyAuthBasicAPIErrorResponse(conflictResp.JSON409, t) } // TestUserDelete verifies that a deleted user is no longer accessible. func TestUserDelete(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id - deleteResp, err := basicAuthClient.DeleteUserWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) - getResp, err := basicAuthClient.GetUserWithResponse( + getResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusNotFound, t) } // TestUserCreateOASValidation verifies that creating a user with a name that is too short // or a password that is outside the allowed length range is rejected with 400. func TestUserCreateOASValidation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // Name below minLength: 5 — must be rejected. - shortNameResp, err := basicAuthClient.CreateUserWithResponse( + shortNameResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: "ab", Password: "validpassword"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(shortNameResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(shortNameResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(shortNameResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(shortNameResp.JSON400, t) // Password below minLength: 10 — must be rejected. - shortPasswordResp, err := basicAuthClient.CreateUserWithResponse( + shortPasswordResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "short"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "short"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(shortPasswordResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(shortPasswordResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(shortPasswordResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(shortPasswordResp.JSON400, t) // Password above maxLength: 40 — must be rejected. - longPasswordResp, err := basicAuthClient.CreateUserWithResponse( + longPasswordResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "this-password-is-way-too-long-for-the-schema-limits"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "this-password-is-way-too-long-for-the-schema-limits"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(longPasswordResp.StatusCode(), http.StatusBadRequest, t) - verifyAuthBasicAPIErrorResponse(longPasswordResp.JSON400, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(longPasswordResp.StatusCode(), http.StatusBadRequest, t) + lib.VerifyAuthBasicAPIErrorResponse(longPasswordResp.JSON400, t) } // TestUserChangePassword verifies the full change-password flow: a user can log in, // change their password, and then log in again with the new password. func TestUserChangePassword(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id oldPassword := "oldpassword123" newPassword := "newpassword456" - name := username() + name := lib.Username() - createUserResp2, err := basicAuthClient.CreateUserWithResponse( + createUserResp2, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, authbasicapi.CreateUserJSONRequestBody{Name: name, Password: oldPassword}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp2.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp2.StatusCode(), http.StatusCreated, t) userID2 := createUserResp2.JSON201.Id - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), orgID, authbasicapi.LoginJSONRequestBody{Username: name, Password: oldPassword}, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - orgUserRequestEditor := sessionCookieRequestEditor(loginResp.HTTPResponse, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + orgUserRequestEditor := lib.SessionCookieRequestEditor(loginResp.HTTPResponse, t) - changeResp, err := basicAuthClient.ChangePasswordWithResponse( + changeResp, err := lib.BasicAuthClient.ChangePasswordWithResponse( t.Context(), orgID, userID2, authbasicapi.ChangePasswordJSONRequestBody{OldPassword: oldPassword, Password: newPassword}, authbasicapi.RequestEditorFn(orgUserRequestEditor), ) - checkErr(err, t) - verifyStatusCode(changeResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changeResp.StatusCode(), http.StatusNoContent, t) // Login with new password must succeed. - newLoginResp, err := basicAuthClient.LoginWithResponse( + newLoginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), orgID, authbasicapi.LoginJSONRequestBody{Username: name, Password: newPassword}, ) - checkErr(err, t) - verifyStatusCode(newLoginResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(newLoginResp.StatusCode(), http.StatusNoContent, t) // Login with old password must now fail. - oldLoginResp, err := basicAuthClient.LoginWithResponse( + oldLoginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), orgID, authbasicapi.LoginJSONRequestBody{Username: name, Password: oldPassword}, ) - checkErr(err, t) - verifyStatusCode(oldLoginResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(oldLoginResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(oldLoginResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(oldLoginResp.JSON401, t) } // TestUserChangePasswordOASValidation verifies that the OAS validator rejects change-password @@ -376,203 +377,203 @@ func TestUserChangePassword(t *testing.T) { // Note: the spec does not define a 400 response body for this endpoint, so only the // status code is checked. func TestUserChangePasswordOASValidation(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) // oldPassword below minLength: 10 — must be rejected before auth checks. - shortOldPwResp, err := basicAuthClient.ChangePasswordWithResponse( + shortOldPwResp, err := lib.BasicAuthClient.ChangePasswordWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.ChangePasswordJSONRequestBody{OldPassword: "short", Password: "validpassword123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(shortOldPwResp.StatusCode(), http.StatusBadRequest, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(shortOldPwResp.StatusCode(), http.StatusBadRequest, t) // new password below minLength: 10 — must be rejected. - shortNewPwResp, err := basicAuthClient.ChangePasswordWithResponse( + shortNewPwResp, err := lib.BasicAuthClient.ChangePasswordWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.ChangePasswordJSONRequestBody{OldPassword: "validoldpassword", Password: "short"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(shortNewPwResp.StatusCode(), http.StatusBadRequest, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(shortNewPwResp.StatusCode(), http.StatusBadRequest, t) } // TestUserNoSession verifies that every user-scoped endpoint returns 401 with a populated // error body when called without a session header. func TestUserNoSession(t *testing.T) { // CreateUser — no session. - createResp, err := basicAuthClient.CreateUserWithResponse( + createResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, ) - checkErr(err, t) - verifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(createResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(createResp.JSON401, t) // ListUsers — no session. - listResp, err := basicAuthClient.ListUsersWithResponse( + listResp, err := lib.BasicAuthClient.ListUsersWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), ) - checkErr(err, t) - verifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(listResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(listResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(listResp.JSON401, t) // GetUser — no session. - getResp, err := basicAuthClient.GetUserWithResponse( + getResp, err := lib.BasicAuthClient.GetUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), ) - checkErr(err, t) - verifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(getResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(getResp.JSON401, t) // UpdateUser — no session. - updateResp, err := basicAuthClient.UpdateUserWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), - authbasicapi.UpdateUserJSONRequestBody{Id: int64(alwaysUserID), Name: username()}, + authbasicapi.UpdateUserJSONRequestBody{Id: int64(alwaysUserID), Name: lib.Username()}, ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(updateResp.JSON401, t) // DeleteUser — no session. - deleteResp, err := basicAuthClient.DeleteUserWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(deleteResp.JSON401, t) // UpdateUserGroups — no session. - updateGroupsResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + updateGroupsResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.UpdateUserGroupsJSONRequestBody{}, ) - checkErr(err, t) - verifyStatusCode(updateGroupsResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(updateGroupsResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateGroupsResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(updateGroupsResp.JSON401, t) // GetUserGroups — no session. - getGroupsResp, err := basicAuthClient.GetUserGroupsWithResponse( + getGroupsResp, err := lib.BasicAuthClient.GetUserGroupsWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), ) - checkErr(err, t) - verifyStatusCode(getGroupsResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(getGroupsResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(getGroupsResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(getGroupsResp.JSON401, t) // ChangePassword — no session. - changePwResp, err := basicAuthClient.ChangePasswordWithResponse( + changePwResp, err := lib.BasicAuthClient.ChangePasswordWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), authbasicapi.ChangePasswordJSONRequestBody{OldPassword: "validoldpassword", Password: "validnewpassword"}, ) - checkErr(err, t) - verifyStatusCode(changePwResp.StatusCode(), http.StatusUnauthorized, t) - verifyAuthBasicAPIErrorResponse(changePwResp.JSON401, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(changePwResp.StatusCode(), http.StatusUnauthorized, t) + lib.VerifyAuthBasicAPIErrorResponse(changePwResp.JSON401, t) } // TestUserDeleteNotFound verifies deleting an already-deleted user. func TestUserDeleteNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id // First delete succeeds. - deleteResp, err := basicAuthClient.DeleteUserWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Second delete must return 404 (no body defined in spec). - deleteAgainResp, err := basicAuthClient.DeleteUserWithResponse( + deleteAgainResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteAgainResp.StatusCode(), http.StatusNoContent, t) } // TestUserUpdateNotFound verifies that attempting to update a deleted user returns 404 // (no body defined in spec). func TestUserUpdateNotFound(t *testing.T) { - superRequestEditor := superLogin(t) + superRequestEditor := lib.SuperLogin(t) - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( + createOrgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, + authbasicapi.CreateOrganisationJSONRequestBody{Name: lib.OrgName()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) orgID := createOrgResp.JSON201.Id - createUserResp, err := basicAuthClient.CreateUserWithResponse( + createUserResp, err := lib.BasicAuthClient.CreateUserWithResponse( t.Context(), orgID, - authbasicapi.CreateUserJSONRequestBody{Name: username(), Password: "password123"}, + authbasicapi.CreateUserJSONRequestBody{Name: lib.Username(), Password: "password123"}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) userID := createUserResp.JSON201.Id // Delete the user first. - deleteResp, err := basicAuthClient.DeleteUserWithResponse( + deleteResp, err := lib.BasicAuthClient.DeleteUserWithResponse( t.Context(), orgID, userID, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(deleteResp.StatusCode(), http.StatusNoContent, t) // Update the deleted user must return 404 (no body defined in spec). - updateResp, err := basicAuthClient.UpdateUserWithResponse( + updateResp, err := lib.BasicAuthClient.UpdateUserWithResponse( t.Context(), orgID, userID, - authbasicapi.UpdateUserJSONRequestBody{Id: userID, Name: username()}, + authbasicapi.UpdateUserJSONRequestBody{Id: userID, Name: lib.Username()}, authbasicapi.RequestEditorFn(superRequestEditor), ) - checkErr(err, t) - verifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(updateResp.StatusCode(), http.StatusNotFound, t) } diff --git a/test/suites/integration/auth_basic_test.go b/test/suites/integration/auth_basic_test.go index 815810d..b229290 100644 --- a/test/suites/integration/auth_basic_test.go +++ b/test/suites/integration/auth_basic_test.go @@ -2,6 +2,7 @@ package integration import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "strconv" "testing" @@ -10,7 +11,7 @@ import ( ) func TestAuthBasicCall(t *testing.T) { - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ @@ -18,18 +19,18 @@ func TestAuthBasicCall(t *testing.T) { Password: alwaysUserPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - sessionCookie, err := extractSessionCookie(loginResp.HTTPResponse) - checkErr(err, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + sessionCookie, err := lib.ExtractSessionCookie(loginResp.HTTPResponse) + lib.CheckErr(err, t) - response := protectedGet( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", getHost(), getPort()), + response := lib.ProtectedGet( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", lib.GetHost(), lib.GetPort()), t, sessionCookie, ) - echoResponse := verifyGWResponse(response, http.StatusOK, t) + echoResponse := lib.VerifyGWResponse(response, http.StatusOK, t) requestHeaders := http.Header(echoResponse.Headers) if requestHeaders.Get("x-krb-org") != strconv.Itoa(int(alwaysOrgID)) { t.Fatalf("OrgID %s did not match expected %d", requestHeaders.Get("x-krb-org"), alwaysOrgID) @@ -43,12 +44,12 @@ func TestAuthBasicCall(t *testing.T) { } func TestAuthBasicUnauthenticated(t *testing.T) { - response := get( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", getHost(), getPort()), + response := lib.Get( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", lib.GetHost(), lib.GetPort()), t, ) - echoResponse := verifyGWResponse(response, http.StatusUnauthorized, t) + echoResponse := lib.VerifyGWResponse(response, http.StatusUnauthorized, t) requestHeaders := http.Header(echoResponse.Headers) if vals := requestHeaders.Values("x-krb-user"); len(vals) != 0 { t.Fatal("User ID should not have been set") @@ -58,13 +59,13 @@ func TestAuthBasicUnauthenticated(t *testing.T) { t.Fatal("Org ID should not have been set") } - response = get( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", getHost(), getPort()), + response = lib.Get( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/hi", lib.GetHost(), lib.GetPort()), t, http.Header{"x-krb-session": {"fake"}}, ) - echoResponse = verifyGWResponse(response, http.StatusUnauthorized, t) + echoResponse = lib.VerifyGWResponse(response, http.StatusUnauthorized, t) if _, ok := echoResponse.Headers["x-krb-user"]; ok { t.Fatal("User ID should not have been set") } @@ -74,12 +75,12 @@ func TestAuthBasicUnauthenticated(t *testing.T) { } func TestAuthBasicUnauthenticatedExempted(t *testing.T) { - response := get( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/unprotected", getHost(), getPort()), + response := lib.Get( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/unprotected", lib.GetHost(), lib.GetPort()), t, ) - echoResponse := verifyGWResponse(response, http.StatusOK, t) + echoResponse := lib.VerifyGWResponse(response, http.StatusOK, t) requestHeaders := http.Header(echoResponse.Headers) if vals := requestHeaders.Values("x-krb-user"); len(vals) != 0 { t.Fatal("User ID should not have been set") @@ -89,12 +90,12 @@ func TestAuthBasicUnauthenticatedExempted(t *testing.T) { t.Fatal("Org ID should not have been set") } - response = get( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/unprotected/nested", getHost(), getPort()), + response = lib.Get( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/unprotected/nested", lib.GetHost(), lib.GetPort()), t, ) - echoResponse = verifyGWResponse(response, http.StatusOK, t) + echoResponse = lib.VerifyGWResponse(response, http.StatusOK, t) requestHeaders = http.Header(echoResponse.Headers) if vals := requestHeaders.Values("x-krb-user"); len(vals) != 0 { t.Fatal("User ID should not have been set") @@ -106,7 +107,7 @@ func TestAuthBasicUnauthenticatedExempted(t *testing.T) { } func TestAuthBasicAuthorizedPleb(t *testing.T) { - loginResp, err := basicAuthClient.LoginWithResponse( + loginResp, err := lib.BasicAuthClient.LoginWithResponse( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ @@ -114,18 +115,18 @@ func TestAuthBasicAuthorizedPleb(t *testing.T) { Password: alwaysUserPassword, }, ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - sessionCookie, err := extractSessionCookie(loginResp.HTTPResponse) - checkErr(err, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + sessionCookie, err := lib.ExtractSessionCookie(loginResp.HTTPResponse) + lib.CheckErr(err, t) - response := protectedGet( - fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/long/hello", getHost(), getPort()), + response := lib.ProtectedGet( + fmt.Sprintf("http://%s:%d/gw/backend/protected-echo/long/hello", lib.GetHost(), lib.GetPort()), t, sessionCookie, ) - echoResponse := verifyGWResponse(response, http.StatusOK, t) + echoResponse := lib.VerifyGWResponse(response, http.StatusOK, t) requestHeaders := http.Header(echoResponse.Headers) if vals := requestHeaders.Values("x-krb-user"); len(vals) == 0 { t.Fatal("User ID should have been set") diff --git a/test/suites/integration/auth_sessions.go b/test/suites/integration/auth_sessions.go deleted file mode 100644 index 1649f9d..0000000 --- a/test/suites/integration/auth_sessions.go +++ /dev/null @@ -1,51 +0,0 @@ -package integration - -import ( - "net/http" - "testing" - - adminapi "github.com/trebent/kerberos/test/client/admin" -) - -func refreshCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { - t.Helper() - refreshCookie, err := extractRefreshCookie(response) - if err != nil { - t.Fatalf("failed to extract refresh cookie: %v", err) - } - - return makeRequestEditorFromCookie(refreshCookie) -} - -func sessionCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { - sessionCookie, err := extractSessionCookie(response) - if err != nil { - t.Fatalf("failed to extract session cookie: %v", err) - } - - return makeRequestEditorFromCookie(sessionCookie) -} - -// superLogin logs in as the superuser and returns a request editor to use. -func superLogin(t *testing.T) RequestEditorFn { - t.Helper() - resp, err := adminClient.LoginSuperuserWithResponse( - t.Context(), - adminapi.LoginSuperuserJSONRequestBody{ClientId: superUserClientID, ClientSecret: superUserClientSecret}, - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) - return sessionCookieRequestEditor(resp.HTTPResponse, t) -} - -// adminUserLogin logs in as a non-superuser admin and returns the request editor to use. -func adminUserLogin(t *testing.T, name, pass string) RequestEditorFn { - t.Helper() - resp, err := adminClient.LoginWithResponse( - t.Context(), - adminapi.LoginJSONRequestBody{Username: name, Password: pass}, - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) - return sessionCookieRequestEditor(resp.HTTPResponse, t) -} diff --git a/test/suites/integration/basic_auth.go b/test/suites/integration/basic_auth.go deleted file mode 100644 index a2e3174..0000000 --- a/test/suites/integration/basic_auth.go +++ /dev/null @@ -1,35 +0,0 @@ -package integration - -import ( - "net/http" - "testing" - - authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" -) - -// orgWithSession is a helper that creates a fresh organisation and returns its ID along -// with an admin session request editor for that organisation. It uses the provided superuser session to -// create the organisation. -func orgWithSession(t *testing.T, requestEditor RequestEditorFn) (authbasicapi.Orgid, RequestEditorFn) { - t.Helper() - createOrgResp, err := basicAuthClient.CreateOrganisationWithResponse( - t.Context(), - authbasicapi.CreateOrganisationJSONRequestBody{Name: orgName()}, - authbasicapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) - - loginResp, err := basicAuthClient.LoginWithResponse( - t.Context(), - createOrgResp.JSON201.Id, - authbasicapi.LoginJSONRequestBody{ - Username: createOrgResp.JSON201.AdminUsername, - Password: createOrgResp.JSON201.AdminPassword, - }, - ) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) - - return createOrgResp.JSON201.Id, sessionCookieRequestEditor(loginResp.HTTPResponse, t) -} diff --git a/test/suites/integration/cookies_test.go b/test/suites/integration/cookies_test.go index 7a815c7..b5a6a35 100644 --- a/test/suites/integration/cookies_test.go +++ b/test/suites/integration/cookies_test.go @@ -2,6 +2,7 @@ package integration import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -12,22 +13,22 @@ import ( func TestCookies_admin(t *testing.T) { t.Run("Verify superuser cookie attributes", func(t *testing.T) { t.Parallel() - resp, err := adminClient.LoginSuperuser( + resp, err := lib.AdminClient.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) validateAdminCookieAttributes(resp.Cookies(), "/api/admin/superuser/refresh", t) }) t.Run("Verify admin user cookie attributes", func(t *testing.T) { t.Parallel() - resp, err := adminClient.Login( + resp, err := lib.AdminClient.Login( t.Context(), adminapi.LoginJSONRequestBody{ Username: alwaysAdminUser, @@ -35,8 +36,8 @@ func TestCookies_admin(t *testing.T) { }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) validateAdminCookieAttributes(resp.Cookies(), "/api/admin/refresh", t) }) } @@ -44,15 +45,15 @@ func TestCookies_admin(t *testing.T) { func TestCookies_basicauth(t *testing.T) { t.Run("Verify basic auth cookie attributes", func(t *testing.T) { t.Parallel() - loginResp, err := basicAuthClient.Login( + loginResp, err := lib.BasicAuthClient.Login( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ Username: alwaysUser, Password: alwaysUserPassword, }) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode, http.StatusNoContent, t) var refresh, session, csrf bool for _, cookie := range loginResp.Cookies() { switch cookie.Name { diff --git a/test/suites/integration/cors_test.go b/test/suites/integration/cors_test.go index 47e6182..c7e7786 100644 --- a/test/suites/integration/cors_test.go +++ b/test/suites/integration/cors_test.go @@ -3,6 +3,7 @@ package integration import ( "context" "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -13,11 +14,11 @@ import ( func TestCORS_admin(t *testing.T) { t.Run("OPTIONS preflight with Origin - CORS headers returned", func(t *testing.T) { t.Parallel() - url := fmt.Sprintf("http://%s:%d/api/admin/login", getHost(), getAdminPort()) - resp := options(url, t, http.Header{"Origin": []string{"http://www.safe.com"}}) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + url := fmt.Sprintf("http://%s:%d/api/admin/login", lib.GetHost(), lib.GetAdminPort()) + resp := lib.Options(url, t, http.Header{"Origin": []string{"http://www.safe.com"}}) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) if resp.Header.Get("Access-Control-Allow-Methods") == "" { t.Fatal("Expected Access-Control-Allow-Methods to be set") } @@ -25,48 +26,48 @@ func TestCORS_admin(t *testing.T) { t.Run("Non-browser request - accepted", func(t *testing.T) { t.Parallel() - resp, err := adminClient.LoginSuperuser( + resp, err := lib.AdminClient.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) // In the integration suite, all origins are valid. t.Run("Browser request - accepted", func(t *testing.T) { t.Parallel() - resp, err := adminClient.LoginSuperuser( + resp, err := lib.AdminClient.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, func(ctx context.Context, req *http.Request) error { req.Header.Set("Origin", "http://www.safe.com") return nil }, ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) }) } func TestCORS_basicauth(t *testing.T) { t.Run("OPTIONS preflight with Origin - CORS headers returned", func(t *testing.T) { t.Parallel() - url := fmt.Sprintf("http://%s:%d/api/auth/basic/organisations/%d/login", getHost(), getAdminPort(), alwaysOrgID) - resp := options(url, t, http.Header{"Origin": []string{"http://www.safe.com"}}) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + url := fmt.Sprintf("http://%s:%d/api/auth/basic/organisations/%d/login", lib.GetHost(), lib.GetAdminPort(), alwaysOrgID) + resp := lib.Options(url, t, http.Header{"Origin": []string{"http://www.safe.com"}}) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) if resp.Header.Get("Access-Control-Allow-Methods") == "" { t.Fatal("Expected Access-Control-Allow-Methods to be set") } @@ -74,7 +75,7 @@ func TestCORS_basicauth(t *testing.T) { t.Run("Browser request - accepted", func(t *testing.T) { t.Parallel() - resp, err := basicAuthClient.Login( + resp, err := lib.BasicAuthClient.Login( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ @@ -85,55 +86,55 @@ func TestCORS_basicauth(t *testing.T) { req.Header.Set("Origin", "http://www.safe.com") return nil }) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) }) t.Run("Non-browser request - accepted", func(t *testing.T) { t.Parallel() - resp, err := basicAuthClient.Login( + resp, err := lib.BasicAuthClient.Login( t.Context(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.LoginJSONRequestBody{ Username: alwaysUser, Password: alwaysUserPassword, }) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) } func TestCORS_gateway(t *testing.T) { - baseURL := fmt.Sprintf("http://localhost:%d/gw/backend/echo", getPort()) + baseURL := fmt.Sprintf("http://localhost:%d/gw/backend/echo", lib.GetPort()) // normal echo has allowAll, but since Origin is omitted, we should not see a returned CORS header. t.Run("Non-browser request - accepted", func(t *testing.T) { t.Parallel() // No Origin set - resp := get(baseURL+"/hi", t) - verifyStatusCode(resp.StatusCode, http.StatusOK, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + resp := lib.Get(baseURL+"/hi", t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusOK, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) // normal echo has allowAll, expect headers t.Run("Browser request - accepted", func(t *testing.T) { t.Parallel() - resp := get(baseURL+"/hi", t, http.Header{"Origin": []string{"http://www.something.com"}}) - verifyStatusCode(resp.StatusCode, http.StatusOK, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.something.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + resp := lib.Get(baseURL+"/hi", t, http.Header{"Origin": []string{"http://www.something.com"}}) + lib.VerifyStatusCode(resp.StatusCode, http.StatusOK, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.something.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) }) // normal echo has allowAll, OPTIONS with Origin should return CORS headers t.Run("OPTIONS preflight with Origin - CORS headers returned", func(t *testing.T) { t.Parallel() - resp := options(baseURL+"/hi", t, http.Header{"Origin": []string{"http://www.something.com"}}) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.something.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + resp := lib.Options(baseURL+"/hi", t, http.Header{"Origin": []string{"http://www.something.com"}}) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.something.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) if resp.Header.Get("Access-Control-Allow-Methods") == "" { t.Fatal("Expected Access-Control-Allow-Methods to be set") } @@ -142,9 +143,9 @@ func TestCORS_gateway(t *testing.T) { // Send to protected-echo since it has no CORS conf., expect no headers t.Run("Browser request - no configured CORS", func(t *testing.T) { t.Parallel() - protectedURL := fmt.Sprintf("http://localhost:%d/gw/backend/protected-echo/unprotected", getPort()) - resp := get(protectedURL, t, http.Header{"Origin": []string{"http://www.something.com"}}) - verifyStatusCode(resp.StatusCode, http.StatusOK, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + protectedURL := fmt.Sprintf("http://localhost:%d/gw/backend/protected-echo/unprotected", lib.GetPort()) + resp := lib.Get(protectedURL, t, http.Header{"Origin": []string{"http://www.something.com"}}) + lib.VerifyStatusCode(resp.StatusCode, http.StatusOK, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) } diff --git a/test/suites/integration/debug.go b/test/suites/integration/debug.go deleted file mode 100644 index 6d9505d..0000000 --- a/test/suites/integration/debug.go +++ /dev/null @@ -1,31 +0,0 @@ -package integration - -import ( - "fmt" - "net/http" - "testing" - - adminapi "github.com/trebent/kerberos/test/client/admin" -) - -// startDebugSession is a helper that starts a debug session for the given backend and returns its ID. -func startDebugSession(t *testing.T, requestEditor RequestEditorFn, backend string) int { - t.Helper() - resp, err := adminClient.StartDebugSessionWithResponse( - t.Context(), - backend, - adminapi.StartDebugSessionJSONRequestBody{}, - adminapi.RequestEditorFn(requestEditor), - ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode(), http.StatusOK, t) - return resp.JSON200.Id -} - -// makeGatewayRequest sends a GET request through the gateway to the given backend path. -func makeGatewayRequest(t *testing.T, backend, path string) { - t.Helper() - url := fmt.Sprintf("http://localhost:%d/gw/backend/%s%s", getPort(), backend, path) - resp := get(url, t) - defer resp.Body.Close() -} diff --git a/test/suites/integration/gateway_test.go b/test/suites/integration/gateway_test.go index eb4ea2b..cccfcb2 100644 --- a/test/suites/integration/gateway_test.go +++ b/test/suites/integration/gateway_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" ) @@ -12,7 +13,7 @@ import ( func TestGWHappy(t *testing.T) { t.Parallel() - baseURL := fmt.Sprintf("http://localhost:%d/gw/backend/echo", getPort()) + baseURL := fmt.Sprintf("http://localhost:%d/gw/backend/echo", lib.GetPort()) bodyData := []byte(`{"test": "value"}`) cases := []struct { @@ -38,7 +39,7 @@ func TestGWHappy(t *testing.T) { // HEAD responses carry no body; verify the status code only. if tc.method == http.MethodHead { - response := head(url, t) + response := lib.Head(url, t) defer response.Body.Close() if response.StatusCode != http.StatusOK { t.Fatalf("unexpected status code: got %d, want %d", response.StatusCode, http.StatusOK) @@ -57,8 +58,8 @@ func TestGWHappy(t *testing.T) { t.Fatalf("failed to create request: %v", err) } - response := do(req, t) - decoded := verifyGWResponse(response, http.StatusOK, t) + response := lib.Do(req, t) + decoded := lib.VerifyGWResponse(response, http.StatusOK, t) if decoded.URL != tc.path { t.Errorf("unexpected URL in response: got %s, want %s", decoded.URL, tc.path) @@ -93,20 +94,20 @@ func TestGWNoBackend(t *testing.T) { testData := "{\"test\": \"value\"}" urlSegment := "/idontexist/" - url := fmt.Sprintf("http://localhost:%d/gw/backend%s", getPort(), urlSegment) + url := fmt.Sprintf("http://localhost:%d/gw/backend%s", lib.GetPort(), urlSegment) t.Logf("Sending to non-existent backend url %s", url) - response := post(url, []byte(testData), t) + response := lib.Post(url, []byte(testData), t) - _ = verifyGWResponse(response, http.StatusNotFound, t) + _ = lib.VerifyGWResponse(response, http.StatusNotFound, t) } func TestGWBackendFormat(t *testing.T) { t.Parallel() testData := "{\"test\": \"value\"}" - url := fmt.Sprintf("http://localhost:%d/gw/back", getPort()) + url := fmt.Sprintf("http://localhost:%d/gw/back", lib.GetPort()) t.Logf("Sending to funky url %s", url) - response := post(url, []byte(testData), t) + response := lib.Post(url, []byte(testData), t) - _ = verifyGWResponse(response, http.StatusBadRequest, t) + _ = lib.VerifyGWResponse(response, http.StatusBadRequest, t) } diff --git a/test/suites/integration/main_test.go b/test/suites/integration/main_test.go index 9d6c275..1b01dd9 100644 --- a/test/suites/integration/main_test.go +++ b/test/suites/integration/main_test.go @@ -2,6 +2,7 @@ package integration import ( "context" + lib "github.com/trebent/kerberos/test/lib" "math/rand/v2" "net/http" "os" @@ -15,12 +16,12 @@ func TestMain(m *testing.M) { println("Running TestMain, setting up test foundation...") // Init atomic iterator with random number - a.Store(rand.Int32()) + lib.InitNames(rand.Int32()) - loginResp, err := adminClient.LoginSuperuserWithResponse( + loginResp, err := lib.AdminClient.LoginSuperuserWithResponse( context.Background(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, ) if err != nil { @@ -29,13 +30,13 @@ func TestMain(m *testing.M) { if loginResp.StatusCode() != http.StatusNoContent { panic("superuser login response did not indicate success: " + loginResp.Status()) } - cookie, err := extractSessionCookie(loginResp.HTTPResponse) + cookie, err := lib.ExtractSessionCookie(loginResp.HTTPResponse) if err != nil { panic(err) } - requestEditorSuper := makeRequestEditorFromCookie(cookie) + requestEditorSuper := lib.MakeRequestEditorFromCookie(cookie) - createAdminUserResp, err := adminClient.CreateUserWithResponse( + createAdminUserResp, err := lib.AdminClient.CreateUserWithResponse( context.Background(), adminapi.CreateUserJSONRequestBody{ Username: alwaysAdminUser, @@ -50,7 +51,7 @@ func TestMain(m *testing.M) { panic("create admin user response did not indicate success: " + createAdminUserResp.Status()) } - orgResp, err := basicAuthClient.CreateOrganisationWithResponse( + orgResp, err := lib.BasicAuthClient.CreateOrganisationWithResponse( context.Background(), authbasicapi.CreateOrganisationJSONRequestBody{Name: alwaysOrg}, authbasicapi.RequestEditorFn(requestEditorSuper), @@ -61,7 +62,7 @@ func TestMain(m *testing.M) { if orgResp.StatusCode() != http.StatusCreated { if orgResp.StatusCode() == http.StatusConflict { - orgListResp, err := basicAuthClient.ListOrganisationsWithResponse( + orgListResp, err := lib.BasicAuthClient.ListOrganisationsWithResponse( context.Background(), authbasicapi.RequestEditorFn(requestEditorSuper), ) @@ -87,7 +88,7 @@ func TestMain(m *testing.M) { alwaysOrgID = int(orgResp.JSON201.Id) } - userResp, err := basicAuthClient.CreateUserWithResponse( + userResp, err := lib.BasicAuthClient.CreateUserWithResponse( context.Background(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateUserJSONRequestBody{Name: alwaysUser, Password: alwaysUserPassword}, @@ -98,7 +99,7 @@ func TestMain(m *testing.M) { } if userResp.StatusCode() != http.StatusCreated { if userResp.StatusCode() == http.StatusConflict { - userListResp, err := basicAuthClient.ListUsersWithResponse( + userListResp, err := lib.BasicAuthClient.ListUsersWithResponse( context.Background(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.RequestEditorFn(requestEditorSuper), @@ -138,7 +139,7 @@ func TestMain(m *testing.M) { panic("failed to find staff group id") } - updateUserGroupsResp, err := basicAuthClient.UpdateUserGroupsWithResponse( + updateUserGroupsResp, err := lib.BasicAuthClient.UpdateUserGroupsWithResponse( context.Background(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.Userid(alwaysUserID), @@ -163,7 +164,7 @@ func TestMain(m *testing.M) { } func createOrGetGroup(name string, requestEditor authbasicapi.RequestEditorFn) int { - groupCreateResp, err := basicAuthClient.CreateGroupWithResponse( + groupCreateResp, err := lib.BasicAuthClient.CreateGroupWithResponse( context.Background(), authbasicapi.Orgid(alwaysOrgID), authbasicapi.CreateGroupJSONRequestBody{Name: name}, @@ -174,7 +175,7 @@ func createOrGetGroup(name string, requestEditor authbasicapi.RequestEditorFn) i } if groupCreateResp.StatusCode() != http.StatusCreated { if groupCreateResp.StatusCode() == http.StatusConflict { - groupListResp, err := basicAuthClient.ListGroupsWithResponse( + groupListResp, err := lib.BasicAuthClient.ListGroupsWithResponse( context.Background(), authbasicapi.Orgid(alwaysOrgID), requestEditor, diff --git a/test/suites/integration/metrics_test.go b/test/suites/integration/metrics_test.go index 0d7e618..99ed419 100644 --- a/test/suites/integration/metrics_test.go +++ b/test/suites/integration/metrics_test.go @@ -2,6 +2,7 @@ package integration import ( "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -14,12 +15,12 @@ import ( func TestMetricsBasic(t *testing.T) { startMetrics := fetchMetrics(t) - url := fmt.Sprintf("http://%s:%d/gw/backend/echo/hi", getHost(), getPort()) - _ = get(url, t) - _ = put(url, []byte("metrics test"), t) - _ = post(url, []byte("metrics test"), t) - _ = delete(url, t) - _ = patch(url, []byte("metrics test"), t) + url := fmt.Sprintf("http://%s:%d/gw/backend/echo/hi", lib.GetHost(), lib.GetPort()) + _ = lib.Get(url, t) + _ = lib.Put(url, []byte("metrics test"), t) + _ = lib.Post(url, []byte("metrics test"), t) + _ = lib.Delete(url, t) + _ = lib.Patch(url, []byte("metrics test"), t) endMetrics := fetchMetrics(t) for metricName, endMetric := range endMetrics { @@ -54,13 +55,13 @@ func TestMetricsBasic(t *testing.T) { func fetchMetrics(t *testing.T) map[string]*io_prometheus_client.MetricFamily { // Verify metrics standings - t.Logf("Metrics host and port %s:%d", getHost(), getMetricsPort()) - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d/metrics", getHost(), getMetricsPort()), nil) + t.Logf("Metrics host and port %s:%d", lib.GetHost(), lib.GetMetricsPort()) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d/metrics", lib.GetHost(), lib.GetMetricsPort()), nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } - resp, err := client.Do(req) + resp, err := lib.Client.Do(req) if err != nil { t.Fatalf("Failed to send request: %v", err) } diff --git a/test/suites/integration/shared_bindings.go b/test/suites/integration/shared_bindings.go deleted file mode 100644 index 8dfc998..0000000 --- a/test/suites/integration/shared_bindings.go +++ /dev/null @@ -1,20 +0,0 @@ -package integration - -import testlib "github.com/trebent/kerberos/test/lib" - -type RequestEditorFn = testlib.RequestEditorFn - -var ( - checkErr = testlib.CheckErr - verifyStatusCode = testlib.VerifyStatusCode - verifyHeader = testlib.VerifyHeader - verifyHeaderMissing = testlib.VerifyHeaderMissing - extractSessionCookie = testlib.ExtractSessionCookie - extractRefreshCookie = testlib.ExtractRefreshCookie - makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie - getAdminPort = testlib.GetAdminPort - getPort = testlib.GetPort - getHost = testlib.GetHost - getMetricsPort = testlib.GetMetricsPort - getJaegerAPIPort = testlib.GetJaegerAPIPort -) diff --git a/test/suites/integration/state.go b/test/suites/integration/state.go index 3318c64..1abd4b0 100644 --- a/test/suites/integration/state.go +++ b/test/suites/integration/state.go @@ -1,46 +1,14 @@ package integration -import ( - "fmt" - "net/http" - "sync/atomic" - "time" - - adminapi "github.com/trebent/kerberos/test/client/admin" - authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" -) - var ( - client = &http.Client{Timeout: 4 * time.Second} - - basicAuthClient, _ = authbasicapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), - ) - adminClient, _ = adminapi.NewClientWithResponses( - fmt.Sprintf("http://%s:%d", getHost(), getAdminPort()), - ) - alwaysOrgID = 0 alwaysUserID = 0 alwaysGroupStaffID = 0 alwaysGroupPlebID = 0 alwaysGroupDevID = 0 - - // Used to generate unique names. - // This is initialised with a random int32 in TestMain. - a = atomic.Int32{} ) const ( - superUserClientID = "admin" - superUserClientSecret = "secret" -) - -const ( - orgNameBase = "Org" - usernameBase = "Smith" - groupNameBase = "Group" - // Always resource names, used to denote resource that all tests can expect to be present. // Always resource must never be altered or deleted by test cases, and are set up by test main. alwaysOrg = "always" @@ -51,18 +19,3 @@ const ( alwaysGroupPleb = "pleb" alwaysGroupDev = "dev" ) - -// Returns a guaranteed unique username. -func username() string { - return fmt.Sprintf("%s-%d", usernameBase, a.Add(1)) -} - -// Returns a guaranteed unique org name. -func orgName() string { - return fmt.Sprintf("%s-%d", orgNameBase, a.Add(1)) -} - -// Returns a guaranteed unique group name. -func groupName() string { - return fmt.Sprintf("%s-%d", groupNameBase, a.Add(1)) -} diff --git a/test/suites/integration/tracing_test.go b/test/suites/integration/tracing_test.go index 2c9862c..318f9bf 100644 --- a/test/suites/integration/tracing_test.go +++ b/test/suites/integration/tracing_test.go @@ -3,6 +3,7 @@ package integration import ( "errors" "fmt" + lib "github.com/trebent/kerberos/test/lib" "io" "net/http" "strings" @@ -18,9 +19,9 @@ import ( // Verifies that basic tracing works as expected. func TestTracingBasic(t *testing.T) { start := time.Now() - response := get(fmt.Sprintf("http://%s:%d/gw/backend/echo/hi", getHost(), getPort()), t) + response := lib.Get(fmt.Sprintf("http://%s:%d/gw/backend/echo/hi", lib.GetHost(), lib.GetPort()), t) - decodedResponse := verifyGWResponse(response, http.StatusOK, t) + decodedResponse := lib.VerifyGWResponse(response, http.StatusOK, t) traceParent, exists := decodedResponse.Headers["Traceparent"] if !exists || len(traceParent) == 0 { @@ -29,7 +30,7 @@ func TestTracingBasic(t *testing.T) { t.Logf("Traceparent header: %s", traceParent[0]) } - conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", getJaegerAPIPort()), grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", lib.GetJaegerAPIPort()), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { t.Fatalf("Failed to connect to jaeger: %v", err) } diff --git a/test/suites/lib/admin_user.go b/test/suites/lib/admin_user.go new file mode 100644 index 0000000..1a0bded --- /dev/null +++ b/test/suites/lib/admin_user.go @@ -0,0 +1,64 @@ +package lib + +import ( + "net/http" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +// MustGetAdminUserID fetches the admin user list and returns the ID of the user with the given username. +func MustGetAdminUserID(t *testing.T, requestEditor RequestEditorFn, name string) int { + t.Helper() + resp, err := AdminClient.GetUsersWithResponse( + t.Context(), + adminapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) + for _, u := range *resp.JSON200 { + if u.Username == name { + return u.Id + } + } + t.Fatalf("admin user %q not found in list", name) + return 0 +} + +// CreateAdminUserInGroup creates a fresh admin user, creates a group with the specified +// permissionIDs, adds the user to that group, and returns the user's session. +func CreateAdminUserInGroup(t *testing.T, requestEditor RequestEditorFn, permissionIDs []int) RequestEditorFn { + t.Helper() + + const pass = "testpassword1" + name := Username() + + createUserResp, err := AdminClient.CreateUserWithResponse( + t.Context(), + adminapi.CreateUserJSONRequestBody{Username: name, Password: pass}, + adminapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(createUserResp.StatusCode(), http.StatusCreated, t) + + userID := MustGetAdminUserID(t, requestEditor, name) + + grpResp, err := AdminClient.CreateGroupWithResponse( + t.Context(), + adminapi.CreateGroupJSONRequestBody{Name: GroupName(), PermissionIDs: permissionIDs}, + adminapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(grpResp.StatusCode(), http.StatusCreated, t) + + updateResp, err := AdminClient.UpdateUserGroupsWithResponse( + t.Context(), + userID, + adminapi.UpdateUserGroupsJSONRequestBody{GroupIDs: []int{grpResp.JSON201.Id}}, + adminapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(updateResp.StatusCode(), http.StatusNoContent, t) + + return AdminUserLogin(t, name, pass) +} diff --git a/test/suites/lib/auth.go b/test/suites/lib/auth.go new file mode 100644 index 0000000..d33d6f1 --- /dev/null +++ b/test/suites/lib/auth.go @@ -0,0 +1,50 @@ +package lib + +import ( + "net/http" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +func RefreshCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { + t.Helper() + refreshCookie, err := ExtractRefreshCookie(response) + if err != nil { + t.Fatalf("failed to extract refresh cookie: %v", err) + } + return MakeRequestEditorFromCookie(refreshCookie) +} + +func SessionCookieRequestEditor(response *http.Response, t *testing.T) RequestEditorFn { + t.Helper() + sessionCookie, err := ExtractSessionCookie(response) + if err != nil { + t.Fatalf("failed to extract session cookie: %v", err) + } + return MakeRequestEditorFromCookie(sessionCookie) +} + +// SuperLogin logs in as the superuser and returns a request editor to use. +func SuperLogin(t *testing.T) RequestEditorFn { + t.Helper() + resp, err := AdminClient.LoginSuperuserWithResponse( + t.Context(), + adminapi.LoginSuperuserJSONRequestBody{ClientId: SuperUserClientID, ClientSecret: SuperUserClientSecret}, + ) + CheckErr(err, t) + VerifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) + return SessionCookieRequestEditor(resp.HTTPResponse, t) +} + +// AdminUserLogin logs in as a non-superuser admin and returns the request editor to use. +func AdminUserLogin(t *testing.T, name, pass string) RequestEditorFn { + t.Helper() + resp, err := AdminClient.LoginWithResponse( + t.Context(), + adminapi.LoginJSONRequestBody{Username: name, Password: pass}, + ) + CheckErr(err, t) + VerifyStatusCode(resp.StatusCode(), http.StatusNoContent, t) + return SessionCookieRequestEditor(resp.HTTPResponse, t) +} diff --git a/test/suites/lib/basic_auth.go b/test/suites/lib/basic_auth.go new file mode 100644 index 0000000..c6641aa --- /dev/null +++ b/test/suites/lib/basic_auth.go @@ -0,0 +1,34 @@ +package lib + +import ( + "net/http" + "testing" + + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +// OrgWithSession creates a fresh organisation and returns its ID along with an +// admin session request editor for that organisation. +func OrgWithSession(t *testing.T, requestEditor RequestEditorFn) (authbasicapi.Orgid, RequestEditorFn) { + t.Helper() + createOrgResp, err := BasicAuthClient.CreateOrganisationWithResponse( + t.Context(), + authbasicapi.CreateOrganisationJSONRequestBody{Name: OrgName()}, + authbasicapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(createOrgResp.StatusCode(), http.StatusCreated, t) + + loginResp, err := BasicAuthClient.LoginWithResponse( + t.Context(), + createOrgResp.JSON201.Id, + authbasicapi.LoginJSONRequestBody{ + Username: createOrgResp.JSON201.AdminUsername, + Password: createOrgResp.JSON201.AdminPassword, + }, + ) + CheckErr(err, t) + VerifyStatusCode(loginResp.StatusCode(), http.StatusNoContent, t) + + return createOrgResp.JSON201.Id, SessionCookieRequestEditor(loginResp.HTTPResponse, t) +} diff --git a/test/suites/lib/clients.go b/test/suites/lib/clients.go new file mode 100644 index 0000000..be1c500 --- /dev/null +++ b/test/suites/lib/clients.go @@ -0,0 +1,26 @@ +package lib + +import ( + "fmt" + "net/http" + "time" + + adminapi "github.com/trebent/kerberos/test/client/admin" + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +const ( + SuperUserClientID = "admin" + SuperUserClientSecret = "secret" +) + +var ( + Client = &http.Client{Timeout: 4 * time.Second} + + AdminClient, _ = adminapi.NewClientWithResponses( + fmt.Sprintf("http://%s:%d", GetHost(), GetAdminPort()), + ) + BasicAuthClient, _ = authbasicapi.NewClientWithResponses( + fmt.Sprintf("http://%s:%d", GetHost(), GetAdminPort()), + ) +) diff --git a/test/suites/lib/debug.go b/test/suites/lib/debug.go new file mode 100644 index 0000000..f9bd6e5 --- /dev/null +++ b/test/suites/lib/debug.go @@ -0,0 +1,31 @@ +package lib + +import ( + "fmt" + "net/http" + "testing" + + adminapi "github.com/trebent/kerberos/test/client/admin" +) + +// StartDebugSession starts a debug session for the given backend and returns its ID. +func StartDebugSession(t *testing.T, requestEditor RequestEditorFn, backend string) int { + t.Helper() + resp, err := AdminClient.StartDebugSessionWithResponse( + t.Context(), + backend, + adminapi.StartDebugSessionJSONRequestBody{}, + adminapi.RequestEditorFn(requestEditor), + ) + CheckErr(err, t) + VerifyStatusCode(resp.StatusCode(), http.StatusOK, t) + return resp.JSON200.Id +} + +// MakeGatewayRequest sends a GET request through the gateway to the given backend path. +func MakeGatewayRequest(t *testing.T, backend, path string) { + t.Helper() + url := fmt.Sprintf("http://localhost:%d/gw/backend/%s%s", GetPort(), backend, path) + resp := Get(url, t) + defer resp.Body.Close() +} diff --git a/test/suites/integration/http_requests.go b/test/suites/lib/http_requests.go similarity index 69% rename from test/suites/integration/http_requests.go rename to test/suites/lib/http_requests.go index 799411b..bfd4a1e 100644 --- a/test/suites/integration/http_requests.go +++ b/test/suites/lib/http_requests.go @@ -1,4 +1,4 @@ -package integration +package lib import ( "bytes" @@ -18,131 +18,116 @@ type EchoResponse struct { Body json.RawMessage `json:"body,omitempty"` } -func get(url string, t *testing.T, headers ...http.Header) *http.Response { +func Get(url string, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func protectedGet(url string, t *testing.T, session *http.Cookie) *http.Response { +func ProtectedGet(url string, t *testing.T, session *http.Cookie) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - req.AddCookie(session) - - return do(req, t) + return Do(req, t) } -func post(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { +func Post(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func put(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { +func Put(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body)) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func delete(url string, t *testing.T, headers ...http.Header) *http.Response { +func Delete(url string, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodDelete, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func patch(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { +func Patch(url string, body []byte, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodPatch, url, bytes.NewBuffer(body)) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func trace(url string, t *testing.T, headers ...http.Header) *http.Response { +func Trace(url string, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodTrace, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func head(url string, t *testing.T, headers ...http.Header) *http.Response { +func Head(url string, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func options(url string, t *testing.T, headers ...http.Header) *http.Response { +func Options(url string, t *testing.T, headers ...http.Header) *http.Response { t.Helper() req, err := http.NewRequest(http.MethodOptions, url, nil) if err != nil { t.Fatalf("failed to create request: %v", err) } - - return do(req, t, headers...) + return Do(req, t, headers...) } -func do(req *http.Request, t *testing.T, headers ...http.Header) *http.Response { +func Do(req *http.Request, t *testing.T, headers ...http.Header) *http.Response { t.Helper() - for _, headers := range headers { - for key, values := range headers { + for _, h := range headers { + for key, values := range h { req.Header[key] = values } } - - resp, err := client.Do(req) + resp, err := Client.Do(req) if err != nil { t.Fatalf("failed to send request: %v", err) } - return resp } -func verifyGWResponse(resp *http.Response, expectedCode int, t *testing.T) *EchoResponse { +func VerifyGWResponse(resp *http.Response, expectedCode int, t *testing.T) *EchoResponse { t.Helper() defer resp.Body.Close() - if resp.StatusCode != expectedCode { t.Fatalf("unexpected status code: got %d, want %d", resp.StatusCode, expectedCode) } - response := &EchoResponse{} if err := json.NewDecoder(resp.Body).Decode(response); err != nil { t.Fatalf("failed to decode response body: %v", err) } - return response } -func verifyAdminAPIErrorResponse(er *adminapi.APIErrorResponse, t *testing.T) { +func VerifyAdminAPIErrorResponse(er *adminapi.APIErrorResponse, t *testing.T) { t.Helper() if er != nil { if len(er.Errors) == 0 { @@ -153,7 +138,7 @@ func verifyAdminAPIErrorResponse(er *adminapi.APIErrorResponse, t *testing.T) { } } -func verifyAuthBasicAPIErrorResponse(er *authbasicapi.APIErrorResponse, t *testing.T) { +func VerifyAuthBasicAPIErrorResponse(er *authbasicapi.APIErrorResponse, t *testing.T) { t.Helper() if er != nil { if len(er.Errors) == 0 { @@ -164,14 +149,14 @@ func verifyAuthBasicAPIErrorResponse(er *authbasicapi.APIErrorResponse, t *testi } } -func matches[T comparable](one, two T, t *testing.T) { +func Matches[T comparable](one, two T, t *testing.T) { t.Helper() if one != two { t.Fatalf("%v is not equal to %v", one, two) } } -func containsAll[T comparable](source, reference []T, t *testing.T) { +func ContainsAll[T comparable](source, reference []T, t *testing.T) { t.Helper() for _, item := range source { if !slices.Contains(reference, item) { diff --git a/test/suites/lib/names.go b/test/suites/lib/names.go new file mode 100644 index 0000000..790e7a5 --- /dev/null +++ b/test/suites/lib/names.go @@ -0,0 +1,29 @@ +package lib + +import ( + "fmt" + "sync/atomic" +) + +var a atomic.Int32 + +// InitNames seeds the atomic counter used to generate unique names. +// Call this from TestMain with a random seed. +func InitNames(seed int32) { + a.Store(seed) +} + +// Username returns a guaranteed unique username. +func Username() string { + return fmt.Sprintf("Smith-%d", a.Add(1)) +} + +// OrgName returns a guaranteed unique organisation name. +func OrgName() string { + return fmt.Sprintf("Org-%d", a.Add(1)) +} + +// GroupName returns a guaranteed unique group name. +func GroupName() string { + return fmt.Sprintf("Group-%d", a.Add(1)) +} diff --git a/test/suites/security/config.go b/test/suites/security/config.go index a639125..f7db582 100644 --- a/test/suites/security/config.go +++ b/test/suites/security/config.go @@ -8,9 +8,6 @@ const ( adminPort = 30001 echoPort = 15000 - superUserClientID = "admin" - superUserClientSecret = "secret" - adminUser = "security-admin" adminUserPassword = "security-admin-password" diff --git a/test/suites/security/cookies_test.go b/test/suites/security/cookies_test.go index d32fe2e..3c169b7 100644 --- a/test/suites/security/cookies_test.go +++ b/test/suites/security/cookies_test.go @@ -1,6 +1,7 @@ package security import ( + lib "github.com/trebent/kerberos/test/lib" "net/http" "testing" @@ -15,13 +16,13 @@ func TestCookies_admin(t *testing.T) { resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) validateAdminCookieAttributes(resp.Cookies(), t) }) @@ -36,8 +37,8 @@ func TestCookies_admin(t *testing.T) { }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) validateAdminCookieAttributes(resp.Cookies(), t) }) } @@ -50,8 +51,8 @@ func TestCookies_basicauth(t *testing.T) { Username: basicAuthUser, Password: basicAuthPassword, }) - checkErr(err, t) - verifyStatusCode(loginResp.StatusCode, http.StatusNoContent, t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(loginResp.StatusCode, http.StatusNoContent, t) var refresh, session, csrf bool for _, cookie := range loginResp.Cookies() { switch cookie.Name { diff --git a/test/suites/security/cors_test.go b/test/suites/security/cors_test.go index d3341e2..c16e6fd 100644 --- a/test/suites/security/cors_test.go +++ b/test/suites/security/cors_test.go @@ -3,6 +3,7 @@ package security import ( "context" "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "net/url" "testing" @@ -18,14 +19,14 @@ func TestCORS_admin(t *testing.T) { resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, // No request editor to set an Origin, should pass automatically. ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) t.Run("Browser request, valid Origin", func(t *testing.T) { @@ -34,18 +35,18 @@ func TestCORS_admin(t *testing.T) { resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, func(ctx context.Context, req *http.Request) error { req.Header.Set("Origin", "http://www.safe.com") return nil }, ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) }) t.Run("Browser request, invalid Origin", func(t *testing.T) { @@ -54,17 +55,17 @@ func TestCORS_admin(t *testing.T) { resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, func(ctx context.Context, req *http.Request) error { req.Header.Set("Origin", "http://www.bad.com") return nil }, ) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusForbidden, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusForbidden, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) } @@ -79,9 +80,9 @@ func TestCORS_basicauth(t *testing.T) { req.Header.Set("Origin", "http://www.safe.com") return nil }) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusForbidden, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusForbidden, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) t.Run("Non-browser request - accepted", func(t *testing.T) { @@ -91,9 +92,9 @@ func TestCORS_basicauth(t *testing.T) { Username: basicAuthUser, Password: basicAuthPassword, }) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusNoContent, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusNoContent, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) } @@ -103,17 +104,17 @@ func TestCORS_gateway(t *testing.T) { client := tlsClient(t) // mtls-echo using denyAll means we should not see a returned CORS header. - resp, err := client.Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", getPort())) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusOK, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", lib.GetPort())) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusOK, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) t.Run("Browser request, denyAll set", func(t *testing.T) { t.Parallel() client := tlsClient(t) - url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", getPort())) + url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", lib.GetPort())) req := &http.Request{ Method: http.MethodGet, URL: url, @@ -124,16 +125,16 @@ func TestCORS_gateway(t *testing.T) { // mtls-echo using denyAll means we should get denied. resp, err := client.Do(req) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusForbidden, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusForbidden, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) // tls-echo using allowedOrigins means we should see a returned CORS header for a valid Origin. t.Run("Browser request, valid Origin", func(t *testing.T) { t.Parallel() client := tlsClient(t) - url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", getPort())) + url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", lib.GetPort())) req := &http.Request{ Method: http.MethodGet, URL: url, @@ -143,17 +144,17 @@ func TestCORS_gateway(t *testing.T) { } resp, err := client.Do(req) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusOK, t) - verifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) - verifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusOK, t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Origin", "http://www.safe.com", t) + lib.VerifyHeader(resp.Header, "Access-Control-Allow-Credentials", "true", t) }) // tls-echo using allowedOrigins means we should not see a returned CORS header for an invalid Origin. t.Run("Browser request, invalid Origin", func(t *testing.T) { t.Parallel() client := tlsClient(t) - url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", getPort())) + url, _ := url.Parse(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", lib.GetPort())) req := &http.Request{ Method: http.MethodGet, URL: url, @@ -163,8 +164,8 @@ func TestCORS_gateway(t *testing.T) { } resp, err := client.Do(req) - checkErr(err, t) - verifyStatusCode(resp.StatusCode, http.StatusForbidden, t) - verifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) + lib.CheckErr(err, t) + lib.VerifyStatusCode(resp.StatusCode, http.StatusForbidden, t) + lib.VerifyHeaderMissing(resp.Header, "Access-Control-Allow-Origin", t) }) } diff --git a/test/suites/security/main_test.go b/test/suites/security/main_test.go index 6df0800..a9c1f42 100644 --- a/test/suites/security/main_test.go +++ b/test/suites/security/main_test.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "os" "testing" @@ -31,7 +32,7 @@ func TestMain(m *testing.M) { } adminClient, err := adminapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), adminapi.WithHTTPClient(httpClient), ) if err != nil { @@ -40,8 +41,8 @@ func TestMain(m *testing.M) { loginResp, err := adminClient.LoginSuperuserWithResponse( context.Background(), adminapi.LoginSuperuserJSONRequestBody{ - ClientId: superUserClientID, - ClientSecret: superUserClientSecret, + ClientId: lib.SuperUserClientID, + ClientSecret: lib.SuperUserClientSecret, }, ) if err != nil { @@ -50,11 +51,11 @@ func TestMain(m *testing.M) { if loginResp.StatusCode() != http.StatusNoContent { panic("superuser login response did not indicate success: " + loginResp.Status()) } - cookie, err := extractSessionCookie(loginResp.HTTPResponse) + cookie, err := lib.ExtractSessionCookie(loginResp.HTTPResponse) if err != nil { panic(err) } - requestEditorSuper := makeRequestEditorFromCookie(cookie) + requestEditorSuper := lib.MakeRequestEditorFromCookie(cookie) createAdminUserResp, err := adminClient.CreateUserWithResponse( context.Background(), @@ -72,7 +73,7 @@ func TestMain(m *testing.M) { } basicAuthClient, err := authbasicapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), authbasicapi.WithHTTPClient(httpClient), ) if err != nil { diff --git a/test/suites/security/shared_bindings.go b/test/suites/security/shared_bindings.go deleted file mode 100644 index 382d1f5..0000000 --- a/test/suites/security/shared_bindings.go +++ /dev/null @@ -1,17 +0,0 @@ -package security - -import testlib "github.com/trebent/kerberos/test/lib" - -type RequestEditorFn = testlib.RequestEditorFn - -var ( - checkErr = testlib.CheckErr - verifyStatusCode = testlib.VerifyStatusCode - verifyHeader = testlib.VerifyHeader - verifyHeaderMissing = testlib.VerifyHeaderMissing - getHost = testlib.GetHost - getPort = testlib.GetPort - getAdminPort = testlib.GetAdminPort - extractSessionCookie = testlib.ExtractSessionCookie - makeRequestEditorFromCookie = testlib.MakeRequestEditorFromCookie -) diff --git a/test/suites/security/tls_clients.go b/test/suites/security/tls_clients.go index 7938782..2b4cf5c 100644 --- a/test/suites/security/tls_clients.go +++ b/test/suites/security/tls_clients.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + lib "github.com/trebent/kerberos/test/lib" "net/http" "os" "testing" @@ -18,10 +19,10 @@ import ( func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { t.Helper() client, err := adminapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), adminapi.WithHTTPClient(tlsClient(t)), ) - checkErr(err, t) + lib.CheckErr(err, t) return client } @@ -30,10 +31,10 @@ func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { t.Helper() client, err := authbasicapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", getHost(), getAdminPort()), + fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), authbasicapi.WithHTTPClient(tlsClient(t)), ) - checkErr(err, t) + lib.CheckErr(err, t) return client } From 70b7faf68b09068c0be6d9900a7088959ee5268a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:40:01 +0000 Subject: [PATCH 4/7] refactor(test): move TLS helpers to lib, use lib ports in security suite Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- test/suites/lib/tls_clients.go | 81 +++++++++++++++++++++++++++++ test/suites/security/config.go | 4 -- test/suites/security/tls_clients.go | 59 +++------------------ test/suites/security/tls_test.go | 12 +++-- 4 files changed, 94 insertions(+), 62 deletions(-) create mode 100644 test/suites/lib/tls_clients.go diff --git a/test/suites/lib/tls_clients.go b/test/suites/lib/tls_clients.go new file mode 100644 index 0000000..27aa145 --- /dev/null +++ b/test/suites/lib/tls_clients.go @@ -0,0 +1,81 @@ +package lib + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "net/http" + "os" + "testing" + "time" + + adminapi "github.com/trebent/kerberos/test/client/admin" + authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" +) + +// AdminResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against +// the test CA but sends no client certificate. certDir is the path to the directory containing ca.crt. +func AdminResponsesTLSClient(t *testing.T, certDir string) *adminapi.ClientWithResponses { + t.Helper() + client, err := adminapi.NewClientWithResponses( + fmt.Sprintf("https://%s:%d", GetHost(), GetAdminPort()), + adminapi.WithHTTPClient(TLSClient(t, certDir)), + ) + CheckErr(err, t) + return client +} + +// BasicAuthResponsesTLSClient returns an authbasicapi.ClientWithResponses that verifies the server cert against +// the test CA but sends no client certificate. certDir is the path to the directory containing ca.crt. +func BasicAuthResponsesTLSClient(t *testing.T, certDir string) *authbasicapi.ClientWithResponses { + t.Helper() + client, err := authbasicapi.NewClientWithResponses( + fmt.Sprintf("https://%s:%d", GetHost(), GetAdminPort()), + authbasicapi.WithHTTPClient(TLSClient(t, certDir)), + ) + CheckErr(err, t) + return client +} + +// TLSClient returns an http.Client that verifies the server cert against the +// test CA but sends no client certificate. certDir is the path to the directory containing ca.crt. +func TLSClient(t *testing.T, certDir string) *http.Client { + t.Helper() + return &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: CAPool(t, certDir), + }, + }, + } +} + +// PlainClient returns an http.Client that uses plain HTTP (no TLS). +func PlainClient() *http.Client { + return &http.Client{Timeout: 5 * time.Second} +} + +// CAPool loads the test CA certificate into a new cert pool. +// certDir is the path to the directory containing ca.crt. +func CAPool(t *testing.T, certDir string) *x509.CertPool { + t.Helper() + pool, err := GetCAPool(certDir) + if err != nil { + t.Fatalf("Failed to load CA pool: %v", err) + } + return pool +} + +// GetCAPool loads the CA certificate from certDir/ca.crt and returns a cert pool. +func GetCAPool(certDir string) (*x509.CertPool, error) { + pem, err := os.ReadFile(certDir + "/ca.crt") + if err != nil { + return nil, fmt.Errorf("read CA cert: %w", err) + } + pool := x509.NewCertPool() + if !pool.AppendCertsFromPEM(pem) { + return nil, fmt.Errorf("no certificates found in ca.crt") + } + return pool, nil +} diff --git a/test/suites/security/config.go b/test/suites/security/config.go index f7db582..3c1248f 100644 --- a/test/suites/security/config.go +++ b/test/suites/security/config.go @@ -4,10 +4,6 @@ const ( // certDir is relative to the test working directory (test/suites/security/). certDir = "../../certs" - kerberosPort = 30000 - adminPort = 30001 - echoPort = 15000 - adminUser = "security-admin" adminUserPassword = "security-admin-password" diff --git a/test/suites/security/tls_clients.go b/test/suites/security/tls_clients.go index 2b4cf5c..b460dca 100644 --- a/test/suites/security/tls_clients.go +++ b/test/suites/security/tls_clients.go @@ -1,81 +1,34 @@ package security import ( - "crypto/tls" "crypto/x509" - "fmt" - lib "github.com/trebent/kerberos/test/lib" "net/http" - "os" "testing" - "time" adminapi "github.com/trebent/kerberos/test/client/admin" authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" + testlib "github.com/trebent/kerberos/test/lib" ) -// adminResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against -// the test CA but sends no client certificate. func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { t.Helper() - client, err := adminapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), - adminapi.WithHTTPClient(tlsClient(t)), - ) - lib.CheckErr(err, t) - return client + return testlib.AdminResponsesTLSClient(t, certDir) } -// basicAuthResponsesTLSClient returns an adminapi.ClientWithResponses that verifies the server cert against -// the test CA but sends no client certificate. func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { t.Helper() - client, err := authbasicapi.NewClientWithResponses( - fmt.Sprintf("https://%s:%d", lib.GetHost(), lib.GetAdminPort()), - authbasicapi.WithHTTPClient(tlsClient(t)), - ) - lib.CheckErr(err, t) - return client + return testlib.BasicAuthResponsesTLSClient(t, certDir) } -// tlsClient returns an http.Client that verifies the server cert against the -// test CA but sends no client certificate. func tlsClient(t *testing.T) *http.Client { t.Helper() - return &http.Client{ - Timeout: 5 * time.Second, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: caPool(t), - }, - }, - } + return testlib.TLSClient(t, certDir) } -// plainClient returns an http.Client that uses plain HTTP (no TLS). func plainClient() *http.Client { - return &http.Client{Timeout: 5 * time.Second} -} - -// caPool loads the test CA certificate into a new cert pool. -func caPool(t *testing.T) *x509.CertPool { - t.Helper() - pool, err := getCAPool() - if err != nil { - t.Fatalf("Failed to load CA pool: %v", err) - } - - return pool + return testlib.PlainClient() } func getCAPool() (*x509.CertPool, error) { - pem, err := os.ReadFile(certDir + "/ca.crt") - if err != nil { - return nil, fmt.Errorf("read CA cert: %w", err) - } - pool := x509.NewCertPool() - if !pool.AppendCertsFromPEM(pem) { - return nil, fmt.Errorf("no certificates found in ca.crt") - } - return pool, nil + return testlib.GetCAPool(certDir) } diff --git a/test/suites/security/tls_test.go b/test/suites/security/tls_test.go index b28947e..d9d56eb 100644 --- a/test/suites/security/tls_test.go +++ b/test/suites/security/tls_test.go @@ -4,6 +4,8 @@ import ( "fmt" "net/http" "testing" + + testlib "github.com/trebent/kerberos/test/lib" ) // ---- Admin API ---- @@ -13,7 +15,7 @@ import ( func TestAdminAPITLS(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/api/admin/flow", adminPort)) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/api/admin/flow", testlib.GetAdminPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -28,7 +30,7 @@ func TestAdminAPITLS(t *testing.T) { func TestAdminAPIPlainHTTP(t *testing.T) { t.Parallel() - resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/api/admin/flow", adminPort)) + resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/api/admin/flow", testlib.GetAdminPort())) if err != nil { t.Fatalf("Unexpected error when sending plain HTTP request: %v", err) } @@ -44,7 +46,7 @@ func TestAdminAPIPlainHTTP(t *testing.T) { func TestGWAPITLS_mTLS_echo(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", kerberosPort)) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", testlib.GetPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -59,7 +61,7 @@ func TestGWAPITLS_mTLS_echo(t *testing.T) { func TestGWAPITLS_TLS_echo(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", kerberosPort)) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", testlib.GetPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -74,7 +76,7 @@ func TestGWAPITLS_TLS_echo(t *testing.T) { func TestGWAPIPlainHTTP(t *testing.T) { t.Parallel() - resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/gw/backend/mtls-echo/hi", kerberosPort)) + resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/gw/backend/mtls-echo/hi", testlib.GetPort())) if err != nil { t.Fatalf("Unexpected error when sending plain HTTP request: %v", err) } From 4d766aa63fae39c86182a55ee267d221c3a06096 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:42:49 +0000 Subject: [PATCH 5/7] refactor(test): replace InitNames with func init(), rename testlib alias to lib Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- test/suites/integration/main_test.go | 4 ---- test/suites/lib/names.go | 7 +++---- test/suites/security/tls_clients.go | 12 ++++++------ test/suites/security/tls_test.go | 12 ++++++------ 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/test/suites/integration/main_test.go b/test/suites/integration/main_test.go index 1b01dd9..2740908 100644 --- a/test/suites/integration/main_test.go +++ b/test/suites/integration/main_test.go @@ -3,7 +3,6 @@ package integration import ( "context" lib "github.com/trebent/kerberos/test/lib" - "math/rand/v2" "net/http" "os" "testing" @@ -15,9 +14,6 @@ import ( func TestMain(m *testing.M) { println("Running TestMain, setting up test foundation...") - // Init atomic iterator with random number - lib.InitNames(rand.Int32()) - loginResp, err := lib.AdminClient.LoginSuperuserWithResponse( context.Background(), adminapi.LoginSuperuserJSONRequestBody{ ClientId: lib.SuperUserClientID, diff --git a/test/suites/lib/names.go b/test/suites/lib/names.go index 790e7a5..e2af19e 100644 --- a/test/suites/lib/names.go +++ b/test/suites/lib/names.go @@ -2,15 +2,14 @@ package lib import ( "fmt" + "math/rand/v2" "sync/atomic" ) var a atomic.Int32 -// InitNames seeds the atomic counter used to generate unique names. -// Call this from TestMain with a random seed. -func InitNames(seed int32) { - a.Store(seed) +func init() { + a.Store(rand.Int32()) } // Username returns a guaranteed unique username. diff --git a/test/suites/security/tls_clients.go b/test/suites/security/tls_clients.go index b460dca..4a15961 100644 --- a/test/suites/security/tls_clients.go +++ b/test/suites/security/tls_clients.go @@ -7,28 +7,28 @@ import ( adminapi "github.com/trebent/kerberos/test/client/admin" authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" - testlib "github.com/trebent/kerberos/test/lib" + lib "github.com/trebent/kerberos/test/lib" ) func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { t.Helper() - return testlib.AdminResponsesTLSClient(t, certDir) + return lib.AdminResponsesTLSClient(t, certDir) } func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { t.Helper() - return testlib.BasicAuthResponsesTLSClient(t, certDir) + return lib.BasicAuthResponsesTLSClient(t, certDir) } func tlsClient(t *testing.T) *http.Client { t.Helper() - return testlib.TLSClient(t, certDir) + return lib.TLSClient(t, certDir) } func plainClient() *http.Client { - return testlib.PlainClient() + return lib.PlainClient() } func getCAPool() (*x509.CertPool, error) { - return testlib.GetCAPool(certDir) + return lib.GetCAPool(certDir) } diff --git a/test/suites/security/tls_test.go b/test/suites/security/tls_test.go index d9d56eb..7da1e8c 100644 --- a/test/suites/security/tls_test.go +++ b/test/suites/security/tls_test.go @@ -5,7 +5,7 @@ import ( "net/http" "testing" - testlib "github.com/trebent/kerberos/test/lib" + lib "github.com/trebent/kerberos/test/lib" ) // ---- Admin API ---- @@ -15,7 +15,7 @@ import ( func TestAdminAPITLS(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/api/admin/flow", testlib.GetAdminPort())) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/api/admin/flow", lib.GetAdminPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -30,7 +30,7 @@ func TestAdminAPITLS(t *testing.T) { func TestAdminAPIPlainHTTP(t *testing.T) { t.Parallel() - resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/api/admin/flow", testlib.GetAdminPort())) + resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/api/admin/flow", lib.GetAdminPort())) if err != nil { t.Fatalf("Unexpected error when sending plain HTTP request: %v", err) } @@ -46,7 +46,7 @@ func TestAdminAPIPlainHTTP(t *testing.T) { func TestGWAPITLS_mTLS_echo(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", testlib.GetPort())) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/mtls-echo/hi", lib.GetPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -61,7 +61,7 @@ func TestGWAPITLS_mTLS_echo(t *testing.T) { func TestGWAPITLS_TLS_echo(t *testing.T) { t.Parallel() - resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", testlib.GetPort())) + resp, err := tlsClient(t).Get(fmt.Sprintf("https://localhost:%d/gw/backend/tls-echo/hi", lib.GetPort())) if err != nil { t.Fatalf("HTTPS request failed: %v", err) } @@ -76,7 +76,7 @@ func TestGWAPITLS_TLS_echo(t *testing.T) { func TestGWAPIPlainHTTP(t *testing.T) { t.Parallel() - resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/gw/backend/mtls-echo/hi", testlib.GetPort())) + resp, err := plainClient().Get(fmt.Sprintf("http://localhost:%d/gw/backend/mtls-echo/hi", lib.GetPort())) if err != nil { t.Fatalf("Unexpected error when sending plain HTTP request: %v", err) } From 1160a948c126984cebf8e5aef6f5aa070bc28593 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:46:33 +0000 Subject: [PATCH 6/7] refactor(test): remove security/tls_clients.go wiring file, call lib directly Co-authored-by: maansaake <15028979+maansaake@users.noreply.github.com> --- test/suites/security/cookies_test.go | 6 ++--- test/suites/security/cors_test.go | 10 ++++---- test/suites/security/main_test.go | 2 +- test/suites/security/tls_clients.go | 34 ---------------------------- 4 files changed, 9 insertions(+), 43 deletions(-) delete mode 100644 test/suites/security/tls_clients.go diff --git a/test/suites/security/cookies_test.go b/test/suites/security/cookies_test.go index 3c169b7..afa4df1 100644 --- a/test/suites/security/cookies_test.go +++ b/test/suites/security/cookies_test.go @@ -12,7 +12,7 @@ import ( func TestCookies_admin(t *testing.T) { t.Run("Verify superuser cookie attributes", func(t *testing.T) { t.Parallel() - client := adminResponsesTLSClient(t) + client := lib.AdminResponsesTLSClient(t, certDir) resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ @@ -28,7 +28,7 @@ func TestCookies_admin(t *testing.T) { t.Run("Verify admin user cookie attributes", func(t *testing.T) { t.Parallel() - client := adminResponsesTLSClient(t) + client := lib.AdminResponsesTLSClient(t, certDir) resp, err := client.Login( t.Context(), adminapi.LoginJSONRequestBody{ @@ -46,7 +46,7 @@ func TestCookies_admin(t *testing.T) { func TestCookies_basicauth(t *testing.T) { t.Run("Verify basic auth cookie attributes", func(t *testing.T) { t.Parallel() - client := basicAuthResponsesTLSClient(t) + client := lib.BasicAuthResponsesTLSClient(t, certDir) loginResp, err := client.Login(t.Context(), orgID, authbasicapi.LoginJSONRequestBody{ Username: basicAuthUser, Password: basicAuthPassword, diff --git a/test/suites/security/cors_test.go b/test/suites/security/cors_test.go index c16e6fd..54b5f87 100644 --- a/test/suites/security/cors_test.go +++ b/test/suites/security/cors_test.go @@ -15,7 +15,7 @@ import ( func TestCORS_admin(t *testing.T) { t.Run("Non-browser request", func(t *testing.T) { t.Parallel() - client := adminResponsesTLSClient(t) + client := lib.AdminResponsesTLSClient(t, certDir) resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ @@ -31,7 +31,7 @@ func TestCORS_admin(t *testing.T) { t.Run("Browser request, valid Origin", func(t *testing.T) { t.Parallel() - client := adminResponsesTLSClient(t) + client := lib.AdminResponsesTLSClient(t, certDir) resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ @@ -51,7 +51,7 @@ func TestCORS_admin(t *testing.T) { t.Run("Browser request, invalid Origin", func(t *testing.T) { t.Parallel() - client := adminResponsesTLSClient(t) + client := lib.AdminResponsesTLSClient(t, certDir) resp, err := client.LoginSuperuser( t.Context(), adminapi.LoginSuperuserJSONRequestBody{ @@ -72,7 +72,7 @@ func TestCORS_admin(t *testing.T) { func TestCORS_basicauth(t *testing.T) { t.Run("Browser request - denied", func(t *testing.T) { t.Parallel() - client := basicAuthResponsesTLSClient(t) + client := lib.BasicAuthResponsesTLSClient(t, certDir) resp, err := client.Login(t.Context(), orgID, authbasicapi.LoginJSONRequestBody{ Username: basicAuthUser, Password: basicAuthPassword, @@ -87,7 +87,7 @@ func TestCORS_basicauth(t *testing.T) { t.Run("Non-browser request - accepted", func(t *testing.T) { t.Parallel() - client := basicAuthResponsesTLSClient(t) + client := lib.BasicAuthResponsesTLSClient(t, certDir) resp, err := client.Login(t.Context(), orgID, authbasicapi.LoginJSONRequestBody{ Username: basicAuthUser, Password: basicAuthPassword, diff --git a/test/suites/security/main_test.go b/test/suites/security/main_test.go index a9c1f42..b695ae3 100644 --- a/test/suites/security/main_test.go +++ b/test/suites/security/main_test.go @@ -17,7 +17,7 @@ import ( func TestMain(m *testing.M) { println("Running TestMain, setting up test foundation...") - pool, err := getCAPool() + pool, err := lib.GetCAPool(certDir) if err != nil { panic(err) } diff --git a/test/suites/security/tls_clients.go b/test/suites/security/tls_clients.go deleted file mode 100644 index 4a15961..0000000 --- a/test/suites/security/tls_clients.go +++ /dev/null @@ -1,34 +0,0 @@ -package security - -import ( - "crypto/x509" - "net/http" - "testing" - - adminapi "github.com/trebent/kerberos/test/client/admin" - authbasicapi "github.com/trebent/kerberos/test/client/auth/basic" - lib "github.com/trebent/kerberos/test/lib" -) - -func adminResponsesTLSClient(t *testing.T) *adminapi.ClientWithResponses { - t.Helper() - return lib.AdminResponsesTLSClient(t, certDir) -} - -func basicAuthResponsesTLSClient(t *testing.T) *authbasicapi.ClientWithResponses { - t.Helper() - return lib.BasicAuthResponsesTLSClient(t, certDir) -} - -func tlsClient(t *testing.T) *http.Client { - t.Helper() - return lib.TLSClient(t, certDir) -} - -func plainClient() *http.Client { - return lib.PlainClient() -} - -func getCAPool() (*x509.CertPool, error) { - return lib.GetCAPool(certDir) -} From 9fa383efef871455734a273b705fe2f69f3fecf9 Mon Sep 17 00:00:00 2001 From: maansaake Date: Sun, 23 Aug 2026 09:51:46 +0200 Subject: [PATCH 7/7] bump go --- test/suites/go.mod | 2 +- tools/go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/suites/go.mod b/test/suites/go.mod index 53d95da..f28f81d 100644 --- a/test/suites/go.mod +++ b/test/suites/go.mod @@ -1,6 +1,6 @@ module github.com/trebent/kerberos/test -go 1.26.5 +go 1.26.6 require ( github.com/jaegertracing/jaeger-idl v0.9.0 diff --git a/tools/go.mod b/tools/go.mod index bcceb23..954fd46 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,6 +1,6 @@ module github.com/trebent/kerberos/tools -go 1.26.5 +go 1.26.6 tool golang.org/x/vuln/cmd/govulncheck