sync: 同步 v1.0.4 并脱敏配置与镜像
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package fullsyncretry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
func TestReplayAndStatusProxy(t *testing.T) {
|
||||
calls := 0
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls++
|
||||
if r.Header.Get("Authorization") != "" {
|
||||
t.Error("Admin JWT must not be forwarded to Worker")
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
var body map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(body) != 1 || body["requestedBy"] != "42" {
|
||||
t.Errorf("unexpected Worker request: %+v", body)
|
||||
}
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
_, _ = w.Write([]byte(`{"replayRunId":"replay-1","status":"accepted"}`))
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"replayRunId":"replay-1","sourceRunId":"source","status":"completed","remaining":0,"enqueued":3}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL}
|
||||
r, err := client.Replay(context.Background(), "source", "42", 0)
|
||||
if err != nil || r.ReplayRunID != "replay-1" {
|
||||
t.Fatalf("replay: %+v %v", r, err)
|
||||
}
|
||||
s, err := client.Get(context.Background(), "replay-1")
|
||||
if err != nil || s.Enqueued != 3 || calls != 2 {
|
||||
t.Fatalf("status: %+v %v, calls=%d", s, err, calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunQueriesAndFailures(t *testing.T) {
|
||||
calls := 0
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls++
|
||||
switch {
|
||||
case r.Method == http.MethodGet && r.URL.Path == "/internal/v1/full-sync-runs":
|
||||
if r.URL.Query().Get("syncKind") != "traffic_usage" || r.URL.Query().Get("limit") != "7" {
|
||||
t.Fatalf("query = %s", r.URL.RawQuery)
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"items":[{"source":"live","run":{"runId":"run-1","operation":"current_month_usage_full_sync","status":"running"}}],"total":1}`))
|
||||
case r.Method == http.MethodGet && r.URL.Path == "/internal/v1/full-sync-runs/run-1":
|
||||
_, _ = w.Write([]byte(`{"source":"archive","run":{"runId":"run-1","operation":"current_month_usage_full_sync","status":"completed"},"rounds":[]}`))
|
||||
case r.Method == http.MethodGet && r.URL.Path == "/internal/v1/full-sync-runs/run-1/failures":
|
||||
_, _ = w.Write([]byte(`{"items":[{"taskId":"task-1","cardId":1,"errorCategory":"business","errorMessage":"failed","round":2}],"nextCursor":"next"}`))
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL}
|
||||
list, err := client.ListRuns(context.Background(), "traffic_usage", 7)
|
||||
if err != nil || list.Total != 1 || len(list.Items) != 1 {
|
||||
t.Fatalf("list = %+v, err = %v", list, err)
|
||||
}
|
||||
view, err := client.Run(context.Background(), "run-1")
|
||||
if err != nil || view.Source != "archive" {
|
||||
t.Fatalf("run = %+v, err = %v", view, err)
|
||||
}
|
||||
page, err := client.Failures(context.Background(), "run-1", 100, "cursor")
|
||||
if err != nil || len(page.Items) != 1 || page.NextCursor != "next" || calls != 3 {
|
||||
t.Fatalf("failures = %+v, err = %v, calls = %d", page, err, calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplayWorkerTimeout(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(50 * time.Millisecond) }))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL, HTTP: &http.Client{Timeout: time.Millisecond}}
|
||||
_, err := client.Replay(context.Background(), "source", "42", 0)
|
||||
if err == nil || !strings.Contains(err.Error(), "Worker unavailable") {
|
||||
t.Fatalf("timeout: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplayValidationAndWorkerErrors(t *testing.T) {
|
||||
calls := 0
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls++
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
_, _ = w.Write([]byte(`{"error":{"message":"ICCID secret"}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL}
|
||||
for _, id := range []string{"", "a/b", "{bad}", strings.Repeat("a", 129)} {
|
||||
if _, err := client.Replay(context.Background(), id, "42", 0); gerror.Code(err) != gcode.CodeInvalidParameter {
|
||||
t.Fatalf("id=%q: %v", id, err)
|
||||
}
|
||||
}
|
||||
if calls != 0 {
|
||||
t.Fatal("invalid source triggered Worker")
|
||||
}
|
||||
// The edge must reject an oversized round budget before calling Worker.
|
||||
for _, rounds := range []int{-1, MaxReplayRounds + 1} {
|
||||
if _, err := client.Replay(context.Background(), "source", "42", rounds); gerror.Code(err) != gcode.CodeInvalidParameter {
|
||||
t.Fatalf("maxRounds=%d: %v", rounds, err)
|
||||
}
|
||||
}
|
||||
if calls != 0 {
|
||||
t.Fatal("invalid maxRounds triggered Worker")
|
||||
}
|
||||
_, err := client.Replay(context.Background(), "source", "42", 0)
|
||||
if gerror.Code(err) != gcode.CodeInvalidParameter || strings.Contains(err.Error(), "ICCID") {
|
||||
t.Fatalf("error leaked Worker body: %v", err)
|
||||
}
|
||||
for _, status := range []int{400, 401, 404, 409, 422, 500} {
|
||||
if workerError(status) == nil {
|
||||
t.Fatalf("missing error mapping for %d", status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The round budget must reach Worker only when the caller asks for one, so an
|
||||
// omitted value keeps the Worker-side configured default authoritative.
|
||||
func TestReplayForwardsMaxRoundsOnlyWhenSet(t *testing.T) {
|
||||
var bodies []map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var body map[string]any
|
||||
_ = json.NewDecoder(r.Body).Decode(&body)
|
||||
bodies = append(bodies, body)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
_, _ = w.Write([]byte(`{"replayRunId":"replay-1","status":"accepted"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL}
|
||||
|
||||
if _, err := client.Replay(context.Background(), "source", "42", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := client.Replay(context.Background(), "source", "42", 7); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(bodies) != 2 {
|
||||
t.Fatalf("expected 2 Worker calls, got %d", len(bodies))
|
||||
}
|
||||
if _, present := bodies[0]["maxRounds"]; present {
|
||||
t.Fatalf("omitted budget must not be sent: %+v", bodies[0])
|
||||
}
|
||||
if got := bodies[1]["maxRounds"]; got != float64(7) {
|
||||
t.Fatalf("explicit budget must be forwarded, got %+v", bodies[1])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package fullsyncretry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
func TestListRunsAcceptsFiveKindsAndRejectsUnknownFilters(t *testing.T) {
|
||||
var filters []string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
filters = append(filters, r.URL.Query().Get("syncKind"))
|
||||
_, _ = w.Write([]byte(`{"items":null,"total":0}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
client := Client{BaseURL: server.URL}
|
||||
kinds := []string{"", "traffic_usage", "sim_status", "imei", "traffic_usage_daily", "traffic_usage_monthly"}
|
||||
for i, kind := range kinds {
|
||||
result, err := client.ListRuns(context.Background(), kind, 100)
|
||||
if err != nil || result.Items == nil || len(filters) != i+1 || filters[i] != kind {
|
||||
t.Fatalf("kind=%q result=%+v filters=%v error=%v", kind, result, filters, err)
|
||||
}
|
||||
}
|
||||
for _, query := range []struct {
|
||||
kind string
|
||||
limit int
|
||||
}{{"unknown", 10}, {"IMEI", 10}, {"", -1}, {"imei", 101}} {
|
||||
if _, err := client.ListRuns(context.Background(), query.kind, query.limit); gerror.Code(err) != gcode.CodeInvalidParameter {
|
||||
t.Fatalf("invalid filter %+v: %v", query, err)
|
||||
}
|
||||
}
|
||||
if len(filters) != len(kinds) {
|
||||
t.Fatal("invalid filter reached Worker")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user