From cbff8d4f6ad1787e91fae0565a1f80069c5ab89b Mon Sep 17 00:00:00 2001 From: aniket866 Date: Tue, 30 Jun 2026 00:54:58 +0530 Subject: [PATCH 1/2] fix : Automatic-OIDC-Access-Token Signed-off-by: aniket866 --- pkg/connectors/microcks_client_test.go | 167 +++++++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/pkg/connectors/microcks_client_test.go b/pkg/connectors/microcks_client_test.go index 2fe423e7..cf3f168e 100644 --- a/pkg/connectors/microcks_client_test.go +++ b/pkg/connectors/microcks_client_test.go @@ -1,13 +1,20 @@ package connectors import ( + "encoding/base64" + "encoding/json" + "fmt" "io" "net/http" "net/http/httptest" + "net/url" "os" "path/filepath" "strings" "testing" + "time" + + "github.com/microcks/microcks-cli/pkg/config" ) func TestUploadArtifactStreamsWithoutBuffering(t *testing.T) { @@ -102,3 +109,163 @@ func TestDownloadArtifactReturnsResponseBody(t *testing.T) { t.Fatalf("expected response body %q, got %q", expectedBody, msg) } } + +func createDummyJWT(exp int64) string { + header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"none","typ":"JWT"}`)) + payload := base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"exp":%d}`, exp))) + return header + "." + payload + "." +} + +func TestRefreshAuthToken_ValidTokenNoRefresh(t *testing.T) { + // A token with expiration 1 hour in the future + futureTime := time.Now().Add(1 * time.Hour).Unix() + dummyToken := createDummyJWT(futureTime) + + // Setup local config + localCfg := &config.LocalConfig{ + CurrentContext: "test-context", + Contexts: []config.ContextRef{ + {Name: "test-context", Server: "localhost", User: "test-user"}, + }, + Servers: []config.Server{ + {Name: "localhost", Server: "localhost"}, + }, + Users: []config.User{ + {Name: "test-user", AuthToken: dummyToken, RefreshToken: "some-refresh-token"}, + }, + } + + mc := µcksClient{ + AuthToken: dummyToken, + RefreshToken: "some-refresh-token", + } + + // Calling refreshAuthToken with a valid token should do nothing and return nil + err := mc.refreshAuthToken(localCfg, "test-context", "") + if err != nil { + t.Fatalf("refreshAuthToken failed: %v", err) + } + + // Verify token was not modified + if mc.AuthToken != dummyToken { + t.Errorf("expected AuthToken to remain %q, got %q", dummyToken, mc.AuthToken) + } +} + +func TestRefreshAuthToken_ExpiredTokenTriggersRefresh(t *testing.T) { + // A token with expiration 1 hour in the past + pastTime := time.Now().Add(-1 * time.Hour).Unix() + expiredToken := createDummyJWT(pastTime) + + // We need a temporary config file path since the function calls WriteLocalConfig + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "config.yaml") + + // Setup local config. Note: refreshAuthToken uses the context name ("test-context") + // as the name of the user to upsert, so we name the user "test-context" to match. + localCfg := &config.LocalConfig{ + CurrentContext: "test-context", + Contexts: []config.ContextRef{ + {Name: "test-context", Server: "http://localhost", User: "test-context"}, + }, + Servers: []config.Server{ + {Server: "http://localhost"}, + }, + Users: []config.User{ + {Name: "test-context", AuthToken: expiredToken, RefreshToken: "old-refresh-token"}, + }, + Auths: []config.Auth{ + {Server: "http://localhost", ClientId: "cli", ClientSecret: "secret"}, + }, + } + + // Write initial localconfig to the temp file + if err := config.WriteLocalConfig(*localCfg, configPath); err != nil { + t.Fatalf("failed to write local config: %v", err) + } + + // Spin up mock server handling Microcks client / Keycloak routes + var mockServer *httptest.Server + mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + switch r.URL.Path { + case "/api/keycloak/config": + // Return keycloak config pointing to this mock server + resp := map[string]interface{}{ + "enabled": true, + "auth-server-url": mockServer.URL, + "realm": "microcks", + } + json.NewEncoder(w).Encode(resp) + case "/realms/microcks/.well-known/openid-configuration": + // Return OIDC metadata pointing to token endpoint on mock server + resp := map[string]string{ + "authorization_endpoint": mockServer.URL + "/realms/microcks/protocol/openid-connect/auth", + "token_endpoint": mockServer.URL + "/realms/microcks/protocol/openid-connect/token", + } + json.NewEncoder(w).Encode(resp) + case "/realms/microcks/protocol/openid-connect/token": + // Verify request body for refresh token grant + if err := r.ParseForm(); err != nil { + t.Fatalf("failed to parse form: %v", err) + } + if r.FormValue("grant_type") != "refresh_token" { + t.Errorf("unexpected grant_type: %q", r.FormValue("grant_type")) + } + if r.FormValue("refresh_token") != "old-refresh-token" { + t.Errorf("unexpected refresh_token: %q", r.FormValue("refresh_token")) + } + + // Return new tokens + resp := map[string]string{ + "access_token": "new-access-token", + "refresh_token": "new-refresh-token", + } + json.NewEncoder(w).Encode(resp) + default: + t.Fatalf("unexpected request to: %s", r.URL.Path) + } + })) + defer mockServer.Close() + + apiURL, err := url.Parse(mockServer.URL + "/api/") + if err != nil { + t.Fatalf("failed to parse URL: %v", err) + } + + mc := µcksClient{ + APIURL: apiURL, + AuthToken: expiredToken, + RefreshToken: "old-refresh-token", + httpClient: mockServer.Client(), + } + + err = mc.refreshAuthToken(localCfg, "test-context", configPath) + if err != nil { + t.Fatalf("refreshAuthToken failed: %v", err) + } + + // Verify client tokens were updated + if mc.AuthToken != "new-access-token" { + t.Errorf("expected AuthToken to be refreshed to %q, got %q", "new-access-token", mc.AuthToken) + } + if mc.RefreshToken != "new-refresh-token" { + t.Errorf("expected RefreshToken to be refreshed to %q, got %q", "new-refresh-token", mc.RefreshToken) + } + + // Verify local config was updated and written back to file + updatedCfg, err := config.ReadLocalConfig(configPath) + if err != nil { + t.Fatalf("failed to read back config: %v", err) + } + user, err := updatedCfg.GetUser("test-context") + if err != nil { + t.Fatalf("failed to get user: %v", err) + } + if user.AuthToken != "new-access-token" { + t.Errorf("expected config AuthToken to be %q, got %q", "new-access-token", user.AuthToken) + } + if user.RefreshToken != "new-refresh-token" { + t.Errorf("expected config RefreshToken to be %q, got %q", "new-refresh-token", user.RefreshToken) + } +} From c515d3449949050152b3984f0322c0303e8455c0 Mon Sep 17 00:00:00 2001 From: aniket866 Date: Mon, 5 Oct 2026 02:09:17 +0530 Subject: [PATCH 2/2] fix: resolve nil context in token refresh and restore master test suite Signed-off-by: aniket866 --- pkg/connectors/keycloak_client.go | 13 +- pkg/connectors/microcks_client.go | 21 +- pkg/connectors/microcks_client_test.go | 338 ++++++++++++++++++++++++- 3 files changed, 361 insertions(+), 11 deletions(-) diff --git a/pkg/connectors/keycloak_client.go b/pkg/connectors/keycloak_client.go index 825da662..4cb2eb65 100644 --- a/pkg/connectors/keycloak_client.go +++ b/pkg/connectors/keycloak_client.go @@ -79,12 +79,19 @@ func NewKeycloakClientWithContext(ctx context.Context, realmURL string, username return &kc, nil } +func (c *keycloakClient) context() context.Context { + if c.ctx != nil { + return c.ctx + } + return context.Background() +} + // ConnectAndGetToken implementation on keycloakClient structure func (c *keycloakClient) ConnectAndGetToken() (string, error) { rel := &url.URL{Path: "protocol/openid-connect/token"} u := c.BaseURL.ResolveReference(rel) - req, err := http.NewRequestWithContext(c.ctx, "POST", u.String(), strings.NewReader(url.Values{"grant_type": {"client_credentials"}}.Encode())) + req, err := http.NewRequestWithContext(c.context(), "POST", u.String(), strings.NewReader(url.Values{"grant_type": {"client_credentials"}}.Encode())) if err != nil { return "", err } @@ -132,7 +139,7 @@ func (c *keycloakClient) GetOIDCConfig() (*oauth2.Config, error) { u := c.BaseURL.ResolveReference(rel) // Create HTTP request - req, err := http.NewRequestWithContext(c.ctx, "GET", u.String(), nil) + req, err := http.NewRequestWithContext(c.context(), "GET", u.String(), nil) if err != nil { return nil, errors.Wrap(errors.KindGeneric, fmt.Errorf("creating Keycloak OIDC request: %w", err)) } @@ -186,7 +193,7 @@ func (c *keycloakClient) ConnectAndGetTokenAndRefreshToken(username, password st data.Set("password", password) data.Set("grant_type", "password") // Create HTTP request - req, err := http.NewRequestWithContext(c.ctx, "POST", u.String(), bytes.NewBufferString(data.Encode())) + req, err := http.NewRequestWithContext(c.context(), "POST", u.String(), bytes.NewBufferString(data.Encode())) if err != nil { return "", "", errors.Wrap(errors.KindGeneric, fmt.Errorf("creating Keycloak token request: %w", err)) } diff --git a/pkg/connectors/microcks_client.go b/pkg/connectors/microcks_client.go index 3e121ae0..f59d8281 100644 --- a/pkg/connectors/microcks_client.go +++ b/pkg/connectors/microcks_client.go @@ -285,12 +285,19 @@ func (c *microcksClient) HttpClient() *http.Client { return c.httpClient } +func (c *microcksClient) context() context.Context { + if c.ctx != nil { + return c.ctx + } + return context.Background() +} + func (c *microcksClient) GetKeycloakURL() (string, error) { // Ensure we have a correct URL for retrieving Keycloal configuration. rel := &url.URL{Path: "keycloak/config"} u := c.APIURL.ResolveReference(rel) - req, err := http.NewRequestWithContext(c.ctx, "GET", u.String(), nil) + req, err := http.NewRequestWithContext(c.context(), "GET", u.String(), nil) if err != nil { return "", errors.Wrap(errors.KindGeneric, fmt.Errorf("creating Keycloak config request: %w", err)) } @@ -391,7 +398,7 @@ func (c *microcksClient) redeemRefreshToken(auth config.Auth) (string, string, e if err != nil { return "", "", err } - kc, err := NewKeycloakClientWithContext(c.ctx, keyCloakUrl, "", "") + kc, err := NewKeycloakClientWithContext(c.context(), keyCloakUrl, "", "") if err != nil { return "", "", err } @@ -403,7 +410,7 @@ func (c *microcksClient) redeemRefreshToken(auth config.Auth) (string, string, e oauth2Conf.ClientSecret = auth.ClientSecret httpClient := c.httpClient - ctx := oidc.ClientContext(c.ctx, httpClient) + ctx := oidc.ClientContext(c.context(), httpClient) t := &oauth2.Token{ RefreshToken: c.RefreshToken, @@ -493,7 +500,7 @@ func (c *microcksClient) getJSON(path string, query url.Values, out any, dumpLab } u := c.APIURL.ResolveReference(rel) - req, err := http.NewRequestWithContext(c.ctx, "GET", u.String(), nil) + req, err := http.NewRequestWithContext(c.context(), "GET", u.String(), nil) if err != nil { return err } @@ -568,7 +575,7 @@ func (c *microcksClient) CreateTestResult(serviceID string, testEndpoint string, return "", errors.Wrap(errors.KindGeneric, fmt.Errorf("failed to marshal test request: %w", err)) } - req, err := http.NewRequestWithContext(c.ctx, "POST", u.String(), bytes.NewReader(input)) + req, err := http.NewRequestWithContext(c.context(), "POST", u.String(), bytes.NewReader(input)) if err != nil { return "", errors.Wrap(errors.KindGeneric, fmt.Errorf("creating test request: %w", err)) } @@ -673,7 +680,7 @@ func (c *microcksClient) UploadArtifact(specificationFilePath string, mainArtifa rel := &url.URL{Path: "artifact/upload"} u := c.APIURL.ResolveReference(rel) - req, err := http.NewRequestWithContext(c.ctx, "POST", u.String(), pr) + req, err := http.NewRequestWithContext(c.context(), "POST", u.String(), pr) if err != nil { return "", errors.Wrap(errors.KindGeneric, fmt.Errorf("creating artifact upload request: %w", err)) } @@ -741,7 +748,7 @@ func (c *microcksClient) DownloadArtifact(artifactURL string, mainArtifact bool, rel := &url.URL{Path: "artifact/download"} u := c.APIURL.ResolveReference(rel) - req, err := http.NewRequestWithContext(c.ctx, "POST", u.String(), body) + req, err := http.NewRequestWithContext(c.context(), "POST", u.String(), body) if err != nil { return "", errors.Wrap(errors.KindGeneric, fmt.Errorf("creating artifact download request: %w", err)) } diff --git a/pkg/connectors/microcks_client_test.go b/pkg/connectors/microcks_client_test.go index 2d95ade4..9b491f9c 100644 --- a/pkg/connectors/microcks_client_test.go +++ b/pkg/connectors/microcks_client_test.go @@ -17,6 +17,7 @@ package connectors import ( + "context" "encoding/base64" "encoding/json" "fmt" @@ -31,6 +32,7 @@ import ( "time" "github.com/microcks/microcks-cli/pkg/config" + microckserrors "github.com/microcks/microcks-cli/pkg/errors" ) func TestUploadArtifact(t *testing.T) { @@ -140,6 +142,338 @@ func TestDownloadArtifactReturnsResponseBody(t *testing.T) { } } +func TestGetKeycloakURLRejectsMalformedConfig(t *testing.T) { + tests := []struct { + name string + body string + want string + }{ + { + name: "missing enabled", + body: `{"auth-server-url":"http://keycloak","realm":"microcks"}`, + want: "enabled", + }, + { + name: "invalid auth server url", + body: `{"enabled":true,"auth-server-url":42,"realm":"microcks"}`, + want: "auth-server-url", + }, + { + name: "invalid realm", + body: `{"enabled":true,"auth-server-url":"http://keycloak","realm":42}`, + want: "realm", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/keycloak/config" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + w.Header().Set("Content-Type", "application/json") + if _, err := w.Write([]byte(tt.body)); err != nil { + t.Fatalf("failed to write response: %v", err) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + + _, err = client.GetKeycloakURL() + if err == nil { + t.Fatal("GetKeycloakURL returned nil error") + } + if got := microckserrors.KindOf(err); got != microckserrors.KindAPI { + t.Fatalf("KindOf = %v, want %v", got, microckserrors.KindAPI) + } + if !strings.Contains(err.Error(), tt.want) { + t.Fatalf("error %q does not mention %q", err.Error(), tt.want) + } + }) + } +} + +func TestCreateTestResultClassifiesMalformedResponses(t *testing.T) { + tests := []struct { + name string + body string + want string + }{ + {name: "invalid json", body: `not-json`, want: "parse test creation response"}, + {name: "missing id", body: `{}`, want: "missing 'id'"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/tests" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + w.WriteHeader(http.StatusCreated) + if _, err := w.Write([]byte(tt.body)); err != nil { + t.Fatalf("failed to write response: %v", err) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + + _, err = client.CreateTestResult("service:1.0", "http://example.test", "OPEN_API_SCHEMA", "", 1000, "", "", "") + if err == nil { + t.Fatal("CreateTestResult returned nil error") + } + if got := microckserrors.KindOf(err); got != microckserrors.KindAPI { + t.Fatalf("KindOf = %v, want %v", got, microckserrors.KindAPI) + } + if !strings.Contains(err.Error(), tt.want) { + t.Fatalf("error %q does not mention %q", err.Error(), tt.want) + } + }) + } +} + +func TestCreateTestResultRejectsInvalidFilteredOperations(t *testing.T) { + client, err := NewMicrocksClient("http://localhost:8585") + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + + _, err = client.CreateTestResult("service:1.0", "http://example.test", "OPEN_API_SCHEMA", "", 1000, "{", "", "") + if err == nil { + t.Fatal("CreateTestResult returned nil error") + } + if got := microckserrors.KindOf(err); got != microckserrors.KindUsage { + t.Fatalf("KindOf = %v, want %v", got, microckserrors.KindUsage) + } +} + +func TestGetFullTestResultChecksStatusBeforeParsing(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/tests/missing" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + w.WriteHeader(http.StatusNotFound) + if _, err := w.Write([]byte("missing test result")); err != nil { + t.Fatalf("failed to write response: %v", err) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + + _, err = client.GetFullTestResult("missing") + if err == nil { + t.Fatal("GetFullTestResult returned nil error") + } + if got := microckserrors.KindOf(err); got != microckserrors.KindNotFound { + t.Fatalf("KindOf = %v, want %v", got, microckserrors.KindNotFound) + } + if !strings.Contains(err.Error(), "HTTP 404") { + t.Fatalf("error %q does not mention HTTP 404", err.Error()) + } +} + +func TestListServicesFetchesServicesEndpoint(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/services" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + if got := r.URL.Query().Get("page"); got != "1" { + t.Fatalf("unexpected page: %s", got) + } + if got := r.URL.Query().Get("size"); got != "25" { + t.Fatalf("unexpected size: %s", got) + } + if err := json.NewEncoder(w).Encode([]Service{{ + ID: "svc-1", + Name: "Catalog API", + Version: "1.0.0", + Type: "REST", + }}); err != nil { + t.Fatalf("failed to encode services response: %v", err) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + services, err := client.ListServices(1, 25) + if err != nil { + t.Fatalf("ListServices returned error: %v", err) + } + if len(services) != 1 || services[0].ID != "svc-1" { + t.Fatalf("unexpected services: %#v", services) + } +} + +func TestGetServiceResolvesNameVersionReference(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api/services": + if err := json.NewEncoder(w).Encode([]Service{{ + ID: "svc-1", + Name: "Catalog API", + Version: "1.0.0", + Type: "REST", + }}); err != nil { + t.Fatalf("failed to encode services response: %v", err) + } + case "/api/services/svc-1": + if err := json.NewEncoder(w).Encode(ServiceDetail{ + Service: Service{ + ID: "svc-1", + Name: "Catalog API", + Version: "1.0.0", + Type: "REST", + }, + }); err != nil { + t.Fatalf("failed to encode service detail response: %v", err) + } + default: + t.Fatalf("unexpected path: %s", r.URL.Path) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + detail, err := client.GetService("Catalog API:1.0.0") + if err != nil { + t.Fatalf("GetService returned error: %v", err) + } + if detail.Service.ID != "svc-1" { + t.Fatalf("unexpected service detail: %#v", detail) + } +} + +func TestGetServiceResolvesNameVersionAcrossPages(t *testing.T) { + firstPage := make([]Service, serviceLookupPageSize) + for i := range firstPage { + firstPage[i] = Service{ + ID: "filler", + Name: "Other API", + Version: "1.0.0", + Type: "REST", + } + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api/services": + if got := r.URL.Query().Get("size"); got != "100" { + t.Fatalf("unexpected size: %s", got) + } + switch r.URL.Query().Get("page") { + case "0": + if err := json.NewEncoder(w).Encode(firstPage); err != nil { + t.Fatalf("failed to encode first page response: %v", err) + } + case "1": + if err := json.NewEncoder(w).Encode([]Service{{ + ID: "svc-2", + Name: "Catalog API", + Version: "1.0.0", + Type: "REST", + }}); err != nil { + t.Fatalf("failed to encode second page response: %v", err) + } + default: + t.Fatalf("unexpected page: %s", r.URL.Query().Get("page")) + } + case "/api/services/svc-2": + if err := json.NewEncoder(w).Encode(ServiceDetail{ + Service: Service{ + ID: "svc-2", + Name: "Catalog API", + Version: "1.0.0", + Type: "REST", + }, + }); err != nil { + t.Fatalf("failed to encode service detail response: %v", err) + } + default: + t.Fatalf("unexpected path: %s", r.URL.Path) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + detail, err := client.GetService("Catalog API:1.0.0") + if err != nil { + t.Fatalf("GetService returned error: %v", err) + } + if detail.Service.ID != "svc-2" { + t.Fatalf("unexpected service detail: %#v", detail) + } +} + +func TestListTestResultsFetchesTestsEndpoint(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/api/tests" { + t.Fatalf("unexpected path: %s", r.URL.Path) + } + if got := r.URL.Query().Get("serviceId"); got != "svc-1" { + t.Fatalf("unexpected serviceId: %s", got) + } + if err := json.NewEncoder(w).Encode([]TestResultSummary{{ + ID: "test-1", + ServiceID: "svc-1", + Success: true, + }}); err != nil { + t.Fatalf("failed to encode test results response: %v", err) + } + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + results, err := client.ListTestResults("svc-1", 0, 50) + if err != nil { + t.Fatalf("ListTestResults returned error: %v", err) + } + if len(results) != 1 || results[0].ID != "test-1" { + t.Fatalf("unexpected test results: %#v", results) + } +} + +func TestGetFullTestResultClassifiesNotFound(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "missing", http.StatusNotFound) + })) + defer server.Close() + + client, err := NewMicrocksClient(server.URL) + if err != nil { + t.Fatalf("NewMicrocksClient returned error: %v", err) + } + _, err = client.GetFullTestResult("missing") + if err == nil { + t.Fatal("expected error, got nil") + } + if got := microckserrors.KindOf(err); got != microckserrors.KindNotFound { + t.Fatalf("KindOf = %v, want KindNotFound", got) + } +} + func createDummyJWT(exp int64) string { header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"none","typ":"JWT"}`)) payload := base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"exp":%d}`, exp))) @@ -166,6 +500,7 @@ func TestRefreshAuthToken_ValidTokenNoRefresh(t *testing.T) { } mc := µcksClient{ + ctx: context.Background(), AuthToken: dummyToken, RefreshToken: "some-refresh-token", } @@ -245,7 +580,7 @@ func TestRefreshAuthToken_ExpiredTokenTriggersRefresh(t *testing.T) { if r.FormValue("refresh_token") != "old-refresh-token" { t.Errorf("unexpected refresh_token: %q", r.FormValue("refresh_token")) } - + // Return new tokens resp := map[string]string{ "access_token": "new-access-token", @@ -264,6 +599,7 @@ func TestRefreshAuthToken_ExpiredTokenTriggersRefresh(t *testing.T) { } mc := µcksClient{ + ctx: context.Background(), APIURL: apiURL, AuthToken: expiredToken, RefreshToken: "old-refresh-token",