package config import ( "os" "path/filepath" "strings" "testing" ) func setAgentEnvironment(t *testing.T) string { t.Helper() root := t.TempDir() state := filepath.Join(root, "session.json") for name, value := range map[string]string{ "AGENT_ID": "agent-mock", "CELL_ID": "cell-mock", "AGENT_GRPC_LISTEN": "127.0.0.1:0", "AGENT_SESSION_PATH": state, "AGENT_RECOVERY_ROOT": filepath.Join(root, "recovery"), "DISPATCHER_ID": "11111111-1111-4111-8111-111111111111", "DISPATCHER_GRPC_ENDPOINT": "127.0.0.1:39443", "DISPATCHER_GRPC_SERVER_NAME": "dispatcher.local", "MTLS_CA_FILE": filepath.Join(root, "ca.pem"), "MTLS_CERT_FILE": filepath.Join(root, "agent.pem"), "MTLS_KEY_FILE": filepath.Join(root, "agent.key"), "MTLS_PEER_CERT_FINGERPRINTS": strings.Repeat("a", 64), "AGENT_MOCK_SCENARIO_FILE": filepath.Join(root, "scenario.json"), "AGENT_MOCK_APPLIED_SIP_FILE": filepath.Join(root, "applied-sip.json"), } { t.Setenv(name, value) } return state } func TestLoadAgentEnvironmentRefusesNonMockBeforeResources(t *testing.T) { for _, mode := range []string{"real", "mixed", ""} { t.Run(mode, func(t *testing.T) { state := setAgentEnvironment(t) if _, err := LoadAgentEnvironment(mode); err == nil || !strings.Contains(err.Error(), "Mock") { t.Fatalf("unapproved Agent mode was admitted: %v", err) } if _, err := os.Stat(state); !os.IsNotExist(err) { t.Fatalf("mode refusal opened Agent state: %v", err) } }) } } func TestLoadSIPOnlyAgentEnvironmentDoesNotRequireMockCalls(t *testing.T) { setAgentEnvironment(t) t.Setenv("AGENT_MOCK_SCENARIO_FILE", "") t.Setenv("AGENT_MOCK_APPLIED_SIP_FILE", "") t.Setenv("DISPATCHER_GRPC_ENDPOINT", "") t.Setenv("DISPATCHER_GRPC_SERVER_NAME", "") for name, value := range map[string]string{ "ASTERISK_CONFIG_DIR": "/tmp/asterisk-config", "ASTERISK_BIN": "/tmp/asterisk", "ASTERISK_LIBRARY_DIR": "/tmp/asterisk-libraries", } { t.Setenv(name, value) } settings, err := LoadAgentEnvironment("sip-only") if err != nil || settings.AsteriskConfigDir != "/tmp/asterisk-config" || settings.MockScenarioFile != "" { t.Fatalf("SIP-only Agent requires real native paths, not Mock fixtures: %+v %v", settings, err) } } func TestLoadNonprodRealAgentRequiresNativeCallAndEvidenceSettings(t *testing.T) { state := setAgentEnvironment(t) t.Setenv("AGENT_MOCK_SCENARIO_FILE", "") t.Setenv("AGENT_MOCK_APPLIED_SIP_FILE", "") for name, value := range map[string]string{ "ASTERISK_CONFIG_DIR": "/tmp/asterisk-config", "ASTERISK_BIN": "/tmp/asterisk", "ASTERISK_LIBRARY_DIR": "/tmp/asterisk-libraries", "AGENT_EVIDENCE_ROOT": "/tmp/nonprod-call-evidence", "AGENT_OSS_ALLOWED_HOST": "test.oss-cn-beijing.aliyuncs.com", } { t.Setenv(name, value) } settings, err := LoadAgentEnvironment("nonprod-real") if err != nil || settings.AsteriskConfigDir == "" || settings.DispatcherEndpoint == "" || settings.EvidenceRoot != "/tmp/nonprod-call-evidence" || settings.OSSAllowedHost != "test.oss-cn-beijing.aliyuncs.com" || settings.MockScenarioFile != "" { t.Fatalf("nonproduction real mode must use explicit native, capture and OSS settings: %+v %v", settings, err) } if _, err := os.Stat(state); !os.IsNotExist(err) { t.Fatalf("configuration inspection opened durable session: %v", err) } for _, name := range []string{"ASTERISK_CONFIG_DIR", "ASTERISK_BIN", "ASTERISK_LIBRARY_DIR", "AGENT_EVIDENCE_ROOT", "AGENT_OSS_ALLOWED_HOST", "DISPATCHER_GRPC_ENDPOINT", "DISPATCHER_GRPC_SERVER_NAME"} { t.Run(name, func(t *testing.T) { t.Setenv(name, "") if _, err := LoadAgentEnvironment("nonprod-real"); err == nil || !strings.Contains(err.Error(), name) { t.Fatalf("missing real-call setting must block startup: %v", err) } t.Setenv(name, map[string]string{ "ASTERISK_CONFIG_DIR": "/tmp/asterisk-config", "ASTERISK_BIN": "/tmp/asterisk", "ASTERISK_LIBRARY_DIR": "/tmp/asterisk-libraries", "AGENT_EVIDENCE_ROOT": "/tmp/nonprod-call-evidence", "AGENT_OSS_ALLOWED_HOST": "test.oss-cn-beijing.aliyuncs.com", "DISPATCHER_GRPC_ENDPOINT": "127.0.0.1:39443", "DISPATCHER_GRPC_SERVER_NAME": "dispatcher.local", }[name]) }) } } func TestLoadAgentEnvironmentRequiresExplicitDeploymentValues(t *testing.T) { for _, name := range []string{ "AGENT_ID", "CELL_ID", "AGENT_GRPC_LISTEN", "AGENT_SESSION_PATH", "AGENT_RECOVERY_ROOT", "DISPATCHER_ID", "DISPATCHER_GRPC_ENDPOINT", "DISPATCHER_GRPC_SERVER_NAME", "MTLS_CA_FILE", "MTLS_CERT_FILE", "MTLS_KEY_FILE", "MTLS_PEER_CERT_FINGERPRINTS", "AGENT_MOCK_SCENARIO_FILE", "AGENT_MOCK_APPLIED_SIP_FILE", } { t.Run(name, func(t *testing.T) { setAgentEnvironment(t) t.Setenv(name, "") if _, err := LoadAgentEnvironment("mock"); err == nil || !strings.Contains(err.Error(), name) { t.Fatalf("missing current Agent setting silently used a legacy default: %v", err) } }) } } func TestLoadAgentEnvironmentRequiresLocalMockEndpointsAndDoesNotOpenFiles(t *testing.T) { state := setAgentEnvironment(t) settings, err := LoadAgentEnvironment("mock") if err != nil { t.Fatal(err) } if settings.AgentID != "agent-mock" || settings.CellID != "cell-mock" || settings.DispatcherID != "11111111-1111-4111-8111-111111111111" || settings.Listen != "127.0.0.1:0" || settings.SessionPath != state || settings.DispatcherEndpoint != "127.0.0.1:39443" { t.Fatal("explicit deployment identity or address was rewritten") } if _, err := os.Stat(state); !os.IsNotExist(err) { t.Fatalf("Agent preflight opened durable state: %v", err) } for _, tc := range []struct{ name, value string }{ {"AGENT_GRPC_LISTEN", "0.0.0.0:39444"}, {"DISPATCHER_ID", "unapproved-dispatcher"}, {"DISPATCHER_GRPC_ENDPOINT", "saas.example.invalid:443"}, } { t.Run(tc.name, func(t *testing.T) { setAgentEnvironment(t) t.Setenv(tc.name, tc.value) if _, err := LoadAgentEnvironment("mock"); err == nil || !strings.Contains(err.Error(), tc.name) || strings.Contains(err.Error(), tc.value) { t.Fatalf("external Mock address was accepted or leaked: %v", err) } }) } }