package shadow import ( "context" "testing" "time" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" ) func newTestStore(t *testing.T) *Store { t.Helper() mr := miniredis.RunT(t) rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()}) t.Cleanup(func() { rdb.Close() }) return New(rdb) } // markOnline seeds Redis the way device-control-service's Touch() would, // without depending on that service's code. func markOnline(t *testing.T, s *Store, deviceID string, lastSeen time.Time) { t.Helper() ctx := context.Background() if err := s.rdb.SAdd(ctx, knownDevicesKey, deviceID).Err(); err != nil { t.Fatalf("seed known device: %v", err) } if err := s.rdb.Set(ctx, statusKey(deviceID), StatusOnline, 0).Err(); err != nil { t.Fatalf("seed status: %v", err) } if err := s.rdb.Set(ctx, lastSeenKey(deviceID), lastSeen.Unix(), 0).Err(); err != nil { t.Fatalf("seed last_seen: %v", err) } } func TestKnownDevices_ListsSeededDevices(t *testing.T) { ctx := context.Background() s := newTestStore(t) markOnline(t, s, "d1", time.Now()) markOnline(t, s, "d2", time.Now()) got, err := s.KnownDevices(ctx) if err != nil { t.Fatalf("known devices: %v", err) } if len(got) != 2 { t.Fatalf("got %d known devices, want 2 (%v)", len(got), got) } } func TestMarkOfflineIfStale(t *testing.T) { ctx := context.Background() s := newTestStore(t) markOnline(t, s, "d1", time.Now()) changed, err := s.MarkOfflineIfStale(ctx, "d1", time.Hour) if err != nil { t.Fatalf("mark offline (not stale): %v", err) } if changed { t.Fatal("device just touched should not be considered stale") } changed, err = s.MarkOfflineIfStale(ctx, "d1", -time.Second) // any age counts as stale if err != nil { t.Fatalf("mark offline (stale): %v", err) } if !changed { t.Fatal("expected status to flip to offline") } // Already offline: a second call should report no further change. changed, err = s.MarkOfflineIfStale(ctx, "d1", -time.Second) if err != nil { t.Fatalf("mark offline (already offline): %v", err) } if changed { t.Fatal("expected no change once already offline") } } func TestMarkOfflineIfStale_UnknownDeviceIsNoop(t *testing.T) { ctx := context.Background() s := newTestStore(t) changed, err := s.MarkOfflineIfStale(ctx, "ghost", time.Second) if err != nil { t.Fatalf("unexpected error: %v", err) } if changed { t.Fatal("unknown device should never be reported as changed") } }