Skip to content

Add integration tests for secrets#1601

Merged
Krishanx92 merged 2 commits intowso2:mainfrom
RakhithaRR:secret-tests
Mar 31, 2026
Merged

Add integration tests for secrets#1601
Krishanx92 merged 2 commits intowso2:mainfrom
RakhithaRR:secret-tests

Conversation

@RakhithaRR
Copy link
Copy Markdown
Contributor

@RakhithaRR RakhithaRR commented Mar 31, 2026

Purpose

This PR adds integration tests for Secret operations and LLM Provider flows that involve secrets.

Summary by CodeRabbit

  • Tests
    • Added end-to-end integration tests for secret management (create, read, update, delete, list), covering success paths, validation errors, duplicate/conflict behavior, and idempotent deletes.
    • Added test steps and scenario registration to drive the new secret scenarios and included provider integration cases that reference secrets.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Warning

Rate limit exceeded

@RakhithaRR has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 40 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 40 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1745d3e6-26e4-4284-8dd8-788f73369a81

📥 Commits

Reviewing files that changed from the base of the PR and between de81fb6 and 9564d1f.

📒 Files selected for processing (2)
  • gateway/it/features/secrets.feature
  • gateway/it/steps_secrets.go

Walkthrough

Adds end-to-end secret management tests: a new Gherkin feature exercising secret CRUD, validation, and LlmProvider secret references, plus Go step definitions implementing HTTP interactions and test-suite registration for those steps.

Changes

Cohort / File(s) Summary
Feature Spec
gateway/it/features/secrets.feature
New Gherkin scenarios covering secret create/read/update/delete, error cases (400/404/409), special/long values, list behavior, and LlmProvider flows that reference secrets.
Step Implementations
gateway/it/steps_secrets.go
New SecretSteps with HTTP-backed step bindings for secrets endpoints (POST /secrets, GET /secrets/{name}, PUT /secrets/{name}, DELETE /secrets/{name}), local scenario state tracking (lastSecret), JSON parsing of responses, and TestState store/use handlers.
Test Suite Integration
gateway/it/suite_test.go
Included features/secrets.feature in feature paths and registered RegisterSecretSteps during scenario initialization.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Test as Test Runner
participant Gateway as Gateway Controller
participant Upstream as Upstream LLM
Note over Test,Gateway: Secret creation and provider setup
Test->>Gateway: POST /secrets (create secret)
Gateway-->>Test: 201 Created (secret metadata)
Test->>Gateway: POST /llm/providers (create provider referencing $secret{...})
Gateway-->>Test: 201 Created (provider metadata)
Note over Test,Upstream: Request using provider authorization resolved from secret
Test->>Gateway: POST /v1/chat/completions (uses provider)
Gateway->>Upstream: Forward request with Authorization (secret value)
Upstream-->>Gateway: 200 (chat completion)
Gateway-->>Test: 200 (chat.completion response)
Note over Test,Gateway: Cleanup
Test->>Gateway: DELETE /llm/providers/{id}
Gateway-->>Test: 200
Test->>Gateway: DELETE /secrets/{name}
Gateway-->>Test: 200

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped in to test each secret and key,
tiny JSON burrows, safe as can be.
I stitched provider headers with a twitch of my paw,
made chatbots speak true with the secret they saw.
Delete, recreate — then dance! 🥕🔐

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only provides the Purpose section from the template while missing critical sections like Goals, Approach, User stories, Documentation, Automation tests, Security checks, and Test environment. Complete the PR description by adding Goals (what solutions are introduced), Approach (how tests are implemented), Automation tests section (detailing test coverage), and other required template sections.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding integration tests for secrets, which matches the primary content of all three modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
gateway/it/suite_test.go (1)

328-328: Missing secretSteps.Reset() call in the Before hook may cause state leakage between scenarios.

Unlike httpSteps and jwtSteps which are global variables with Reset() called in the Before hook (lines 286-291), the secretSteps instance is created locally within RegisterSecretSteps and is not accessible for reset. This means lastSecret state may persist across scenarios, potentially causing test flakiness.

Consider either:

  1. Making secretSteps a package-level variable (like jwtSteps) so it can be reset in the Before hook, or
  2. Having RegisterSecretSteps return the instance so it can be stored and reset.
Option 1: Add secretSteps as a package-level variable
 	// jwtSteps provides JWT authentication steps
 	jwtSteps *JWTSteps
+
+	// secretSteps provides secret management steps
+	secretSteps *SecretSteps

Then in InitializeTestSuite after line 227:

secretSteps = NewSecretSteps(testState, httpSteps)

