@@ -5,25 +5,26 @@ import (
55 "fmt"
66 "os"
77 "sync"
8+ "sync/atomic"
89 "testing"
910 "time"
1011
1112 "github.com/segmentio/ctlstore/pkg/ldbwriter"
1213)
1314
1415type fake struct {
15- size int64
16- err error
17- wg sync.WaitGroup
18- statCallCount int
19- checkCallCount int
16+ size int64
17+ err error
18+ wg sync.WaitGroup
19+ statCallCount atomic. Int64
20+ cpCallCount atomic. Int64
2021}
2122
2223func (f * fake ) Stat () func (m * WALMonitor ) {
2324 return func (m * WALMonitor ) {
2425 m .walSizeFunc = func (p string ) (int64 , error ) {
2526 defer f .wg .Done ()
26- f .statCallCount ++
27+ f .statCallCount . Add ( 1 )
2728 v , err := m .getWALSize (p )
2829 f .size = v
2930 f .err = err
@@ -43,13 +44,14 @@ func (f *fake) Ticker() func(m *WALMonitor) {
4344func (f * fake ) Checkpointer () func (m * WALMonitor ) {
4445 return func (m * WALMonitor ) {
4546 m .cpTesterFunc = func () (* ldbwriter.PragmaWALResult , error ) {
46- f .checkCallCount ++
47+ defer f .wg .Done ()
48+ f .cpCallCount .Add (1 )
4749 return nil , fmt .Errorf ("fail" )
4850 }
4951 }
5052}
5153
52- func TestWALMonitorSize (t * testing.T ) {
54+ func TestWALMonitorTooSmall (t * testing.T ) {
5355 tmpdir := t .TempDir ()
5456 f , err := os .CreateTemp (tmpdir , "*.ldb-wal" )
5557 if err != nil {
@@ -66,10 +68,57 @@ func TestWALMonitorSize(t *testing.T) {
6668 }
6769
6870 var fake fake
69- fake .wg .Add (1 )
71+ fake .wg .Add (2 )
7072 mon := NewMonitor (MonitorConfig {
71- PollInterval : time .Millisecond ,
72- Path : f .Name (),
73+ PollInterval : time .Millisecond ,
74+ Path : f .Name (),
75+ WALCheckpointThresholdSize : int64 (n + 1 ),
76+ }, nil , fake .Stat (), fake .Ticker (), fake .Checkpointer ())
77+
78+ ctx , cancel := context .WithCancel (context .Background ())
79+ go mon .Start (ctx )
80+ // wait for fake stat call
81+ fake .wg .Wait ()
82+ cancel ()
83+
84+ if fake .statCallCount .Load () == 0 {
85+ t .Errorf ("Stat should have been called at least once" )
86+ }
87+
88+ if fake .cpCallCount .Load () != 0 {
89+ t .Errorf ("Checkpoint should not have been called since the file wasn't large enough" )
90+ }
91+ if fake .err != nil {
92+ t .Errorf ("unexpected error on stat: %v" , fake .err )
93+ }
94+
95+ if int64 (n ) != fake .size {
96+ t .Errorf ("expected file size of %d, got %d" , n , fake .size )
97+ }
98+ }
99+
100+ func TestWALMonitorBigEnough (t * testing.T ) {
101+ tmpdir := t .TempDir ()
102+ f , err := os .CreateTemp (tmpdir , "*.ldb-wal" )
103+ if err != nil {
104+ t .Fatal (err )
105+ }
106+
107+ n , err := f .WriteString ("some random bytes!" )
108+ if err != nil {
109+ t .Fatal (err )
110+ }
111+
112+ if f .Sync () != nil {
113+ t .Fatal (err )
114+ }
115+
116+ var fake fake
117+ fake .wg .Add (2 )
118+ mon := NewMonitor (MonitorConfig {
119+ PollInterval : time .Millisecond ,
120+ Path : f .Name (),
121+ WALCheckpointThresholdSize : int64 (n - 1 ),
73122 }, nil , fake .Stat (), fake .Ticker (), fake .Checkpointer ())
74123
75124 ctx , cancel := context .WithCancel (context .Background ())
@@ -78,11 +127,11 @@ func TestWALMonitorSize(t *testing.T) {
78127 fake .wg .Wait ()
79128 cancel ()
80129
81- if fake .statCallCount == 0 {
130+ if fake .statCallCount . Load () == 0 {
82131 t .Errorf ("Stat should have been called at least once" )
83132 }
84133
85- if fake .checkCallCount == 0 {
134+ if fake .cpCallCount . Load () == 0 {
86135 t .Errorf ("Checkpoint should have been called at least once" )
87136 }
88137 if fake .err != nil {
@@ -103,16 +152,16 @@ func TestNoWALPath(t *testing.T) {
103152
104153 mon .Start (context .Background ())
105154
106- if fake .statCallCount != 0 {
155+ if fake .statCallCount . Load () != 0 {
107156 t .Errorf ("Stat should not have been called" )
108157 }
109158
110- if fake .checkCallCount != 0 {
159+ if fake .cpCallCount . Load () != 0 {
111160 t .Errorf ("Checkpoint should not have been called" )
112161 }
113162}
114163
115- func TestWALMonitorStopsOnError (t * testing.T ) {
164+ func TestWALMonitorStopsOnStatError (t * testing.T ) {
116165 var fake fake
117166 fake .wg .Add (5 )
118167 mon := NewMonitor (MonitorConfig {
@@ -122,11 +171,41 @@ func TestWALMonitorStopsOnError(t *testing.T) {
122171
123172 mon .Start (context .Background ())
124173 fake .wg .Wait ()
125- if fake .statCallCount != 5 {
126- t .Errorf ("Stat should have been called 5 times, got %d" , fake .statCallCount )
174+ if fake .statCallCount . Load () != 5 {
175+ t .Errorf ("Stat should have been called 5 times, got %d" , fake .statCallCount . Load () )
127176 }
128177
129- if fake .checkCallCount != 5 {
130- t .Errorf ("Checkpoint should have have been called 5 times, got %d" , fake .checkCallCount )
178+ if fake .cpCallCount .Load () != 0 {
179+ t .Errorf ("Checkpoint should not have been called" )
180+ }
181+ }
182+
183+ func TestWALMonitorStopsOnCheckpointError (t * testing.T ) {
184+ tmpdir := t .TempDir ()
185+ f , err := os .CreateTemp (tmpdir , "*.ldb-wal" )
186+ if err != nil {
187+ t .Fatal (err )
188+ }
189+
190+ _ , err = f .WriteString ("some random bytes!" )
191+ if err != nil {
192+ t .Fatal (err )
193+ }
194+
195+ var fake fake
196+ fake .wg .Add (10 )
197+ mon := NewMonitor (MonitorConfig {
198+ PollInterval : 50 * time .Microsecond ,
199+ Path : f .Name (),
200+ }, nil , fake .Stat (), fake .Checkpointer ())
201+
202+ mon .Start (context .Background ())
203+ fake .wg .Wait ()
204+ if fake .statCallCount .Load () != 5 {
205+ t .Errorf ("Stat should have been called 5 times, got %d" , fake .statCallCount .Load ())
206+ }
207+
208+ if fake .cpCallCount .Load () != 5 {
209+ t .Errorf ("Checkpoint should not have been called" )
131210 }
132211}
0 commit comments