fix
This commit is contained in:
@@ -337,7 +337,6 @@ func TestHandleV1GetProcessCompletedIncludesProcessedItems(t *testing.T) {
|
||||
t.Parallel()
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
jobID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
productID := "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||
s := &Server{
|
||||
testGetJob: func(_ context.Context, companyID, id uuid.UUID) (processing.Job, error) {
|
||||
if companyID != cid || id != jobID {
|
||||
@@ -357,7 +356,7 @@ func TestHandleV1GetProcessCompletedIncludesProcessedItems(t *testing.T) {
|
||||
}
|
||||
return []processing.V1ProcessJobItem{{
|
||||
"ean": "0123456789012",
|
||||
"id": productID,
|
||||
"id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
|
||||
"status": "processed",
|
||||
"title": "Acme Widget",
|
||||
}}, nil
|
||||
@@ -393,9 +392,12 @@ func TestHandleV1GetProcessCompletedIncludesProcessedItems(t *testing.T) {
|
||||
if !ok {
|
||||
t.Fatalf("item=%T", items[0])
|
||||
}
|
||||
if item["status"] != "processed" || item["id"] != productID || item["ean"] != "0123456789012" {
|
||||
if item["status"] != "processed" || item["ean"] != "0123456789012" {
|
||||
t.Fatalf("item=%v", item)
|
||||
}
|
||||
if _, ok := item["id"]; ok {
|
||||
t.Fatalf("id must be omitted from public process items: %v", item)
|
||||
}
|
||||
if _, ok := body.Data["processed_at"]; !ok {
|
||||
t.Fatalf("missing processed_at: %v", body.Data)
|
||||
}
|
||||
@@ -447,6 +449,90 @@ func TestHandleGetProcessingJobCompletedIncludesItems(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleV1GetProcessJobOmitsAIEnhance(t *testing.T) {
|
||||
t.Parallel()
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
jobID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
note := "GPT: rewrite title with --- Title --- markers"
|
||||
errMsg := "openai: invalid api-key sk-live-secret"
|
||||
s := &Server{
|
||||
testGetJob: func(_ context.Context, companyID, id uuid.UUID) (processing.Job, error) {
|
||||
return processing.Job{
|
||||
ID: jobID,
|
||||
CompanyID: companyID,
|
||||
Status: "processing",
|
||||
ProcessingType: "full",
|
||||
CurrentStep: "ai_enhance",
|
||||
StepProgress: []processing.StepProgress{{
|
||||
Step: "ai_enhance", Status: "running", Note: note,
|
||||
}},
|
||||
Error: &errMsg,
|
||||
TotalProducts: 2,
|
||||
ProcessedProducts: 1,
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxCompanyID, cid)
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/process/"+jobID.String(), nil)
|
||||
rctx := chi.NewRouteContext()
|
||||
rctx.URLParams.Add("id", jobID.String())
|
||||
req = req.WithContext(context.WithValue(ctx, chi.RouteCtxKey, rctx))
|
||||
s.handleV1GetProcessJob(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
raw := rec.Body.String()
|
||||
if strings.Contains(raw, "ai_enhance") {
|
||||
t.Fatalf("public process poll leaked ai_enhance: %s", raw)
|
||||
}
|
||||
if strings.Contains(raw, "GPT:") || strings.Contains(raw, "--- Title ---") {
|
||||
t.Fatalf("public process poll leaked step notes: %s", raw)
|
||||
}
|
||||
if strings.Contains(raw, "current_step") || strings.Contains(raw, "step_progress") || strings.Contains(raw, "company_id") {
|
||||
t.Fatalf("public process poll leaked internals: %s", raw)
|
||||
}
|
||||
var body map[string]any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body["status"] != "processing" {
|
||||
t.Fatalf("status=%v", body["status"])
|
||||
}
|
||||
if body["total_products"].(float64) != 2 || body["processed_products"].(float64) != 1 {
|
||||
t.Fatalf("counts=%v", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleGetProcessingJobKeepsCurrentStep(t *testing.T) {
|
||||
t.Parallel()
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
jobID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := &Server{
|
||||
testGetJob: func(_ context.Context, companyID, id uuid.UUID) (processing.Job, error) {
|
||||
return processing.Job{
|
||||
ID: jobID,
|
||||
CompanyID: companyID,
|
||||
Status: "processing",
|
||||
CurrentStep: "ai_enhance",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxCompanyID, cid)
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/processing/jobs/"+jobID.String(), nil)
|
||||
rctx := chi.NewRouteContext()
|
||||
rctx.URLParams.Add("id", jobID.String())
|
||||
req = req.WithContext(context.WithValue(ctx, chi.RouteCtxKey, rctx))
|
||||
s.handleGetProcessingJob(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !strings.Contains(rec.Body.String(), "ai_enhance") {
|
||||
t.Fatalf("dashboard GET should keep current_step: %s", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleV1ListProcessJobsUnauthorizedWithoutCompany(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &Server{}
|
||||
@@ -500,3 +586,126 @@ func TestAssertV1ProcessGatesNilBilling(t *testing.T) {
|
||||
t.Fatalf("nil billing must no-op: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func processJobWithSEOMetaItems(cid, jobID uuid.UUID) *Server {
|
||||
return &Server{
|
||||
testGetJob: func(_ context.Context, companyID, id uuid.UUID) (processing.Job, error) {
|
||||
return processing.Job{
|
||||
ID: jobID,
|
||||
CompanyID: companyID,
|
||||
Status: "completed",
|
||||
ProcessingType: "full",
|
||||
TotalProducts: 1,
|
||||
}, nil
|
||||
},
|
||||
testLoadV1ProcessJobItems: func(context.Context, uuid.UUID, uuid.UUID, string) ([]processing.V1ProcessJobItem, error) {
|
||||
return []processing.V1ProcessJobItem{{
|
||||
"ean": "0123456789012",
|
||||
"status": "processed",
|
||||
"name": "Acme Widget",
|
||||
"meta_title": "Acme | Widget",
|
||||
"meta_description": "A widget for tests",
|
||||
}}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getProcessJSONItem(t *testing.T, rec *httptest.ResponseRecorder, wrapped bool) map[string]any {
|
||||
t.Helper()
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data := raw
|
||||
if wrapped {
|
||||
var ok bool
|
||||
data, ok = raw["data"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("data=%T body=%s", raw["data"], rec.Body.String())
|
||||
}
|
||||
}
|
||||
items, ok := data["items"].([]any)
|
||||
if !ok || len(items) != 1 {
|
||||
t.Fatalf("items=%v", data["items"])
|
||||
}
|
||||
item, ok := items[0].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("item=%T", items[0])
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func TestA1ProcessEndpointsOmitSEOMeta(t *testing.T) {
|
||||
t.Parallel()
|
||||
cid := uuid.MustParse("604f23a8-b66e-4b21-8b45-0d72b68f4790")
|
||||
jobID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := processJobWithSEOMetaItems(cid, jobID)
|
||||
ctx := context.WithValue(context.Background(), ctxCompanyID, cid)
|
||||
|
||||
legacyRec := httptest.NewRecorder()
|
||||
legacyReq := httptest.NewRequest(http.MethodGet, "/api/v1/products/process/"+jobID.String(), nil)
|
||||
rctx := chi.NewRouteContext()
|
||||
rctx.URLParams.Add("id", jobID.String())
|
||||
legacyReq = legacyReq.WithContext(context.WithValue(ctx, chi.RouteCtxKey, rctx))
|
||||
s.handleV1GetProcess(legacyRec, legacyReq)
|
||||
legacyItem := getProcessJSONItem(t, legacyRec, true)
|
||||
if _, ok := legacyItem["meta_title"]; ok {
|
||||
t.Fatalf("GET /products/process/{id} A1 meta_title=%v", legacyItem["meta_title"])
|
||||
}
|
||||
if _, ok := legacyItem["meta_description"]; ok {
|
||||
t.Fatalf("GET /products/process/{id} A1 meta_description=%v", legacyItem["meta_description"])
|
||||
}
|
||||
|
||||
jobRec := httptest.NewRecorder()
|
||||
jobReq := httptest.NewRequest(http.MethodGet, "/api/v1/process/"+jobID.String(), nil)
|
||||
jrctx := chi.NewRouteContext()
|
||||
jrctx.URLParams.Add("id", jobID.String())
|
||||
jobReq = jobReq.WithContext(context.WithValue(ctx, chi.RouteCtxKey, jrctx))
|
||||
s.handleGetProcessingJob(jobRec, jobReq)
|
||||
jobItem := getProcessJSONItem(t, jobRec, false)
|
||||
if _, ok := jobItem["meta_title"]; ok {
|
||||
t.Fatalf("GET /process/{id} A1 meta_title=%v", jobItem["meta_title"])
|
||||
}
|
||||
if _, ok := jobItem["meta_description"]; ok {
|
||||
t.Fatalf("GET /process/{id} A1 meta_description=%v", jobItem["meta_description"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonA1ProcessEndpointsKeepSEOMeta(t *testing.T) {
|
||||
t.Parallel()
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
jobID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := processJobWithSEOMetaItems(cid, jobID)
|
||||
ctx := context.WithValue(context.Background(), ctxCompanyID, cid)
|
||||
|
||||
legacyRec := httptest.NewRecorder()
|
||||
legacyReq := httptest.NewRequest(http.MethodGet, "/api/v1/products/process/"+jobID.String(), nil)
|
||||
rctx := chi.NewRouteContext()
|
||||
rctx.URLParams.Add("id", jobID.String())
|
||||
legacyReq = legacyReq.WithContext(context.WithValue(ctx, chi.RouteCtxKey, rctx))
|
||||
s.handleV1GetProcess(legacyRec, legacyReq)
|
||||
legacyItem := getProcessJSONItem(t, legacyRec, true)
|
||||
if legacyItem["meta_title"] != "Acme | Widget" {
|
||||
t.Fatalf("non-A1 GET /products/process/{id} meta_title=%v", legacyItem["meta_title"])
|
||||
}
|
||||
if legacyItem["meta_description"] != "A widget for tests" {
|
||||
t.Fatalf("non-A1 GET /products/process/{id} meta_description=%v", legacyItem["meta_description"])
|
||||
}
|
||||
|
||||
jobRec := httptest.NewRecorder()
|
||||
jobReq := httptest.NewRequest(http.MethodGet, "/api/v1/process/"+jobID.String(), nil)
|
||||
jrctx := chi.NewRouteContext()
|
||||
jrctx.URLParams.Add("id", jobID.String())
|
||||
jobReq = jobReq.WithContext(context.WithValue(ctx, chi.RouteCtxKey, jrctx))
|
||||
s.handleGetProcessingJob(jobRec, jobReq)
|
||||
jobItem := getProcessJSONItem(t, jobRec, false)
|
||||
if jobItem["meta_title"] != "Acme | Widget" {
|
||||
t.Fatalf("non-A1 GET /process/{id} meta_title=%v", jobItem["meta_title"])
|
||||
}
|
||||
if jobItem["meta_description"] != "A widget for tests" {
|
||||
t.Fatalf("non-A1 GET /process/{id} meta_description=%v", jobItem["meta_description"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user