Update the Before hook:

 		if jwtSteps != nil {
 			jwtSteps.Reset()
 		}
+		if secretSteps != nil {
+			secretSteps.Reset()
+		}

And modify RegisterSecretSteps to accept the pre-created instance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gateway/it/suite_test.go` at line 328, The tests leak secretSteps state
because RegisterSecretSteps constructs a local secretSteps whose lastSecret
isn't reset between scenarios; change to create a package-level secretSteps (or
have RegisterSecretSteps return the instance) so it can be reset in the Before
hook like jwtSteps/httpSteps. Concretely, instantiate secretSteps via
NewSecretSteps(testState, httpSteps) during InitializeTestSuite (or capture the
returned instance from RegisterSecretSteps) and add secretSteps.Reset() in the
Before hook alongside jwtSteps.Reset()/httpSteps.Reset(); update
RegisterSecretSteps signature to accept or return the secretSteps instance
accordingly so lastSecret is cleared each scenario.
gateway/it/features/secrets.feature (1)

346-348: Scenario title is misleading: returning 404 for non-existent resource is not idempotent behavior.

The title says "Delete secret is idempotent" but the expectation is 404 for a non-existent secret. True idempotent delete operations typically return success (200/204) regardless of whether the resource exists. Consider renaming the scenario to better reflect what's being tested:

-  Scenario: Delete secret is idempotent - deleting non-existent secret returns 404
+  Scenario: Delete non-existent secret returns 404
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gateway/it/features/secrets.feature` around lines 346 - 348, The scenario
title is misleading: it claims idempotency but asserts a 404 for a missing
secret; update the Scenario line that currently reads "Delete secret is
idempotent - deleting non-existent secret returns 404" to a clear title such as
"Delete non-existent secret returns 404" (or similar) so the title matches the
expectation in the steps ("When I delete the secret
\"non-existent-secret-99999\"" / "Then the response status should be 404").
gateway/it/steps_secrets.go (1)

89-101: Silent error swallowing on JSON unmarshal could mask API response format changes.

If the API response structure changes or the unmarshal fails for other reasons, the error is silently ignored and lastSecret won't be updated. This could lead to confusing test failures later when storeSecretName is called.

Consider logging or returning the error:

