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_00", |
| 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_01", |
| 34 }, |
| 35 { |
| 36 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000
, time.UTC), |
| 37 seq: 15, |
| 38 id: "20010101T010101.100000000Z_0f", |
| 39 }, |
| 40 { |
| 41 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000
, time.UTC), |
| 42 seq: 16, |
| 43 id: "20010101T010101.100000000Z_110", |
| 44 }, |
| 45 { |
| 46 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000
, time.UTC), |
| 47 seq: 255, |
| 48 id: "20010101T010101.100000000Z_1ff", |
| 49 }, |
| 50 { |
| 51 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000
, time.UTC), |
| 52 seq: 256, |
| 53 id: "20010101T010101.100000000Z_2100", |
| 54 }, |
| 55 { |
| 56 ts: time.Date(2001, time.January, 1, 1, 1, 1, 100000000
, time.UTC), |
| 57 seq: 0xFFFFFFFFFFFFFFFF, |
| 58 id: "20010101T010101.100000000Z_fffffffffffffffff", |
| 59 }, |
| 60 } |
| 61 for _, testCase := range testCases { |
| 62 assert.Equal(t, testCase.id, formatId(testCase.ts, testCase.seq)
) |
| 63 ts, seq, err := parseId(testCase.id) |
| 64 assert.NoError(t, err) |
| 65 assert.True(t, testCase.ts.Equal(ts)) |
| 66 assert.Equal(t, testCase.seq, seq) |
| 67 assert.Equal(t, time.UTC, ts.Location()) |
| 68 } |
| 69 |
| 70 // Invalid timestamps: |
| 71 for _, invalidId := range []string{ |
| 72 // Missing seq num. |
| 73 "20091110T234506.000001500Z", |
| 74 // Two-digit year. |
| 75 "091110T234506.000001500Z_00", |
| 76 // Invalid month. |
| 77 "20010001T010101.100000000Z_0f", |
| 78 // Missing T. |
| 79 "20010101010101.100000000Z_0f", |
| 80 // Missing Z. |
| 81 "20010101T010101.100000000_0f", |
| 82 // Empty seq num. |
| 83 "20010101T010101.100000000Z_", |
| 84 // Seq num too short. |
| 85 "20010101T010101.100000000Z_0", |
| 86 // Invalid char in seq num. |
| 87 "20010101T010101.100000000Z_0g", |
| 88 // Empty timestamp. |
| 89 "_0F", |
| 90 // Sequence num overflows. |
| 91 "20010101T010101.100000000Z_f1ffffffffffffffff", |
| 92 } { |
| 93 _, _, err := parseId(invalidId) |
| 94 assert.Error(t, err) |
| 95 } |
| 96 } |
| 97 |
| 98 // Create a localDB for testing. Call defer util.RemoveAll() on the second |
| 99 // return value. |
| 100 func makeDB(t *testing.T, name string) (db.DB, string) { |
| 101 //testutils.SkipIfShort(t) |
| 102 tmpdir, err := ioutil.TempDir("", name) |
| 103 assert.NoError(t, err) |
| 104 d, err := NewDB(name, filepath.Join(tmpdir, "task.db")) |
| 105 assert.NoError(t, err) |
| 106 return d, tmpdir |
| 107 } |
| 108 |
| 109 // Test that AssignId returns an error if Id is set. |
| 110 func TestAssignIdAlreadyAssigned(t *testing.T) { |
| 111 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 112 defer util.RemoveAll(tmpdir) |
| 113 defer testutils.AssertCloses(t, d) |
| 114 |
| 115 task := &db.Task{} |
| 116 assert.NoError(t, d.AssignId(task)) |
| 117 assert.Error(t, d.AssignId(task)) |
| 118 } |
| 119 |
| 120 // Test that AssignId uses created timestamp when set, and generates unique IDs |
| 121 // for the same timestamp. |
| 122 func TestAssignIdsFromCreatedTs(t *testing.T) { |
| 123 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 124 defer util.RemoveAll(tmpdir) |
| 125 defer testutils.AssertCloses(t, d) |
| 126 |
| 127 tasks := []*db.Task{} |
| 128 addTask := func(ts time.Time) { |
| 129 task := &db.Task{ |
| 130 Created: ts, |
| 131 } |
| 132 assert.NoError(t, d.AssignId(task)) |
| 133 tasks = append(tasks, task) |
| 134 } |
| 135 |
| 136 // Add tasks with various creation timestamps. |
| 137 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 138 addTask(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC)) |
| 139 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| 140 addTask(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.U
TC)) |
| 141 // Repeated timestamps. |
| 142 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 143 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) |
| 144 for i := 0; i < 256; i++ { |
| 145 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) |
| 146 } |
| 147 |
| 148 // Collect IDs. Assert Id is set. |
| 149 ids := make([]string, 0, len(tasks)) |
| 150 for _, task := range tasks { |
| 151 assert.NotEqual(t, "", task.Id) |
| 152 ids = append(ids, task.Id) |
| 153 } |
| 154 |
| 155 // Stable-sort tasks. |
| 156 sort.Stable(db.TaskSlice(tasks)) |
| 157 |
| 158 // Sort IDs. |
| 159 sort.Strings(ids) |
| 160 |
| 161 // Validate that sorted IDs match sorted Tasks. Check that there are no |
| 162 // duplicate IDs. Check that ID timestamp matches created timestamp. |
| 163 prevId := "" |
| 164 for i := 0; i < len(tasks); i++ { |
| 165 assert.Equal(t, ids[i], tasks[i].Id) |
| 166 assert.NotEqual(t, prevId, ids[i]) |
| 167 ts, _, err := parseId(ids[i]) |
| 168 assert.NoError(t, err) |
| 169 assert.True(t, ts.Equal(tasks[i].Created)) |
| 170 prevId = ids[i] |
| 171 } |
| 172 } |
| 173 |
| 174 // Test that AssignId can generate ids when created timestamp is not set, and |
| 175 // generates unique IDs for PutTasks. |
| 176 func TestAssignIdsFromCurrentTime(t *testing.T) { |
| 177 d, tmpdir := makeDB(t, "TestAssignIdsFromCreatedTs") |
| 178 defer util.RemoveAll(tmpdir) |
| 179 defer testutils.AssertCloses(t, d) |
| 180 |
| 181 tasks := []*db.Task{} |
| 182 for i := 0; i < 260; i++ { |
| 183 tasks = append(tasks, &db.Task{}) |
| 184 } |
| 185 |
| 186 begin := time.Now() |
| 187 |
| 188 // Test AssignId. |
| 189 assert.NoError(t, d.AssignId(tasks[5])) |
| 190 assert.NoError(t, d.AssignId(tasks[6])) |
| 191 id5, id6 := tasks[5].Id, tasks[6].Id |
| 192 |
| 193 // Test PutTasks. |
| 194 assert.NoError(t, d.PutTasks(tasks)) |
| 195 |
| 196 end := time.Now() |
| 197 |
| 198 // Check that PutTasks did not change existing Ids. |
| 199 assert.Equal(t, id5, tasks[5].Id) |
| 200 assert.Equal(t, id6, tasks[6].Id) |
| 201 |
| 202 // Order tasks by time of ID assignment. |
| 203 first2 := []*db.Task{tasks[5], tasks[6]} |
| 204 copy(tasks[2:7], tasks[0:5]) |
| 205 copy(tasks[0:2], first2) |
| 206 |
| 207 // Collect IDs. Assert Id is set. |
| 208 ids := make([]string, 0, len(tasks)) |
| 209 for _, task := range tasks { |
| 210 assert.NotEqual(t, "", task.Id) |
| 211 ids = append(ids, task.Id) |
| 212 } |
| 213 |
| 214 // Sort IDs. |
| 215 sort.Strings(ids) |
| 216 |
| 217 // Validate that sorted IDs match Tasks by insertion order. Check that t
here |
| 218 // are no duplicate IDs. Check that begin <= ID timestamp <= end. |
| 219 prevId := "" |
| 220 for i := 0; i < len(tasks); i++ { |
| 221 assert.Equal(t, ids[i], tasks[i].Id) |
| 222 assert.NotEqual(t, prevId, ids[i]) |
| 223 ts, _, err := parseId(ids[i]) |
| 224 assert.NoError(t, err) |
| 225 assert.True(t, begin.Before(ts) || begin.Equal(ts)) |
| 226 assert.True(t, ts.Before(end) || ts.Equal(end)) |
| 227 prevId = ids[i] |
| 228 } |
| 229 } |
| 230 |
| 231 func TestLocalDB(t *testing.T) { |
| 232 d, tmpdir := makeDB(t, "TestLocalDB") |
| 233 defer util.RemoveAll(tmpdir) |
| 234 db.TestDB(t, d) |
| 235 } |
| 236 |
| 237 func TestLocalDBTooManyUsers(t *testing.T) { |
| 238 d, tmpdir := makeDB(t, "TestLocalDBTooManyUsers") |
| 239 defer util.RemoveAll(tmpdir) |
| 240 db.TestTooManyUsers(t, d) |
| 241 } |
OLD | NEW |