feat: add SSE port, protocol config, and port mapping support#3973
feat: add SSE port, protocol config, and port mapping support#3973officialasishkumar wants to merge 6 commits intofix/record-long-lived-connfrom
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Incremental Review (84b3d24 → 7bf10bb)The latest commit (
All previous fixes remain in place from commit
Files Reviewed (1 file in this increment)
Reviewed by claude-4.5-opus-20251124 · 95,132 tokens |
There was a problem hiding this comment.
Pull request overview
Adds protocol-aware port configuration (including SSE), plus a higher-priority port-mapping override mechanism, so replay/rerecord can more flexibly resolve the correct target host/port for different protocols and environments.
Changes:
- Introduces
ssePortand atest.protocolmap for per-protocol port overrides in config (and defaults). - Extends
replaceWithto support port-to-port mappings and wires this through replay simulation toResolveTestTarget. - Adds SSE request detection and uses it to select the correct port during replay/rerecord.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
config/config.go |
Adds SSEPort, protocol map config, and replaceWith.port structure. |
config/default.go |
Updates default config YAML to include ssePort and protocol port sections. |
cli/provider/cmd.go |
Adds --sse-port flag and flag normalization/validation wiring. |
pkg/service/replay/hooks.go |
Computes effective per-test-case config port (HTTP vs SSE vs gRPC) and merges URL replacements + port mappings. |
pkg/util.go |
Adds PortMappings to simulation config, introduces IsSSERequest, and updates ResolveTestTarget precedence to include port mappings. |
pkg/http2.go |
Passes port mappings through gRPC simulation target resolution. |
pkg/service/orchestrator/rerecord.go |
Applies ReRecord.SSEPort when rerecording SSE testcases. |
pkg/util_test.go |
Updates tests for ResolveTestTarget signature change. |
Comments suppressed due to low confidence (3)
pkg/util.go:2812
replacementHasPortdetection can be wrong when a replacement value is a full URL (or contains a path/query). After stripping only the scheme,hasExplicitPortis called on strings that may still include/..., causing explicit ports likehttp://localhost:3000/apito be treated as “no port” and then overridden by config/port mappings. Consider parsingreplacementas a URL whenisHTTP(or extracting the host portion before callinghasExplicitPort).
// Check if the replacement value explicitly defines a port.
checkStr := replacement
if isHTTP {
if strings.HasPrefix(replacement, "http://") {
checkStr = strings.TrimPrefix(replacement, "http://")
} else if strings.HasPrefix(replacement, "https://") {
checkStr = strings.TrimPrefix(replacement, "https://")
}
}
if hasExplicitPort(checkStr) {
replacementHasPort = true
}
pkg/util.go:2820
- URL replacement selection is based on iterating over a map. If multiple
urlReplacementskeys can match the same target, the applied replacement becomes nondeterministic because Go map iteration order is randomized. Consider making the match deterministic (for example: sort keys, prefer longest match, or define an explicit priority order).
// Step 1: Check replaceWith URL
if len(urlReplacements) > 0 {
for substr, replacement := range urlReplacements {
if strings.Contains(finalTarget, substr) {
replacementMatched = true
finalTarget = strings.Replace(finalTarget, substr, replacement, 1)
// Check if the replacement value explicitly defines a port.
checkStr := replacement
if isHTTP {
if strings.HasPrefix(replacement, "http://") {
checkStr = strings.TrimPrefix(replacement, "http://")
} else if strings.HasPrefix(replacement, "https://") {
checkStr = strings.TrimPrefix(replacement, "https://")
}
}
if hasExplicitPort(checkStr) {
replacementHasPort = true
}
logger.Debug("Applied replaceWith substitution",
zap.String("find", substr),
zap.String("replace", replacement),
zap.String("result_target", finalTarget),
zap.Bool("replacement_has_port", replacementHasPort))
break
}
pkg/util_test.go:1202
ResolveTestTargetnow supportsportMappings, but there are no test cases exercising the new precedence rules (URL replacement with explicit port + port mapping override, mapping-only override, etc.). Adding a few table-driven cases here would protect the new behavior and prevent regressions.
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ResolveTestTarget(tt.originalTarget, tt.urlReplacements, nil, tt.configHost, tt.appPort, tt.configPort, tt.isHTTP, logger)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expectedTarget, got)
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Introduce ssePort (top-level + CLI flag), extensible protocol-level port overrides (map[string]ProtocolSettings), and port-to-port mapping in replaceWith for fine-grained replay target resolution. Priority (lowest → highest): appPort → port/grpcPort/ssePort → protocol.<proto>.port → replaceWith URL → replaceWith port mapping. Signed-off-by: Asish Kumar <[email protected]>
- Pass --sse-port 8047 to test SSE protocol routing - Add port mapping test step: disables ping server (SKIP_PING_SERVER=1) and verifies replaceWith port mapping 8050→8000 works correctly Signed-off-by: Asish Kumar <[email protected]>
Signed-off-by: Asish Kumar <[email protected]>
167b81b to
a163217
Compare
Signed-off-by: Asish Kumar <[email protected]>
a163217 to
b896b5e
Compare
🚀 Keploy Performance Test ResultsMulti-Run Validation: Tests run 3 times, pipeline fails only if 2+ runs show regression.
Thresholds: P50 < 5ms, P90 < 15ms, P99 < 70ms, RPS >= 100 (±1% tolerance), Error Rate < 1% ✅ Result: PASSED - Only 1 out of 3 runs failed (threshold: 2) P50, P90, and P99 percentiles naturally filter out outliers |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🚀 Keploy Performance Test ResultsMulti-Run Validation: Tests run 3 times, pipeline fails only if 2+ runs show regression.
Thresholds: P50 < 5ms, P90 < 15ms, P99 < 70ms, RPS >= 100 (±1% tolerance), Error Rate < 1% ✅ Result: PASSED - Only 1 out of 3 runs failed (threshold: 2) P50, P90, and P99 percentiles naturally filter out outliers |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <[email protected]> Signed-off-by: Asish Kumar <[email protected]>
Describe the changes that are made
This pull request introduces enhanced support for protocol-specific port configuration and flexible port replacement logic, especially for Server-Sent Events (SSE) and other protocols. The changes allow users to specify ports at both the top-level and per-protocol level, and to override ports dynamically via configuration. The port replacement mechanism is now more robust, supporting both URL-based and direct port mappings, with a clear precedence order. Additionally, utility functions and configuration structures have been updated to support these features.
Protocol and Port Configuration Enhancements:
SSEPortfields to theTestandReRecordstructs inconfig/config.go, and introduced aProtocolConfigmap for per-protocol port settings. The default configuration inconfig/default.gonow includes protocol-level ports for HTTP, SSE, and gRPC. [1] [2] [3]cli/provider/cmd.goto support the new--sse-portflag, including normalization and validation logic. [1] [2] [3]Flexible Port Replacement Logic:
ReplaceWithconfiguration to support both URL and port mappings, and implemented amergeReplaceWithhelper inpkg/service/replay/hooks.goto merge global and per-test-set replacements for both URLs and ports. [1] [2] [3]SimulationConfigstruct inpkg/util.gonow includes aPortMappingsfield, and all simulation and request preparation logic has been updated to use both URL replacements and port mappings. [1] [2] [3]Precedence and Port Resolution Improvements:
ResolveTestTargetfunction inpkg/util.gohas been overhauled to implement a clear precedence order: AppPort → ConfigPort (including protocol-specific ports) → URL replacements (with explicit port) → port mappings (highest priority). This ensures that the most specific port configuration is always used. [1] [2] [3] [4] [5] [6]SSE Request Detection and Handling:
IsSSERequestutility function topkg/util.goto detect SSE requests based on headers, and updated replay/orchestrator logic to use the correct port for SSE test cases. [1] [2]Test and Maintenance Updates:
pkg/util_test.goto reflect the newResolveTestTargetsignature and logic. [1] [2]These changes provide much greater flexibility and correctness in how ports are configured and overridden for different protocols and test scenarios.
Links & References
Closes: #3974
🔗 Related PRs
🐞 Related Issues
📄 Related Documents
What type of PR is this? (check all applicable)
Added e2e test pipeline?
Added comments for hard-to-understand areas?
Added to documentation?
Are there any sample code or steps to test the changes?
Self Review done?
Any relevant screenshots, recordings or logs?
🧠 Semantics for PR Title & Branch Name
Please ensure your PR title and branch name follow the Keploy semantics:
📌 PR Semantics Guide
📌 Branch Semantics Guide
Examples:
fix: patch MongoDB document update bugfeat/#1-login-flow(You may skip mentioning the issue number in the branch name if the change is small and the PR description clearly explains it.)Additional checklist: