mirror of
https://github.com/sartoopjj/thefeed.git
synced 2026-05-18 06:44:34 +03:00
175 lines
5.7 KiB
Go
175 lines
5.7 KiB
Go
package e2e_test
|
|
|
|
import (
|
|
"io"
|
|
"testing"
|
|
)
|
|
|
|
// createDefaultProfile spins up a dummy "active" profile so the auto-update
|
|
// endpoints have somewhere to write. Returns the resulting profile id.
|
|
func createDefaultProfile(t *testing.T, base string) string {
|
|
t.Helper()
|
|
body := `{"action":"create","profile":{"id":"","nickname":"AU","config":{"domain":"au.example","key":"k","resolvers":["127.0.0.1:9999"],"queryMode":"single","rateLimit":0}}}`
|
|
resp := postJSON(t, base+"/api/profiles", body)
|
|
resp.Body.Close()
|
|
m := decodeJSON(t, getJSON(t, base+"/api/profiles"))
|
|
profs, ok := m["profiles"].([]any)
|
|
if !ok || len(profs) == 0 {
|
|
t.Fatalf("profile not created, got %v", m["profiles"])
|
|
}
|
|
return profs[0].(map[string]any)["id"].(string)
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_GetEmpty(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
resp := getJSON(t, base+"/api/auto-update")
|
|
if resp.StatusCode != 200 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
t.Fatalf("expected 200, got %d body=%s", resp.StatusCode, body)
|
|
}
|
|
m := decodeJSON(t, resp)
|
|
chans, _ := m["channels"].([]any)
|
|
if len(chans) != 0 {
|
|
t.Errorf("expected empty channels, got %v", chans)
|
|
}
|
|
if d, _ := m["defaultIntervalSeconds"].(float64); int(d) != 60 {
|
|
t.Errorf("defaultIntervalSeconds = %v, want 60", m["defaultIntervalSeconds"])
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_ToggleAddsAndRemoves(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
// First toggle: add.
|
|
resp := postJSON(t, base+"/api/auto-update/toggle", `{"channel":"thefeed1"}`)
|
|
if resp.StatusCode != 200 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
t.Fatalf("toggle add: %d body=%s", resp.StatusCode, body)
|
|
}
|
|
m := decodeJSON(t, resp)
|
|
if m["enabled"] != true {
|
|
t.Errorf("first toggle should set enabled=true, got %v", m["enabled"])
|
|
}
|
|
chans := m["channels"].([]any)
|
|
if len(chans) != 1 || chans[0] != "thefeed1" {
|
|
t.Errorf("channels after add = %v, want [thefeed1]", chans)
|
|
}
|
|
|
|
// Second toggle: remove.
|
|
resp2 := postJSON(t, base+"/api/auto-update/toggle", `{"channel":"thefeed1"}`)
|
|
m2 := decodeJSON(t, resp2)
|
|
if m2["enabled"] != false {
|
|
t.Errorf("second toggle should set enabled=false, got %v", m2["enabled"])
|
|
}
|
|
chans2 := m2["channels"]
|
|
if list, ok := chans2.([]any); !ok || len(list) != 0 {
|
|
t.Errorf("channels after remove = %v, want []", chans2)
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_TogglesAtSign(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
// Add with "@chan" — server must store stripped form.
|
|
postJSON(t, base+"/api/auto-update/toggle", `{"channel":"@chan"}`).Body.Close()
|
|
|
|
m := decodeJSON(t, getJSON(t, base+"/api/auto-update"))
|
|
chans := m["channels"].([]any)
|
|
if len(chans) != 1 || chans[0] != "chan" {
|
|
t.Errorf("channels = %v, want [chan]", chans)
|
|
}
|
|
|
|
// Toggle with bare form should remove the same entry.
|
|
resp := postJSON(t, base+"/api/auto-update/toggle", `{"channel":"chan"}`)
|
|
m2 := decodeJSON(t, resp)
|
|
if m2["enabled"] != false {
|
|
t.Errorf("expected enabled=false, got %v", m2["enabled"])
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_PostReplacesList(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
// POST with normalisation cases: leading @, dupes, whitespace.
|
|
body := `{"channels":["@a","b","@a"," c ",""],"intervalSeconds":120}`
|
|
resp := postJSON(t, base+"/api/auto-update", body)
|
|
if resp.StatusCode != 200 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
t.Fatalf("POST: %d body=%s", resp.StatusCode, body)
|
|
}
|
|
m := decodeJSON(t, resp)
|
|
chans := m["channels"].([]any)
|
|
want := []string{"a", "b", "c"}
|
|
if len(chans) != len(want) {
|
|
t.Fatalf("channels len = %d, want %d (%v)", len(chans), len(want), chans)
|
|
}
|
|
for i, w := range want {
|
|
if chans[i] != w {
|
|
t.Errorf("channels[%d] = %v, want %q", i, chans[i], w)
|
|
}
|
|
}
|
|
if iv, _ := m["intervalSeconds"].(float64); int(iv) != 120 {
|
|
t.Errorf("intervalSeconds = %v, want 120", m["intervalSeconds"])
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_IntervalFloor(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
// Anything <60s gets bumped to the 60s floor; 0 stays 0 (means
|
|
// "follow the server's nextFetch cadence with the built-in default").
|
|
resp := postJSON(t, base+"/api/auto-update", `{"channels":["x"],"intervalSeconds":5}`)
|
|
m := decodeJSON(t, resp)
|
|
if iv, _ := m["intervalSeconds"].(float64); int(iv) != 60 {
|
|
t.Errorf("intervalSeconds floor = %v, want 60", m["intervalSeconds"])
|
|
}
|
|
|
|
resp2 := postJSON(t, base+"/api/auto-update", `{"channels":["x"],"intervalSeconds":0}`)
|
|
m2 := decodeJSON(t, resp2)
|
|
if iv, _ := m2["intervalSeconds"].(float64); int(iv) != 0 {
|
|
t.Errorf("intervalSeconds zero = %v, want 0 (default)", m2["intervalSeconds"])
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_NoActiveProfile(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
|
|
// No profile created → no active profile → POST should fail with 400.
|
|
resp := postJSON(t, base+"/api/auto-update/toggle", `{"channel":"x"}`)
|
|
if resp.StatusCode != 400 {
|
|
t.Fatalf("toggle without profile: expected 400, got %d", resp.StatusCode)
|
|
}
|
|
resp.Body.Close()
|
|
|
|
// GET should succeed and return empty channels.
|
|
resp2 := getJSON(t, base+"/api/auto-update")
|
|
if resp2.StatusCode != 200 {
|
|
t.Fatalf("GET without profile: expected 200, got %d", resp2.StatusCode)
|
|
}
|
|
m := decodeJSON(t, resp2)
|
|
chans, _ := m["channels"].([]any)
|
|
if len(chans) != 0 {
|
|
t.Errorf("expected empty channels with no profile, got %v", chans)
|
|
}
|
|
}
|
|
|
|
func TestE2E_AutoUpdate_PersistsAcrossGets(t *testing.T) {
|
|
base, _ := startWebServer(t)
|
|
createDefaultProfile(t, base)
|
|
|
|
postJSON(t, base+"/api/auto-update", `{"channels":["alpha","beta"]}`).Body.Close()
|
|
|
|
// Fresh GET should return the same list.
|
|
m := decodeJSON(t, getJSON(t, base+"/api/auto-update"))
|
|
chans := m["channels"].([]any)
|
|
if len(chans) != 2 || chans[0] != "alpha" || chans[1] != "beta" {
|
|
t.Errorf("channels persisted = %v, want [alpha beta]", chans)
|
|
}
|
|
}
|