package multitable import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "git.iwork-ai.com/xdc/iqudo-top1/internal/config" "git.iwork-ai.com/xdc/iqudo-top1/internal/model" ) func TestUpsertCreatesWhenSourceIDDoesNotExist(t *testing.T) { var gotData map[string]interface{} server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: if r.URL.Path == "/tables/46/columns" { _ = json.NewEncoder(w).Encode([]map[string]interface{}{{"id": 1, "name": "来源ID"}}) return } if r.URL.Query().Get("filters") == "" { t.Fatal("missing source ID filter") } var filters []map[string]interface{} if err := json.Unmarshal([]byte(r.URL.Query().Get("filters")), &filters); err != nil || filters[0]["col"] != "1" { t.Fatalf("filters = %s, want column ID 1", r.URL.Query().Get("filters")) } _ = json.NewEncoder(w).Encode(map[string]interface{}{"items": []interface{}{}}) case http.MethodPost: var body struct { Data map[string]interface{} `json:"data"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { t.Fatal(err) } gotData = body.Data w.WriteHeader(http.StatusCreated) default: t.Fatalf("unexpected method %s", r.Method) } })) defer server.Close() err := NewClient(server.URL, "test-key", time.Second).Upsert(context.Background(), 46, "42", map[string]interface{}{"来源ID": "42", "名称": "宠物医生问诊问药"}) if err != nil { t.Fatalf("Upsert() error = %v", err) } if gotData["来源ID"] != "42" { t.Fatalf("created data = %#v", gotData) } } func TestUpsertUpdatesExistingRecord(t *testing.T) { updated := false server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: if r.URL.Path == "/tables/46/columns" { _ = json.NewEncoder(w).Encode([]map[string]interface{}{{"id": 1, "name": "来源ID"}}) return } _ = json.NewEncoder(w).Encode(map[string]interface{}{"items": []map[string]interface{}{{"id": 99}}}) case http.MethodPut: if r.URL.Path != "/tables/46/records/99" { t.Fatalf("update path = %s", r.URL.Path) } updated = true w.WriteHeader(http.StatusOK) default: t.Fatalf("unexpected method %s", r.Method) } })) defer server.Close() if err := NewClient(server.URL, "test-key", time.Second).Upsert(context.Background(), 46, "42", map[string]interface{}{"来源ID": "42"}); err != nil { t.Fatalf("Upsert() error = %v", err) } if !updated { t.Fatal("existing record was not updated") } } func TestDeletedScenarioFieldCreatesArchivedProjectionFromAuditPayload(t *testing.T) { var created map[string]interface{} server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet && r.URL.Path == "/tables/47/columns" { _ = json.NewEncoder(w).Encode([]map[string]interface{}{{"id": 1, "name": "来源ID"}}) return } if r.Method == http.MethodGet { _ = json.NewEncoder(w).Encode(map[string]interface{}{"items": []interface{}{}}) return } if r.Method == http.MethodPost { var body struct { Data map[string]interface{} `json:"data"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { t.Fatal(err) } created = body.Data w.WriteHeader(http.StatusCreated) return } t.Fatalf("unexpected %s %s", r.Method, r.URL.Path) })) defer server.Close() payload := []byte(`{"scenario_id":9,"field_key":"pet_name","field_name":"宠物姓名","source_path":"pet.name","field_type":"text","required":true,"options":[],"validation":{},"sort_order":1}`) projector := NewProjector(nil, NewClient(server.URL, "test-key", time.Second), config.MultiTableTables{ScenarioFields: 47}) event := model.MultiTableOutbox{Base: model.Base{ID: 3, UpdatedAt: time.Now()}, TenantID: 2, ResourceID: 12, Action: "delete", Payload: payload} if err := projector.deletedScenarioField(context.Background(), event); err != nil { t.Fatalf("deletedScenarioField() error = %v", err) } if created["同步状态"] != "已归档" || created["字段标识"] != "pet_name" || created["外部数据路径"] != "pet.name" || created["是否必填"] != "是" { t.Fatalf("created projection = %#v", created) } }