| Index: build_scheduler/go/db/local_db/local_db_test.go
|
| diff --git a/build_scheduler/go/db/local_db/local_db_test.go b/build_scheduler/go/db/local_db/local_db_test.go
|
| deleted file mode 100644
|
| index a9542d2714dc60f28c7c832b1e280dcf21740761..0000000000000000000000000000000000000000
|
| --- a/build_scheduler/go/db/local_db/local_db_test.go
|
| +++ /dev/null
|
| @@ -1,442 +0,0 @@
|
| -package local_db
|
| -
|
| -import (
|
| - "io/ioutil"
|
| - "path/filepath"
|
| - "sort"
|
| - "testing"
|
| - "time"
|
| -
|
| - assert "github.com/stretchr/testify/require"
|
| - "go.skia.org/infra/build_scheduler/go/db"
|
| - "go.skia.org/infra/go/testutils"
|
| - "go.skia.org/infra/go/util"
|
| -)
|
| -
|
| -// Check that formatId and parseId are inverse operations and produce the
|
| -// expected result.
|
| -func TestFormatParseId(t *testing.T) {
|
| - testCases := []struct {
|
| - ts time.Time
|
| - seq uint64
|
| - id string
|
| - }{
|
| - {
|
| - ts: time.Date(2009, time.November, 10, 23, 45, 6, 1500, time.UTC),
|
| - seq: 0,
|
| - id: "20091110T234506.000001500Z_0000000000000000",
|
| - },
|
| - {
|
| - ts: time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("fake", 45*60)),
|
| - seq: 1,
|
| - // Subtract 45 minutes due to zone.
|
| - id: "20010203T032006.000000000Z_0000000000000001",
|
| - },
|
| - {
|
| - ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000, time.UTC),
|
| - seq: 15,
|
| - id: "20010101T010101.100000000Z_000000000000000f",
|
| - },
|
| - {
|
| - ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000, time.UTC),
|
| - seq: 16,
|
| - id: "20010101T010101.100000000Z_0000000000000010",
|
| - },
|
| - {
|
| - ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000, time.UTC),
|
| - seq: 255,
|
| - id: "20010101T010101.100000000Z_00000000000000ff",
|
| - },
|
| - {
|
| - ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000, time.UTC),
|
| - seq: 0xFFFFFFFFFFFFFFFF,
|
| - id: "20010101T010101.100000000Z_ffffffffffffffff",
|
| - },
|
| - }
|
| - for _, testCase := range testCases {
|
| - assert.Equal(t, testCase.id, formatId(testCase.ts, testCase.seq))
|
| - ts, seq, err := parseId(testCase.id)
|
| - assert.NoError(t, err)
|
| - assert.True(t, testCase.ts.Equal(ts))
|
| - assert.Equal(t, testCase.seq, seq)
|
| - assert.Equal(t, time.UTC, ts.Location())
|
| - }
|
| -
|
| - // Invalid timestamps:
|
| - for _, invalidId := range []string{
|
| - // Missing seq num.
|
| - "20091110T234506.000001500Z",
|
| - // Two-digit year.
|
| - "091110T234506.000001500Z_0000000000000000",
|
| - // Invalid month.
|
| - "20010001T010101.100000000Z_000000000000000f",
|
| - // Missing T.
|
| - "20010101010101.100000000Z_000000000000000f",
|
| - // Missing Z.
|
| - "20010101T010101.100000000_000000000000000f",
|
| - // Empty seq num.
|
| - "20010101T010101.100000000Z_",
|
| - // Invalid char in seq num.
|
| - "20010101T010101.100000000Z_000000000000000g",
|
| - // Invalid char in seq num.
|
| - "20010101T010101.100000000Z_g000000000000000",
|
| - // Empty timestamp.
|
| - "_000000000000000f",
|
| - // Sequence num overflows.
|
| - "20010101T010101.100000000Z_1ffffffffffffffff",
|
| - } {
|
| - _, _, err := parseId(invalidId)
|
| - assert.Error(t, err, "No error for Id: %q", invalidId)
|
| - }
|
| -}
|
| -
|
| -// Check that packV1 and unpackV1 are inverse operations and produce the
|
| -// expected result.
|
| -func TestPackUnpackV1(t *testing.T) {
|
| - testCases := []struct {
|
| - ts time.Time
|
| - data []byte
|
| - packed []byte
|
| - }{
|
| - {
|
| - ts: time.Unix(0, 0x1174f263b54399dc),
|
| - data: []byte{0xab, 0xcd, 0xef, 0x01, 0x23},
|
| - packed: []byte{0x01, 0x11, 0x74, 0xf2, 0x63, 0xb5, 0x43, 0x99, 0xdc, 0xab, 0xcd, 0xef, 0x01, 0x23},
|
| - },
|
| - {
|
| - ts: time.Date(2262, time.April, 11, 23, 47, 16, 854775807, time.UTC),
|
| - data: []byte("Hi Mom!"),
|
| - packed: append([]byte{0x01, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, "Hi Mom!"...),
|
| - },
|
| - {
|
| - ts: time.Unix(0, 0),
|
| - data: []byte{},
|
| - packed: []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
| - },
|
| - }
|
| - for _, testCase := range testCases {
|
| - assert.Equal(t, testCase.packed, packV1(testCase.ts, testCase.data))
|
| - ts, data, err := unpackV1(testCase.packed)
|
| - assert.NoError(t, err)
|
| - assert.True(t, testCase.ts.Equal(ts))
|
| - assert.Equal(t, testCase.data, data)
|
| - assert.Equal(t, time.UTC, ts.Location())
|
| - }
|
| -
|
| - for _, invalid := range [][]byte{
|
| - []byte{},
|
| - []byte{0x00},
|
| - []byte{0x01, 0x00, 0x00},
|
| - []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
| - } {
|
| - _, _, err := unpackV1(invalid)
|
| - assert.Error(t, err)
|
| - }
|
| -}
|
| -
|
| -// Create a localDB for testing. Call defer util.RemoveAll() on the second
|
| -// return value.
|
| -func makeDB(t *testing.T, name string) (db.DB, string) {
|
| - //testutils.SkipIfShort(t)
|
| - tmpdir, err := ioutil.TempDir("", name)
|
| - assert.NoError(t, err)
|
| - d, err := NewDB(name, filepath.Join(tmpdir, "task.db"))
|
| - assert.NoError(t, err)
|
| - return d, tmpdir
|
| -}
|
| -
|
| -// Test that AssignId returns an error if Id is set.
|
| -func TestAssignIdAlreadyAssigned(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs")
|
| - defer util.RemoveAll(tmpdir)
|
| - defer testutils.AssertCloses(t, d)
|
| -
|
| - task := &db.Task{}
|
| - assert.NoError(t, d.AssignId(task))
|
| - assert.Error(t, d.AssignId(task))
|
| -}
|
| -
|
| -// Test that AssignId uses created timestamp when set, and generates unique IDs
|
| -// for the same timestamp.
|
| -func TestAssignIdsFromCreatedTs(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs")
|
| - defer util.RemoveAll(tmpdir)
|
| - defer testutils.AssertCloses(t, d)
|
| -
|
| - tasks := []*db.Task{}
|
| - addTask := func(ts time.Time) {
|
| - task := &db.Task{
|
| - Created: ts,
|
| - }
|
| - assert.NoError(t, d.AssignId(task))
|
| - tasks = append(tasks, task)
|
| - }
|
| -
|
| - // Add tasks with various creation timestamps.
|
| - addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
|
| - addTask(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC))
|
| - addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
|
| - addTask(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.UTC))
|
| - // Repeated timestamps.
|
| - addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
|
| - addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
|
| - for i := 0; i < 256; i++ {
|
| - addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
|
| - }
|
| -
|
| - // Collect IDs. Assert Id is set.
|
| - ids := make([]string, 0, len(tasks))
|
| - for _, task := range tasks {
|
| - assert.NotEqual(t, "", task.Id)
|
| - ids = append(ids, task.Id)
|
| - }
|
| -
|
| - // Stable-sort tasks.
|
| - sort.Stable(db.TaskSlice(tasks))
|
| -
|
| - // Sort IDs.
|
| - sort.Strings(ids)
|
| -
|
| - // Validate that sorted IDs match sorted Tasks. Check that there are no
|
| - // duplicate IDs. Check that ID timestamp matches created timestamp.
|
| - prevId := ""
|
| - for i := 0; i < len(tasks); i++ {
|
| - assert.Equal(t, ids[i], tasks[i].Id)
|
| - assert.NotEqual(t, prevId, ids[i])
|
| - ts, _, err := parseId(ids[i])
|
| - assert.NoError(t, err)
|
| - assert.True(t, ts.Equal(tasks[i].Created))
|
| - prevId = ids[i]
|
| - }
|
| -}
|
| -
|
| -// Test that AssignId can generate ids when created timestamp is not set, and
|
| -// generates unique IDs for PutTasks.
|
| -func TestAssignIdsFromCurrentTime(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestAssignIdsFromCurrentTime")
|
| - defer util.RemoveAll(tmpdir)
|
| - defer testutils.AssertCloses(t, d)
|
| -
|
| - tasks := []*db.Task{}
|
| - for i := 0; i < 260; i++ {
|
| - tasks = append(tasks, &db.Task{})
|
| - }
|
| -
|
| - begin := time.Now()
|
| -
|
| - // Test AssignId.
|
| - assert.NoError(t, d.AssignId(tasks[5]))
|
| - assert.NoError(t, d.AssignId(tasks[6]))
|
| - id5, id6 := tasks[5].Id, tasks[6].Id
|
| -
|
| - // Created time is required.
|
| - for _, task := range tasks {
|
| - task.Created = time.Now()
|
| - }
|
| -
|
| - // Test PutTasks.
|
| - assert.NoError(t, d.PutTasks(tasks))
|
| -
|
| - end := time.Now()
|
| -
|
| - // Check that PutTasks did not change existing Ids.
|
| - assert.Equal(t, id5, tasks[5].Id)
|
| - assert.Equal(t, id6, tasks[6].Id)
|
| -
|
| - // Order tasks by time of ID assignment.
|
| - first2 := []*db.Task{tasks[5], tasks[6]}
|
| - copy(tasks[2:7], tasks[0:5])
|
| - copy(tasks[0:2], first2)
|
| -
|
| - // Collect IDs. Assert Id is set.
|
| - ids := make([]string, 0, len(tasks))
|
| - for _, task := range tasks {
|
| - assert.NotEqual(t, "", task.Id)
|
| - ids = append(ids, task.Id)
|
| - }
|
| -
|
| - // Sort IDs.
|
| - sort.Strings(ids)
|
| -
|
| - // Validate that sorted IDs match Tasks by insertion order. Check that there
|
| - // are no duplicate IDs. Check that begin <= ID timestamp <= end.
|
| - prevId := ""
|
| - for i := 0; i < len(tasks); i++ {
|
| - assert.Equal(t, ids[i], tasks[i].Id)
|
| - assert.NotEqual(t, prevId, ids[i])
|
| - ts, _, err := parseId(ids[i])
|
| - assert.NoError(t, err)
|
| - assert.True(t, begin.Before(ts) || begin.Equal(ts))
|
| - assert.True(t, ts.Before(end) || ts.Equal(end))
|
| - prevId = ids[i]
|
| - }
|
| -}
|
| -
|
| -// Test that PutTask returns an error when AssignId time is too far before (or
|
| -// after) the value subsequently assigned to Task.Created.
|
| -func TestPutTaskValidateCreatedTime(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestPutTaskValidateCreatedTime")
|
| - defer util.RemoveAll(tmpdir)
|
| - defer testutils.AssertCloses(t, d)
|
| -
|
| - task := &db.Task{}
|
| - beforeAssignId := time.Now().Add(-time.Nanosecond)
|
| - assert.NoError(t, d.AssignId(task))
|
| - afterAssignId := time.Now().Add(time.Nanosecond)
|
| -
|
| - // Test "not set".
|
| - {
|
| - err := d.PutTask(task)
|
| - assert.Error(t, err)
|
| - assert.Contains(t, err.Error(), "Created not set.")
|
| - }
|
| -
|
| - // Test "too late".
|
| - {
|
| - task.Created = afterAssignId.Add(MAX_CREATED_TIME_SKEW)
|
| - err := d.PutTask(task)
|
| - assert.Error(t, err)
|
| - assert.Contains(t, err.Error(), "Created too late.")
|
| - }
|
| -
|
| - // Test "too early".
|
| - {
|
| - task.Created = beforeAssignId
|
| - err := d.PutTask(task)
|
| - assert.Error(t, err)
|
| - assert.Contains(t, err.Error(), "Created too early.")
|
| -
|
| - // Verify not in DB.
|
| - noTask, err := d.GetTaskById(task.Id)
|
| - assert.NoError(t, err)
|
| - assert.Nil(t, noTask)
|
| - }
|
| -
|
| - // Test in range.
|
| - {
|
| - task.Created = beforeAssignId.Add(MAX_CREATED_TIME_SKEW)
|
| - err := d.PutTask(task)
|
| - assert.NoError(t, err)
|
| -
|
| - // Verify added to DB.
|
| - taskCopy, err := d.GetTaskById(task.Id)
|
| - assert.NoError(t, err)
|
| - testutils.AssertDeepEqual(t, task, taskCopy)
|
| - }
|
| -
|
| - // We can even change the Created time if we want. (Not necessarily supported
|
| - // by all DB implementations.)
|
| - {
|
| - task.Created = afterAssignId
|
| - err := d.PutTask(task)
|
| - assert.NoError(t, err)
|
| -
|
| - taskCopy, err := d.GetTaskById(task.Id)
|
| - assert.NoError(t, err)
|
| - testutils.AssertDeepEqual(t, task, taskCopy)
|
| - }
|
| -
|
| - // But we can't change it to be out of range.
|
| - {
|
| - prevCreated := task.Created
|
| - task.Created = beforeAssignId
|
| - err := d.PutTask(task)
|
| - assert.Error(t, err)
|
| - assert.Contains(t, err.Error(), "Created too early.")
|
| -
|
| - taskCopy, err := d.GetTaskById(task.Id)
|
| - assert.NoError(t, err)
|
| - assert.True(t, prevCreated.Equal(taskCopy.Created))
|
| - }
|
| -}
|
| -
|
| -// Test that PutTask/s does not modify the passed-in Tasks when there is an
|
| -// error.
|
| -func TestPutTaskLeavesTasksUnchanged(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestPutTaskLeavesTasksUnchanged")
|
| - defer util.RemoveAll(tmpdir)
|
| - defer testutils.AssertCloses(t, d)
|
| -
|
| - begin := time.Now().Add(-time.Nanosecond)
|
| -
|
| - // Create and insert a task that will cause ErrConcurrentUpdate.
|
| - task1 := &db.Task{
|
| - Created: time.Now(),
|
| - }
|
| - assert.NoError(t, d.PutTask(task1))
|
| -
|
| - // Retrieve a copy, modify original.
|
| - task1Cached, err := d.GetTaskById(task1.Id)
|
| - assert.NoError(t, err)
|
| - task1.Status = db.TASK_STATUS_RUNNING
|
| - assert.NoError(t, d.PutTask(task1))
|
| - task1InDb := task1.Copy()
|
| -
|
| - // Create and insert a task to check PutTasks doesn't change DbModified.
|
| - task2 := &db.Task{
|
| - Created: time.Now(),
|
| - }
|
| - assert.NoError(t, d.PutTask(task2))
|
| - task2InDb := task2.Copy()
|
| - task2.Status = db.TASK_STATUS_MISHAP
|
| -
|
| - // Create a task with an Id already set.
|
| - task3 := &db.Task{}
|
| - assert.NoError(t, d.AssignId(task3))
|
| - task3.Created = time.Now()
|
| -
|
| - // Create a task without an Id set.
|
| - task4 := &db.Task{
|
| - Created: time.Now(),
|
| - }
|
| -
|
| - // Make an update to task1Cached.
|
| - task1Cached.Commits = []string{"a", "b"}
|
| -
|
| - // Copy to compare later.
|
| - expectedTasks := []*db.Task{task1Cached.Copy(), task2.Copy(), task3.Copy(), task4.Copy()}
|
| -
|
| - // Attempt to insert; put task1Cached last so that the error comes last.
|
| - err = d.PutTasks([]*db.Task{task2, task3, task4, task1Cached})
|
| - assert.True(t, db.IsConcurrentUpdate(err))
|
| - testutils.AssertDeepEqual(t, expectedTasks, []*db.Task{task1Cached, task2, task3, task4})
|
| -
|
| - // Check that nothing was updated in the DB.
|
| - tasksInDb, err := d.GetTasksFromDateRange(begin, time.Now())
|
| - assert.NoError(t, err)
|
| - assert.Equal(t, 2, len(tasksInDb))
|
| - for _, task := range tasksInDb {
|
| - switch task.Id {
|
| - case task1.Id:
|
| - testutils.AssertDeepEqual(t, task1InDb, task)
|
| - case task2.Id:
|
| - testutils.AssertDeepEqual(t, task2InDb, task)
|
| - default:
|
| - assert.Fail(t, "Unexpected task in DB: %v", task)
|
| - }
|
| - }
|
| -}
|
| -
|
| -func TestLocalDB(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestLocalDB")
|
| - defer util.RemoveAll(tmpdir)
|
| - db.TestDB(t, d)
|
| -}
|
| -
|
| -func TestLocalDBTooManyUsers(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestLocalDBTooManyUsers")
|
| - defer util.RemoveAll(tmpdir)
|
| - db.TestTooManyUsers(t, d)
|
| -}
|
| -
|
| -func TestLocalDBConcurrentUpdate(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestLocalDBConcurrentUpdate")
|
| - defer util.RemoveAll(tmpdir)
|
| - db.TestConcurrentUpdate(t, d)
|
| -}
|
| -
|
| -func TestLocalDBUpdateWithRetries(t *testing.T) {
|
| - d, tmpdir := makeDB(t, "TestLocalDBUpdateWithRetries")
|
| - defer util.RemoveAll(tmpdir)
|
| - db.TestUpdateWithRetries(t, d)
|
| -}
|
|
|