Test: drive the RestApiTool suite through real operations and contexts - #750
Open
AmaadMartin wants to merge 3 commits into
Open
Test: drive the RestApiTool suite through real operations and contexts#750AmaadMartin wants to merge 3 commits into
AmaadMartin wants to merge 3 commits into
Conversation
added 3 commits
August 6, 2026 19:13
The RestApiTool suite proved its claims by replacing the private operationParser with literal parameter arrays and by passing empty object literals as the tool context. Neither reaches OperationParser, so the suite carried no signal about it: with processOperationParameters() emptied, all 26 tests still passed. Each test now declares a real OpenAPIV3.OperationObject and runs through the real parser, and a createToolContext() factory builds a real Context. The runAsync-level 'should fallback to JSON if no requestBody in spec' test is deleted: a body parameter exists only when the operation declares a requestBody with content, and in that case prepareRequestBody never takes the fallback branch. The module-level test of the same name already pins that branch directly, and its Content-Type assertion moves into 'should stringify object body'. The query-parameter test now asserts the exact URL. Its two toContain checks both passed with the path query-string merge removed, because the unmerged URL still contains both substrings.
…ApiTool suite The three auth tests replaced ToolAuthHandler with an object literal cast through unknown, and the setter test cast its security scheme and credential the same way. ToolAuthHandler's constructor is public, so each test now builds a real handler and stubs only prepareAuthCredentials. The security scheme is annotated (the identical literal is already uncast in 'should apply auth credentials to fetch request') and the credential carries its required authType. This removes the last five casts: the file is now at zero.
createToolContext() set three fields no test reads: LlmAgentConfig.model is optional and no test drives an LLM, and createSession already defaults userId and events. The two stub ToolAuthHandlers took an authScheme and an authCredential that no assertion can observe, because both tests replace prepareAuthCredentials, the only consumer of those private fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
N/A
Problem:
core/test/tools/openapi_tool/rest_api_tool_test.tsreached aroundRestApiToolwith 30as unknown ascasts. Eight tests replaced theprivate operationParserwith a literal parameter array, and 14 tests passed{}as the tool context. The suite therefore never ranOperationParserat all: withOperationParser.processOperationParameters()emptied, all 26 tests still passed. This is the guideline violation "Never WidenprivateSo a Test Can Reach It", plus the hard rule againstas unknown as.Solution: Every test now declares a real
OpenAPIV3.OperationObjectand drives the real parser, and acreateToolContext()factory builds a realContext. The three auth tests build a realToolAuthHandler(its constructor is public) and stub onlyprepareAuthCredentials. The cast count goes 30 -> 0, with noany, no@ts-expect-error, noeslint-disable, and noobj['privateField']access. No production file changes.Rewriting existing tests is the deliverable here. The usual rule is "add a new test, do not rewrite an existing one", which exists to protect regression signal. The mutation table below is the proof the signal got stronger, not weaker.
One test is deleted: the
runAsync-levelshould fallback to JSON if no requestBody in spec. It was reachable only by faking the parser. A body-locatedApiParameterexists only whenoperation.requestBodyis a non-$refobject with non-emptycontent(operation_parser.ts:74-90), and in exactly that caseprepareRequestBodytakes the'content' in requestBodybranch (rest_api_tool.ts:243), never theelse if (finalData !== undefined)fallback. The test pinned a state the real pipeline cannot produce. The identically named module-level test still pins that branch directly with no mocking, and the deleted test'sContent-Type: application/jsonassertion moved intoshould stringify object body.One assertion is strengthened, not weakened.
should extract query parameters from pathused twotoContainchecks. Both still passed with the path query-string merge removed, because the unmerged URL is...?existing=param?new_param=valueand still contains both substrings. The test now asserts the exact URL, which makes that mutation lethal. This corrects the plan's prediction that the mutation would dropexisting=param.Collision check:
gh pr list --repo AmaadMartin/adk-js --state open --limit 1000returns 640 open PRs. Five touch this file (#436, #463, #514, #578, #579); all are purely additive and none removes a cast (git diff main...<branch> -- <file> | grep -c '^-.*as unknown as'is 0 for each). The sibling clean-up ofopenapi_toolset_test.ts(#337, #645) is tracked separately and is not touched here.Testing Plan
Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
npx vitest run --project unit:core core/test/tools/openapi_tool/rest_api_tool_test.ts-> 25 passed (26 before, minus the deleted test).npx tsc --noEmit-> 0 errors whose path is this file, matching the baseline. The repo has 2186 pre-existing errors elsewhere; none is new.npx eslint <file>andnpx prettier --check <file>-> clean.Mutation proof. Each mutation was applied to
core/src/tools/openapi_tool/rest_api_tool.ts, the single test file was run, then the source was reverted withgit checkout. All twelve rewritten tests fail:configureCredentialKey-> no-opexpected "spy" to be called with arguments/ received"credentialKey": undefinedbody = argValue->body = undefined"body": undefined, "headers": {}url.replace"http://api.example.com/users/{id}"bodyData[originalName]write"body": undefinedheaders[originalName]->headers[param.name]"headers": {"trace_id": "trace-123"}, expectedtraceIdparameters: schema->parameters: {}expected { name: 'test_tool', …(2) } to deeply equal { name: 'test_tool', …(2) },parameters.properties.user_idmissing"http://api.example.com/test?existing=param?new_param=value"JSON.stringify(finalData)"body": "{\"foo\":\"bar\",\"baz\":\"qux\"}", expectedAny<URLSearchParams>String(finalData)"body": "[object Object]", expectedAny<FormData>expected { Object (error) } to deeply equal { pending: true, …(1) }applyCredential(...)->initialUrl"X-API-Key": "secret_key", received"headers": {}configureAuthScheme-> no-opundefinedwhere the scheme was expectedNegative control. With
OperationParser.processOperationParameters()emptied (operation_parser.ts:52-72):Tests 26 passed (26)Tests 4 failed | 21 passed (25)(path, header, query and declaration tests)The old suite could not see the parser disappear. The new one can.
Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.
Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.
Not applicable. This change is test-only and alters no production behaviour.
tests/e2e/tools/rest_api_tool_auth_e2e_test.tsis untouched.Checklist
[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.