| OLD | NEW |
| (Empty) |
| 1 package db | |
| 2 | |
| 3 import ( | |
| 4 "bytes" | |
| 5 "encoding/gob" | |
| 6 "fmt" | |
| 7 "sort" | |
| 8 "testing" | |
| 9 "time" | |
| 10 | |
| 11 swarming_api "github.com/luci/luci-go/common/api/swarming/swarming/v1" | |
| 12 assert "github.com/stretchr/testify/require" | |
| 13 | |
| 14 "go.skia.org/infra/go/swarming" | |
| 15 "go.skia.org/infra/go/testutils" | |
| 16 ) | |
| 17 | |
| 18 // Test that Task.UpdateFromSwarming returns an error when the input data is | |
| 19 // invalid. | |
| 20 func TestUpdateFromSwarmingInvalid(t *testing.T) { | |
| 21 now := time.Now().UTC().Round(time.Microsecond) | |
| 22 task := &Task{ | |
| 23 Id: "A", | |
| 24 Name: "A", | |
| 25 Repo: "A", | |
| 26 Revision: "A", | |
| 27 Created: now, | |
| 28 Commits: []string{"A", "B"}, | |
| 29 } | |
| 30 copy := task.Copy() | |
| 31 | |
| 32 testError := func(s *swarming_api.SwarmingRpcsTaskResult, msg string) { | |
| 33 changed, err := task.UpdateFromSwarming(s) | |
| 34 assert.False(t, changed) | |
| 35 assert.Error(t, err) | |
| 36 assert.Contains(t, err.Error(), msg) | |
| 37 } | |
| 38 | |
| 39 testError(nil, "Missing TaskResult") | |
| 40 | |
| 41 testError(&swarming_api.SwarmingRpcsTaskResult{ | |
| 42 CreatedTs: now.Format(swarming.TIMESTAMP_FORMAT), | |
| 43 State: SWARMING_STATE_COMPLETED, | |
| 44 Tags: []string{"invalid"}, | |
| 45 }, "Invalid Swarming task tag") | |
| 46 | |
| 47 testError(&swarming_api.SwarmingRpcsTaskResult{ | |
| 48 CreatedTs: "20160817T142302.543490", | |
| 49 State: SWARMING_STATE_COMPLETED, | |
| 50 }, "Unable to parse task creation time") | |
| 51 | |
| 52 testError(&swarming_api.SwarmingRpcsTaskResult{ | |
| 53 CreatedTs: now.Format(swarming.TIMESTAMP_FORMAT), | |
| 54 State: SWARMING_STATE_COMPLETED, | |
| 55 StartedTs: "20160817T142302.543490", | |
| 56 }, "Unable to parse StartedTs") | |
| 57 | |
| 58 testError(&swarming_api.SwarmingRpcsTaskResult{ | |
| 59 CreatedTs: now.Format(swarming.TIMESTAMP_FORMAT), | |
| 60 State: SWARMING_STATE_COMPLETED, | |
| 61 CompletedTs: "20160817T142302.543490", | |
| 62 }, "Unable to parse CompletedTs") | |
| 63 | |
| 64 testError(&swarming_api.SwarmingRpcsTaskResult{ | |
| 65 CreatedTs: now.Format(swarming.TIMESTAMP_FORMAT), | |
| 66 State: SWARMING_STATE_EXPIRED, | |
| 67 AbandonedTs: "20160817T142302.543490", | |
| 68 }, "Unable to parse AbandonedTs") | |
| 69 | |
| 70 // Unchanged. | |
| 71 testutils.AssertDeepEqual(t, task, copy) | |
| 72 } | |
| 73 | |
| 74 // Test that Task.UpdateFromSwarming returns an error when the task "identity" | |
| 75 // fields do not match. | |
| 76 func TestUpdateFromSwarmingMismatched(t *testing.T) { | |
| 77 now := time.Now().UTC().Round(time.Microsecond) | |
| 78 task := &Task{ | |
| 79 Id: "A", | |
| 80 Name: "A", | |
| 81 Repo: "A", | |
| 82 Revision: "A", | |
| 83 Created: now, | |
| 84 Commits: []string{"A", "B"}, | |
| 85 SwarmingTaskId: "A", | |
| 86 } | |
| 87 copy := task.Copy() | |
| 88 | |
| 89 testError := func(s *swarming_api.SwarmingRpcsTaskResult, msg string) { | |
| 90 changed, err := task.UpdateFromSwarming(s) | |
| 91 assert.False(t, changed) | |
| 92 assert.Error(t, err) | |
| 93 assert.Contains(t, err.Error(), msg) | |
| 94 } | |
| 95 | |
| 96 s := &swarming_api.SwarmingRpcsTaskResult{ | |
| 97 TaskId: "A", | |
| 98 CreatedTs: now.Format(swarming.TIMESTAMP_FORMAT), | |
| 99 Failure: false, | |
| 100 State: SWARMING_STATE_COMPLETED, | |
| 101 Tags: []string{ | |
| 102 fmt.Sprintf("%s:B", SWARMING_TAG_ID), | |
| 103 fmt.Sprintf("%s:A", SWARMING_TAG_NAME), | |
| 104 fmt.Sprintf("%s:A", SWARMING_TAG_REPO), | |
| 105 fmt.Sprintf("%s:A", SWARMING_TAG_REVISION), | |
| 106 }, | |
| 107 } | |
| 108 testError(s, "Id does not match") | |
| 109 | |
| 110 s.Tags[0] = fmt.Sprintf("%s:A", SWARMING_TAG_ID) | |
| 111 s.Tags[1] = fmt.Sprintf("%s:B", SWARMING_TAG_NAME) | |
| 112 testError(s, "Name does not match") | |
| 113 | |
| 114 s.Tags[1] = fmt.Sprintf("%s:A", SWARMING_TAG_NAME) | |
| 115 s.Tags[2] = fmt.Sprintf("%s:B", SWARMING_TAG_REPO) | |
| 116 testError(s, "Repo does not match") | |
| 117 | |
| 118 s.Tags[2] = fmt.Sprintf("%s:A", SWARMING_TAG_REPO) | |
| 119 s.Tags[3] = fmt.Sprintf("%s:B", SWARMING_TAG_REVISION) | |
| 120 testError(s, "Revision does not match") | |
| 121 | |
| 122 s.Tags[3] = fmt.Sprintf("%s:A", SWARMING_TAG_REVISION) | |
| 123 s.CreatedTs = now.Add(time.Hour).Format(swarming.TIMESTAMP_FORMAT) | |
| 124 testError(s, "Creation time has changed") | |
| 125 | |
| 126 s.CreatedTs = now.Format(swarming.TIMESTAMP_FORMAT) | |
| 127 s.TaskId = "D" | |
| 128 testError(s, "Swarming task ID does not match") | |
| 129 | |
| 130 // Unchanged. | |
| 131 testutils.AssertDeepEqual(t, task, copy) | |
| 132 } | |
| 133 | |
| 134 // Test that Task.UpdateFromSwarming sets the expected fields in an empty Task. | |
| 135 func TestUpdateFromSwarmingInit(t *testing.T) { | |
| 136 now := time.Now().UTC().Round(time.Microsecond) | |
| 137 task1 := &Task{} | |
| 138 s := &swarming_api.SwarmingRpcsTaskResult{ | |
| 139 TaskId: "E", | |
| 140 // Include both AbandonedTs and CompletedTs to test that Complet
edTs takes | |
| 141 // precedence. | |
| 142 AbandonedTs: now.Add(-1 * time.Minute).Format(swarming.TIMESTAMP
_FORMAT), | |
| 143 CreatedTs: now.Add(-3 * time.Hour).Format(swarming.TIMESTAMP_F
ORMAT), | |
| 144 CompletedTs: now.Add(-2 * time.Minute).Format(swarming.TIMESTAMP
_FORMAT), | |
| 145 Failure: false, | |
| 146 StartedTs: now.Add(-time.Hour).Format(swarming.TIMESTAMP_FORMA
T), | |
| 147 State: SWARMING_STATE_COMPLETED, | |
| 148 Tags: []string{ | |
| 149 fmt.Sprintf("%s:A", SWARMING_TAG_ID), | |
| 150 fmt.Sprintf("%s:B", SWARMING_TAG_NAME), | |
| 151 fmt.Sprintf("%s:C", SWARMING_TAG_REPO), | |
| 152 fmt.Sprintf("%s:D", SWARMING_TAG_REVISION), | |
| 153 }, | |
| 154 OutputsRef: &swarming_api.SwarmingRpcsFilesRef{ | |
| 155 Isolated: "F", | |
| 156 }, | |
| 157 } | |
| 158 changed1, err1 := task1.UpdateFromSwarming(s) | |
| 159 assert.NoError(t, err1) | |
| 160 assert.True(t, changed1) | |
| 161 testutils.AssertDeepEqual(t, task1, &Task{ | |
| 162 Id: "A", | |
| 163 Name: "B", | |
| 164 Repo: "C", | |
| 165 Revision: "D", | |
| 166 Created: now.Add(-3 * time.Hour), | |
| 167 Commits: nil, | |
| 168 Started: now.Add(-time.Hour), | |
| 169 Finished: now.Add(-2 * time.Minute), | |
| 170 Status: TASK_STATUS_SUCCESS, | |
| 171 SwarmingTaskId: "E", | |
| 172 IsolatedOutput: "F", | |
| 173 }) | |
| 174 | |
| 175 // Repeat to get Finished from AbandonedTs. | |
| 176 task2 := &Task{} | |
| 177 s.CompletedTs = "" | |
| 178 s.State = SWARMING_STATE_EXPIRED | |
| 179 changed2, err2 := task2.UpdateFromSwarming(s) | |
| 180 assert.NoError(t, err2) | |
| 181 assert.True(t, changed2) | |
| 182 testutils.AssertDeepEqual(t, task2, &Task{ | |
| 183 Id: "A", | |
| 184 Name: "B", | |
| 185 Repo: "C", | |
| 186 Revision: "D", | |
| 187 Created: now.Add(-3 * time.Hour), | |
| 188 Commits: nil, | |
| 189 Started: now.Add(-time.Hour), | |
| 190 Finished: now.Add(-time.Minute), | |
| 191 Status: TASK_STATUS_MISHAP, | |
| 192 SwarmingTaskId: "E", | |
| 193 IsolatedOutput: "F", | |
| 194 }) | |
| 195 } | |
| 196 | |
| 197 // Test that Task.UpdateFromSwarming updates the expected fields in an existing | |
| 198 // Task. | |
| 199 func TestUpdateFromSwarmingUpdate(t *testing.T) { | |
| 200 now := time.Now().UTC().Round(time.Microsecond) | |
| 201 task := &Task{ | |
| 202 Id: "A", | |
| 203 Name: "B", | |
| 204 Repo: "C", | |
| 205 Revision: "D", | |
| 206 Created: now.Add(-3 * time.Hour), | |
| 207 Commits: []string{"D", "Z"}, | |
| 208 Started: now.Add(-2 * time.Hour), | |
| 209 Finished: now.Add(-1 * time.Hour), | |
| 210 Status: TASK_STATUS_SUCCESS, | |
| 211 SwarmingTaskId: "E", | |
| 212 IsolatedOutput: "F", | |
| 213 } | |
| 214 s := &swarming_api.SwarmingRpcsTaskResult{ | |
| 215 TaskId: "E", | |
| 216 // Include both AbandonedTs and CompletedTs to test that Complet
edTs takes | |
| 217 // precedence. | |
| 218 AbandonedTs: now.Add(-90 * time.Second).Format(swarming.TIMESTAM
P_FORMAT), | |
| 219 CreatedTs: now.Add(-3 * time.Hour).Format(swarming.TIMESTAMP_F
ORMAT), | |
| 220 CompletedTs: now.Add(-1 * time.Minute).Format(swarming.TIMESTAMP
_FORMAT), | |
| 221 Failure: true, | |
| 222 StartedTs: now.Add(-2 * time.Minute).Format(swarming.TIMESTAMP
_FORMAT), | |
| 223 State: SWARMING_STATE_COMPLETED, | |
| 224 Tags: []string{ | |
| 225 fmt.Sprintf("%s:A", SWARMING_TAG_ID), | |
| 226 fmt.Sprintf("%s:B", SWARMING_TAG_NAME), | |
| 227 fmt.Sprintf("%s:C", SWARMING_TAG_REPO), | |
| 228 fmt.Sprintf("%s:D", SWARMING_TAG_REVISION), | |
| 229 }, | |
| 230 OutputsRef: &swarming_api.SwarmingRpcsFilesRef{ | |
| 231 Isolated: "G", | |
| 232 }, | |
| 233 } | |
| 234 changed, err := task.UpdateFromSwarming(s) | |
| 235 assert.NoError(t, err) | |
| 236 assert.True(t, changed) | |
| 237 testutils.AssertDeepEqual(t, task, &Task{ | |
| 238 Id: "A", | |
| 239 Name: "B", | |
| 240 Repo: "C", | |
| 241 Revision: "D", | |
| 242 Created: now.Add(-3 * time.Hour), | |
| 243 Commits: []string{"D", "Z"}, | |
| 244 Started: now.Add(-2 * time.Minute), | |
| 245 Finished: now.Add(-1 * time.Minute), | |
| 246 Status: TASK_STATUS_FAILURE, | |
| 247 SwarmingTaskId: "E", | |
| 248 IsolatedOutput: "G", | |
| 249 }) | |
| 250 | |
| 251 // Make an unrelated change, no change to Task. | |
| 252 s.ModifiedTs = now.Format(swarming.TIMESTAMP_FORMAT) | |
| 253 changed, err = task.UpdateFromSwarming(s) | |
| 254 assert.NoError(t, err) | |
| 255 assert.False(t, changed) | |
| 256 testutils.AssertDeepEqual(t, task, &Task{ | |
| 257 Id: "A", | |
| 258 Name: "B", | |
| 259 Repo: "C", | |
| 260 Revision: "D", | |
| 261 Created: now.Add(-3 * time.Hour), | |
| 262 Commits: []string{"D", "Z"}, | |
| 263 Started: now.Add(-2 * time.Minute), | |
| 264 Finished: now.Add(-1 * time.Minute), | |
| 265 Status: TASK_STATUS_FAILURE, | |
| 266 SwarmingTaskId: "E", | |
| 267 IsolatedOutput: "G", | |
| 268 }) | |
| 269 | |
| 270 // Modify so that we get Finished from AbandonedTs. | |
| 271 s.CompletedTs = "" | |
| 272 s.State = SWARMING_STATE_EXPIRED | |
| 273 changed, err = task.UpdateFromSwarming(s) | |
| 274 assert.NoError(t, err) | |
| 275 assert.True(t, changed) | |
| 276 testutils.AssertDeepEqual(t, task, &Task{ | |
| 277 Id: "A", | |
| 278 Name: "B", | |
| 279 Repo: "C", | |
| 280 Revision: "D", | |
| 281 Created: now.Add(-3 * time.Hour), | |
| 282 Commits: []string{"D", "Z"}, | |
| 283 Started: now.Add(-2 * time.Minute), | |
| 284 Finished: now.Add(-90 * time.Second), | |
| 285 Status: TASK_STATUS_MISHAP, | |
| 286 SwarmingTaskId: "E", | |
| 287 IsolatedOutput: "G", | |
| 288 }) | |
| 289 } | |
| 290 | |
| 291 // Test that Task.UpdateFromSwarming updates the Status field correctly. | |
| 292 func TestUpdateFromSwarmingUpdateStatus(t *testing.T) { | |
| 293 now := time.Now().UTC().Round(time.Microsecond) | |
| 294 | |
| 295 testUpdateStatus := func(s *swarming_api.SwarmingRpcsTaskResult, newStat
us TaskStatus) { | |
| 296 task := &Task{ | |
| 297 Id: "A", | |
| 298 Name: "B", | |
| 299 Repo: "C", | |
| 300 Revision: "D", | |
| 301 Created: now.Add(-3 * time.Hour), | |
| 302 Commits: []string{"D", "Z"}, | |
| 303 Status: TASK_STATUS_SUCCESS, | |
| 304 SwarmingTaskId: "E", | |
| 305 } | |
| 306 changed, err := task.UpdateFromSwarming(s) | |
| 307 assert.NoError(t, err) | |
| 308 assert.True(t, changed) | |
| 309 testutils.AssertDeepEqual(t, task, &Task{ | |
| 310 Id: "A", | |
| 311 Name: "B", | |
| 312 Repo: "C", | |
| 313 Revision: "D", | |
| 314 Created: now.Add(-3 * time.Hour), | |
| 315 Commits: []string{"D", "Z"}, | |
| 316 Status: newStatus, | |
| 317 SwarmingTaskId: "E", | |
| 318 }) | |
| 319 } | |
| 320 | |
| 321 s := &swarming_api.SwarmingRpcsTaskResult{ | |
| 322 TaskId: "E", | |
| 323 CreatedTs: now.Add(-3 * time.Hour).Format(swarming.TIMESTAMP_FOR
MAT), | |
| 324 Failure: false, | |
| 325 State: SWARMING_STATE_PENDING, | |
| 326 Tags: []string{ | |
| 327 fmt.Sprintf("%s:A", SWARMING_TAG_ID), | |
| 328 fmt.Sprintf("%s:B", SWARMING_TAG_NAME), | |
| 329 fmt.Sprintf("%s:C", SWARMING_TAG_REPO), | |
| 330 fmt.Sprintf("%s:D", SWARMING_TAG_REVISION), | |
| 331 }, | |
| 332 OutputsRef: nil, | |
| 333 } | |
| 334 | |
| 335 testUpdateStatus(s, TASK_STATUS_PENDING) | |
| 336 | |
| 337 s.State = SWARMING_STATE_RUNNING | |
| 338 testUpdateStatus(s, TASK_STATUS_RUNNING) | |
| 339 | |
| 340 for _, state := range []string{SWARMING_STATE_BOT_DIED, SWARMING_STATE_C
ANCELED, SWARMING_STATE_EXPIRED, SWARMING_STATE_TIMED_OUT} { | |
| 341 s.State = state | |
| 342 testUpdateStatus(s, TASK_STATUS_MISHAP) | |
| 343 } | |
| 344 | |
| 345 s.State = SWARMING_STATE_COMPLETED | |
| 346 s.Failure = true | |
| 347 testUpdateStatus(s, TASK_STATUS_FAILURE) | |
| 348 } | |
| 349 | |
| 350 func TestUpdateDBFromSwarmingTask(t *testing.T) { | |
| 351 db := NewInMemoryDB() | |
| 352 defer testutils.AssertCloses(t, db) | |
| 353 | |
| 354 // Create task, initialize from swarming, and save. | |
| 355 now := time.Now().UTC().Round(time.Microsecond) | |
| 356 task := &Task{ | |
| 357 Name: "B", | |
| 358 Repo: "C", | |
| 359 Revision: "D", | |
| 360 Commits: []string{"D", "Z"}, | |
| 361 Status: TASK_STATUS_PENDING, | |
| 362 } | |
| 363 assert.NoError(t, db.AssignId(task)) | |
| 364 | |
| 365 s := &swarming_api.SwarmingRpcsTaskResult{ | |
| 366 TaskId: "E", // This is the Swarming TaskId. | |
| 367 CreatedTs: now.Add(time.Second).Format(swarming.TIMESTAMP_FORMAT
), | |
| 368 State: SWARMING_STATE_PENDING, | |
| 369 Tags: []string{ | |
| 370 fmt.Sprintf("%s:%s", SWARMING_TAG_ID, task.Id), | |
| 371 fmt.Sprintf("%s:B", SWARMING_TAG_NAME), | |
| 372 fmt.Sprintf("%s:C", SWARMING_TAG_REPO), | |
| 373 fmt.Sprintf("%s:D", SWARMING_TAG_REVISION), | |
| 374 }, | |
| 375 } | |
| 376 modified, err := task.UpdateFromSwarming(s) | |
| 377 assert.NoError(t, err) | |
| 378 assert.True(t, modified) | |
| 379 assert.NoError(t, db.PutTask(task)) | |
| 380 | |
| 381 // Get update from Swarming. | |
| 382 s.StartedTs = now.Add(time.Minute).Format(swarming.TIMESTAMP_FORMAT) | |
| 383 s.CompletedTs = now.Add(2 * time.Minute).Format(swarming.TIMESTAMP_FORMA
T) | |
| 384 s.State = SWARMING_STATE_COMPLETED | |
| 385 s.Failure = true | |
| 386 s.OutputsRef = &swarming_api.SwarmingRpcsFilesRef{ | |
| 387 Isolated: "G", | |
| 388 } | |
| 389 | |
| 390 assert.NoError(t, UpdateDBFromSwarmingTask(db, s)) | |
| 391 | |
| 392 updatedTask, err := db.GetTaskById(task.Id) | |
| 393 assert.NoError(t, err) | |
| 394 testutils.AssertDeepEqual(t, updatedTask, &Task{ | |
| 395 Id: task.Id, | |
| 396 Name: "B", | |
| 397 Repo: "C", | |
| 398 Revision: "D", | |
| 399 Created: now.Add(time.Second), | |
| 400 Commits: []string{"D", "Z"}, | |
| 401 Started: now.Add(time.Minute), | |
| 402 Finished: now.Add(2 * time.Minute), | |
| 403 Status: TASK_STATUS_FAILURE, | |
| 404 SwarmingTaskId: "E", | |
| 405 IsolatedOutput: "G", | |
| 406 // Use value from updatedTask so they are deep-equal. | |
| 407 DbModified: updatedTask.DbModified, | |
| 408 }) | |
| 409 | |
| 410 lastDbModified := updatedTask.DbModified | |
| 411 | |
| 412 // Make an unrelated change; assert no change to Task. | |
| 413 s.ModifiedTs = now.Format(swarming.TIMESTAMP_FORMAT) | |
| 414 | |
| 415 assert.NoError(t, UpdateDBFromSwarmingTask(db, s)) | |
| 416 updatedTask, err = db.GetTaskById(task.Id) | |
| 417 assert.NoError(t, err) | |
| 418 assert.True(t, lastDbModified.Equal(updatedTask.DbModified)) | |
| 419 } | |
| 420 | |
| 421 // Test that sort.Sort(TaskSlice(...)) works correctly. | |
| 422 func TestSort(t *testing.T) { | |
| 423 tasks := []*Task{} | |
| 424 addTask := func(ts time.Time) { | |
| 425 task := &Task{ | |
| 426 Created: ts, | |
| 427 } | |
| 428 tasks = append(tasks, task) | |
| 429 } | |
| 430 | |
| 431 // Add tasks with various creation timestamps. | |
| 432 addTask(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC))
// 0 | |
| 433 addTask(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC))
// 1 | |
| 434 addTask(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.U
TC)) // 2 | |
| 435 addTask(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
// 3 | |
| 436 | |
| 437 // Manually sort. | |
| 438 expected := []*Task{tasks[1], tasks[3], tasks[0], tasks[2]} | |
| 439 | |
| 440 sort.Sort(TaskSlice(tasks)) | |
| 441 | |
| 442 testutils.AssertDeepEqual(t, expected, tasks) | |
| 443 } | |
| 444 | |
| 445 func TestTaskEncoder(t *testing.T) { | |
| 446 // TODO(benjaminwagner): Is there any way to cause an error? | |
| 447 e := TaskEncoder{} | |
| 448 expectedTasks := map[*Task][]byte{} | |
| 449 for i := 0; i < 25; i++ { | |
| 450 task := &Task{} | |
| 451 task.Id = fmt.Sprintf("Id-%d", i) | |
| 452 task.Name = "Bingo-was-his-name-o" | |
| 453 task.Commits = []string{fmt.Sprintf("a%d", i), fmt.Sprintf("b%d"
, i+1)} | |
| 454 var buf bytes.Buffer | |
| 455 err := gob.NewEncoder(&buf).Encode(task) | |
| 456 assert.NoError(t, err) | |
| 457 expectedTasks[task] = buf.Bytes() | |
| 458 assert.True(t, e.Process(task)) | |
| 459 } | |
| 460 | |
| 461 actualTasks := map[*Task][]byte{} | |
| 462 for task, serialized, err := e.Next(); task != nil; task, serialized, er
r = e.Next() { | |
| 463 assert.NoError(t, err) | |
| 464 actualTasks[task] = serialized | |
| 465 } | |
| 466 testutils.AssertDeepEqual(t, expectedTasks, actualTasks) | |
| 467 } | |
| 468 | |
| 469 func TestTaskEncoderNoTasks(t *testing.T) { | |
| 470 e := TaskEncoder{} | |
| 471 task, serialized, err := e.Next() | |
| 472 assert.NoError(t, err) | |
| 473 assert.Nil(t, task) | |
| 474 assert.Nil(t, serialized) | |
| 475 } | |
| 476 | |
| 477 func TestTaskDecoder(t *testing.T) { | |
| 478 d := TaskDecoder{} | |
| 479 expectedTasks := map[string]*Task{} | |
| 480 for i := 0; i < 250; i++ { | |
| 481 task := &Task{} | |
| 482 task.Id = fmt.Sprintf("Id-%d", i) | |
| 483 task.Name = "Bingo-was-his-name-o" | |
| 484 task.Commits = []string{fmt.Sprintf("a%d", i), fmt.Sprintf("b%d"
, i+1)} | |
| 485 var buf bytes.Buffer | |
| 486 err := gob.NewEncoder(&buf).Encode(task) | |
| 487 assert.NoError(t, err) | |
| 488 expectedTasks[task.Id] = task | |
| 489 assert.True(t, d.Process(buf.Bytes())) | |
| 490 } | |
| 491 | |
| 492 actualTasks := map[string]*Task{} | |
| 493 result, err := d.Result() | |
| 494 assert.NoError(t, err) | |
| 495 assert.Equal(t, len(expectedTasks), len(result)) | |
| 496 for _, task := range result { | |
| 497 actualTasks[task.Id] = task | |
| 498 } | |
| 499 testutils.AssertDeepEqual(t, expectedTasks, actualTasks) | |
| 500 } | |
| 501 | |
| 502 func TestTaskDecoderNoTasks(t *testing.T) { | |
| 503 d := TaskDecoder{} | |
| 504 result, err := d.Result() | |
| 505 assert.NoError(t, err) | |
| 506 assert.Equal(t, 0, len(result)) | |
| 507 } | |
| 508 | |
| 509 func TestTaskDecoderError(t *testing.T) { | |
| 510 task := &Task{} | |
| 511 task.Id = "Id" | |
| 512 var buf bytes.Buffer | |
| 513 err := gob.NewEncoder(&buf).Encode(task) | |
| 514 assert.NoError(t, err) | |
| 515 serialized := buf.Bytes() | |
| 516 invalid := append([]byte("Hi Mom!"), serialized...) | |
| 517 | |
| 518 d := TaskDecoder{} | |
| 519 // Process should return true before it encounters an invalid result. | |
| 520 assert.True(t, d.Process(serialized)) | |
| 521 assert.True(t, d.Process(serialized)) | |
| 522 // Process may return true or false after encountering an invalid value. | |
| 523 _ = d.Process(invalid) | |
| 524 for i := 0; i < 250; i++ { | |
| 525 _ = d.Process(serialized) | |
| 526 } | |
| 527 | |
| 528 // Result should return error. | |
| 529 result, err := d.Result() | |
| 530 assert.Error(t, err) | |
| 531 assert.Equal(t, 0, len(result)) | |
| 532 } | |
| OLD | NEW |