package main import ( "bytes" "context" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" agentpb "git.ipao.vip/rogee/go-sip/gen/agent" "git.ipao.vip/rogee/go-sip/internal/ai" "git.ipao.vip/rogee/go-sip/internal/config" ) type isolatedAgentRecordingClient struct { agentpb.AgentControlServiceClient } func currentAgentSetupFixture(t *testing.T) (config.AgentEnvironment, approvedMockScenario) { t.Helper() root := t.TempDir() if err := os.Chmod(root, 0700); err != nil { t.Fatal(err) } settings := config.AgentEnvironment{ AgentID: "agent-mock", CellID: "cell-mock", DispatcherID: "11111111-1111-4111-8111-111111111111", Listen: "127.0.0.1:0", SessionPath: filepath.Join(root, "session.json"), RecoveryRoot: root, DispatcherEndpoint: "127.0.0.1:39443", DispatcherServerName: "dispatcher.local", CAFile: filepath.Join(root, "ca.pem"), CertFile: filepath.Join(root, "agent.pem"), KeyFile: filepath.Join(root, "agent.key"), PeerFingerprints: map[string]struct{}{strings.Repeat("a", 64): {}}, } scenario := approvedMockScenario{ InboundPCM16: bytes.Repeat([]byte{1, 0}, 1600), Script: ai.ApprovedMockScript{Turns: []ai.ApprovedMockTurn{{Transcript: "synthetic ASR fixture"}}}, MaxWAVBytes: 4096, ExpectedRecording: true, Outcome: "answered", ReasonMessage: "isolated Mock answered", } return settings, scenario } func TestNewCurrentAgentServerBindsMockCallsToOneSessionAndRecoveryRoot(t *testing.T) { settings, scenario := currentAgentSetupFixture(t) server, err := newCurrentAgentServer(context.Background(), settings, scenario, map[string]int64{"trunk-mock": 8}, &isolatedAgentRecordingClient{}) if err != nil || server == nil { t.Fatalf("valid isolated Agent could not be assembled: %v", err) } if _, err := os.Stat(settings.SessionPath); !os.IsNotExist(err) { t.Fatalf("server assembly opened durable session before activation: %v", err) } } func TestNewCurrentAgentServerRefusesUnsafeAdaptersBeforeResources(t *testing.T) { settings, scenario := currentAgentSetupFixture(t) for _, tc := range []struct { name string change func(*config.AgentEnvironment, *approvedMockScenario, *map[string]int64, *agentpb.AgentControlServiceClient) }{ {"missing Agent identity", func(c *config.AgentEnvironment, _ *approvedMockScenario, _ *map[string]int64, _ *agentpb.AgentControlServiceClient) { c.AgentID = "" }}, {"missing authorized Dispatcher", func(c *config.AgentEnvironment, _ *approvedMockScenario, _ *map[string]int64, _ *agentpb.AgentControlServiceClient) { c.DispatcherID = "" }}, {"missing SIP evidence", func(_ *config.AgentEnvironment, _ *approvedMockScenario, sip *map[string]int64, _ *agentpb.AgentControlServiceClient) { *sip = nil }}, {"unknown SIP revision", func(_ *config.AgentEnvironment, _ *approvedMockScenario, sip *map[string]int64, _ *agentpb.AgentControlServiceClient) { (*sip)["trunk-mock"] = 0 }}, {"missing recovery", func(c *config.AgentEnvironment, _ *approvedMockScenario, _ *map[string]int64, _ *agentpb.AgentControlServiceClient) { c.RecoveryRoot = filepath.Join(t.TempDir(), "missing") }}, {"missing scenario", func(_ *config.AgentEnvironment, s *approvedMockScenario, _ *map[string]int64, _ *agentpb.AgentControlServiceClient) { s.MaxWAVBytes = 0 }}, {"missing Dispatcher transport", func(_ *config.AgentEnvironment, _ *approvedMockScenario, _ *map[string]int64, client *agentpb.AgentControlServiceClient) { *client = nil }}, {"typed-nil Dispatcher transport", func(_ *config.AgentEnvironment, _ *approvedMockScenario, _ *map[string]int64, client *agentpb.AgentControlServiceClient) { var typed *isolatedAgentRecordingClient *client = typed }}, } { t.Run(tc.name, func(t *testing.T) { cfg, media := settings, scenario loaded := map[string]int64{"trunk-mock": 8} var client agentpb.AgentControlServiceClient = &isolatedAgentRecordingClient{} tc.change(&cfg, &media, &loaded, &client) if server, err := newCurrentAgentServer(context.Background(), cfg, media, loaded, client); err == nil || server != nil { t.Fatalf("unsafe current Agent assembly was accepted: %v", err) } if _, err := os.Stat(settings.SessionPath); !os.IsNotExist(err) { t.Fatalf("rejected Agent assembly wrote durable session: %v", err) } }) } } func TestLocalMockHTTPClientRefusesExternalAndRedirectedTargets(t *testing.T) { client := localMockHTTPClient() if response, err := client.Get("https://oss.example.invalid/approved"); err == nil || response != nil || !strings.Contains(err.Error(), "not local") { t.Fatalf("Mock uploader contacted an external target: %v", err) } local := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/redirect" { http.Redirect(w, r, "https://oss.example.invalid/approved", http.StatusFound) return } w.WriteHeader(http.StatusOK) })) defer local.Close() response, err := client.Get(local.URL + "/ok") if err != nil || response.StatusCode != http.StatusOK { t.Fatalf("local Mock endpoint was refused: response=%v err=%v", response, err) } _ = response.Body.Close() response, err = client.Get(local.URL + "/redirect") if err != nil || response.StatusCode != http.StatusFound { t.Fatalf("Mock uploader followed an external redirect: response=%v err=%v", response, err) } _ = response.Body.Close() }