package api import ( "encoding/json" "net/http" "testing" "gitea.dooplex.hu/admin/felhom-hub/internal/store" ) // The report ACK advertises the per-customer config_version (v0.26.0). The controller compares it // against its last-applied version and re-pulls + self-restarts on a change. func TestReportACK_ConfigVersion(t *testing.T) { h, st, _ := newTestHandler(t) if err := st.SaveCustomerConfig(&store.CustomerConfig{ CustomerID: "c", RetrievalPassword: "pw", APIKey: "k", ConfigJSON: "{}", }); err != nil { t.Fatalf("SaveCustomerConfig: %v", err) } // First report: ACK carries the baseline version (1). rr := do(h, http.MethodPost, "/report", globalKey, `{"customer_id":"c"}`) if rr.Code != http.StatusOK { t.Fatalf("report status = %d, want 200 (body=%s)", rr.Code, rr.Body.String()) } var ack map[string]interface{} if err := json.Unmarshal(rr.Body.Bytes(), &ack); err != nil { t.Fatalf("decode ACK: %v", err) } cv, ok := ack["config_version"] if !ok { t.Fatalf("ACK missing config_version for a config-managed customer") } if cv.(float64) != 1 { t.Errorf("ACK config_version = %v, want 1 (baseline)", cv) } // Edit the config → the version bumps → the next ACK carries the new version. This is what makes // the box re-pull + restart. RED-PROOF: if SaveCustomerConfig did NOT bump (the bump is dropped), // the ACK would still report 1 here and the box would never converge — this assertion fails. if err := st.SaveCustomerConfig(&store.CustomerConfig{ CustomerID: "c", RetrievalPassword: "pw", APIKey: "k", ConfigJSON: `{"git":{"username":"x"}}`, }); err != nil { t.Fatalf("SaveCustomerConfig (edit): %v", err) } rr = do(h, http.MethodPost, "/report", globalKey, `{"customer_id":"c"}`) if rr.Code != http.StatusOK { t.Fatalf("report status = %d, want 200", rr.Code) } json.Unmarshal(rr.Body.Bytes(), &ack) if ack["config_version"].(float64) != 2 { t.Errorf("ACK config_version after edit = %v, want 2", ack["config_version"]) } } // A report-only customer (no config row) gets no config_version field — it has nothing to pull, and // an old controller that ignores the field behaves exactly as before. func TestReportACK_ConfigVersionOmittedWhenNoConfig(t *testing.T) { h, _, _ := newTestHandler(t) rr := do(h, http.MethodPost, "/report", globalKey, `{"customer_id":"nobody"}`) if rr.Code != http.StatusOK { t.Fatalf("report status = %d, want 200", rr.Code) } var ack map[string]interface{} json.Unmarshal(rr.Body.Bytes(), &ack) if _, ok := ack["config_version"]; ok { t.Errorf("ACK should omit config_version for a report-only (no config) customer; got %v", ack["config_version"]) } }