v0.33.0 62a09f5

favicon_repo_test.go RawHistoryFolder

1package sqlite_test
2
3import (
4	"context"
5	"path/filepath"
6	"testing"
7	"time"
8
9	"github.com/bnema/dumber/internal/application/port"
10	"github.com/bnema/dumber/internal/domain/favicon"
11	"github.com/bnema/dumber/internal/infrastructure/persistence/sqlite"
12	"github.com/bnema/dumber/internal/logging"
13	"github.com/stretchr/testify/assert"
14	"github.com/stretchr/testify/require"
15)
16
17func faviconTestCtx() context.Context {
18	logger := logging.NewFromConfigValues("debug", "console")
19	return logging.WithContext(context.Background(), logger)
20}
21
22func newFaviconRepo(t *testing.T) (context.Context, port.FaviconRepository) {
23	t.Helper()
24	ctx := faviconTestCtx()
25	db, err := sqlite.NewConnection(ctx, filepath.Join(t.TempDir(), "dumber.db"))
26	require.NoError(t, err)
27	t.Cleanup(func() { require.NoError(t, db.Close()) })
28	return ctx, sqlite.NewFaviconRepository(db)
29}
30
31func TestFaviconRepositoryUpsertAndGet(t *testing.T) {
32	ctx, repo := newFaviconRepo(t)
33	updatedAt := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
34	checkedAt := updatedAt.Add(time.Hour)
35
36	meta := favicon.Metadata{
37		Key:           favicon.Key("example.com"),
38		SourceURL:     "https://example.com/favicon.ico",
39		PageURL:       "https://example.com/page",
40		Source:        favicon.SourceEngine,
41		ContentHash:   "sha256:first",
42		ContentType:   "image/png",
43		UpdatedAt:     updatedAt,
44		LastCheckedAt: checkedAt,
45	}
46	require.NoError(t, repo.Upsert(ctx, meta))
47
48	got, err := repo.Get(ctx, favicon.Key("example.com"))
49	require.NoError(t, err)
50	require.NotNil(t, got)
51	assert.Equal(t, meta.Key, got.Key)
52	assert.Equal(t, meta.SourceURL, got.SourceURL)
53	assert.Equal(t, meta.PageURL, got.PageURL)
54	assert.Equal(t, meta.Source, got.Source)
55	assert.Equal(t, meta.ContentHash, got.ContentHash)
56	assert.Equal(t, meta.ContentType, got.ContentType)
57	assert.True(t, meta.UpdatedAt.Equal(got.UpdatedAt), "updated_at = %s", got.UpdatedAt)
58	assert.True(t, meta.LastCheckedAt.Equal(got.LastCheckedAt), "last_checked_at = %s", got.LastCheckedAt)
59
60	replacement := meta
61	replacement.SourceURL = "https://cdn.example.com/icon.png"
62	replacement.Source = favicon.SourcePageDiscovery
63	replacement.ContentHash = "sha256:second"
64	replacement.UpdatedAt = updatedAt.Add(2 * time.Hour)
65	replacement.LastCheckedAt = checkedAt.Add(2 * time.Hour)
66	require.NoError(t, repo.Upsert(ctx, replacement))
67
68	got, err = repo.Get(ctx, favicon.Key("example.com"))
69	require.NoError(t, err)
70	require.NotNil(t, got)
71	assert.Equal(t, replacement.SourceURL, got.SourceURL)
72	assert.Equal(t, replacement.Source, got.Source)
73	assert.Equal(t, replacement.ContentHash, got.ContentHash)
74	assert.True(t, replacement.UpdatedAt.Equal(got.UpdatedAt))
75	assert.True(t, replacement.LastCheckedAt.Equal(got.LastCheckedAt))
76}
77
78func TestFaviconRepositoryGetNotFoundReturnsNil(t *testing.T) {
79	ctx, repo := newFaviconRepo(t)
80
81	got, err := repo.Get(ctx, favicon.Key("missing.example"))
82	require.NoError(t, err)
83	assert.Nil(t, got)
84}
85
86func TestFaviconRepositoryFindFirstUsesCallerCandidateOrder(t *testing.T) {
87	ctx, repo := newFaviconRepo(t)
88	now := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
89	require.NoError(t, repo.Upsert(ctx, favicon.Metadata{Key: favicon.Key("example.com"), Source: favicon.SourceEngine, ContentHash: "parent", UpdatedAt: now, LastCheckedAt: now}))
90	require.NoError(t, repo.Upsert(ctx, favicon.Metadata{Key: favicon.Key("docs.example.com"), Source: favicon.SourceEngine, ContentHash: "child", UpdatedAt: now, LastCheckedAt: now}))
91
92	got, err := repo.FindFirst(ctx, []favicon.Key{favicon.Key("missing.example.com"), favicon.Key("example.com"), favicon.Key("docs.example.com")})
93	require.NoError(t, err)
94	require.NotNil(t, got)
95	assert.Equal(t, favicon.Key("example.com"), got.Key)
96	assert.Equal(t, "parent", got.ContentHash)
97
98	got, err = repo.FindFirst(ctx, nil)
99	require.NoError(t, err)
100	assert.Nil(t, got)
101}
102
103func TestFaviconRepositoryUpdateLastChecked(t *testing.T) {
104	ctx, repo := newFaviconRepo(t)
105	updatedAt := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
106	checkedAt := updatedAt.Add(24 * time.Hour)
107	meta := favicon.Metadata{Key: favicon.Key("example.com"), Source: favicon.SourceEngine, ContentHash: "old", UpdatedAt: updatedAt, LastCheckedAt: updatedAt}
108	require.NoError(t, repo.Upsert(ctx, meta))
109
110	require.NoError(t, repo.UpdateLastChecked(ctx, favicon.Key("example.com"), "new", checkedAt))
111
112	got, err := repo.Get(ctx, favicon.Key("example.com"))
113	require.NoError(t, err)
114	require.NotNil(t, got)
115	assert.Equal(t, "new", got.ContentHash)
116	assert.True(t, updatedAt.Equal(got.UpdatedAt), "updated_at should not change")
117	assert.True(t, checkedAt.Equal(got.LastCheckedAt))
118}
119
120func TestFaviconRepositoryDelete(t *testing.T) {
121	ctx, repo := newFaviconRepo(t)
122	now := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
123	require.NoError(t, repo.Upsert(ctx, favicon.Metadata{Key: favicon.Key("example.com"), Source: favicon.SourceEngine, ContentHash: "hash", UpdatedAt: now, LastCheckedAt: now}))
124
125	require.NoError(t, repo.Delete(ctx, favicon.Key("example.com")))
126
127	got, err := repo.Get(ctx, favicon.Key("example.com"))
128	require.NoError(t, err)
129	assert.Nil(t, got)
130}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close