Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: build_scheduler/go/db/local_db/local_db_test.go

Issue 2296763008: [task scheduler] Move files from build_scheduler/ to task_scheduler/ (Closed) Base URL: https://skia.googlesource.com/buildbot@master
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build_scheduler/go/db/local_db/local_db.go ('k') | build_scheduler/go/db/memory.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 package local_db
2
3 import (
4 "io/ioutil"
5 "path/filepath"
6 "sort"
7 "testing"
8 "time"
9
10 assert "github.com/stretchr/testify/require"
11 "go.skia.org/infra/build_scheduler/go/db"
12 "go.skia.org/infra/go/testutils"
13 "go.skia.org/infra/go/util"
14 )
15
16 // Check that formatId and parseId are inverse operations and produce the
17 // expected result.
18 func TestFormatParseId(t *testing.T) {
19 testCases := []struct {
20 ts time.Time
21 seq uint64
22 id string
23 }{
24 {
25 ts: time.Date(2009, time.November, 10, 23, 45, 6, 1500, time.UTC),
26 seq: 0,
27 id: "20091110T234506.000001500Z_0000000000000000",
28 },
29 {
30 ts: time.Date(2001, time.February, 3, 4, 5, 6, 0, time. FixedZone("fake", 45*60)),
31 seq: 1,
32 // Subtract 45 minutes due to zone.
33 id: "20010203T032006.000000000Z_0000000000000001",
34 },
35 {
36 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000 , time.UTC),
37 seq: 15,
38 id: "20010101T010101.100000000Z_000000000000000f",
39 },
40 {
41 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000 , time.UTC),
42 seq: 16,
43 id: "20010101T010101.100000000Z_0000000000000010",
44 },
45 {
46 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000 , time.UTC),
47 seq: 255,
48 id: "20010101T010101.100000000Z_00000000000000ff",
49 },
50 {
51 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000 , time.UTC),
52 seq: 0xFFFFFFFFFFFFFFFF,
53 id: "20010101T010101.100000000Z_ffffffffffffffff",
54 },
55 }
56 for _, testCase := range testCases {
57 assert.Equal(t, testCase.id, formatId(testCase.ts, testCase.seq) )
58 ts, seq, err := parseId(testCase.id)
59 assert.NoError(t, err)
60 assert.True(t, testCase.ts.Equal(ts))
61 assert.Equal(t, testCase.seq, seq)
62 assert.Equal(t, time.UTC, ts.Location())
63 }
64
65 // Invalid timestamps:
66 for _, invalidId := range []string{
67 // Missing seq num.
68 "20091110T234506.000001500Z",
69 // Two-digit year.
70 "091110T234506.000001500Z_0000000000000000",
71 // Invalid month.
72 "20010001T010101.100000000Z_000000000000000f",
73 // Missing T.
74 "20010101010101.100000000Z_000000000000000f",
75 // Missing Z.
76 "20010101T010101.100000000_000000000000000f",
77 // Empty seq num.
78 "20010101T010101.100000000Z_",
79 // Invalid char in seq num.
80 "20010101T010101.100000000Z_000000000000000g",
81 // Invalid char in seq num.
82 "20010101T010101.100000000Z_g000000000000000",
83 // Empty timestamp.
84 "_000000000000000f",
85 // Sequence num overflows.
86 "20010101T010101.100000000Z_1ffffffffffffffff",
87 } {
88 _, _, err := parseId(invalidId)
89 assert.Error(t, err, "No error for Id: %q", invalidId)
90 }
91 }
92
93 // Check that packV1 and unpackV1 are inverse operations and produce the
94 // expected result.
95 func TestPackUnpackV1(t *testing.T) {
96 testCases := []struct {
97 ts time.Time
98 data []byte
99 packed []byte
100 }{
101 {
102 ts: time.Unix(0, 0x1174f263b54399dc),
103 data: []byte{0xab, 0xcd, 0xef, 0x01, 0x23},
104 packed: []byte{0x01, 0x11, 0x74, 0xf2, 0x63, 0xb5, 0x43, 0x99, 0xdc, 0xab, 0xcd, 0xef, 0x01, 0x23},
105 },
106 {
107 ts: time.Date(2262, time.April, 11, 23, 47, 16, 8547 75807, time.UTC),
108 data: []byte("Hi Mom!"),
109 packed: append([]byte{0x01, 0x7f, 0xff, 0xff, 0xff, 0xff , 0xff, 0xff, 0xff}, "Hi Mom!"...),
110 },
111 {
112 ts: time.Unix(0, 0),
113 data: []byte{},
114 packed: []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
115 },
116 }
117 for _, testCase := range testCases {
118 assert.Equal(t, testCase.packed, packV1(testCase.ts, testCase.da ta))
119 ts, data, err := unpackV1(testCase.packed)
120 assert.NoError(t, err)
121 assert.True(t, testCase.ts.Equal(ts))
122 assert.Equal(t, testCase.data, data)
123 assert.Equal(t, time.UTC, ts.Location())
124 }
125
126 for _, invalid := range [][]byte{
127 []byte{},
128 []byte{0x00},
129 []byte{0x01, 0x00, 0x00},
130 []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
131 } {
132 _, _, err := unpackV1(invalid)
133 assert.Error(t, err)
134 }
135 }
136
137 // Create a localDB for testing. Call defer util.RemoveAll() on the second
138 // return value.
139 func makeDB(t *testing.T, name string) (db.DB, string) {
140 //testutils.SkipIfShort(t)
141 tmpdir, err := ioutil.TempDir("", name)
142 assert.NoError(t, err)
143 d, err := NewDB(name, filepath.Join(tmpdir, "task.db"))
144 assert.NoError(t, err)
145 return d, tmpdir
146 }
147
148 // Test that AssignId returns an error if Id is set.
149 func TestAssignIdAlreadyAssigned(t *testing.T) {
150 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs")
151 defer util.RemoveAll(tmpdir)
152 defer testutils.AssertCloses(t, d)
153
154 task := &db.Task{}
155 assert.NoError(t, d.AssignId(task))
156 assert.Error(t, d.AssignId(task))
157 }
158
159 // Test that AssignId uses created timestamp when set, and generates unique IDs
160 // for the same timestamp.
161 func TestAssignIdsFromCreatedTs(t *testing.T) {
162 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs")
163 defer util.RemoveAll(tmpdir)
164 defer testutils.AssertCloses(t, d)
165
166 tasks := []*db.Task{}
167 addTask := func(ts time.Time) {
168 task := &db.Task{
169 Created: ts,
170 }
171 assert.NoError(t, d.AssignId(task))
172 tasks = append(tasks, task)
173 }
174
175 // Add tasks with various creation timestamps.
176 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
177 addTask(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC))
178 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
179 addTask(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.U TC))
180 // Repeated timestamps.
181 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
182 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
183 for i := 0; i < 256; i++ {
184 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
185 }
186
187 // Collect IDs. Assert Id is set.
188 ids := make([]string, 0, len(tasks))
189 for _, task := range tasks {
190 assert.NotEqual(t, "", task.Id)
191 ids = append(ids, task.Id)
192 }
193
194 // Stable-sort tasks.
195 sort.Stable(db.TaskSlice(tasks))
196
197 // Sort IDs.
198 sort.Strings(ids)
199
200 // Validate that sorted IDs match sorted Tasks. Check that there are no
201 // duplicate IDs. Check that ID timestamp matches created timestamp.
202 prevId := ""
203 for i := 0; i < len(tasks); i++ {
204 assert.Equal(t, ids[i], tasks[i].Id)
205 assert.NotEqual(t, prevId, ids[i])
206 ts, _, err := parseId(ids[i])
207 assert.NoError(t, err)
208 assert.True(t, ts.Equal(tasks[i].Created))
209 prevId = ids[i]
210 }
211 }
212
213 // Test that AssignId can generate ids when created timestamp is not set, and
214 // generates unique IDs for PutTasks.
215 func TestAssignIdsFromCurrentTime(t *testing.T) {
216 d, tmpdir := makeDB(t, "TestAssignIdsFromCurrentTime")
217 defer util.RemoveAll(tmpdir)
218 defer testutils.AssertCloses(t, d)
219
220 tasks := []*db.Task{}
221 for i := 0; i < 260; i++ {
222 tasks = append(tasks, &db.Task{})
223 }
224
225 begin := time.Now()
226
227 // Test AssignId.
228 assert.NoError(t, d.AssignId(tasks[5]))
229 assert.NoError(t, d.AssignId(tasks[6]))
230 id5, id6 := tasks[5].Id, tasks[6].Id
231
232 // Created time is required.
233 for _, task := range tasks {
234 task.Created = time.Now()
235 }
236
237 // Test PutTasks.
238 assert.NoError(t, d.PutTasks(tasks))
239
240 end := time.Now()
241
242 // Check that PutTasks did not change existing Ids.
243 assert.Equal(t, id5, tasks[5].Id)
244 assert.Equal(t, id6, tasks[6].Id)
245
246 // Order tasks by time of ID assignment.
247 first2 := []*db.Task{tasks[5], tasks[6]}
248 copy(tasks[2:7], tasks[0:5])
249 copy(tasks[0:2], first2)
250
251 // Collect IDs. Assert Id is set.
252 ids := make([]string, 0, len(tasks))
253 for _, task := range tasks {
254 assert.NotEqual(t, "", task.Id)
255 ids = append(ids, task.Id)
256 }
257
258 // Sort IDs.
259 sort.Strings(ids)
260
261 // Validate that sorted IDs match Tasks by insertion order. Check that t here
262 // are no duplicate IDs. Check that begin <= ID timestamp <= end.
263 prevId := ""
264 for i := 0; i < len(tasks); i++ {
265 assert.Equal(t, ids[i], tasks[i].Id)
266 assert.NotEqual(t, prevId, ids[i])
267 ts, _, err := parseId(ids[i])
268 assert.NoError(t, err)
269 assert.True(t, begin.Before(ts) || begin.Equal(ts))
270 assert.True(t, ts.Before(end) || ts.Equal(end))
271 prevId = ids[i]
272 }
273 }
274
275 // Test that PutTask returns an error when AssignId time is too far before (or
276 // after) the value subsequently assigned to Task.Created.
277 func TestPutTaskValidateCreatedTime(t *testing.T) {
278 d, tmpdir := makeDB(t, "TestPutTaskValidateCreatedTime")
279 defer util.RemoveAll(tmpdir)
280 defer testutils.AssertCloses(t, d)
281
282 task := &db.Task{}
283 beforeAssignId := time.Now().Add(-time.Nanosecond)
284 assert.NoError(t, d.AssignId(task))
285 afterAssignId := time.Now().Add(time.Nanosecond)
286
287 // Test "not set".
288 {
289 err := d.PutTask(task)
290 assert.Error(t, err)
291 assert.Contains(t, err.Error(), "Created not set.")
292 }
293
294 // Test "too late".
295 {
296 task.Created = afterAssignId.Add(MAX_CREATED_TIME_SKEW)
297 err := d.PutTask(task)
298 assert.Error(t, err)
299 assert.Contains(t, err.Error(), "Created too late.")
300 }
301
302 // Test "too early".
303 {
304 task.Created = beforeAssignId
305 err := d.PutTask(task)
306 assert.Error(t, err)
307 assert.Contains(t, err.Error(), "Created too early.")
308
309 // Verify not in DB.
310 noTask, err := d.GetTaskById(task.Id)
311 assert.NoError(t, err)
312 assert.Nil(t, noTask)
313 }
314
315 // Test in range.
316 {
317 task.Created = beforeAssignId.Add(MAX_CREATED_TIME_SKEW)
318 err := d.PutTask(task)
319 assert.NoError(t, err)
320
321 // Verify added to DB.
322 taskCopy, err := d.GetTaskById(task.Id)
323 assert.NoError(t, err)
324 testutils.AssertDeepEqual(t, task, taskCopy)
325 }
326
327 // We can even change the Created time if we want. (Not necessarily supp orted
328 // by all DB implementations.)
329 {
330 task.Created = afterAssignId
331 err := d.PutTask(task)
332 assert.NoError(t, err)
333
334 taskCopy, err := d.GetTaskById(task.Id)
335 assert.NoError(t, err)
336 testutils.AssertDeepEqual(t, task, taskCopy)
337 }
338
339 // But we can't change it to be out of range.
340 {
341 prevCreated := task.Created
342 task.Created = beforeAssignId
343 err := d.PutTask(task)
344 assert.Error(t, err)
345 assert.Contains(t, err.Error(), "Created too early.")
346
347 taskCopy, err := d.GetTaskById(task.Id)
348 assert.NoError(t, err)
349 assert.True(t, prevCreated.Equal(taskCopy.Created))
350 }
351 }
352
353 // Test that PutTask/s does not modify the passed-in Tasks when there is an
354 // error.
355 func TestPutTaskLeavesTasksUnchanged(t *testing.T) {
356 d, tmpdir := makeDB(t, "TestPutTaskLeavesTasksUnchanged")
357 defer util.RemoveAll(tmpdir)
358 defer testutils.AssertCloses(t, d)
359
360 begin := time.Now().Add(-time.Nanosecond)
361
362 // Create and insert a task that will cause ErrConcurrentUpdate.
363 task1 := &db.Task{
364 Created: time.Now(),
365 }
366 assert.NoError(t, d.PutTask(task1))
367
368 // Retrieve a copy, modify original.
369 task1Cached, err := d.GetTaskById(task1.Id)
370 assert.NoError(t, err)
371 task1.Status = db.TASK_STATUS_RUNNING
372 assert.NoError(t, d.PutTask(task1))
373 task1InDb := task1.Copy()
374
375 // Create and insert a task to check PutTasks doesn't change DbModified.
376 task2 := &db.Task{
377 Created: time.Now(),
378 }
379 assert.NoError(t, d.PutTask(task2))
380 task2InDb := task2.Copy()
381 task2.Status = db.TASK_STATUS_MISHAP
382
383 // Create a task with an Id already set.
384 task3 := &db.Task{}
385 assert.NoError(t, d.AssignId(task3))
386 task3.Created = time.Now()
387
388 // Create a task without an Id set.
389 task4 := &db.Task{
390 Created: time.Now(),
391 }
392
393 // Make an update to task1Cached.
394 task1Cached.Commits = []string{"a", "b"}
395
396 // Copy to compare later.
397 expectedTasks := []*db.Task{task1Cached.Copy(), task2.Copy(), task3.Copy (), task4.Copy()}
398
399 // Attempt to insert; put task1Cached last so that the error comes last.
400 err = d.PutTasks([]*db.Task{task2, task3, task4, task1Cached})
401 assert.True(t, db.IsConcurrentUpdate(err))
402 testutils.AssertDeepEqual(t, expectedTasks, []*db.Task{task1Cached, task 2, task3, task4})
403
404 // Check that nothing was updated in the DB.
405 tasksInDb, err := d.GetTasksFromDateRange(begin, time.Now())
406 assert.NoError(t, err)
407 assert.Equal(t, 2, len(tasksInDb))
408 for _, task := range tasksInDb {
409 switch task.Id {
410 case task1.Id:
411 testutils.AssertDeepEqual(t, task1InDb, task)
412 case task2.Id:
413 testutils.AssertDeepEqual(t, task2InDb, task)
414 default:
415 assert.Fail(t, "Unexpected task in DB: %v", task)
416 }
417 }
418 }
419
420 func TestLocalDB(t *testing.T) {
421 d, tmpdir := makeDB(t, "TestLocalDB")
422 defer util.RemoveAll(tmpdir)
423 db.TestDB(t, d)
424 }
425
426 func TestLocalDBTooManyUsers(t *testing.T) {
427 d, tmpdir := makeDB(t, "TestLocalDBTooManyUsers")
428 defer util.RemoveAll(tmpdir)
429 db.TestTooManyUsers(t, d)
430 }
431
432 func TestLocalDBConcurrentUpdate(t *testing.T) {
433 d, tmpdir := makeDB(t, "TestLocalDBConcurrentUpdate")
434 defer util.RemoveAll(tmpdir)
435 db.TestConcurrentUpdate(t, d)
436 }
437
438 func TestLocalDBUpdateWithRetries(t *testing.T) {
439 d, tmpdir := makeDB(t, "TestLocalDBUpdateWithRetries")
440 defer util.RemoveAll(tmpdir)
441 db.TestUpdateWithRetries(t, d)
442 }
OLDNEW
« no previous file with comments | « build_scheduler/go/db/local_db/local_db.go ('k') | build_scheduler/go/db/memory.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698