1package daemon
2
3import (
4 "context"
5 "errors"
6 "sync/atomic"
7 "testing"
8 "time"
9
10 "github.com/stretchr/testify/mock"
11 "github.com/stretchr/testify/require"
12
13 "github.com/bnema/vev/internal/ports"
14 portsmocks "github.com/bnema/vev/internal/ports/mocks"
15)
16
17func TestSnapshotMultipleMutationsPublishNextRepositoryGeneration(t *testing.T) {
18 d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{})
19 repository := portsmocks.NewMockSnapshotRepository(t)
20 WithSnapshotRepository(repository)(d)
21 startSnapshotEncodeWorker(t, d)
22
23 publications := make(chan ports.SnapshotPublication, 1)
24 repository.EXPECT().Publish(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, publication ports.SnapshotPublication) error {
25 publications <- publication
26 return nil
27 }).Once()
28
29 sess := newSnapshotTestSession(t, "work", false, "/work")
30 markSnapshotDirty(sess)
31 markSnapshotDirty(sess)
32 markSnapshotDirty(sess)
33 require.True(t, d.scheduleSnapshot(sess))
34
35 select {
36 case publication := <-publications:
37 require.Equal(t, uint64(1), publication.Generation)
38 case <-time.After(testWaitTimeout):
39 t.Fatal("snapshot was not published")
40 }
41 awaitSnapshotClean(t, sess)
42}
43
44func TestSnapshotRetryKeepsRepositoryGeneration(t *testing.T) {
45 d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{})
46 repository := portsmocks.NewMockSnapshotRepository(t)
47 WithSnapshotRepository(repository)(d)
48 startSnapshotEncodeWorker(t, d)
49
50 publications := make(chan ports.SnapshotPublication, 2)
51 var attempts atomic.Int32
52 repository.EXPECT().Publish(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, publication ports.SnapshotPublication) error {
53 publications <- publication
54 if attempts.Add(1) == 1 {
55 return errors.New("temporary repository failure")
56 }
57 return nil
58 }).Twice()
59
60 sess := newSnapshotTestSession(t, "work", false, "/work")
61 markSnapshotDirty(sess)
62 require.True(t, d.scheduleSnapshot(sess))
63 select {
64 case publication := <-publications:
65 require.Equal(t, uint64(1), publication.Generation)
66 case <-time.After(testWaitTimeout):
67 t.Fatal("first snapshot was not published")
68 }
69 awaitSnapshotIdle(t, sess)
70 require.True(t, sess.snapDirty.Load())
71
72 require.True(t, d.scheduleFinalSnapshot(sess))
73 select {
74 case publication := <-publications:
75 require.Equal(t, uint64(1), publication.Generation)
76 case <-time.After(testWaitTimeout):
77 t.Fatal("retry snapshot was not published")
78 }
79 awaitSnapshotClean(t, sess)
80}