package handlers import ( "encoding/json" "net/http" "net/http/httptest" "path/filepath" "testing" "time" "git.mchus.pro/mchus/priceforge/internal/localdb" syncsvc "git.mchus.pro/mchus/priceforge/internal/services/sync" "github.com/gin-gonic/gin" ) func TestSyncReadinessOfflineBlocked(t *testing.T) { gin.SetMode(gin.TestMode) dir := t.TempDir() local, err := localdb.New(filepath.Join(dir, "pfs.db")) if err != nil { t.Fatalf("init local db: %v", err) } service := syncsvc.NewService(nil, local) h, err := NewSyncHandler(local, service, nil, filepath.Join("web", "templates"), 5*time.Minute) if err != nil { t.Fatalf("new sync handler: %v", err) } router := gin.New() router.GET("/api/sync/readiness", h.GetReadiness) router.POST("/api/sync/push", h.PushPendingChanges) readinessResp := httptest.NewRecorder() readinessReq, _ := http.NewRequest(http.MethodGet, "/api/sync/readiness", nil) router.ServeHTTP(readinessResp, readinessReq) if readinessResp.Code != http.StatusOK { t.Fatalf("unexpected readiness status: %d", readinessResp.Code) } var readinessBody map[string]any if err := json.Unmarshal(readinessResp.Body.Bytes(), &readinessBody); err != nil { t.Fatalf("decode readiness body: %v", err) } if blocked, _ := readinessBody["blocked"].(bool); !blocked { t.Fatalf("expected blocked readiness, got %v", readinessBody["blocked"]) } pushResp := httptest.NewRecorder() pushReq, _ := http.NewRequest(http.MethodPost, "/api/sync/push", nil) router.ServeHTTP(pushResp, pushReq) if pushResp.Code != http.StatusLocked { t.Fatalf("expected 423 for blocked sync push, got %d body=%s", pushResp.Code, pushResp.Body.String()) } var pushBody map[string]any if err := json.Unmarshal(pushResp.Body.Bytes(), &pushBody); err != nil { t.Fatalf("decode push body: %v", err) } if pushBody["reason_text"] == nil || pushBody["reason_text"] == "" { t.Fatalf("expected reason_text in blocked response, got %v", pushBody) } }