package store_test import ( "testing" "github.com/shiv/internal/store" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func makeTab(name, host string, port int, tls bool) store.RepeaterTab { return store.RepeaterTab{ Name: name, Host: host, Port: port, TLS: tls, TabType: "http", RawRequest: "GET / HTTP/1.1\r\nHost: " + host + "\r\n\r\n", } } func makeWSTab(name, url string, tls bool) store.RepeaterTab { return store.RepeaterTab{ Name: name, Host: url, Port: 0, TLS: tls, TabType: "websocket", RawRequest: url, } } // ── HTTP tab ────────────────────────────────────────────────────────────────── func TestSaveRepeaterTab_PersistsAllFields(t *testing.T) { st := newTestStore(t) tab := store.RepeaterTab{ Name: "My Tab", Host: "example.com", Port: 443, TLS: true, TabType: "http", RawRequest: "GET /api HTTP/1.1\r\nHost: example.com\r\n\r\n", } id, err := st.SaveRepeaterTab(tab) require.NoError(t, err) assert.Positive(t, id) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) got := tabs[0] assert.Equal(t, id, got.ID) assert.Equal(t, "My Tab", got.Name) assert.Equal(t, "example.com", got.Host) assert.Equal(t, 443, got.Port) assert.True(t, got.TLS) assert.Equal(t, "http", got.TabType) assert.Equal(t, tab.RawRequest, got.RawRequest) } func TestSaveRepeaterTab_TLSFalse(t *testing.T) { st := newTestStore(t) id, err := st.SaveRepeaterTab(makeTab("HTTP Tab", "example.com", 80, false)) require.NoError(t, err) assert.Positive(t, id) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.False(t, tabs[0].TLS) assert.Equal(t, "http", tabs[0].TabType) } func TestSaveRepeaterTab_DefaultTabType(t *testing.T) { st := newTestStore(t) // TabType omitted — should default to "http". tab := store.RepeaterTab{ Name: "No Type", Host: "example.com", Port: 80, RawRequest: "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", } _, err := st.SaveRepeaterTab(tab) require.NoError(t, err) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, "http", tabs[0].TabType) } func TestAllRepeaterTabs_OrderedByPosition(t *testing.T) { st := newTestStore(t) for _, name := range []string{"First", "Second", "Third"} { _, err := st.SaveRepeaterTab(makeTab(name, "example.com", 80, false)) require.NoError(t, err) } tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 3) assert.Equal(t, "First", tabs[0].Name) assert.Equal(t, "Second", tabs[1].Name) assert.Equal(t, "Third", tabs[2].Name) } func TestAllRepeaterTabs_PositionAutoIncrements(t *testing.T) { st := newTestStore(t) _, err := st.SaveRepeaterTab(makeTab("A", "a.com", 80, false)) require.NoError(t, err) _, err = st.SaveRepeaterTab(makeTab("B", "b.com", 80, false)) require.NoError(t, err) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 2) assert.Less(t, tabs[0].Position, tabs[1].Position) } func TestUpdateRepeaterTab_UpdatesRequestAndResponse(t *testing.T) { st := newTestStore(t) id, err := st.SaveRepeaterTab(makeTab("Tab", "example.com", 80, false)) require.NoError(t, err) newReq := "POST /submit HTTP/1.1\r\nHost: example.com\r\n\r\nbody" newResp := "HTTP/1.1 200 OK\r\n\r\nok" require.NoError(t, st.UpdateRepeaterTab(id, newReq, newResp)) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, newReq, tabs[0].RawRequest) assert.Equal(t, newResp, tabs[0].LastResponse) } func TestUpdateRepeaterTab_NonExistentIDNoError(t *testing.T) { st := newTestStore(t) assert.NoError(t, st.UpdateRepeaterTab(9999, "req", "resp")) } func TestRenameRepeaterTab(t *testing.T) { st := newTestStore(t) id, err := st.SaveRepeaterTab(makeTab("Old", "example.com", 80, false)) require.NoError(t, err) require.NoError(t, st.RenameRepeaterTab(id, "New Name")) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, "New Name", tabs[0].Name) } func TestDeleteRepeaterTab(t *testing.T) { st := newTestStore(t) id, err := st.SaveRepeaterTab(makeTab("Tab", "example.com", 80, false)) require.NoError(t, err) require.NoError(t, st.DeleteRepeaterTab(id)) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) assert.Empty(t, tabs) } func TestDeleteRepeaterTab_NonExistent(t *testing.T) { st := newTestStore(t) assert.NoError(t, st.DeleteRepeaterTab(9999)) } func TestDeleteRepeaterTab_DoesNotAffectOtherTabs(t *testing.T) { st := newTestStore(t) idKeep, err := st.SaveRepeaterTab(makeTab("Keep", "keep.com", 80, false)) require.NoError(t, err) idDel, err := st.SaveRepeaterTab(makeTab("Delete", "del.com", 80, false)) require.NoError(t, err) require.NoError(t, st.DeleteRepeaterTab(idDel)) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, idKeep, tabs[0].ID) assert.Equal(t, "Keep", tabs[0].Name) } // ── WebSocket tab ───────────────────────────────────────────────────────────── func TestSaveRepeaterTab_WebSocketType(t *testing.T) { st := newTestStore(t) tab := makeWSTab("WS Tab", "wss://echo.websocket.org:443/", true) id, err := st.SaveRepeaterTab(tab) require.NoError(t, err) assert.Positive(t, id) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, "websocket", tabs[0].TabType) assert.Equal(t, "wss://echo.websocket.org:443/", tabs[0].RawRequest) assert.True(t, tabs[0].TLS) } func TestAllRepeaterTabs_MixedTypes(t *testing.T) { st := newTestStore(t) _, err := st.SaveRepeaterTab(makeTab("HTTP", "example.com", 80, false)) require.NoError(t, err) _, err = st.SaveRepeaterTab(makeWSTab("WS", "wss://example.com/ws", true)) require.NoError(t, err) _, err = st.SaveRepeaterTab(makeTab("HTTP2", "other.com", 443, true)) require.NoError(t, err) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 3) assert.Equal(t, "http", tabs[0].TabType) assert.Equal(t, "websocket", tabs[1].TabType) assert.Equal(t, "http", tabs[2].TabType) } func TestSaveRepeaterTab_WebSocketPreservesURL(t *testing.T) { st := newTestStore(t) url := "wss://api.example.com:8443/realtime?token=abc123" tab := makeWSTab("API WS", url, true) id, err := st.SaveRepeaterTab(tab) require.NoError(t, err) full, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, full, 1) assert.Equal(t, id, full[0].ID) assert.Equal(t, url, full[0].RawRequest) assert.Equal(t, "websocket", full[0].TabType) } func TestDeleteRepeaterTab_WebSocket(t *testing.T) { st := newTestStore(t) httpID, err := st.SaveRepeaterTab(makeTab("HTTP", "example.com", 80, false)) require.NoError(t, err) wsID, err := st.SaveRepeaterTab(makeWSTab("WS", "wss://example.com/ws", true)) require.NoError(t, err) require.NoError(t, st.DeleteRepeaterTab(wsID)) tabs, err := st.AllRepeaterTabs() require.NoError(t, err) require.Len(t, tabs, 1) assert.Equal(t, httpID, tabs[0].ID) assert.Equal(t, "http", tabs[0].TabType) }