1
1
package workspaceusage
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
6
+ "flag"
5
7
"os"
6
8
"sort"
7
- "strings"
8
9
"sync"
9
10
"time"
10
11
@@ -84,16 +85,22 @@ func WithFlushInterval(d time.Duration) Option {
84
85
85
86
// WithFlushChannel allows passing a channel that receives
86
87
// the number of marked workspaces every time Tracker flushes.
87
- // For testing only.
88
+ // For testing only and will panic if used outside of tests .
88
89
func WithFlushChannel (c chan int ) Option {
90
+ if flag .Lookup ("test.v" ) == nil {
91
+ panic ("developer error: WithFlushChannel is not to be used outside of tests." )
92
+ }
89
93
return func (h * Tracker ) {
90
94
h .flushCh = c
91
95
}
92
96
}
93
97
94
98
// WithTickChannel allows passing a channel to replace a ticker.
95
- // For testing only.
99
+ // For testing only and will panic if used outside of tests .
96
100
func WithTickChannel (c chan time.Time ) Option {
101
+ if flag .Lookup ("test.v" ) == nil {
102
+ panic ("developer error: WithTickChannel is not to be used outside of tests." )
103
+ }
97
104
return func (h * Tracker ) {
98
105
h .tickCh = c
99
106
h .stopTick = func () {}
@@ -125,11 +132,6 @@ func (wut *Tracker) flush(now time.Time) {
125
132
return
126
133
}
127
134
128
- // For ease of testing, sort the IDs lexically
129
- sort .Slice (ids , func (i , j int ) bool {
130
- // For some unfathomable reason, byte arrays are not comparable?
131
- return strings .Compare (ids [i ].String (), ids [j ].String ()) < 0
132
- })
133
135
// Set a short-ish timeout for this. We don't want to hang forever.
134
136
ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
135
137
defer cancel ()
@@ -147,7 +149,15 @@ func (wut *Tracker) flush(now time.Time) {
147
149
wut .log .Info (ctx , "updated workspaces last_used_at" , slog .F ("count" , count ), slog .F ("now" , now ))
148
150
}
149
151
152
+ // Loop periodically flushes every tick.
153
+ // If Loop is called after Close, it will panic. Don't do this.
150
154
func (wut * Tracker ) Loop () {
155
+ // Calling Loop after Close() is an error.
156
+ select {
157
+ case <- wut .doneCh :
158
+ panic ("developer error: Loop called after Close" )
159
+ default :
160
+ }
151
161
defer func () {
152
162
wut .log .Debug (context .Background (), "workspace usage tracker loop exited" )
153
163
}()
@@ -165,7 +175,8 @@ func (wut *Tracker) Loop() {
165
175
}
166
176
}
167
177
168
- // Close stops Tracker and performs a final flush.
178
+ // Close stops Tracker and returns once Loop has exited.
179
+ // After calling Close(), Loop must not be called.
169
180
func (wut * Tracker ) Close () {
170
181
wut .stopOnce .Do (func () {
171
182
wut .stopCh <- struct {}{}
@@ -202,6 +213,11 @@ func (s *uuidSet) UniqueAndClear() []uuid.UUID {
202
213
for k := range s .m {
203
214
l = append (l , k )
204
215
}
216
+ // For ease of testing, sort the IDs lexically
217
+ sort .Slice (l , func (i , j int ) bool {
218
+ // For some unfathomable reason, byte arrays are not comparable?
219
+ return bytes .Compare (l [i ][:], l [j ][:]) < 0
220
+ })
205
221
s .m = make (map [uuid.UUID ]struct {})
206
222
return l
207
223
}
0 commit comments