discrawl/internal/syncer/message_sync_progress_test.go
2026-05-05 15:00:21 -07:00

113 lines
3.0 KiB
Go

package syncer
import (
"bytes"
"context"
"errors"
"io"
"log/slog"
"strings"
"sync"
"testing"
"time"
"github.com/bwmarrin/discordgo"
"github.com/stretchr/testify/require"
)
type lockedBuffer struct {
mu sync.Mutex
buf bytes.Buffer
}
func (b *lockedBuffer) Write(p []byte) (int, error) {
b.mu.Lock()
defer b.mu.Unlock()
return b.buf.Write(p)
}
func (b *lockedBuffer) String() string {
b.mu.Lock()
defer b.mu.Unlock()
return b.buf.String()
}
func newTestLogger(w io.Writer) *slog.Logger {
return slog.New(slog.NewTextHandler(w, &slog.HandlerOptions{
Level: slog.LevelInfo,
ReplaceAttr: func(_ []string, attr slog.Attr) slog.Attr {
if attr.Key == slog.TimeKey {
return slog.Attr{}
}
return attr
},
}))
}
func TestMessageSyncProgressFinishReportsSummaryCounts(t *testing.T) {
t.Parallel()
_, cancel := context.WithCancel(context.Background())
defer cancel()
out := &lockedBuffer{}
svc := New(&fakeClient{}, nil, newTestLogger(out))
svc.messageSyncLogEvery = time.Hour
svc.messageSyncWaitEvery = time.Hour
progress := newMessageSyncProgress(svc, "g1", 3, SyncOptions{Full: true, Concurrency: 2})
require.NotNil(t, progress)
first := &discordgo.Channel{ID: "c1", Name: "missing"}
second := &discordgo.Channel{ID: "c2", Name: "gone"}
third := &discordgo.Channel{ID: "c3", Name: "ok"}
progress.start(first)
progress.recordSkip(first, errors.New(`HTTP 403 Forbidden, {"message": "Missing Access", "code": 50001}`))
progress.start(second)
progress.recordSkip(second, errors.New(`HTTP 404 Not Found, {"message": "Unknown Channel", "code": 10003}`))
progress.start(third)
progress.record(third, 42)
progress.finish(nil)
logs := out.String()
require.Contains(t, logs, `msg="message sync finished"`)
require.Contains(t, logs, `processed_channels=3`)
require.Contains(t, logs, `percent=100.0`)
require.Contains(t, logs, `completion=100.0%`)
require.Contains(t, logs, `messages_written=42`)
require.Contains(t, logs, `skipped_missing_access_channels=1`)
require.Contains(t, logs, `skipped_unknown_channel_channels=1`)
require.Contains(t, logs, `deferred_channels=0`)
}
func TestMessageSyncProgressReportsWaitingHeartbeat(t *testing.T) {
t.Parallel()
_, cancel := context.WithCancel(context.Background())
defer cancel()
out := &lockedBuffer{}
svc := New(&fakeClient{}, nil, newTestLogger(out))
svc.messageSyncLogEvery = time.Hour
svc.messageSyncWaitEvery = 10 * time.Millisecond
progress := newMessageSyncProgress(svc, "g1", 1, SyncOptions{Full: true, Concurrency: 1})
require.NotNil(t, progress)
channel := &discordgo.Channel{ID: "c1", Name: "slowpoke"}
progress.start(channel)
require.Eventually(t, func() bool {
return strings.Contains(out.String(), `msg="message sync waiting"`)
}, time.Second, 10*time.Millisecond)
progress.finish(nil)
logs := out.String()
require.Contains(t, logs, `oldest_active_channel_id=c1`)
require.Contains(t, logs, `oldest_active_channel_name=slowpoke`)
require.Contains(t, logs, `active_channels=1`)
require.Contains(t, logs, `percent=0.0`)
require.Contains(t, logs, `completion=0.0%`)
}