main pico / pkg / apps / pipe / db_test.go
Antonio Mika  ·  2026-10-10
  1package pipe
  2
  3import (
  4	"log/slog"
  5	"testing"
  6	"time"
  7
  8	"github.com/picosh/pico/pkg/db/postgres"
  9	"github.com/picosh/pico/pkg/db/postgres/pgtest"
 10)
 11
 12var testDB *PsqlDB
 13
 14func TestMain(m *testing.M) {
 15	pgtest.Main(m)
 16}
 17
 18func cleanupTestData(t *testing.T) {
 19	t.Helper()
 20	if testDB == nil {
 21		testDB = NewDB(postgres.NewDB(pgtest.URL(t), slog.New(slog.DiscardHandler)))
 22	}
 23	pgtest.Clean(t, testDB.Db)
 24}
 25
 26func TestUpsertPipeMonitor(t *testing.T) {
 27	cleanupTestData(t)
 28
 29	user, _ := testDB.RegisterUser("pipemonitorowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipemonitorowner", "comment", "")
 30
 31	winEnd := time.Now().Add(time.Hour)
 32	err := testDB.UpsertPipeMonitor(user.ID, "test-topic", 5*time.Minute, &winEnd)
 33	if err != nil {
 34		t.Fatalf("UpsertPipeMonitor failed: %v", err)
 35	}
 36
 37	monitor, err := testDB.FindPipeMonitorByTopic(user.ID, "test-topic")
 38	if err != nil {
 39		t.Fatalf("FindPipeMonitorByTopic failed: %v", err)
 40	}
 41	if monitor.Topic != "test-topic" {
 42		t.Errorf("expected topic 'test-topic', got '%s'", monitor.Topic)
 43	}
 44	if monitor.WindowDur != 5*time.Minute {
 45		t.Errorf("expected window_dur 5m, got %v", monitor.WindowDur)
 46	}
 47}
 48
 49func TestUpsertPipeMonitor_Update(t *testing.T) {
 50	cleanupTestData(t)
 51
 52	user, _ := testDB.RegisterUser("pipeupdateowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipeupdateowner", "comment", "")
 53
 54	winEnd1 := time.Now().Add(time.Hour)
 55	err := testDB.UpsertPipeMonitor(user.ID, "update-topic", 5*time.Minute, &winEnd1)
 56	if err != nil {
 57		t.Fatalf("first UpsertPipeMonitor failed: %v", err)
 58	}
 59
 60	winEnd2 := time.Now().Add(2 * time.Hour)
 61	err = testDB.UpsertPipeMonitor(user.ID, "update-topic", 10*time.Minute, &winEnd2)
 62	if err != nil {
 63		t.Fatalf("second UpsertPipeMonitor failed: %v", err)
 64	}
 65
 66	monitor, err := testDB.FindPipeMonitorByTopic(user.ID, "update-topic")
 67	if err != nil {
 68		t.Fatalf("FindPipeMonitorByTopic failed: %v", err)
 69	}
 70	if monitor.WindowDur != 10*time.Minute {
 71		t.Errorf("expected window_dur 10m after update, got %v", monitor.WindowDur)
 72	}
 73}
 74
 75func TestUpdatePipeMonitorLastPing(t *testing.T) {
 76	cleanupTestData(t)
 77
 78	user, _ := testDB.RegisterUser("pipepingowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipepingowner", "comment", "")
 79
 80	winEnd := time.Now().Add(time.Hour)
 81	err := testDB.UpsertPipeMonitor(user.ID, "ping-topic", 5*time.Minute, &winEnd)
 82	if err != nil {
 83		t.Fatalf("UpsertPipeMonitor failed: %v", err)
 84	}
 85
 86	lastPing := time.Now()
 87	err = testDB.UpdatePipeMonitorLastPing(user.ID, "ping-topic", &lastPing)
 88	if err != nil {
 89		t.Fatalf("UpdatePipeMonitorLastPing failed: %v", err)
 90	}
 91
 92	monitor, err := testDB.FindPipeMonitorByTopic(user.ID, "ping-topic")
 93	if err != nil {
 94		t.Fatalf("FindPipeMonitorByTopic failed: %v", err)
 95	}
 96	if monitor.LastPing == nil {
 97		t.Error("expected last_ping to be set, got nil")
 98	}
 99}
100
101func TestRemovePipeMonitor(t *testing.T) {
102	cleanupTestData(t)
103
104	user, _ := testDB.RegisterUser("piperemoveowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI piperemoveowner", "comment", "")
105
106	winEnd := time.Now().Add(time.Hour)
107	err := testDB.UpsertPipeMonitor(user.ID, "remove-topic", 5*time.Minute, &winEnd)
108	if err != nil {
109		t.Fatalf("UpsertPipeMonitor failed: %v", err)
110	}
111
112	err = testDB.RemovePipeMonitor(user.ID, "remove-topic")
113	if err != nil {
114		t.Fatalf("RemovePipeMonitor failed: %v", err)
115	}
116
117	_, err = testDB.FindPipeMonitorByTopic(user.ID, "remove-topic")
118	if err == nil {
119		t.Error("expected error finding removed monitor, got nil")
120	}
121}
122
123func TestFindPipeMonitorByTopic_NotFound(t *testing.T) {
124	cleanupTestData(t)
125
126	user, _ := testDB.RegisterUser("pipenotfoundowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipenotfoundowner", "comment", "")
127
128	_, err := testDB.FindPipeMonitorByTopic(user.ID, "nonexistent-topic")
129	if err == nil {
130		t.Error("expected error for nonexistent monitor, got nil")
131	}
132}
133
134func TestFindPipeMonitorsByUser(t *testing.T) {
135	cleanupTestData(t)
136
137	user, _ := testDB.RegisterUser("pipemonlistowner", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipemonlistowner", "comment", "")
138
139	winEnd := time.Now().Add(time.Hour)
140	_ = testDB.UpsertPipeMonitor(user.ID, "service-a", 5*time.Minute, &winEnd)
141	_ = testDB.UpsertPipeMonitor(user.ID, "service-b", 10*time.Minute, &winEnd)
142	_ = testDB.UpsertPipeMonitor(user.ID, "service-c", 1*time.Hour, &winEnd)
143
144	monitors, err := testDB.FindPipeMonitorsByUser(user.ID)
145	if err != nil {
146		t.Fatalf("FindPipeMonitorsByUser failed: %v", err)
147	}
148
149	if len(monitors) != 3 {
150		t.Errorf("expected 3 monitors, got %d", len(monitors))
151	}
152
153	// Should be ordered by topic
154	if monitors[0].Topic != "service-a" {
155		t.Errorf("expected first topic 'service-a', got %s", monitors[0].Topic)
156	}
157	if monitors[1].Topic != "service-b" {
158		t.Errorf("expected second topic 'service-b', got %s", monitors[1].Topic)
159	}
160	if monitors[2].Topic != "service-c" {
161		t.Errorf("expected third topic 'service-c', got %s", monitors[2].Topic)
162	}
163}
164
165func TestFindPipeMonitorsByUser_Empty(t *testing.T) {
166	cleanupTestData(t)
167
168	user, _ := testDB.RegisterUser("pipenomonitors", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI pipenomonitors", "comment", "")
169
170	monitors, err := testDB.FindPipeMonitorsByUser(user.ID)
171	if err != nil {
172		t.Fatalf("FindPipeMonitorsByUser failed: %v", err)
173	}
174
175	if len(monitors) != 0 {
176		t.Errorf("expected 0 monitors for user with none, got %d", len(monitors))
177	}
178}