package main import ( "context" "errors" "testing" "time" "github.com/itworx/pulse/internal/agentsource" "github.com/itworx/pulse/internal/agentstore" "github.com/itworx/pulse/internal/config" "github.com/itworx/pulse/internal/notification" "github.com/jackc/pgx/v5/pgxpool" ) type channelStoreStub struct { channels map[string]notification.Channel creates int updates int } func TestContainerDiscoveryProviderUsesAgentSnapshotStore(t *testing.T) { pool := &pgxpool.Pool{} provider, ok := containerDiscoveryProvider(pool).(agentsource.ContainerProvider) if !ok { t.Fatalf("container discovery provider = %T, want agentsource.ContainerProvider", containerDiscoveryProvider(pool)) } store, ok := provider.Reader.(agentstore.PostgresStore) if !ok || store.Pool != pool { t.Fatalf("container discovery reader = %#v, want PostgresStore with worker pool", provider.Reader) } } func (store *channelStoreStub) CreateChannel(_ context.Context, channel notification.Channel) (notification.Channel, error) { if _, exists := store.channels[channel.ID]; exists { return notification.Channel{}, notification.ErrConflict } store.creates++ channel.Revision = 1 store.channels[channel.ID] = channel return channel, nil } func (store *channelStoreStub) GetChannel(_ context.Context, id string) (notification.Channel, error) { channel, exists := store.channels[id] if !exists { return notification.Channel{}, notification.ErrNotFound } return channel, nil } func (store *channelStoreStub) ListChannels(context.Context, int) ([]notification.Channel, error) { channels := make([]notification.Channel, 0, len(store.channels)) for _, channel := range store.channels { channels = append(channels, channel) } return channels, nil } func (store *channelStoreStub) UpdateChannel(_ context.Context, channel notification.Channel, expected int64) (notification.Channel, error) { current, exists := store.channels[channel.ID] if !exists { return notification.Channel{}, notification.ErrNotFound } if current.Revision != expected { return notification.Channel{}, notification.ErrConflict } store.updates++ channel.Revision = expected + 1 store.channels[channel.ID] = channel return channel, nil } func (store *channelStoreStub) DeleteChannel(_ context.Context, id string) error { if _, exists := store.channels[id]; !exists { return notification.ErrNotFound } delete(store.channels, id) return nil } func TestConfigureWebhookChannelReconcilesWithoutRevisionChurn(t *testing.T) { store := &channelStoreStub{channels: map[string]notification.Channel{}} application := config.Config{ Environment: config.Development, NotificationWebhookURL: "http://127.0.0.1:18080/pulse", NotificationWebhookToken: "runtime-only", NotificationWebhookTimeout: 3 * time.Second, } factories, err := configureWebhookChannel(context.Background(), application, store) if err != nil { t.Fatal(err) } channel := store.channels[notification.DefaultWebhookChannelID] if store.creates != 1 || store.updates != 0 || !channel.Enabled || channel.SecretRef.ID != notification.WebhookSecretReference { t.Fatalf("channel=%+v creates=%d updates=%d", channel, store.creates, store.updates) } if _, exists := channel.Configuration["token"]; exists { t.Fatal("runtime credential entered persistent configuration") } if _, err := factories["webhook"].Sender(context.Background(), channel); err != nil { t.Fatal(err) } if _, err := configureWebhookChannel(context.Background(), application, store); err != nil { t.Fatal(err) } if store.creates != 1 || store.updates != 0 { t.Fatalf("idempotent reconciliation created=%d updated=%d", store.creates, store.updates) } } func TestConfigureWebhookChannelDisablesRemovedRuntimeConfiguration(t *testing.T) { store := &channelStoreStub{channels: map[string]notification.Channel{ notification.DefaultWebhookChannelID: { ID: notification.DefaultWebhookChannelID, Name: "Pulse webhook", Type: "webhook", Enabled: true, SecretRef: notification.SecretRef{ID: notification.WebhookSecretReference}, Revision: 4, }, }} factories, err := configureWebhookChannel(context.Background(), config.Config{}, store) if err != nil { t.Fatal(err) } if len(factories) != 0 || store.updates != 1 || store.channels[notification.DefaultWebhookChannelID].Enabled { t.Fatalf("factories=%v updates=%d channel=%+v", factories, store.updates, store.channels[notification.DefaultWebhookChannelID]) } if _, err := configureWebhookChannel(context.Background(), config.Config{}, nil); !errors.Is(err, notification.ErrUnavailable) { t.Fatalf("nil repository error=%v", err) } }