package main import ( "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "git.ipao.vip/rogee/go-sip/internal/configread" ) const testDispatcher = "c046b893-8628-4589-ae50-619d049248a6" func testDataDir(t *testing.T) string { t.Helper() root := t.TempDir() if err := os.Mkdir(filepath.Join(root, "tasks"), 0700); err != nil { t.Fatal(err) } for target, source := range map[string]string{ "sip.json": "config-read-sip.json", "providers.json": "config-read-providers.json", "quota.json": "config-read-quota.json", "tasks/task-full.json": "config-read-task-full.json", } { original, err := os.ReadFile(filepath.Join("..", "..", "..", "contracts", "local", "examples", source)) if err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, target), original, 0600); err != nil { t.Fatal(err) } } return root } func TestSaaSMockServesFormalReadContract(t *testing.T) { data, err := loadDataset(testDataDir(t), testDispatcher) if err != nil { t.Fatal(err) } server := httptest.NewServer(data.handler("test-only-secret")) defer server.Close() client, err := configread.NewClient(server.URL, testDispatcher, "test-only-secret", server.Client()) if err != nil { t.Fatal(err) } ctx := context.Background() sip, err := client.ReadSIP(ctx) if err != nil { t.Fatal(err) } providers, err := client.ReadProviders(ctx) if err != nil { t.Fatal(err) } tasks, cursor, err := client.ReadAllTasks(ctx) if err != nil || len(tasks) != 1 || tasks[0].TaskID != "task-full" || cursor == "" { t.Fatalf("formal task discovery: count=%d cursor=%q err=%v", len(tasks), cursor, err) } snapshot, err := client.ReadTask(ctx, "task-full", 1001, sip, providers) if err != nil || snapshot.Task.TaskID != "task-full" || snapshot.Quota.TenantID != snapshot.Task.TenantID { t.Fatalf("formal task/quota read: task=%q quota=%d err=%v", snapshot.Task.TaskID, snapshot.Quota.TenantID, err) } if _, err := client.ReadTask(ctx, "absent", 1001, sip, providers); err == nil { t.Fatal("unknown task must fail closed") } wrong, err := configread.NewClient(server.URL, testDispatcher, "wrong-secret", server.Client()) if err != nil { t.Fatal(err) } if _, err := wrong.ReadSIP(ctx); err == nil || !strings.Contains(err.Error(), "HTTP 403") { t.Fatalf("wrong dispatcher identity should be rejected: %v", err) } request, err := http.NewRequest(http.MethodPost, server.URL+"/internal/v1/dispatcher/sip", nil) if err != nil { t.Fatal(err) } request.Header.Set("X-DISPATCHER-id", testDispatcher) request.Header.Set("X-DISPATCHER-SECRET-KEY", "test-only-secret") response, err := server.Client().Do(request) if err != nil { t.Fatal(err) } defer response.Body.Close() if response.StatusCode != http.StatusMethodNotAllowed { t.Fatalf("configuration must stay read-only: HTTP %d", response.StatusCode) } } func TestSaaSMockDiscoversSixDistinctTasks(t *testing.T) { root := testDataDir(t) original, err := os.ReadFile(filepath.Join(root, "tasks", "task-full.json")) if err != nil { t.Fatal(err) } for n := 2; n <= 6; n++ { var task map[string]any if err := json.Unmarshal(original, &task); err != nil { t.Fatal(err) } id := fmt.Sprintf("task-%d", n) task["task_id"] = id body, err := json.Marshal(task) if err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "tasks", id+".json"), body, 0600); err != nil { t.Fatal(err) } } data, err := loadDataset(root, testDispatcher) if err != nil { t.Fatal(err) } server := httptest.NewServer(data.handler("test-only-secret")) defer server.Close() client, err := configread.NewClient(server.URL, testDispatcher, "test-only-secret", server.Client()) if err != nil { t.Fatal(err) } tasks, cursor, err := client.ReadAllTasks(context.Background()) if err != nil || len(tasks) != 6 || cursor != "mock-complete" { t.Fatalf("six independent formal tasks were not discovered: count=%d cursor=%q err=%v", len(tasks), cursor, err) } } func TestSaaSMockRejectsInvalidOwnerAtStartup(t *testing.T) { root := testDataDir(t) path := filepath.Join(root, "tasks", "task-full.json") original, err := os.ReadFile(path) if err != nil { t.Fatal(err) } bad := strings.Replace(string(original), testDispatcher, "00000000-0000-4000-8000-000000000000", 1) if err := os.WriteFile(path, []byte(bad), 0600); err != nil { t.Fatal(err) } if _, err := loadDataset(root, testDispatcher); err == nil { t.Fatal("a task assigned to another dispatcher cannot be served") } }