@skyramp/mcp 0.3.2-rc.pom-3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/commandLibrary.d.ts +1 -0
- package/build/commands/commandLibrary.js +19 -13
- package/build/commands/localDevTestChangesCommand.d.ts +15 -0
- package/build/commands/localDevTestChangesCommand.js +201 -0
- package/build/index.js +80 -6
- package/build/prompts/code-reuse.js +3 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
- package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
- package/build/prompts/local-dev/local-dev-plan.js +429 -0
- package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
- package/build/prompts/local-dev/local-dev-prompts.js +190 -0
- package/build/prompts/pom-aware-code-reuse.js +12 -0
- package/build/prompts/prompt-utils.d.ts +8 -0
- package/build/prompts/prompt-utils.js +33 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +37 -14
- package/build/prompts/sut-setup/shared.js +16 -12
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +24 -7
- package/build/prompts/test-recommendation/scopeAssessment.js +111 -12
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
- package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
- package/build/prompts/testbot/testbot-prompts.js +32 -52
- package/build/recommendation/planRanker.d.ts +15 -2
- package/build/recommendation/planRanker.js +76 -5
- package/build/resources/testbotResource.js +2 -1
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +2 -1
- package/build/services/TestExecutionService.js +8 -3
- package/build/services/TestGenerationService.d.ts +2 -2
- package/build/services/TestGenerationService.js +39 -21
- package/build/services/containerEnv.js +3 -1
- package/build/tool-phases.js +6 -0
- package/build/tools/code-refactor/codeReuseTool.js +43 -4
- package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
- package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
- package/build/tools/code-refactor/reuse-outcome.js +158 -0
- package/build/tools/code-refactor/reuse-state.d.ts +45 -0
- package/build/tools/code-refactor/reuse-state.js +140 -0
- package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
- package/build/tools/enrichTestWithMocksTool.js +726 -0
- package/build/tools/executeSkyrampTestTool.d.ts +11 -0
- package/build/tools/executeSkyrampTestTool.js +62 -21
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
- package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
- package/build/tools/generate-tests/generateContractRestTool.js +2 -2
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
- package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
- package/build/tools/generate-tests/generateMockRestTool.js +391 -22
- package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
- package/build/tools/generate-tests/planGuard.js +2 -22
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
- package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
- package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
- package/build/tools/localDevWorkerComposeTool.js +264 -0
- package/build/tools/one-click/oneClickTool.d.ts +13 -0
- package/build/tools/one-click/oneClickTool.js +195 -24
- package/build/tools/preflightMockCheckTool.d.ts +2 -0
- package/build/tools/preflightMockCheckTool.js +96 -0
- package/build/tools/queryProxyMocksTool.d.ts +70 -0
- package/build/tools/queryProxyMocksTool.js +522 -0
- package/build/tools/runExistingTestsTool.d.ts +31 -0
- package/build/tools/runExistingTestsTool.js +214 -13
- package/build/tools/submitReportTool.js +38 -3
- package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
- package/build/tools/test-management/analyzeChangesTool.js +63 -40
- package/build/tools/test-management/registerTestPlanTool.js +55 -7
- package/build/tools/trace/startTraceCollectionTool.js +3 -3
- package/build/types/FrontendIntegration.d.ts +3 -0
- package/build/types/FrontendIntegration.js +3 -0
- package/build/types/OneClickCommands.d.ts +1 -1
- package/build/types/Recommendation.d.ts +20 -0
- package/build/types/Recommendation.js +32 -6
- package/build/types/RepositoryAnalysis.d.ts +131 -14
- package/build/types/RepositoryAnalysis.js +16 -2
- package/build/types/ReuseOutcome.d.ts +63 -0
- package/build/types/ReuseOutcome.js +33 -0
- package/build/types/TestExecution.d.ts +1 -0
- package/build/types/TestTypes.d.ts +25 -7
- package/build/types/TestTypes.js +22 -6
- package/build/types/TestbotReport.d.ts +7 -0
- package/build/types/index.d.ts +2 -0
- package/build/types/index.js +1 -0
- package/build/utils/AnalysisStateManager.d.ts +26 -0
- package/build/utils/AnalysisStateManager.js +31 -1
- package/build/utils/analyze-openapi.js +18 -1
- package/build/utils/branchDiff.d.ts +17 -1
- package/build/utils/branchDiff.js +99 -14
- package/build/utils/featureFlags.d.ts +31 -0
- package/build/utils/featureFlags.js +37 -0
- package/build/utils/frontendIntegration.js +8 -1
- package/build/utils/grpcMockValidation.d.ts +1 -0
- package/build/utils/grpcMockValidation.js +49 -0
- package/build/utils/httpMethodValidation.d.ts +4 -0
- package/build/utils/httpMethodValidation.js +15 -0
- package/build/utils/logger.js +1 -1
- package/build/utils/mockCompatibility.d.ts +49 -0
- package/build/utils/mockCompatibility.js +82 -0
- package/build/utils/pom-scope/pom-files.js +7 -0
- package/build/utils/pom-verify/bindings.js +11 -1
- package/build/utils/pom-verify/re-exports.d.ts +10 -0
- package/build/utils/pom-verify/re-exports.js +61 -0
- package/build/utils/pom-verify/resolve.d.ts +4 -1
- package/build/utils/pom-verify/resolve.js +7 -4
- package/build/utils/pom-verify/verify.d.ts +5 -0
- package/build/utils/pom-verify/verify.js +25 -3
- package/build/utils/progress.js +10 -5
- package/build/utils/proxy-terminal.js +3 -3
- package/build/utils/routeParsers.d.ts +3 -9
- package/build/utils/routeParsers.js +79 -4
- package/build/utils/utils.js +2 -2
- package/build/utils/versions.d.ts +4 -3
- package/build/utils/versions.js +3 -1
- package/build/utils/workspaceAuth.d.ts +46 -0
- package/build/utils/workspaceAuth.js +156 -1
- package/build/workspace/testSuites.d.ts +2 -1
- package/build/workspace/testSuites.js +1 -1
- package/build/workspace/workspace.d.ts +108 -32
- package/build/workspace/workspace.js +32 -4
- package/package.json +5 -2
- package/build/adapters/jestAdapter.test.d.ts +0 -1
- package/build/adapters/jestAdapter.test.js +0 -93
- package/build/adapters/mochaAdapter.test.d.ts +0 -1
- package/build/adapters/mochaAdapter.test.js +0 -63
- package/build/adapters/playwrightAdapter.test.d.ts +0 -1
- package/build/adapters/playwrightAdapter.test.js +0 -169
- package/build/adapters/pytestAdapter.test.d.ts +0 -1
- package/build/adapters/pytestAdapter.test.js +0 -90
- package/build/prompts/code-reuse.test.d.ts +0 -1
- package/build/prompts/code-reuse.test.js +0 -62
- package/build/prompts/pom-aware-code-reuse.test.d.ts +0 -1
- package/build/prompts/pom-aware-code-reuse.test.js +0 -11
- package/build/prompts/test-maintenance/drift-analysis-prompt.test.d.ts +0 -1
- package/build/prompts/test-maintenance/drift-analysis-prompt.test.js +0 -51
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +0 -1
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -264
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +0 -1
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +0 -126
- package/build/prompts/test-recommendation/promptPlan.test.d.ts +0 -1
- package/build/prompts/test-recommendation/promptPlan.test.js +0 -336
- package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +0 -1
- package/build/prompts/test-recommendation/scopeAssessment.test.js +0 -371
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +0 -1
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +0 -1925
- package/build/prompts/testbot/testbot-prompts.test.d.ts +0 -1
- package/build/prompts/testbot/testbot-prompts.test.js +0 -451
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +0 -1
- package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +0 -138
- package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +0 -1
- package/build/recommendation/budgeters/fixedNBudgeter.test.js +0 -66
- package/build/recommendation/discriminators.test.d.ts +0 -1
- package/build/recommendation/discriminators.test.js +0 -324
- package/build/recommendation/diversity.test.d.ts +0 -1
- package/build/recommendation/diversity.test.js +0 -77
- package/build/recommendation/planRanker.test.d.ts +0 -1
- package/build/recommendation/planRanker.test.js +0 -110
- package/build/resources/testbotResource.test.d.ts +0 -1
- package/build/resources/testbotResource.test.js +0 -44
- package/build/services/AnalyticsService.test.d.ts +0 -1
- package/build/services/AnalyticsService.test.js +0 -86
- package/build/services/ScenarioGenerationService.integration.test.d.ts +0 -1
- package/build/services/ScenarioGenerationService.integration.test.js +0 -162
- package/build/services/ScenarioGenerationService.test.d.ts +0 -1
- package/build/services/ScenarioGenerationService.test.js +0 -414
- package/build/services/TestDiscoveryService.test.d.ts +0 -1
- package/build/services/TestDiscoveryService.test.js +0 -983
- package/build/services/TestExecutionService.test.d.ts +0 -1
- package/build/services/TestExecutionService.test.js +0 -1032
- package/build/services/TestGenerationService.test.d.ts +0 -1
- package/build/services/TestGenerationService.test.js +0 -578
- package/build/tool-phase-coverage.test.d.ts +0 -1
- package/build/tool-phase-coverage.test.js +0 -49
- package/build/tools/code-refactor/codeReuseTool.test.d.ts +0 -1
- package/build/tools/code-refactor/codeReuseTool.test.js +0 -572
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +0 -433
- package/build/tools/generate-tests/generateContractRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateContractRestTool.test.js +0 -142
- package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.test.js +0 -159
- package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateLoadRestTool.test.js +0 -169
- package/build/tools/generate-tests/generateUIRestTool.test.d.ts +0 -1
- package/build/tools/generate-tests/generateUIRestTool.test.js +0 -32
- package/build/tools/generate-tests/planGuard.test.d.ts +0 -1
- package/build/tools/generate-tests/planGuard.test.js +0 -185
- package/build/tools/generate-tests/scenarioLint.test.d.ts +0 -1
- package/build/tools/generate-tests/scenarioLint.test.js +0 -100
- package/build/tools/runExistingTestsTool.test.d.ts +0 -1
- package/build/tools/runExistingTestsTool.test.js +0 -379
- package/build/tools/submitReportTool.test.d.ts +0 -1
- package/build/tools/submitReportTool.test.js +0 -1428
- package/build/tools/test-management/actionsTool.test.d.ts +0 -1
- package/build/tools/test-management/actionsTool.test.js +0 -436
- package/build/tools/test-management/analyzeChangesTool.test.d.ts +0 -1
- package/build/tools/test-management/analyzeChangesTool.test.js +0 -522
- package/build/tools/test-management/analyzeTestHealthTool.test.d.ts +0 -1
- package/build/tools/test-management/analyzeTestHealthTool.test.js +0 -385
- package/build/tools/test-management/registerTestPlanTool.test.d.ts +0 -1
- package/build/tools/test-management/registerTestPlanTool.test.js +0 -296
- package/build/tools/trace/resolveSaveStoragePath.test.d.ts +0 -1
- package/build/tools/trace/resolveSaveStoragePath.test.js +0 -17
- package/build/tools/trace/resolveSessionPaths.test.d.ts +0 -1
- package/build/tools/trace/resolveSessionPaths.test.js +0 -104
- package/build/tools/trace/sessionState.test.d.ts +0 -1
- package/build/tools/trace/sessionState.test.js +0 -17
- package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +0 -1
- package/build/tools/workspace/initializeWorkspaceTool.test.js +0 -139
- package/build/tools/workspace/serviceUpsert.test.d.ts +0 -1
- package/build/tools/workspace/serviceUpsert.test.js +0 -50
- package/build/utils/AnalysisStateManager.test.d.ts +0 -1
- package/build/utils/AnalysisStateManager.test.js +0 -134
- package/build/utils/dartRouteExtractor.test.d.ts +0 -1
- package/build/utils/dartRouteExtractor.test.js +0 -307
- package/build/utils/docker.test.d.ts +0 -1
- package/build/utils/docker.test.js +0 -114
- package/build/utils/featureFlags.test.d.ts +0 -1
- package/build/utils/featureFlags.test.js +0 -81
- package/build/utils/fileWalk.test.d.ts +0 -1
- package/build/utils/fileWalk.test.js +0 -252
- package/build/utils/frontendIntegration.test.d.ts +0 -1
- package/build/utils/frontendIntegration.test.js +0 -229
- package/build/utils/frontendSelectors.test.d.ts +0 -1
- package/build/utils/frontendSelectors.test.js +0 -118
- package/build/utils/gitStaging.test.d.ts +0 -1
- package/build/utils/gitStaging.test.js +0 -111
- package/build/utils/httpDefaults.test.d.ts +0 -1
- package/build/utils/httpDefaults.test.js +0 -21
- package/build/utils/importerHop.test.d.ts +0 -1
- package/build/utils/importerHop.test.js +0 -469
- package/build/utils/pathAffinityClassification.test.d.ts +0 -1
- package/build/utils/pathAffinityClassification.test.js +0 -208
- package/build/utils/planMatchKeys.test.d.ts +0 -1
- package/build/utils/planMatchKeys.test.js +0 -123
- package/build/utils/pom-scope/index.test.d.ts +0 -1
- package/build/utils/pom-scope/index.test.js +0 -278
- package/build/utils/pom-scope/pom-files.test.d.ts +0 -1
- package/build/utils/pom-scope/pom-files.test.js +0 -29
- package/build/utils/pom-scope/scoring.test.d.ts +0 -1
- package/build/utils/pom-scope/scoring.test.js +0 -39
- package/build/utils/pom-scope/selector-extractor.test.d.ts +0 -1
- package/build/utils/pom-scope/selector-extractor.test.js +0 -67
- package/build/utils/pom-verify/bindings.test.d.ts +0 -1
- package/build/utils/pom-verify/bindings.test.js +0 -164
- package/build/utils/pom-verify/calls.test.d.ts +0 -1
- package/build/utils/pom-verify/calls.test.js +0 -61
- package/build/utils/pom-verify/resolve.test.d.ts +0 -1
- package/build/utils/pom-verify/resolve.test.js +0 -114
- package/build/utils/pom-verify/verify.test.d.ts +0 -1
- package/build/utils/pom-verify/verify.test.js +0 -374
- package/build/utils/pr-comment-parser.test.d.ts +0 -1
- package/build/utils/pr-comment-parser.test.js +0 -428
- package/build/utils/progress.test.d.ts +0 -1
- package/build/utils/progress.test.js +0 -37
- package/build/utils/projectMetadata.test.d.ts +0 -1
- package/build/utils/projectMetadata.test.js +0 -172
- package/build/utils/pythonMountPrefixes.test.d.ts +0 -1
- package/build/utils/pythonMountPrefixes.test.js +0 -113
- package/build/utils/repoScanner.test.d.ts +0 -1
- package/build/utils/repoScanner.test.js +0 -190
- package/build/utils/reportVerification.test.d.ts +0 -1
- package/build/utils/reportVerification.test.js +0 -185
- package/build/utils/routeParsers.test.d.ts +0 -1
- package/build/utils/routeParsers.test.js +0 -1011
- package/build/utils/scenarioDrafting.test.d.ts +0 -1
- package/build/utils/scenarioDrafting.test.js +0 -876
- package/build/utils/sourceRouteExtractor.test.d.ts +0 -1
- package/build/utils/sourceRouteExtractor.test.js +0 -738
- package/build/utils/telemetry.test.d.ts +0 -1
- package/build/utils/telemetry.test.js +0 -70
- package/build/utils/trace-parser.test.d.ts +0 -6
- package/build/utils/trace-parser.test.js +0 -140
- package/build/utils/uiPageEnumerator.test.d.ts +0 -1
- package/build/utils/uiPageEnumerator.test.js +0 -824
- package/build/utils/utils.test.d.ts +0 -1
- package/build/utils/utils.test.js +0 -103
- package/build/utils/walkerCharacterization.test.d.ts +0 -1
- package/build/utils/walkerCharacterization.test.js +0 -233
- package/build/utils/workspaceAuth.test.d.ts +0 -1
- package/build/utils/workspaceAuth.test.js +0 -260
- package/build/workspace/testSuites.test.d.ts +0 -1
- package/build/workspace/testSuites.test.js +0 -23
- package/build/workspace/workspace.test.d.ts +0 -1
- package/build/workspace/workspace.test.js +0 -264
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SkyrampClient } from "@skyramp/skyramp";
|
|
3
|
+
import { MockProtocol, RuntimeEnvironment, runtimeEnvironmentInputSchema } from "../../types/TestTypes.js";
|
|
4
|
+
export { MockProtocol } from "../../types/TestTypes.js";
|
|
5
|
+
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
6
|
+
import { logger } from "../../utils/logger.js";
|
|
7
|
+
import { getEntryPoint } from "../../utils/telemetry.js";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import { getRestMockMethodValidationError, normalizeRestMockMethod, } from "../../utils/httpMethodValidation.js";
|
|
10
|
+
import { getGrpcMockResponseValidationError } from "../../utils/grpcMockValidation.js";
|
|
11
|
+
import { validateMockCompatibility } from "../../utils/mockCompatibility.js";
|
|
12
|
+
import { buildTrafficConfigOptions, validateTrafficConfig, } from "./generateMockRestTool.js";
|
|
13
|
+
export const BATCH_MOCK_PROTOCOL_EXAMPLES = `
|
|
14
|
+
<example protocol="rest">
|
|
15
|
+
Batch REST item. Required fields: protocol="rest", endpointURL, method unless apiSchema is provided.
|
|
16
|
+
{
|
|
17
|
+
"protocol": "rest",
|
|
18
|
+
"endpointURL": "http://identity-service:4000/api/internal/v1/users/validate",
|
|
19
|
+
"method": "POST",
|
|
20
|
+
"requestAware": true,
|
|
21
|
+
"responseData": "{\"valid\":true}"
|
|
22
|
+
}
|
|
23
|
+
</example>
|
|
24
|
+
|
|
25
|
+
<example protocol="rest-traffic-simulation">
|
|
26
|
+
Batch REST item with traffic simulation. minLatency/maxLatency inject a random delay per response; dropRate drops a percentage of requests.
|
|
27
|
+
{
|
|
28
|
+
"protocol": "rest",
|
|
29
|
+
"endpointURL": "http://payment-service:5001/payments",
|
|
30
|
+
"method": "POST",
|
|
31
|
+
"responseData": "{\"status\":\"ok\"}",
|
|
32
|
+
"minLatency": 500,
|
|
33
|
+
"maxLatency": 1000,
|
|
34
|
+
"dropRate": 10
|
|
35
|
+
}
|
|
36
|
+
</example>
|
|
37
|
+
|
|
38
|
+
<example protocol="rest-conditional">
|
|
39
|
+
Batch REST item with conditional response selection. Use "when" to match request fields.
|
|
40
|
+
{
|
|
41
|
+
"protocol": "rest",
|
|
42
|
+
"endpointURL": "http://payment-service:5001/api/v1/orders",
|
|
43
|
+
"method": "POST",
|
|
44
|
+
"when": {"request.body.payment.method": "card"},
|
|
45
|
+
"requestSchema": "{\"type\":\"object\",\"required\":[\"orderId\",\"payment\"]}",
|
|
46
|
+
"responseData": "{\"status\":\"confirmed\"}",
|
|
47
|
+
"responseStatusCode": "201",
|
|
48
|
+
"noMatchStatusCode": 404,
|
|
49
|
+
"validationFailureStatusCode": 422
|
|
50
|
+
}
|
|
51
|
+
</example>
|
|
52
|
+
|
|
53
|
+
<example protocol="grpc">
|
|
54
|
+
Batch gRPC item. Required fields: protocol="grpc", endpointURL as host:port, protoPath, grpcServiceName. method is the RPC name; empty means all service methods.
|
|
55
|
+
{
|
|
56
|
+
"protocol": "grpc",
|
|
57
|
+
"endpointURL": "profile-service:50051",
|
|
58
|
+
"protoPath": "/repo/proto/profiles.proto",
|
|
59
|
+
"grpcServiceName": "ProfileService",
|
|
60
|
+
"method": "GetProfile",
|
|
61
|
+
"responseData": "{\"id\":\"profile_123\"}"
|
|
62
|
+
}
|
|
63
|
+
</example>
|
|
64
|
+
|
|
65
|
+
<example protocol="grpc-traffic-simulation">
|
|
66
|
+
Batch gRPC item with traffic simulation. Same latency/drop fields as REST.
|
|
67
|
+
{
|
|
68
|
+
"protocol": "grpc",
|
|
69
|
+
"endpointURL": "profile-service:50051",
|
|
70
|
+
"protoPath": "/repo/proto/profiles.proto",
|
|
71
|
+
"grpcServiceName": "ProfileService",
|
|
72
|
+
"method": "GetProfile",
|
|
73
|
+
"responseData": "{\"eligible\":true}",
|
|
74
|
+
"minLatency": 200,
|
|
75
|
+
"maxLatency": 800,
|
|
76
|
+
"dropRate": 5
|
|
77
|
+
}
|
|
78
|
+
</example>
|
|
79
|
+
|
|
80
|
+
<example protocol="grpc-status-error">
|
|
81
|
+
Batch gRPC status error item. Do not provide responseData with grpcStatusCode.
|
|
82
|
+
{
|
|
83
|
+
"protocol": "grpc",
|
|
84
|
+
"endpointURL": "profile-service:50051",
|
|
85
|
+
"protoPath": "/repo/proto/profiles.proto",
|
|
86
|
+
"grpcServiceName": "ProfileService",
|
|
87
|
+
"method": "GetProfile",
|
|
88
|
+
"grpcStatusCode": 5,
|
|
89
|
+
"grpcStatusMessage": "profile not found"
|
|
90
|
+
}
|
|
91
|
+
</example>
|
|
92
|
+
|
|
93
|
+
<example protocol="kafka-producer">
|
|
94
|
+
Batch Kafka producer validation item. Required fields: protocol="kafka", endpointURL as broker host:port, kafkaTopic, and requestData. Do not pass method or responseData. Traffic simulation is NOT supported for Kafka.
|
|
95
|
+
{
|
|
96
|
+
"protocol": "kafka",
|
|
97
|
+
"endpointURL": "broker:9092",
|
|
98
|
+
"kafkaTopic": "orders",
|
|
99
|
+
"requestData": "{\"order_id\":\"ord_123\"}"
|
|
100
|
+
}
|
|
101
|
+
</example>
|
|
102
|
+
|
|
103
|
+
<example protocol="kafka-consumer">
|
|
104
|
+
Batch Kafka consumer message item. Required fields: protocol="kafka", endpointURL as broker host:port, kafkaTopic, and responseData. Do not pass method or requestData. Traffic simulation is NOT supported for Kafka.
|
|
105
|
+
{
|
|
106
|
+
"protocol": "kafka",
|
|
107
|
+
"endpointURL": "broker:9092",
|
|
108
|
+
"kafkaTopic": "orders",
|
|
109
|
+
"responseData": "{\"accepted\":true}"
|
|
110
|
+
}
|
|
111
|
+
</example>`;
|
|
112
|
+
const mockSpecSchema = z.object({
|
|
113
|
+
protocol: z
|
|
114
|
+
.nativeEnum(MockProtocol)
|
|
115
|
+
.default(MockProtocol.Rest)
|
|
116
|
+
.describe("Protocol for this mock: 'rest', 'grpc', or 'kafka'. See <example> blocks in the tool description for required fields."),
|
|
117
|
+
endpointURL: z
|
|
118
|
+
.string()
|
|
119
|
+
.describe("For REST: the base URL or endpoint URL. " +
|
|
120
|
+
"For gRPC: the target service address as host:port. " +
|
|
121
|
+
"For Kafka: the broker address as host:port."),
|
|
122
|
+
method: z
|
|
123
|
+
.string()
|
|
124
|
+
.default("")
|
|
125
|
+
.describe("For REST: HTTP method, required unless apiSchema is provided. For gRPC: RPC method name, empty generates all service methods. For Kafka: MUST be empty; use kafkaTopic."),
|
|
126
|
+
responseData: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("REST/gRPC response body data; Kafka consumer messages. Inline JSON/YAML or @/path/to/file."),
|
|
130
|
+
responseStatusCode: z
|
|
131
|
+
.string()
|
|
132
|
+
.default("")
|
|
133
|
+
.refine((val) => !val || /^\d{3}$/.test(val), {
|
|
134
|
+
message: "Must be a 3-digit HTTP status code (e.g., '200', '201') or empty string",
|
|
135
|
+
})
|
|
136
|
+
.describe("HTTP status code the mock should return (e.g., '200', '201')."),
|
|
137
|
+
grpcStatusCode: z
|
|
138
|
+
.number()
|
|
139
|
+
.int()
|
|
140
|
+
.min(1)
|
|
141
|
+
.max(16)
|
|
142
|
+
.optional()
|
|
143
|
+
.describe("For protocol='grpc' error mocks only. Non-OK gRPC status code number. Do not combine with responseData."),
|
|
144
|
+
grpcStatusMessage: z
|
|
145
|
+
.string()
|
|
146
|
+
.optional()
|
|
147
|
+
.describe("For protocol='grpc' error mocks only. gRPC status message to return with grpcStatusCode."),
|
|
148
|
+
requestData: z
|
|
149
|
+
.string()
|
|
150
|
+
.default("")
|
|
151
|
+
.describe("REST request body sample for request-aware mocks; Kafka producer validation payload/schema."),
|
|
152
|
+
requestAware: z
|
|
153
|
+
.boolean()
|
|
154
|
+
.default(false)
|
|
155
|
+
.describe("When true, generates a dynamic mock that varies by request."),
|
|
156
|
+
apiSchema: z
|
|
157
|
+
.string()
|
|
158
|
+
.default("")
|
|
159
|
+
.describe("Path or URL to OpenAPI/Swagger schema file."),
|
|
160
|
+
protoPath: z
|
|
161
|
+
.string()
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("Required for protocol='grpc'. Path to the .proto file."),
|
|
164
|
+
grpcServiceName: z
|
|
165
|
+
.string()
|
|
166
|
+
.optional()
|
|
167
|
+
.describe("Required for protocol='grpc'. gRPC service name."),
|
|
168
|
+
protobufExtraFiles: z
|
|
169
|
+
.array(z.string())
|
|
170
|
+
.optional()
|
|
171
|
+
.describe("Optional extra .proto files for gRPC compilation."),
|
|
172
|
+
protobufExtraImportPath: z
|
|
173
|
+
.array(z.string())
|
|
174
|
+
.optional()
|
|
175
|
+
.describe("Optional extra import directories for protobuf compilation."),
|
|
176
|
+
kafkaTopic: z
|
|
177
|
+
.string()
|
|
178
|
+
.optional()
|
|
179
|
+
.describe("Required for protocol='kafka'. Kafka topic name."),
|
|
180
|
+
minLatency: z
|
|
181
|
+
.number()
|
|
182
|
+
.int()
|
|
183
|
+
.min(0)
|
|
184
|
+
.optional()
|
|
185
|
+
.describe("Minimum injected response delay in milliseconds for traffic simulation (REST and gRPC only)."),
|
|
186
|
+
maxLatency: z
|
|
187
|
+
.number()
|
|
188
|
+
.int()
|
|
189
|
+
.min(0)
|
|
190
|
+
.optional()
|
|
191
|
+
.describe("Maximum injected response delay in milliseconds for traffic simulation (REST and gRPC only)."),
|
|
192
|
+
dropRate: z
|
|
193
|
+
.number()
|
|
194
|
+
.int()
|
|
195
|
+
.min(0)
|
|
196
|
+
.max(100)
|
|
197
|
+
.optional()
|
|
198
|
+
.describe("Percentage [0-100] of requests dropped/errored for traffic simulation (REST and gRPC only)."),
|
|
199
|
+
when: z
|
|
200
|
+
.record(z.unknown())
|
|
201
|
+
.optional()
|
|
202
|
+
.describe("Conditional-selection predicate (operator map) for REST and gRPC mocks. " +
|
|
203
|
+
"Keys are request paths (request.body.<jsonpath>, request.path.<name>, etc.); " +
|
|
204
|
+
"values are a bare value (equality) or an operator object ({eq,ne,gt,gte,lt,lte,in,contains,regex,exists}). " +
|
|
205
|
+
'Example: {"request.body.payment.method": "card"}'),
|
|
206
|
+
requestSchema: z
|
|
207
|
+
.string()
|
|
208
|
+
.optional()
|
|
209
|
+
.describe("Explicit JSON Schema (string) to validate the request body. REST and gRPC only."),
|
|
210
|
+
noMatchStatusCode: z
|
|
211
|
+
.number()
|
|
212
|
+
.int()
|
|
213
|
+
.min(100)
|
|
214
|
+
.max(599)
|
|
215
|
+
.optional()
|
|
216
|
+
.describe("HTTP status code when no `when` branch matches (default 404). REST and gRPC only."),
|
|
217
|
+
validationFailureStatusCode: z
|
|
218
|
+
.number()
|
|
219
|
+
.int()
|
|
220
|
+
.min(100)
|
|
221
|
+
.max(599)
|
|
222
|
+
.optional()
|
|
223
|
+
.describe("HTTP status code when request validation fails (default 400). REST and gRPC only."),
|
|
224
|
+
output: z
|
|
225
|
+
.string()
|
|
226
|
+
.optional()
|
|
227
|
+
.describe("Optional output file name for this mock. Use when multiple mocks share the same endpoint and method so generated files do not overwrite each other."),
|
|
228
|
+
outputDir: z
|
|
229
|
+
.string()
|
|
230
|
+
.optional()
|
|
231
|
+
.describe("Optional output directory for this mock. Defaults to the batch-level outputDir."),
|
|
232
|
+
});
|
|
233
|
+
function validateMockSpec(spec) {
|
|
234
|
+
const protocol = spec.protocol ?? MockProtocol.Rest;
|
|
235
|
+
if (protocol === MockProtocol.Rest) {
|
|
236
|
+
const methodError = getRestMockMethodValidationError(spec.method);
|
|
237
|
+
if (methodError)
|
|
238
|
+
return methodError;
|
|
239
|
+
if (!spec.apiSchema && !spec.method) {
|
|
240
|
+
return "REST mock method is required unless apiSchema is provided for schema-wide generation";
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (protocol === MockProtocol.Grpc) {
|
|
244
|
+
const missing = [];
|
|
245
|
+
if (!spec.protoPath)
|
|
246
|
+
missing.push("protoPath");
|
|
247
|
+
if (!spec.grpcServiceName)
|
|
248
|
+
missing.push("grpcServiceName");
|
|
249
|
+
if (missing.length > 0) {
|
|
250
|
+
return `gRPC mock requires: ${missing.join(", ")}`;
|
|
251
|
+
}
|
|
252
|
+
if (spec.grpcStatusCode !== undefined && spec.responseData?.trim()) {
|
|
253
|
+
return "gRPC status error mocks must use grpcStatusCode/grpcStatusMessage instead of responseData";
|
|
254
|
+
}
|
|
255
|
+
if (spec.grpcStatusMessage && spec.grpcStatusCode === undefined) {
|
|
256
|
+
return "grpcStatusMessage requires grpcStatusCode";
|
|
257
|
+
}
|
|
258
|
+
const grpcResponseError = getGrpcMockResponseValidationError(spec.responseData);
|
|
259
|
+
if (grpcResponseError)
|
|
260
|
+
return grpcResponseError;
|
|
261
|
+
}
|
|
262
|
+
if (protocol === MockProtocol.Kafka) {
|
|
263
|
+
if (!spec.kafkaTopic)
|
|
264
|
+
return "Kafka mock requires: kafkaTopic";
|
|
265
|
+
if (spec.method) {
|
|
266
|
+
return "Kafka mock method must be empty; use kafkaTopic for the topic name. Produce validation uses requestData and consumer messages use responseData";
|
|
267
|
+
}
|
|
268
|
+
const hasRequestData = Boolean(spec.requestData && spec.requestData.trim());
|
|
269
|
+
const hasResponseData = Boolean(spec.responseData && spec.responseData.trim());
|
|
270
|
+
if (hasRequestData === hasResponseData) {
|
|
271
|
+
return "Kafka mock requires exactly one of requestData (producer validation) or responseData (consumer messages)";
|
|
272
|
+
}
|
|
273
|
+
if (spec.minLatency !== undefined ||
|
|
274
|
+
spec.maxLatency !== undefined ||
|
|
275
|
+
spec.dropRate !== undefined) {
|
|
276
|
+
return "traffic config (minLatency/maxLatency/dropRate) is not applicable for Kafka mocks";
|
|
277
|
+
}
|
|
278
|
+
if (spec.when !== undefined ||
|
|
279
|
+
spec.requestSchema !== undefined ||
|
|
280
|
+
spec.noMatchStatusCode !== undefined ||
|
|
281
|
+
spec.validationFailureStatusCode !== undefined) {
|
|
282
|
+
return "conditional response fields (when/requestSchema/noMatchStatusCode/validationFailureStatusCode) are not applicable for Kafka mocks";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const trafficError = validateTrafficConfig(spec);
|
|
286
|
+
if (trafficError)
|
|
287
|
+
return trafficError;
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
function buildGenerateOptions(spec, shared) {
|
|
291
|
+
const protocol = spec.protocol ?? MockProtocol.Rest;
|
|
292
|
+
const language = shared.language ?? "python";
|
|
293
|
+
const framework = shared.framework ??
|
|
294
|
+
(language === "typescript" || language === "javascript"
|
|
295
|
+
? "playwright"
|
|
296
|
+
: "");
|
|
297
|
+
const outputDir = spec.outputDir ?? shared.outputDir;
|
|
298
|
+
const common = {
|
|
299
|
+
protocol,
|
|
300
|
+
language,
|
|
301
|
+
framework,
|
|
302
|
+
outputDir,
|
|
303
|
+
output: spec.output,
|
|
304
|
+
force: true,
|
|
305
|
+
overwrite: true,
|
|
306
|
+
runtime: shared.runtime,
|
|
307
|
+
dockerNetwork: shared.dockerNetwork,
|
|
308
|
+
entrypoint: getEntryPoint(),
|
|
309
|
+
};
|
|
310
|
+
const responseDataOption = spec.responseData !== undefined &&
|
|
311
|
+
!(protocol === MockProtocol.Grpc && spec.grpcStatusCode !== undefined)
|
|
312
|
+
? { responseData: spec.responseData }
|
|
313
|
+
: {};
|
|
314
|
+
const trafficConfig = buildTrafficConfigOptions(spec);
|
|
315
|
+
if (protocol === MockProtocol.Grpc) {
|
|
316
|
+
return {
|
|
317
|
+
...common,
|
|
318
|
+
...responseDataOption,
|
|
319
|
+
...trafficConfig,
|
|
320
|
+
method: spec.method ?? "",
|
|
321
|
+
url: spec.endpointURL,
|
|
322
|
+
protoPath: spec.protoPath,
|
|
323
|
+
service: spec.grpcServiceName,
|
|
324
|
+
grpcStatusCode: spec.grpcStatusCode,
|
|
325
|
+
grpcStatusMessage: spec.grpcStatusMessage,
|
|
326
|
+
extraFiles: spec.protobufExtraFiles ?? [],
|
|
327
|
+
extraImports: spec.protobufExtraImportPath ?? [],
|
|
328
|
+
when: spec.when,
|
|
329
|
+
requestSchema: spec.requestSchema,
|
|
330
|
+
noMatchStatusCode: spec.noMatchStatusCode,
|
|
331
|
+
validationFailureStatusCode: spec.validationFailureStatusCode,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (protocol === MockProtocol.Kafka) {
|
|
335
|
+
return {
|
|
336
|
+
...common,
|
|
337
|
+
...responseDataOption,
|
|
338
|
+
url: spec.endpointURL,
|
|
339
|
+
topic: spec.kafkaTopic,
|
|
340
|
+
requestData: spec.requestData?.trim() ? spec.requestData : undefined,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
// REST
|
|
344
|
+
return {
|
|
345
|
+
...common,
|
|
346
|
+
...responseDataOption,
|
|
347
|
+
...trafficConfig,
|
|
348
|
+
method: normalizeRestMockMethod(spec.method),
|
|
349
|
+
uri: spec.endpointURL,
|
|
350
|
+
apiSchema: spec.apiSchema ? [spec.apiSchema] : [],
|
|
351
|
+
requestData: spec.requestData ?? "",
|
|
352
|
+
responseStatusCode: spec.responseStatusCode ?? "",
|
|
353
|
+
requestAware: spec.requestAware ?? false,
|
|
354
|
+
mockPort: 0,
|
|
355
|
+
optionalFields: false,
|
|
356
|
+
when: spec.when,
|
|
357
|
+
requestSchema: spec.requestSchema,
|
|
358
|
+
noMatchStatusCode: spec.noMatchStatusCode ?? 0,
|
|
359
|
+
validationFailureStatusCode: spec.validationFailureStatusCode ?? 0,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
export async function executeBatchMockGeneration(params) {
|
|
363
|
+
const { mocks, outputDir } = params;
|
|
364
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
365
|
+
const client = new SkyrampClient();
|
|
366
|
+
const results = [];
|
|
367
|
+
for (let i = 0; i < mocks.length; i++) {
|
|
368
|
+
const spec = mocks[i];
|
|
369
|
+
const protocol = spec.protocol ?? MockProtocol.Rest;
|
|
370
|
+
const method = spec.method ?? "";
|
|
371
|
+
// Validate spec
|
|
372
|
+
const validationError = validateMockSpec(spec);
|
|
373
|
+
if (validationError) {
|
|
374
|
+
results.push({
|
|
375
|
+
index: i,
|
|
376
|
+
protocol,
|
|
377
|
+
endpointURL: spec.endpointURL,
|
|
378
|
+
method,
|
|
379
|
+
topic: spec.kafkaTopic,
|
|
380
|
+
success: false,
|
|
381
|
+
error: validationError,
|
|
382
|
+
});
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const dockerLocalDev = params.runtime === "docker" || Boolean(params.dockerNetwork?.trim());
|
|
386
|
+
const compatibility = validateMockCompatibility([{ ...spec, protocol }], {
|
|
387
|
+
dockerLocalDev,
|
|
388
|
+
});
|
|
389
|
+
const blockingWarnings = compatibility.warnings.filter((warning) => warning.blocking);
|
|
390
|
+
if (blockingWarnings.length > 0) {
|
|
391
|
+
results.push({
|
|
392
|
+
index: i,
|
|
393
|
+
protocol,
|
|
394
|
+
endpointURL: spec.endpointURL,
|
|
395
|
+
method,
|
|
396
|
+
topic: spec.kafkaTopic,
|
|
397
|
+
success: false,
|
|
398
|
+
error: blockingWarnings
|
|
399
|
+
.map((warning) => `${warning.code}: ${warning.message} Suggestion: ${warning.suggestion}`)
|
|
400
|
+
.join("\n"),
|
|
401
|
+
});
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const resolvedOutputDir = spec.outputDir ?? outputDir;
|
|
405
|
+
fs.mkdirSync(resolvedOutputDir, { recursive: true });
|
|
406
|
+
// Build options and generate
|
|
407
|
+
const options = buildGenerateOptions(spec, {
|
|
408
|
+
outputDir,
|
|
409
|
+
runtime: params.runtime,
|
|
410
|
+
dockerNetwork: params.dockerNetwork,
|
|
411
|
+
language: params.language,
|
|
412
|
+
framework: params.framework,
|
|
413
|
+
});
|
|
414
|
+
try {
|
|
415
|
+
let result;
|
|
416
|
+
if (protocol === MockProtocol.Grpc) {
|
|
417
|
+
result = await client.generateGrpcMock(options);
|
|
418
|
+
}
|
|
419
|
+
else if (protocol === MockProtocol.Kafka) {
|
|
420
|
+
result = await client.generateKafkaMock(options);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
result = await client.generateRestMock(options);
|
|
424
|
+
}
|
|
425
|
+
if (!result || !result.toLowerCase().includes("success")) {
|
|
426
|
+
results.push({
|
|
427
|
+
index: i,
|
|
428
|
+
protocol,
|
|
429
|
+
endpointURL: spec.endpointURL,
|
|
430
|
+
method,
|
|
431
|
+
topic: spec.kafkaTopic,
|
|
432
|
+
success: false,
|
|
433
|
+
error: `Mock generation failed: ${result || "no output from backend"}`,
|
|
434
|
+
});
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
results.push({
|
|
438
|
+
index: i,
|
|
439
|
+
protocol,
|
|
440
|
+
endpointURL: spec.endpointURL,
|
|
441
|
+
method,
|
|
442
|
+
topic: spec.kafkaTopic,
|
|
443
|
+
success: true,
|
|
444
|
+
outputDir: resolvedOutputDir,
|
|
445
|
+
output: spec.output,
|
|
446
|
+
detail: result,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
451
|
+
logger.error("Batch mock generation failed for spec", {
|
|
452
|
+
index: i,
|
|
453
|
+
protocol,
|
|
454
|
+
endpointURL: spec.endpointURL,
|
|
455
|
+
error: errorMessage,
|
|
456
|
+
});
|
|
457
|
+
results.push({
|
|
458
|
+
index: i,
|
|
459
|
+
protocol,
|
|
460
|
+
endpointURL: spec.endpointURL,
|
|
461
|
+
method,
|
|
462
|
+
topic: spec.kafkaTopic,
|
|
463
|
+
success: false,
|
|
464
|
+
error: errorMessage,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const succeeded = results.filter((r) => r.success);
|
|
469
|
+
const failed = results.filter((r) => !r.success);
|
|
470
|
+
const summaryLines = [
|
|
471
|
+
`## Batch Mock Generation Summary`,
|
|
472
|
+
``,
|
|
473
|
+
`- **Total:** ${mocks.length}`,
|
|
474
|
+
`- **Succeeded:** ${succeeded.length}`,
|
|
475
|
+
`- **Failed:** ${failed.length}`,
|
|
476
|
+
`- **Default Output Directory:** ${outputDir}`,
|
|
477
|
+
``,
|
|
478
|
+
];
|
|
479
|
+
if (succeeded.length > 0) {
|
|
480
|
+
summaryLines.push(`### Successful Mocks`);
|
|
481
|
+
for (const r of succeeded) {
|
|
482
|
+
summaryLines.push(`- [${r.index}] ${r.protocol.toUpperCase()} ${r.endpointURL} ${r.method || (r.protocol === MockProtocol.Kafka ? `topic:${r.topic ?? "?"}` : "(all methods)")}${r.output ? ` -> ${r.outputDir ?? outputDir}/${r.output}` : ""}`);
|
|
483
|
+
}
|
|
484
|
+
summaryLines.push(``);
|
|
485
|
+
}
|
|
486
|
+
if (failed.length > 0) {
|
|
487
|
+
summaryLines.push(`### Failed Mocks`);
|
|
488
|
+
for (const r of failed) {
|
|
489
|
+
summaryLines.push(`- [${r.index}] ${r.protocol.toUpperCase()} ${r.endpointURL} ${r.method || (r.protocol === MockProtocol.Kafka ? `topic:${r.topic ?? "?"}` : "(all methods)")}: ${r.error}`);
|
|
490
|
+
}
|
|
491
|
+
summaryLines.push(``);
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
content: [{ type: "text", text: summaryLines.join("\n") }],
|
|
495
|
+
isError: failed.length > 0,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
const TOOL_NAME = "skyramp_batch_mock_generation";
|
|
499
|
+
const batchMockSchema = {
|
|
500
|
+
mocks: z
|
|
501
|
+
.array(mockSpecSchema)
|
|
502
|
+
.min(1)
|
|
503
|
+
.describe("Array of mock specifications. Each element describes one mock to generate."),
|
|
504
|
+
outputDir: z
|
|
505
|
+
.string()
|
|
506
|
+
.describe("Directory where generated mock files will be written."),
|
|
507
|
+
runtime: runtimeEnvironmentInputSchema
|
|
508
|
+
.default(RuntimeEnvironment.LOCAL)
|
|
509
|
+
.describe("Runtime environment: 'local', 'docker', or 'k8s' (also accepts 'kubernetes')."),
|
|
510
|
+
dockerNetwork: z
|
|
511
|
+
.string()
|
|
512
|
+
.default("")
|
|
513
|
+
.describe("Docker network name for containerized testing."),
|
|
514
|
+
language: z
|
|
515
|
+
.string()
|
|
516
|
+
.default("python")
|
|
517
|
+
.describe("Programming language for generated mocks (python, typescript, javascript, java)."),
|
|
518
|
+
framework: z
|
|
519
|
+
.string()
|
|
520
|
+
.default("")
|
|
521
|
+
.describe("Testing framework (e.g., pytest, playwright)."),
|
|
522
|
+
};
|
|
523
|
+
export function registerBatchMockTool(server) {
|
|
524
|
+
server.registerTool(TOOL_NAME, {
|
|
525
|
+
description: `Generate multiple mock server implementations in a single call using Skyramp.
|
|
526
|
+
|
|
527
|
+
This tool accepts an array of mock specifications and generates all mocks in one operation,
|
|
528
|
+
avoiding the need for N separate tool calls when mocking multiple downstream services.
|
|
529
|
+
|
|
530
|
+
Each mock spec can target REST, gRPC, or Kafka protocols. Partial failures are handled
|
|
531
|
+
gracefully — if some mocks fail, the others still succeed and are reported.
|
|
532
|
+
|
|
533
|
+
Use this tool when you need to mock 2+ downstream services simultaneously (e.g., for a
|
|
534
|
+
local-dev workflow with multiple dependencies).
|
|
535
|
+
|
|
536
|
+
${BATCH_MOCK_PROTOCOL_EXAMPLES}`,
|
|
537
|
+
inputSchema: batchMockSchema,
|
|
538
|
+
}, async (params) => {
|
|
539
|
+
const result = await executeBatchMockGeneration(params);
|
|
540
|
+
AnalyticsService.pushTestGenerationToolEvent(TOOL_NAME, result, params).catch(() => {
|
|
541
|
+
// Silently ignore analytics errors
|
|
542
|
+
});
|
|
543
|
+
return result;
|
|
544
|
+
});
|
|
545
|
+
}
|
|
@@ -5,7 +5,7 @@ import { ScenarioGenerationService } from "../../services/ScenarioGenerationServ
|
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import { baseSchema, AUTH_PLACEHOLDER_TOKEN, HttpMethod } from "../../types/TestTypes.js";
|
|
7
7
|
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveAuthFromWorkspace, getWorkspaceDefaultQueryParams, mergeQueryParamsJson } from "../../utils/workspaceAuth.js";
|
|
9
9
|
import yaml from "js-yaml";
|
|
10
10
|
import { logger } from "../../utils/logger.js";
|
|
11
11
|
import { guardScenarioApproved } from "./planGuard.js";
|
|
@@ -81,7 +81,9 @@ If you provide nested objects, the service JSON-stringifies them as a fallback,
|
|
|
81
81
|
|
|
82
82
|
Use this for GET request filters, search terms, pagination, sorting — any parameter that belongs in the URL query string.
|
|
83
83
|
|
|
84
|
-
CRITICAL: For search/filter/list endpoints (e.g., GET /products/search?q=bear&limit=10), parameters MUST go here, NOT in requestBody. GET request bodies are non-standard and may be ignored or rejected by servers and frameworks
|
|
84
|
+
CRITICAL: For search/filter/list endpoints (e.g., GET /products/search?q=bear&limit=10), parameters MUST go here, NOT in requestBody. GET request bodies are non-standard and may be ignored or rejected by servers and frameworks.
|
|
85
|
+
|
|
86
|
+
Workspace-configured api.defaultQueryParams (if set) are merged into every step automatically — no need to repeat them here. An explicit value for the same key in a step overrides the workspace default for that step only.`),
|
|
85
87
|
responseBody: z
|
|
86
88
|
.string()
|
|
87
89
|
.optional()
|
|
@@ -239,26 +241,11 @@ Call \`skyramp_integration_test_generation\` with the returned \`scenarioFile\`
|
|
|
239
241
|
if (params.authHeader === undefined) {
|
|
240
242
|
try {
|
|
241
243
|
const repoPath = params.outputDir || process.cwd();
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (!resolvedHeader && wsAuth.authScheme !== undefined) {
|
|
248
|
-
resolvedHeader = "Authorization";
|
|
249
|
-
}
|
|
250
|
-
if (resolvedHeader && wsAuth.authType !== WorkspaceAuthType.None) {
|
|
251
|
-
logger.info("Auth header was empty — resolved from workspace config", {
|
|
252
|
-
authHeader: resolvedHeader,
|
|
253
|
-
authType: wsAuth.authType,
|
|
254
|
-
});
|
|
255
|
-
params.authHeader = resolvedHeader;
|
|
256
|
-
// Scheme only applies to Authorization headers; use header name (not authType) to detect.
|
|
257
|
-
if (isAuthorizationHeaderName(resolvedHeader)) {
|
|
258
|
-
// Prefer explicit authScheme from workspace (for custom schemes like "Ghost", "Hawk").
|
|
259
|
-
// Fall back to getAuthScheme() for standard types (bearer→Bearer, token→Token).
|
|
260
|
-
// Use ?? to preserve intentionally empty authScheme ("" = raw token, no prefix).
|
|
261
|
-
params.authScheme = params.authScheme ?? wsAuth.authScheme ?? getAuthScheme(wsAuth.authType);
|
|
244
|
+
const resolved = await resolveAuthFromWorkspace(repoPath, params.authHeader, params.authScheme);
|
|
245
|
+
if (resolved) {
|
|
246
|
+
params.authHeader = resolved.authHeader;
|
|
247
|
+
if (resolved.authScheme !== undefined) {
|
|
248
|
+
params.authScheme = resolved.authScheme;
|
|
262
249
|
}
|
|
263
250
|
}
|
|
264
251
|
}
|
|
@@ -266,6 +253,19 @@ Call \`skyramp_integration_test_generation\` with the returned \`scenarioFile\`
|
|
|
266
253
|
logger.warning("Could not resolve auth from workspace config");
|
|
267
254
|
}
|
|
268
255
|
}
|
|
256
|
+
let defaultQueryParams;
|
|
257
|
+
try {
|
|
258
|
+
const repoPath = params.outputDir || process.cwd();
|
|
259
|
+
defaultQueryParams = await getWorkspaceDefaultQueryParams(repoPath);
|
|
260
|
+
if (defaultQueryParams) {
|
|
261
|
+
logger.info("Merged workspace defaultQueryParams into queryParams", {
|
|
262
|
+
keys: Object.keys(defaultQueryParams),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
logger.warning("Could not resolve default query params from workspace config");
|
|
268
|
+
}
|
|
269
269
|
// Separate try/catch so auth errors don't silently swallow schema population.
|
|
270
270
|
// Walk up from outputDir with a sync existsSync check — one stat per level,
|
|
271
271
|
// one read+parse only when found — instead of an async readWorkspaceConfigRaw
|
|
@@ -410,7 +410,9 @@ Call \`skyramp_integration_test_generation\` with the returned \`scenarioFile\`
|
|
|
410
410
|
method: step.method,
|
|
411
411
|
path: step.path,
|
|
412
412
|
requestBody: step.requestBody,
|
|
413
|
-
queryParams:
|
|
413
|
+
queryParams: defaultQueryParams
|
|
414
|
+
? mergeQueryParamsJson(step.queryParams, defaultQueryParams)
|
|
415
|
+
: step.queryParams,
|
|
414
416
|
responseBody: step.responseBody,
|
|
415
417
|
statusCode: step.statusCode,
|
|
416
418
|
responseHeaders: step.responseHeaders,
|
|
@@ -367,8 +367,8 @@ const TOOL_NAME = TOOL_CONTRACT_TEST_GENERATION;
|
|
|
367
367
|
const MODES_SECTION = CONSUMER_MODE_ENABLED
|
|
368
368
|
? `**Modes:**
|
|
369
369
|
- Default (no mode set): both \`providerMode\` and \`consumerMode\` default to false. This generates both provider and consumer contract tests — equivalent to setting both modes to true.
|
|
370
|
-
- \`providerMode\`: set to true ONLY if the user explicitly requests a provider-side contract test. Optionally specify \`providerOutput\` for the output file path.
|
|
371
|
-
- \`consumerMode\`: set to true ONLY if the user explicitly requests a consumer-side contract test. Optionally specify \`consumerOutput\` for the output file path.
|
|
370
|
+
- \`providerMode\`: set to true ONLY if the user explicitly requests a provider-side contract test. Optionally specify \`providerOutput\` for the output file path. Provider tests hit the real endpoint — no mocks.
|
|
371
|
+
- \`consumerMode\`: set to true ONLY if the user explicitly requests a consumer-side contract test. Optionally specify \`consumerOutput\` for the output file path. Consumer tests include mocks wired inline (\`client.apply_mock(mock)\` in the test function) — no separate \`skyramp_enrich_test_with_mocks\` call needed.
|
|
372
372
|
- Both \`providerMode\` and \`consumerMode\` can be enabled simultaneously to generate both sides.`
|
|
373
373
|
: `**Mode:**
|
|
374
374
|
- Only provider-side contract tests are generated. Pass \`providerMode: true\` (or omit it — the tool always behaves as provider-only). Optionally specify \`providerOutput\` for the output file path.`;
|
|
@@ -8,6 +8,6 @@ export declare class E2ETestService extends TestGenerationService {
|
|
|
8
8
|
responseData?: string;
|
|
9
9
|
playwrightInput?: string;
|
|
10
10
|
}): any;
|
|
11
|
-
protected handleApiAnalysis(
|
|
11
|
+
protected handleApiAnalysis(_params: BaseTestParams): Promise<CallToolResult | null>;
|
|
12
12
|
}
|
|
13
13
|
export declare function registerE2ETestTool(server: McpServer): void;
|
|
@@ -13,6 +13,6 @@ export declare class LoadTestService extends TestGenerationService {
|
|
|
13
13
|
loadRampupInterval?: string;
|
|
14
14
|
loadTargetRPS?: string;
|
|
15
15
|
}): any;
|
|
16
|
-
protected handleApiAnalysis(
|
|
16
|
+
protected handleApiAnalysis(_params: BaseTestParams): Promise<CallToolResult | null>;
|
|
17
17
|
}
|
|
18
18
|
export declare function registerLoadTestTool(server: McpServer): void;
|