Suggested improvement
 	if s.httpSteps.LastResponse().StatusCode == 201 {
 		var response struct {
 			Secret struct {
 				Metadata struct {
 					Name string `json:"name"`
 				} `json:"metadata"`
 			} `json:"secret"`
 		}
-		if err := json.Unmarshal(s.httpSteps.LastBody(), &response); err == nil {
+		if err := json.Unmarshal(s.httpSteps.LastBody(), &response); err != nil {
+			return fmt.Errorf("failed to parse secret response: %w", err)
+		}
+		if response.Secret.Metadata.Name != "" {
 			s.lastSecret.name = response.Secret.Metadata.Name
 			s.lastSecret.exists = true
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gateway/it/steps_secrets.go` around lines 89 - 101, The JSON unmarshal error
is currently ignored which can hide API changes and leave s.lastSecret unset;
update the block around s.httpSteps.LastResponse(), s.httpSteps.LastBody() and
the json.Unmarshal call so that if json.Unmarshal returns a non-nil err you
surface it (e.g., call t.Fatalf / s.t.Fatalf or s.logger.Errorf and fail the
test) instead of swallowing it, and include the error and raw response body in
the log/failure message so callers of storeSecretName can reliably rely on
s.lastSecret being set when a 201 response is returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@gateway/it/features/secrets.feature`:
- Around line 392-399: The cleanup misses deleting the secret "upstream-secret"
created earlier; update the scenario to delete that secret as part of teardown
by adding a step to authenticate (if needed) and call the secret-deletion step
(e.g., the same step pattern used for LLM provider deletion: "When I delete the
secret \"upstream-secret\"") after the provider deletion so the secret is
removed and won't pollute subsequent runs.

In `@gateway/it/steps_secrets.go`:
- Around line 159-171: The updateSecretWithValue function currently builds JSON
via fmt.Sprintf which allows injection (same issue as createSecretWithValue);
replace the manual sprintf JSON construction in updateSecretWithValue by
constructing a Go struct or map with fields apiVersion, kind, metadata (name),
spec (displayName, description, value) and then use json.Marshal to produce the
payload so values are properly escaped; mirror the same fix applied to
createSecretWithValue and update any variables referencing the old config string
to use the marshaled bytes.
- Around line 106-118: createSecretWithValue currently constructs JSON via
fmt.Sprintf which allows JSON injection/malformed output when name or value
contain quotes, backslashes, or newlines; change it to build a Go struct
(matching apiVersion, kind, metadata.name, spec.displayName, spec.description,
spec.value) or map[string]interface{} populated with the name and value, then
call json.Marshal to produce the request body string; replace the fmt.Sprintf
usage in createSecretWithValue with the marshaled JSON (handle/maybe return
marshal errors) so values are properly escaped.
- Around line 184-188: Change the status check in the test helper from 204 to
200 so the test updates secret state correctly: in the block that inspects
s.httpSteps.LastResponse().StatusCode, replace the 204 check with 200 (so when
DeleteSecret returns http.StatusOK the code sets s.lastSecret.exists = false for
the matching s.lastSecret.name). This aligns the test helper with the
DeleteSecret handler and feature expectations.

---

Nitpick comments:
In `@gateway/it/features/secrets.feature`:
- Around line 346-348: The scenario title is misleading: it claims idempotency
but asserts a 404 for a missing secret; update the Scenario line that currently
reads "Delete secret is idempotent - deleting non-existent secret returns 404"
to a clear title such as "Delete non-existent secret returns 404" (or similar)
so the title matches the expectation in the steps ("When I delete the secret
\"non-existent-secret-99999\"" / "Then the response status should be 404").

In `@gateway/it/steps_secrets.go`:
- Around line 89-101: The JSON unmarshal error is currently ignored which can
hide API changes and leave s.lastSecret unset; update the block around
s.httpSteps.LastResponse(), s.httpSteps.LastBody() and the json.Unmarshal call
so that if json.Unmarshal returns a non-nil err you surface it (e.g., call
t.Fatalf / s.t.Fatalf or s.logger.Errorf and fail the test) instead of
swallowing it, and include the error and raw response body in the log/failure
message so callers of storeSecretName can reliably rely on s.lastSecret being
set when a 201 response is returned.

In `@gateway/it/suite_test.go`:
- Line 328: The tests leak secretSteps state because RegisterSecretSteps
constructs a local secretSteps whose lastSecret isn't reset between scenarios;
change to create a package-level secretSteps (or have RegisterSecretSteps return
the instance) so it can be reset in the Before hook like jwtSteps/httpSteps.
Concretely, instantiate secretSteps via NewSecretSteps(testState, httpSteps)
during InitializeTestSuite (or capture the returned instance from
RegisterSecretSteps) and add secretSteps.Reset() in the Before hook alongside
jwtSteps.Reset()/httpSteps.Reset(); update RegisterSecretSteps signature to
accept or return the secretSteps instance accordingly so lastSecret is cleared
each scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b81c986-feb3-4355-8795-b4a90a2e315d

📥 Commits

Reviewing files that changed from the base of the PR and between 8683419 and 4747707.

📒 Files selected for processing (3)
  • gateway/it/features/secrets.feature
  • gateway/it/steps_secrets.go
  • gateway/it/suite_test.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@gateway/it/steps_secrets.go`:
- Around line 89-100: The JSON unmarshal error in the create-success branch is
being ignored; update the block that calls
json.Unmarshal(s.httpSteps.LastBody(), &response) to check the returned error
and treat it as a test/step failure (do not silently continue). If
json.Unmarshal returns an error, fail the step (e.g. return the error or call
the test failure helper) and include the raw LastBody() and the unmarshal error
in the failure message; only set s.lastSecret.name and s.lastSecret.exists =
true when unmarshal succeeds. Reference: s.httpSteps.LastResponse(),
s.httpSteps.LastBody(), json.Unmarshal, and s.lastSecret.
- Around line 57-78: RegisterSecretSteps reuses a single SecretSteps instance
across scenarios so lastSecret state persists; ensure SecretSteps.Reset() is
invoked before each scenario (add ctx.Before hook calling secretSteps.Reset() or
call secretSteps.Reset() from InitializeScenario) and update createSecret (and
createSecretWithValue) to handle json.Unmarshal errors properly by
returning/propagating the error or failing the step instead of silently ignoring
it so lastSecret.name is not left unset; update storeSecretName/deleteSecret
consumers to assume lastSecret is valid only after successful unmarshalling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22db5dc0-8691-4369-96ce-6e716cd81fb0

📥 Commits

Reviewing files that changed from the base of the PR and between 4747707 and de81fb6.

📒 Files selected for processing (2)
  • gateway/it/features/secrets.feature
  • gateway/it/steps_secrets.go
✅ Files skipped from review due to trivial changes (1)
  • gateway/it/features/secrets.feature

@Krishanx92 Krishanx92 merged commit 31cf1ac into wso2:main Mar 31, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants