@@ -5,6 +5,7 @@ package testutil
5
5
6
6
import (
7
7
"fmt"
8
+ "sort"
8
9
9
10
"github.com/google/go-cmp/cmp"
10
11
"github.com/google/go-cmp/cmp/cmpopts"
@@ -414,6 +415,21 @@ func RemoveEqualEvents(in []ExpEvent, expected ExpEvent) ([]ExpEvent, int) {
414
415
return in , matches
415
416
}
416
417
418
+ // SortExpEvents sorts a list of ExpEvents so they can be compared for equality.
419
+ //
420
+ // This is a stable sort which only sorts nearly identical contiguous events by
421
+ // object identifier, to make the full list easier to validate.
422
+ //
423
+ // You may need to remove StatusEvents from the list before comparing, because
424
+ // these events are fully asynchronous and non-contiguous.
425
+ //
426
+ // Comparison Options:
427
+ // A) Expect(received).To(testutil.Equal(expected))
428
+ // B) testutil.assertEqual(t, expected, received)
429
+ func SortExpEvents (events []ExpEvent ) {
430
+ sort .SliceStable (events , GroupedEventsByID (events ).Less )
431
+ }
432
+
417
433
// GroupedEventsByID implements sort.Interface for []ExpEvent based on
418
434
// the serialized ObjMetadata of Apply, Prune, and Delete events within the same
419
435
// task group.
@@ -428,48 +444,48 @@ func (ape GroupedEventsByID) Swap(i, j int) { ape[i], ape[j] = ape[j], ape[i] }
428
444
func (ape GroupedEventsByID ) Less (i , j int ) bool {
429
445
if ape [i ].EventType != ape [j ].EventType {
430
446
// don't change order if not the same type
431
- return false
447
+ return i < j
432
448
}
433
449
switch ape [i ].EventType {
434
450
case event .ApplyType :
435
- if ape [i ].ApplyEvent .GroupName != ape [j ].ApplyEvent .GroupName {
436
- // don't change order if not the same task group
437
- return false
451
+ if ape [i ].ApplyEvent .GroupName == ape [j ].ApplyEvent .GroupName &&
452
+ ape [i ].ApplyEvent .Status == ape [j ].ApplyEvent .Status &&
453
+ ape [i ].ApplyEvent .Identifier .GroupKind == ape [j ].ApplyEvent .Identifier .GroupKind {
454
+ // apply events are predictably ordered by GroupKind, due to
455
+ // ordering.SortableMetas.
456
+ // So we only need to sort by namespace & name.
457
+ return ape [i ].ApplyEvent .Identifier .String () < ape [j ].ApplyEvent .Identifier .String ()
438
458
}
439
- return ape [i ].ApplyEvent .Identifier .String () < ape [j ].ApplyEvent .Identifier .String ()
440
459
case event .PruneType :
441
- if ape [i ].PruneEvent .GroupName != ape [j ].PruneEvent .GroupName {
442
- // don't change order if not the same task group
443
- return false
460
+ if ape [i ].PruneEvent .GroupName == ape [j ].PruneEvent .GroupName &&
461
+ ape [i ].PruneEvent .Status == ape [j ].PruneEvent .Status &&
462
+ ape [i ].PruneEvent .Identifier .GroupKind == ape [j ].PruneEvent .Identifier .GroupKind {
463
+ // prune events are predictably ordered by GroupKind, due to
464
+ // ordering.SortableMetas (reversed).
465
+ // So we only need to sort by namespace & name.
466
+ return ape [i ].PruneEvent .Identifier .String () < ape [j ].PruneEvent .Identifier .String ()
444
467
}
445
- return ape [i ].PruneEvent .Identifier .String () < ape [j ].PruneEvent .Identifier .String ()
446
468
case event .DeleteType :
447
- if ape [i ].DeleteEvent .GroupName != ape [j ].DeleteEvent .GroupName {
448
- // don't change order if not the same task group
449
- return false
469
+ if ape [i ].DeleteEvent .GroupName == ape [j ].DeleteEvent .GroupName &&
470
+ ape [i ].DeleteEvent .Status == ape [j ].DeleteEvent .Status &&
471
+ ape [i ].DeleteEvent .Identifier .GroupKind == ape [j ].DeleteEvent .Identifier .GroupKind {
472
+ // delete events are predictably ordered by GroupKind, due to
473
+ // ordering.SortableMetas (reversed).
474
+ // So we only need to sort by namespace & name.
475
+ return ape [i ].DeleteEvent .Identifier .String () < ape [j ].DeleteEvent .Identifier .String ()
450
476
}
451
- return ape [i ].DeleteEvent .Identifier .String () < ape [j ].DeleteEvent .Identifier .String ()
452
477
case event .WaitType :
453
- if ape [i ].WaitEvent .GroupName != ape [j ].WaitEvent .GroupName {
454
- // don't change order if not the same task group
455
- return false
456
- }
457
- if ape [i ].WaitEvent .Status != ape [j ].WaitEvent .Status {
458
- // don't change order if not the same status
459
- return false
460
- }
461
- if ape [i ].WaitEvent .Status != event .ReconcileSuccessful {
462
- // pending, skipped, and timeout status are predictably ordered
478
+ if ape [i ].WaitEvent .GroupName == ape [j ].WaitEvent .GroupName &&
479
+ ape [i ].WaitEvent .Status == ape [j ].WaitEvent .Status &&
480
+ ape [i ].WaitEvent .Status == event .ReconcileSuccessful {
481
+ // pending, skipped, and timeout operations are predictably ordered
463
482
// using the order in WaitTask.Ids.
464
483
// So we only need to sort Reconciled events, which occur in the
465
484
// order the Waitask receives StatusEvents with Current/NotFound.
466
- return false
485
+ return ape [ i ]. WaitEvent . Identifier . String () < ape [ j ]. WaitEvent . Identifier . String ()
467
486
}
468
- return ape [i ].WaitEvent .Identifier .String () < ape [j ].WaitEvent .Identifier .String ()
469
487
case event .ValidationType :
470
488
return ape [i ].ValidationEvent .Identifiers .Hash () < ape [j ].ValidationEvent .Identifiers .Hash ()
471
- default :
472
- // don't change order if not ApplyType, PruneType, or DeleteType
473
- return false
474
489
}
490
+ return i < j
475
491
}
0 commit comments