forked from tailscale/tailscale
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdelete_test.go
152 lines (135 loc) · 4.14 KB
/
delete_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package taildrop
import (
"os"
"path/filepath"
"slices"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"tailscale.com/ipn"
"tailscale.com/ipn/store/mem"
"tailscale.com/tstest"
"tailscale.com/tstime"
"tailscale.com/util/must"
)
func TestDeleter(t *testing.T) {
dir := t.TempDir()
must.Do(touchFile(filepath.Join(dir, "foo.partial")))
must.Do(touchFile(filepath.Join(dir, "bar.partial")))
must.Do(touchFile(filepath.Join(dir, "fizz")))
must.Do(touchFile(filepath.Join(dir, "fizz.deleted")))
must.Do(touchFile(filepath.Join(dir, "buzz.deleted"))) // lacks a matching "buzz" file
checkDirectory := func(want ...string) {
t.Helper()
var got []string
for _, de := range must.Get(os.ReadDir(dir)) {
got = append(got, de.Name())
}
slices.Sort(got)
slices.Sort(want)
if diff := cmp.Diff(got, want); diff != "" {
t.Fatalf("directory mismatch (-got +want):\n%s", diff)
}
}
clock := tstest.NewClock(tstest.ClockOpts{Start: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)})
advance := func(d time.Duration) {
t.Helper()
t.Logf("advance: %v", d)
clock.Advance(d)
}
eventsChan := make(chan string, 1000)
checkEvents := func(want ...string) {
t.Helper()
tm := time.NewTimer(10 * time.Second)
defer tm.Stop()
var got []string
for range want {
select {
case event := <-eventsChan:
t.Logf("event: %s", event)
got = append(got, event)
case <-tm.C:
t.Fatalf("timed out waiting for event: got %v, want %v", got, want)
}
}
slices.Sort(got)
slices.Sort(want)
if diff := cmp.Diff(got, want); diff != "" {
t.Fatalf("events mismatch (-got +want):\n%s", diff)
}
}
eventHook := func(event string) { eventsChan <- event }
var m Manager
var fd fileDeleter
m.opts.Logf = t.Logf
m.opts.Clock = tstime.DefaultClock{Clock: clock}
m.opts.Dir = dir
m.opts.State = must.Get(mem.New(nil, ""))
must.Do(m.opts.State.WriteState(ipn.TaildropReceivedKey, []byte{1}))
fd.Init(&m, eventHook)
defer fd.Shutdown()
insert := func(name string) {
t.Helper()
t.Logf("insert: %v", name)
fd.Insert(name)
}
remove := func(name string) {
t.Helper()
t.Logf("remove: %v", name)
fd.Remove(name)
}
checkEvents("start full-scan")
checkEvents("end full-scan", "start waitAndDelete")
checkDirectory("foo.partial", "bar.partial", "buzz.deleted")
advance(deleteDelay / 2)
checkDirectory("foo.partial", "bar.partial", "buzz.deleted")
advance(deleteDelay / 2)
checkEvents("deleted foo.partial", "deleted bar.partial", "deleted buzz.deleted")
checkEvents("end waitAndDelete")
checkDirectory()
must.Do(touchFile(filepath.Join(dir, "one.partial")))
insert("one.partial")
checkEvents("start waitAndDelete")
advance(deleteDelay / 4)
must.Do(touchFile(filepath.Join(dir, "two.partial")))
insert("two.partial")
advance(deleteDelay / 4)
must.Do(touchFile(filepath.Join(dir, "three.partial")))
insert("three.partial")
advance(deleteDelay / 4)
must.Do(touchFile(filepath.Join(dir, "four.partial")))
insert("four.partial")
advance(deleteDelay / 4)
checkEvents("deleted one.partial")
checkDirectory("two.partial", "three.partial", "four.partial")
checkEvents("end waitAndDelete", "start waitAndDelete")
advance(deleteDelay / 4)
checkEvents("deleted two.partial")
checkDirectory("three.partial", "four.partial")
checkEvents("end waitAndDelete", "start waitAndDelete")
advance(deleteDelay / 4)
checkEvents("deleted three.partial")
checkDirectory("four.partial")
checkEvents("end waitAndDelete", "start waitAndDelete")
advance(deleteDelay / 4)
checkEvents("deleted four.partial")
checkDirectory()
checkEvents("end waitAndDelete")
insert("wuzz.partial")
checkEvents("start waitAndDelete")
remove("wuzz.partial")
checkEvents("end waitAndDelete")
}
// Test that the asynchronous full scan of the taildrop directory does not occur
// on a cold start if taildrop has never received any files.
func TestDeleterInitWithoutTaildrop(t *testing.T) {
var m Manager
var fd fileDeleter
m.opts.Logf = t.Logf
m.opts.Dir = t.TempDir()
m.opts.State = must.Get(mem.New(nil, ""))
fd.Init(&m, func(event string) { t.Errorf("unexpected event: %v", event) })
fd.Shutdown()
}