1 package notmain
2
3 import (
4 "compress/gzip"
5 "fmt"
6 "os"
7 "testing"
8 "time"
9
10 "github.com/letsencrypt/boulder/test"
11 )
12
13
14
15
16
17 var testTime = time.Time{}.Add(time.Hour + time.Minute + time.Second + time.Millisecond + time.Microsecond).Local()
18
19 func TestOpenFile(t *testing.T) {
20 tmpPlain, err := os.CreateTemp(os.TempDir(), "plain")
21 test.AssertNotError(t, err, "failed to create temporary file")
22 defer os.Remove(tmpPlain.Name())
23 _, err = tmpPlain.Write([]byte("test-1\ntest-2"))
24 test.AssertNotError(t, err, "failed to write to temp file")
25 tmpPlain.Close()
26
27 tmpGzip, err := os.CreateTemp(os.TempDir(), "gzip-*.gz")
28 test.AssertNotError(t, err, "failed to create temporary file")
29 defer os.Remove(tmpGzip.Name())
30 gzipWriter := gzip.NewWriter(tmpGzip)
31 _, err = gzipWriter.Write([]byte("test-1\ntest-2"))
32 test.AssertNotError(t, err, "failed to write to temp file")
33 gzipWriter.Flush()
34 gzipWriter.Close()
35 tmpGzip.Close()
36
37 checkFile := func(path string) {
38 t.Helper()
39 scanner, err := openFile(path)
40 test.AssertNotError(t, err, fmt.Sprintf("failed to open %q", path))
41 var lines []string
42 for scanner.Scan() {
43 lines = append(lines, scanner.Text())
44 }
45 test.AssertNotError(t, scanner.Err(), fmt.Sprintf("failed to read from %q", path))
46 test.AssertEquals(t, len(lines), 2)
47 test.AssertDeepEquals(t, lines, []string{"test-1", "test-2"})
48 }
49
50 checkFile(tmpPlain.Name())
51 checkFile(tmpGzip.Name())
52 }
53
54 func TestLoadIssuanceLog(t *testing.T) {
55
56 for _, tc := range []struct {
57 name string
58 loglines string
59 expMap map[string][]time.Time
60 expEarliest time.Time
61 expLatest time.Time
62 expErrStr string
63 }{
64 {
65 "empty file",
66 "",
67 map[string][]time.Time{},
68 time.Time{},
69 time.Time{},
70 "",
71 },
72 {
73 "no matches",
74 "some text\nsome other text",
75 map[string][]time.Time{},
76 time.Time{},
77 time.Time{},
78 "",
79 },
80 {
81 "bad json",
82 "Certificate request - successful JSON=this is not valid json",
83 map[string][]time.Time{},
84 time.Time{},
85 time.Time{},
86 "failed to unmarshal JSON",
87 },
88 {
89 "bad timestamp",
90 "2009-11-10 23:00:00 UTC Certificate request - successful JSON={}",
91 map[string][]time.Time{},
92 time.Time{},
93 time.Time{},
94 "failed to parse timestamp",
95 },
96 {
97 "normal behavior",
98 `header
99 0001-01-01T01:01:01.001001+00:00 Certificate request - successful JSON={"SerialNumber": "1", "Names":["example.com"], "Requester":0}
100 0001-01-01T02:01:01.001001+00:00 Certificate request - successful JSON={"SerialNumber": "2", "Names":["2.example.com", "3.example.com"], "Requester":0}
101 filler
102 0001-01-01T03:01:01.001001+00:00 Certificate request - successful JSON={"SerialNumber": "3", "Names":["2.example.com"], "Requester":0}
103 trailer`,
104 map[string][]time.Time{
105 "example.com": {testTime},
106 "2.example.com": {testTime.Add(time.Hour), testTime.Add(2 * time.Hour)},
107 "3.example.com": {testTime.Add(time.Hour)},
108 },
109 testTime,
110 testTime.Add(2 * time.Hour),
111 "",
112 },
113 } {
114 t.Run(tc.name, func(t *testing.T) {
115 tmp, err := os.CreateTemp(os.TempDir(), "TestLoadIssuanceLog")
116 test.AssertNotError(t, err, "failed to create temporary log file")
117 defer os.Remove(tmp.Name())
118 _, err = tmp.Write([]byte(tc.loglines))
119 test.AssertNotError(t, err, "failed to write temporary log file")
120 err = tmp.Close()
121 test.AssertNotError(t, err, "failed to close temporary log file")
122
123 resMap, resEarliest, resLatest, resError := loadIssuanceLog(tmp.Name())
124 if tc.expErrStr != "" {
125 test.AssertError(t, resError, "loadIssuanceLog should have errored")
126 test.AssertContains(t, resError.Error(), tc.expErrStr)
127 return
128 }
129 test.AssertNotError(t, resError, "loadIssuanceLog shouldn't have errored")
130 test.AssertDeepEquals(t, resMap, tc.expMap)
131 test.AssertEquals(t, resEarliest, tc.expEarliest)
132 test.AssertEquals(t, resLatest, tc.expLatest)
133 })
134 }
135 }
136
137 func TestProcessCAALog(t *testing.T) {
138 for _, tc := range []struct {
139 name string
140 loglines string
141 issuances map[string][]time.Time
142 earliest time.Time
143 latest time.Time
144 tolerance time.Duration
145 expMap map[string][]time.Time
146 expErrStr string
147 }{
148 {
149 "empty file",
150 "",
151 map[string][]time.Time{"example.com": {testTime}},
152 time.Time{},
153 time.Time{},
154 time.Second,
155 map[string][]time.Time{"example.com": {testTime}},
156 "",
157 },
158 {
159 "no matches",
160 "",
161 map[string][]time.Time{"example.com": {testTime}},
162 time.Time{},
163 time.Time{},
164 time.Second,
165 map[string][]time.Time{"example.com": {testTime}},
166 "",
167 },
168 {
169 "outside 8hr window",
170 `header
171 0001-01-01T01:01:01.001001+00:00 Checked CAA records for example.com, [Present: true, ...
172 filler
173 0001-01-01T21:01:01.001001+00:00 Checked CAA records for example.com, [Present: true, ...
174 trailer`,
175 map[string][]time.Time{"example.com": {testTime.Add(10 * time.Hour)}},
176 testTime,
177 testTime.Add(24 * time.Hour),
178 time.Second,
179 map[string][]time.Time{"example.com": {testTime.Add(10 * time.Hour)}},
180 "",
181 },
182 {
183 "outside earliest and latest",
184 `header
185 0001-01-01T01:01:01.001001+00:00 Checked CAA records for example.com, [Present: true, ...
186 filler
187 0001-01-01T21:01:01.001001+00:00 Checked CAA records for example.com, [Present: true, ...
188 trailer`,
189 map[string][]time.Time{"example.com": {testTime.Add(24 * time.Hour)}},
190 testTime.Add(10 * time.Hour),
191 testTime.Add(11 * time.Hour),
192 time.Second,
193 map[string][]time.Time{"example.com": {testTime.Add(24 * time.Hour)}},
194 "",
195 },
196 {
197 "present: false",
198 `header
199 0001-01-01T01:01:01.001001+00:00 Checked CAA records for a.b.example.com, [Present: false, ...
200 trailer`,
201 map[string][]time.Time{
202 "a.b.example.com": {testTime.Add(time.Hour)},
203 "b.example.com": {testTime.Add(time.Hour)},
204 "example.com": {testTime.Add(time.Hour)},
205 "other.com": {testTime.Add(time.Hour)},
206 },
207 testTime,
208 testTime.Add(2 * time.Hour),
209 time.Second,
210 map[string][]time.Time{"other.com": {testTime.Add(time.Hour)}},
211 "",
212 },
213 } {
214 t.Run(tc.name, func(t *testing.T) {
215 fmt.Println(tc.name)
216 tmp, err := os.CreateTemp(os.TempDir(), "TestProcessCAALog")
217 test.AssertNotError(t, err, "failed to create temporary log file")
218 defer os.Remove(tmp.Name())
219 _, err = tmp.Write([]byte(tc.loglines))
220 test.AssertNotError(t, err, "failed to write temporary log file")
221 err = tmp.Close()
222 test.AssertNotError(t, err, "failed to close temporary log file")
223
224 resError := processCAALog(tmp.Name(), tc.issuances, tc.earliest, tc.latest, tc.tolerance)
225 if tc.expErrStr != "" {
226 test.AssertError(t, resError, "processCAALog should have errored")
227 test.AssertContains(t, resError.Error(), tc.expErrStr)
228 return
229 }
230
231
232 test.AssertDeepEquals(t, tc.issuances, tc.expMap)
233 })
234 }
235 }
236
237 func TestRemoveCoveredTimestamps(t *testing.T) {
238 for _, tc := range []struct {
239 name string
240 timestamps []time.Time
241 cover time.Time
242 tolerance time.Duration
243 expected []time.Time
244 }{
245 {
246 "empty input",
247 []time.Time{},
248 testTime,
249 time.Second,
250 []time.Time{},
251 },
252 {
253 "normal functioning",
254 []time.Time{testTime.Add(-1 * time.Hour), testTime.Add(5 * time.Hour), testTime.Add(10 * time.Hour)},
255 testTime,
256 time.Second,
257 []time.Time{testTime.Add(-1 * time.Hour), testTime.Add(10 * time.Hour)},
258 },
259 {
260 "tolerance",
261 []time.Time{testTime.Add(-1 * time.Second), testTime.Add(8*time.Hour + 1*time.Second)},
262 testTime,
263 time.Second,
264 []time.Time{},
265 },
266 {
267 "intolerance",
268 []time.Time{testTime.Add(-2 * time.Second), testTime.Add(8*time.Hour + 2*time.Second)},
269 testTime,
270 time.Second,
271 []time.Time{testTime.Add(-2 * time.Second), testTime.Add(8*time.Hour + 2*time.Second)},
272 },
273 } {
274 t.Run(tc.name, func(t *testing.T) {
275 result := removeCoveredTimestamps(tc.timestamps, tc.cover, tc.tolerance)
276 test.AssertDeepEquals(t, result, tc.expected)
277 })
278 }
279 }
280
View as plain text