feat: simplify SOP to immediate-effect configuration

This commit is contained in:
Eric 1549169735@qq.com
2026-08-18 16:27:02 +08:00
parent c5ab886b70
commit 8de48fb05e
150 changed files with 6764 additions and 1626 deletions

View File

@@ -0,0 +1,120 @@
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)
}
}