OLD | NEW |
(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 // Create a localDB for testing. Call defer util.RemoveAll() on the second |
| 94 // return value. |
| 95 func makeDB(t *testing.T, name string) (db.DB, string) { |
| 96 //testutils.SkipIfShort(t) |
| 97 tmpdir, err := ioutil.TempDir("", name) |
| 98 assert.NoError(t, err) |
| 99 d, err := NewDB(name, filepath.Join(tmpdir, "task.db")) |
| 100 assert.NoError(t, err) |
| 101 return d, tmpdir |
| 102 } |
| 103 |
| 104 // Test that AssignId returns an error if Id is set. |
| 105 func TestAssignIdAlreadyAssigned(t *testing.T) { |
| 106 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 107 defer util.RemoveAll(tmpdir) |
| 108 defer testutils.AssertCloses(t, d) |
| 109 |
| 110 task := &db.Task{} |
| 111 assert.NoError(t, d.AssignId(task)) |
| 112 assert.Error(t, d.AssignId(task)) |
| 113 } |
| 114 |
| 115 // Test that AssignId uses created timestamp when set, and generates unique IDs |
| 116 // for the same timestamp. |
| 117 func TestAssignIdsFromCreatedTs(t *testing.T) { |
| 118 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 119 defer util.RemoveAll(tmpdir) |
| 120 defer testutils.AssertCloses(t, d) |
| 121 |
| 122 tasks := []*db.Task{} |
| 123 addTask := func(ts time.Time) { |
| 124 task := &db.Task{ |
| 125 Created: ts, |
| 126 } |
| 127 assert.NoError(t, d.AssignId(task)) |
| 128 tasks = append(tasks, task) |
| 129 } |
| 130 |
| 131 // Add tasks with various creation timestamps. |
| 132 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 133 addTask(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC)) |
| 134 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| 135 addTask(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.U
TC)) |
| 136 // Repeated timestamps. |
| 137 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 138 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| 139 for i := 0; i < 256; i++ { |
| 140 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 141 } |
| 142 |
| 143 // Collect IDs. Assert Id is set. |
| 144 ids := make([]string, 0, len(tasks)) |
| 145 for _, task := range tasks { |
| 146 assert.NotEqual(t, "", task.Id) |
| 147 ids = append(ids, task.Id) |
| 148 } |
| 149 |
| 150 // Stable-sort tasks. |
| 151 sort.Stable(db.TaskSlice(tasks)) |
| 152 |
| 153 // Sort IDs. |
| 154 sort.Strings(ids) |
| 155 |
| 156 // Validate that sorted IDs match sorted Tasks. Check that there are no |
| 157 // duplicate IDs. Check that ID timestamp matches created timestamp. |
| 158 prevId := "" |
| 159 for i := 0; i < len(tasks); i++ { |
| 160 assert.Equal(t, ids[i], tasks[i].Id) |
| 161 assert.NotEqual(t, prevId, ids[i]) |
| 162 ts, _, err := parseId(ids[i]) |
| 163 assert.NoError(t, err) |
| 164 assert.True(t, ts.Equal(tasks[i].Created)) |
| 165 prevId = ids[i] |
| 166 } |
| 167 } |
| 168 |
| 169 // Test that AssignId can generate ids when created timestamp is not set, and |
| 170 // generates unique IDs for PutTasks. |
| 171 func TestAssignIdsFromCurrentTime(t *testing.T) { |
| 172 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 173 defer util.RemoveAll(tmpdir) |
| 174 defer testutils.AssertCloses(t, d) |
| 175 |
| 176 tasks := []*db.Task{} |
| 177 for i := 0; i < 260; i++ { |
| 178 tasks = append(tasks, &db.Task{}) |
| 179 } |
| 180 |
| 181 begin := time.Now() |
| 182 |
| 183 // Test AssignId. |
| 184 assert.NoError(t, d.AssignId(tasks[5])) |
| 185 assert.NoError(t, d.AssignId(tasks[6])) |
| 186 id5, id6 := tasks[5].Id, tasks[6].Id |
| 187 |
| 188 // Test PutTasks. |
| 189 assert.NoError(t, d.PutTasks(tasks)) |
| 190 |
| 191 end := time.Now() |
| 192 |
| 193 // Check that PutTasks did not change existing Ids. |
| 194 assert.Equal(t, id5, tasks[5].Id) |
| 195 assert.Equal(t, id6, tasks[6].Id) |
| 196 |
| 197 // Order tasks by time of ID assignment. |
| 198 first2 := []*db.Task{tasks[5], tasks[6]} |
| 199 copy(tasks[2:7], tasks[0:5]) |
| 200 copy(tasks[0:2], first2) |
| 201 |
| 202 // Collect IDs. Assert Id is set. |
| 203 ids := make([]string, 0, len(tasks)) |
| 204 for _, task := range tasks { |
| 205 assert.NotEqual(t, "", task.Id) |
| 206 ids = append(ids, task.Id) |
| 207 } |
| 208 |
| 209 // Sort IDs. |
| 210 sort.Strings(ids) |
| 211 |
| 212 // Validate that sorted IDs match Tasks by insertion order. Check that t
here |
| 213 // are no duplicate IDs. Check that begin <= ID timestamp <= end. |
| 214 prevId := "" |
| 215 for i := 0; i < len(tasks); i++ { |
| 216 assert.Equal(t, ids[i], tasks[i].Id) |
| 217 assert.NotEqual(t, prevId, ids[i]) |
| 218 ts, _, err := parseId(ids[i]) |
| 219 assert.NoError(t, err) |
| 220 assert.True(t, begin.Before(ts) || begin.Equal(ts)) |
| 221 assert.True(t, ts.Before(end) || ts.Equal(end)) |
| 222 prevId = ids[i] |
| 223 } |
| 224 } |
| 225 |
| 226 func TestLocalDB(t *testing.T) { |
| 227 d, tmpdir := makeDB(t, "TestLocalDB") |
| 228 defer util.RemoveAll(tmpdir) |
| 229 db.TestDB(t, d) |
| 230 } |
| 231 |
| 232 func TestLocalDBTooManyUsers(t *testing.T) { |
| 233 d, tmpdir := makeDB(t, "TestLocalDBTooManyUsers") |
| 234 defer util.RemoveAll(tmpdir) |
| 235 db.TestTooManyUsers(t, d) |
| 236 } |
OLD | NEW |