package rpc import ( "context" "os" "strings" "testing" "time" agentpb "git.ipao.vip/rogee/go-sip/gen/agent" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func TestApplySIPOnlyAllowsActivatedSIPService(t *testing.T) { now := time.Date(2026, 10, 3, 9, 0, 0, 0, time.UTC) const id = "c046b893-8628-4589-ae50-619d049248a6" attempts := 0 apply := func(_ context.Context, _ []byte) (map[string]int64, error) { attempts++ return map[string]int64{"trunk-mock": 8}, nil } server := NewServer(ServerOptions{ Mode: "sip-only", Now: func() time.Time { return now }, Status: &agentpb.AgentStatus{AgentId: "agent-1", CellId: "cell-1", BootId: "boot-1"}, ApplySIP: apply, }) _, err := server.ActivateAgent(context.Background(), &agentpb.ActivateAgentRequest{ Meta: testMeta("activate-sip", "", 0), Binding: &agentpb.AgentBinding{AgentId: "agent-1", CellId: "cell-1", ExpectedBootId: "boot-1", DispatcherEpoch: "epoch-1", SessionGeneration: 1, DispatcherId: id}, ActivationOperationId: "activate-sip", }) if err != nil { t.Fatal(err) } body, err := os.ReadFile("../../contracts/schema/examples/config-read-sip.json") if err != nil { t.Fatal(err) } body = []byte(strings.ReplaceAll(string(body), `"transport":null`, `"transport":"udp"`)) body = []byte(strings.ReplaceAll(string(body), `"auth_mode":null`, `"auth_mode":"ip"`)) body = []byte(strings.ReplaceAll(string(body), `"registration_required":null`, `"registration_required":false`)) body = []byte(strings.ReplaceAll(string(body), `"server_host":"sip.example.invalid"`, `"server_host":"127.0.0.1"`)) req := &agentpb.ApplySIPRequest{Meta: testMeta("apply-sip", "apply-sip", 1), ApprovedSnapshotJson: body} if _, err := server.ApplySIP(context.Background(), req); err != nil { t.Fatal(err) } if attempts != 1 { t.Fatalf("apply attempts = %d", attempts) } for name, changed := range map[string][]byte{ "unsupported digest": []byte(strings.Replace(string(body), `"auth_mode":"ip"`, `"auth_mode":"digest"`, 1)), "unsupported registration": []byte(strings.Replace(string(body), `"registration_required":false`, `"registration_required":true`, 1)), "unsupported transport": []byte(strings.Replace(string(body), `"transport":"udp"`, `"transport":"tcp"`, 1)), "wrong dispatcher": []byte(strings.Replace(string(body), id, "66b3c533-11ec-4afb-b6bd-d2941fa7513d", 1)), } { t.Run(name, func(t *testing.T) { if _, err := server.ApplySIP(context.Background(), &agentpb.ApplySIPRequest{Meta: req.Meta, ApprovedSnapshotJson: changed}); status.Code(err) != codes.InvalidArgument || attempts != 1 { t.Fatalf("invalid SIP reached native loader: attempts=%d err=%v", attempts, err) } }) } server.applySIP = func(context.Context, []byte) (map[string]int64, error) { return map[string]int64{"trunk-mock": 7}, nil } if _, err := server.ApplySIP(context.Background(), req); status.Code(err) != codes.Unavailable { t.Fatalf("stale native load was reported as success: %v", err) } server.mode = "mock" if _, err := server.ApplySIP(context.Background(), req); status.Code(err) != codes.FailedPrecondition || attempts != 1 { t.Fatalf("mock boundary allowed real SIP apply: attempts=%d err=%v", attempts, err) } server.mode, server.applySIP = "nonprod-real", apply if _, err := server.ApplySIP(context.Background(), req); err != nil || attempts != 2 { t.Fatalf("nonprod-real must observe native SIP through the same approved path: attempts=%d err=%v", attempts, err) } }