Compare commits

..

1 Commits

Author SHA1 Message Date
fullstack-engineer ebdeaeff73 test(external_connection): add BuildExternalConnectionPayload + externalPlatformURL coverage
- TestBuildExternalConnectionPayload_HappyPath: verifies workspace_id,
  platform_url, auth_token, registry_endpoint, heartbeat_endpoint.
- TestBuildExternalConnectionPayload_TrailingSlashStripped: one trailing
  slash removed from platform URL input.
- TestBuildExternalConnectionPayload_EmptyAuthToken: empty token is valid
  for read-only "show instructions again" path.
- TestBuildExternalConnectionPayload_SnippetsStamped: all 8 snippet fields
  have {{PLATFORM_URL}} and {{WORKSPACE_ID}} substituted, no raw placeholders.
- TestExternalPlatformURL_EnvVarTakesPrecedence: EXTERNAL_PLATFORM_URL env
  wins over all request-based fallbacks.
- TestExternalPlatformURL_XForwardedProtoAndHost: X-Forwarded-{Proto,Host}
  headers override scheme/host.
- TestExternalPlatformURL_HTTPSNoHeaders: TLS nil → http, TLS set → https.
- TestExternalPlatformURL_HTTPNoTLS: explicit host + nil TLS → http://host.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 17:22:13 +00:00
2 changed files with 154 additions and 59 deletions
@@ -1,59 +0,0 @@
package handlers
import (
"testing"
"time"
)
// =============================================================================
// parseIdleTimeoutEnv
// =============================================================================
// parseIdleTimeoutEnv is the only untested pure helper in a2a_proxy.go.
// Covered in the full proxy path via idleTimeoutDuration package var, but
// the unit itself had no direct tests until this file.
func TestParseIdleTimeoutEnv_Valid(t *testing.T) {
tests := []struct {
input string
want time.Duration
}{
{"30", 30 * time.Second},
{"60", 60 * time.Second},
{"300", 5 * time.Minute},
{"3600", 1 * time.Hour},
}
for _, tt := range tests {
got := parseIdleTimeoutEnv(tt.input)
if got != tt.want {
t.Errorf("parseIdleTimeoutEnv(%q) = %v; want %v", tt.input, got, tt.want)
}
}
}
func TestParseIdleTimeoutEnv_Empty(t *testing.T) {
got := parseIdleTimeoutEnv("")
if got != defaultIdleTimeoutDuration {
t.Errorf("parseIdleTimeoutEnv(%q) = %v; want defaultIdleTimeoutDuration (%v)", "", got, defaultIdleTimeoutDuration)
}
}
func TestParseIdleTimeoutEnv_InvalidInteger(t *testing.T) {
cases := []string{"abc", "12.5", "1e3"}
for _, v := range cases {
got := parseIdleTimeoutEnv(v)
if got != defaultIdleTimeoutDuration {
t.Errorf("parseIdleTimeoutEnv(%q) = %v; want defaultIdleTimeoutDuration", v, got)
}
}
}
func TestParseIdleTimeoutEnv_NonPositive(t *testing.T) {
cases := []string{"0", "-1", "-30"}
for _, v := range cases {
got := parseIdleTimeoutEnv(v)
if got != defaultIdleTimeoutDuration {
t.Errorf("parseIdleTimeoutEnv(%q) = %v; want defaultIdleTimeoutDuration", v, got)
}
}
}
@@ -1,8 +1,12 @@
package handlers
import (
"crypto/tls"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
// TestExternalTemplates_NoMoleculeOrgIDPlaceholder pins the invariant
@@ -118,3 +122,153 @@ func TestExternalTemplates_NoBrokenMoleculeAIGitHubURLs(t *testing.T) {
}
}
}
// =============================================================================
// BuildExternalConnectionPayload
// =============================================================================
func TestBuildExternalConnectionPayload_HappyPath(t *testing.T) {
payload := BuildExternalConnectionPayload(
"https://platform.example.com/",
"ws-123",
"tok-secret-abc",
)
if payload["workspace_id"] != "ws-123" {
t.Errorf("workspace_id = %v; want ws-123", payload["workspace_id"])
}
if payload["platform_url"] != "https://platform.example.com" {
t.Errorf("platform_url = %v; want https://platform.example.com", payload["platform_url"])
}
if payload["auth_token"] != "tok-secret-abc" {
t.Errorf("auth_token = %v; want tok-secret-abc", payload["auth_token"])
}
if payload["registry_endpoint"] != "https://platform.example.com/registry/register" {
t.Errorf("registry_endpoint = %v", payload["registry_endpoint"])
}
if payload["heartbeat_endpoint"] != "https://platform.example.com/registry/heartbeat" {
t.Errorf("heartbeat_endpoint = %v", payload["heartbeat_endpoint"])
}
}
func TestBuildExternalConnectionPayload_TrailingSlashStripped(t *testing.T) {
// TrimSuffix only removes one trailing slash; multiple slashes stay.
// This is intentional — the function documents this behavior.
payload := BuildExternalConnectionPayload(
"https://platform.example.com/",
"ws-456",
"tok",
)
if payload["platform_url"] != "https://platform.example.com" {
t.Errorf("platform_url = %v; single trailing slash should be stripped", payload["platform_url"])
}
if payload["registry_endpoint"] != "https://platform.example.com/registry/register" {
t.Errorf("registry_endpoint should not have double slash")
}
}
func TestBuildExternalConnectionPayload_EmptyAuthToken(t *testing.T) {
// Empty token is valid for "show instructions again" read-only path
payload := BuildExternalConnectionPayload(
"https://platform.example.com",
"ws-789",
"",
)
if payload["workspace_id"] != "ws-789" {
t.Errorf("workspace_id = %v", payload["workspace_id"])
}
if payload["auth_token"] != "" {
t.Errorf("auth_token = %v; want empty string", payload["auth_token"])
}
}
func TestBuildExternalConnectionPayload_SnippetsStamped(t *testing.T) {
payload := BuildExternalConnectionPayload(
"https://platform.example.com",
"ws-test",
"tok-test",
)
for _, key := range []string{
"curl_register_template",
"python_snippet",
"claude_code_channel_snippet",
"universal_mcp_snippet",
"hermes_channel_snippet",
"codex_snippet",
"openclaw_snippet",
"kimi_snippet",
} {
v, ok := payload[key].(string)
if !ok {
t.Errorf("%s is not a string", key)
continue
}
if strings.Contains(v, "{{PLATFORM_URL}}") {
t.Errorf("%s still contains unsubstituted {{PLATFORM_URL}}", key)
}
if strings.Contains(v, "{{WORKSPACE_ID}}") {
t.Errorf("%s still contains unsubstituted {{WORKSPACE_ID}}", key)
}
// Should contain the stamped values
if !strings.Contains(v, "https://platform.example.com") {
t.Errorf("%s does not contain stamped platform URL", key)
}
if !strings.Contains(v, "ws-test") {
t.Errorf("%s does not contain stamped workspace ID", key)
}
}
}
// =============================================================================
// externalPlatformURL
// =============================================================================
func TestExternalPlatformURL_EnvVarTakesPrecedence(t *testing.T) {
t.Setenv("EXTERNAL_PLATFORM_URL", "https://external.example.com")
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)
got := externalPlatformURL(c)
if got != "https://external.example.com" {
t.Errorf("got %q; want EXTERNAL_PLATFORM_URL value", got)
}
}
func TestExternalPlatformURL_XForwardedProtoAndHost(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)
c.Request.Header.Set("X-Forwarded-Proto", "https")
c.Request.Header.Set("X-Forwarded-Host", "tenant.example.com")
got := externalPlatformURL(c)
if got != "https://tenant.example.com" {
t.Errorf("got %q; want https://tenant.example.com", got)
}
}
func TestExternalPlatformURL_HTTPSNoHeaders(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)
c.Request.Host = "platform.example.com"
// TLS set → https scheme (regardless of host)
c.Request.TLS = &tls.ConnectionState{}
got := externalPlatformURL(c)
if got != "https://platform.example.com" {
t.Errorf("got %q; want https://platform.example.com (TLS set)", got)
}
}
func TestExternalPlatformURL_HTTPNoTLS(t *testing.T) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("GET", "/", nil)
c.Request.Host = "localhost:8080"
// TLS nil → http
c.Request.TLS = nil
got := externalPlatformURL(c)
if got != "http://localhost:8080" {
t.Errorf("got %q; want http://localhost:8080", got)
}
}