package storage import ( "reflect" "testing" "github.com/containers/storage/pkg/idtools" "github.com/google/go-intervals/intervalset" "github.com/stretchr/testify/assert" ) func TestMinMaxInt(t *testing.T) { assert.Equal(t, 5, minInt(5, 8)) assert.Equal(t, 3, minInt(10, 3)) assert.Equal(t, 2, minInt(2, 2)) assert.Equal(t, 8, maxInt(5, 8)) assert.Equal(t, 10, maxInt(10, 3)) assert.Equal(t, 2, maxInt(2, 2)) } func allIntervals(s *idSet) []interval { iterator, cancel := s.iterator() defer cancel() var out []interval for i := iterator(); i != nil; i = iterator() { out = append(out, *i) } return out } func idSetsEqual(x, y *idSet) bool { return reflect.DeepEqual(allIntervals(x), allIntervals(y)) } func TestNewIDSet(t *testing.T) { tests := []struct { name string intervals []interval want *idSet }{ { "Nil", nil, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "Empty", []interval{}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "OneValidRange", []interval{{3, 4}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{3, 4}})}, }, { "OneEmptyRange", []interval{{3, 3}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "OneInvalidRange", []interval{{3, 2}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "TwoRanges", []interval{{1, 4}, {6, 8}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}, interval{6, 8}})}, }, { "SecondRangeEmpty", []interval{{1, 4}, {6, 6}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}})}, }, { "SecondRangeInvalid", []interval{{1, 4}, {6, 5}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}})}, }, { "TwoOverlappingRanges", []interval{{1, 4}, {3, 6}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 6}})}, }, { "TwoAdjacentRanges", []interval{{1, 4}, {4, 6}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 6}})}, }, { "TwoUnorderedRanges", []interval{{6, 8}, {1, 4}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}, interval{6, 8}})}, }, { "ThreeRanges", []interval{{1, 4}, {6, 8}, {11, 20}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}, interval{6, 8}, interval{11, 20}})}, }, { "ThreeRangesWithOverlap", []interval{{1, 4}, {3, 8}, {11, 20}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 8}, interval{11, 20}})}, }, { "FourOverlappingRanges", []interval{{1, 4}, {6, 8}, {11, 20}, {3, 30}}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 30}})}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := newIDSet(tt.intervals); !idSetsEqual(got, tt.want) { t.Errorf("newIDSet() = %v, want %v", got, tt.want) } }) } } func TestGetHostAndContainerIDs(t *testing.T) { tests := []struct { name string idMaps []idtools.IDMap wantContainerIDs *idSet wantHostIDs *idSet }{ { "Nil", nil, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "Empty", []idtools.IDMap{}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "OneInvalidInterval", []idtools.IDMap{ {ContainerID: 10, HostID: 20, Size: -1}, }, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "OneEmptyInterval", []idtools.IDMap{ {ContainerID: 10, HostID: 20, Size: -1}, }, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, }, { "OneValidInterval", []idtools.IDMap{ {ContainerID: 10, HostID: 20, Size: 5}, }, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 15}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{20, 25}})}, }, { "TwoValidIntervals", []idtools.IDMap{ {ContainerID: 10, HostID: 20, Size: 5}, {ContainerID: 30, HostID: 25, Size: 10}, }, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 15}, interval{30, 40}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{20, 35}})}, }, { "MultipleIntervals", []idtools.IDMap{ {ContainerID: 10, HostID: 20, Size: 10}, {ContainerID: 30, HostID: 28, Size: 20}, {ContainerID: 40, HostID: 30, Size: -1}, {ContainerID: 45, HostID: 50, Size: 0}, {ContainerID: 48, HostID: 60, Size: 20}, }, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}, interval{30, 68}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{20, 48}, interval{60, 80}})}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := getHostIDs(tt.idMaps); !idSetsEqual(got, tt.wantHostIDs) { t.Errorf("getHostIDs() = %v, want %v", got, tt.wantHostIDs) } if got := getContainerIDs(tt.idMaps); !idSetsEqual(got, tt.wantContainerIDs) { t.Errorf("getContainerIDs() = %v, want %v", got, tt.wantContainerIDs) } }) } } var idSetOperatorsTestCases = []struct { name string x *idSet y *idSet subtractWant *idSet unionWant *idSet zipWant []idtools.IDMap }{ { "NilAndNil", nil, nil, nil, nil, ([]idtools.IDMap)(nil), }, { "NilAndNotNil", nil, newIDSet([]interval{{1, 5}}), nil, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, ([]idtools.IDMap)(nil), }, { "NotNilAndNil", newIDSet([]interval{{1, 5}}), nil, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, ([]idtools.IDMap)(nil), }, { "EmptyAndEmpty", newIDSet([]interval{}), newIDSet([]interval{}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet(nil)}, ([]idtools.IDMap)(nil), }, { "EmptyAndNotEmpty", newIDSet([]interval{}), newIDSet([]interval{{1, 5}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, ([]idtools.IDMap)(nil), }, { "NotEmptyAndEmpty", newIDSet([]interval{{1, 5}}), newIDSet([]interval{}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, ([]idtools.IDMap)(nil), }, { "OneIntervalAndSameInterval", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{1, 5}}), &idSet{set: intervalset.NewImmutableSet(nil)}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, []idtools.IDMap{{ContainerID: 1, HostID: 1, Size: 4}}, }, { "OneIntervalAndSingleSmallerInterval", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{3, 4}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 3}, interval{4, 5}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, []idtools.IDMap{{ContainerID: 3, HostID: 1, Size: 1}}, }, { "OneIntervalAndSingleBiggerInterval", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{0, 8}}), &idSet{set: intervalset.NewImmutableSet(nil)}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{0, 8}})}, []idtools.IDMap{{ContainerID: 0, HostID: 1, Size: 4}}, }, { "OneIntervalAndSingleIntervalLeft", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{1, 3}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{3, 5}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, []idtools.IDMap{{ContainerID: 1, HostID: 1, Size: 2}}, }, { "OneIntervalAndSingleIntervalRight", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{2, 5}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 2}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}})}, []idtools.IDMap{{ContainerID: 2, HostID: 1, Size: 3}}, }, { "OneIntervalAndSingleIntervalLeftAndBeyond", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{-2, 3}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{3, 5}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{-2, 5}})}, []idtools.IDMap{{ContainerID: -2, HostID: 1, Size: 4}}, }, { "OneIntervalAndSingleIntervalRightAndBeyond", newIDSet([]interval{{1, 5}}), newIDSet([]interval{{2, 8}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 2}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 8}})}, []idtools.IDMap{{ContainerID: 2, HostID: 1, Size: 4}}, }, { "OneIntervalAndSingleIntervalAdjacentLeft", newIDSet([]interval{{10, 20}}), newIDSet([]interval{{2, 10}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{2, 20}})}, []idtools.IDMap{{ContainerID: 2, HostID: 10, Size: 8}}, }, { "OneIntervalAndSingleIntervalAdjacentRight", newIDSet([]interval{{10, 20}}), newIDSet([]interval{{20, 30}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 30}})}, []idtools.IDMap{{ContainerID: 20, HostID: 10, Size: 10}}, }, { "OneIntervalAndSingleIntervalNonOverlapLeft", newIDSet([]interval{{10, 20}}), newIDSet([]interval{{2, 5}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{2, 5}, interval{10, 20}})}, []idtools.IDMap{{ContainerID: 2, HostID: 10, Size: 3}}, }, { "OneIntervalAndSingleIntervalNonOverlapRight", newIDSet([]interval{{10, 20}}), newIDSet([]interval{{25, 30}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}, interval{25, 30}})}, []idtools.IDMap{{ContainerID: 25, HostID: 10, Size: 5}}, }, { "OneIntervalAndMultipleIntervals", newIDSet([]interval{{10, 100}}), newIDSet([]interval{ {2, 5}, {8, 10}, {20, 30}, {40, 50}, {80, 120}, }), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{10, 20}, interval{30, 40}, interval{50, 80}})}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{2, 5}, interval{8, 120}})}, []idtools.IDMap{ {ContainerID: 2, HostID: 10, Size: 3}, {ContainerID: 8, HostID: 13, Size: 2}, {ContainerID: 20, HostID: 15, Size: 10}, {ContainerID: 40, HostID: 25, Size: 10}, {ContainerID: 80, HostID: 35, Size: 40}, }, }, { "MultipleIntervalsAndSingle", newIDSet([]interval{ {2, 5}, {8, 10}, {20, 30}, {40, 50}, {80, 120}, }), newIDSet([]interval{{10, 45}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{ interval{2, 5}, interval{8, 10}, interval{45, 50}, interval{80, 120}, })}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{2, 5}, interval{8, 50}, interval{80, 120}})}, []idtools.IDMap{ {ContainerID: 10, HostID: 2, Size: 3}, {ContainerID: 13, HostID: 8, Size: 2}, {ContainerID: 15, HostID: 20, Size: 10}, {ContainerID: 25, HostID: 40, Size: 10}, {ContainerID: 35, HostID: 80, Size: 10}, }, }, { "MultipleIntervalsAndMultipleIntervals", newIDSet([]interval{ {2, 5}, {8, 10}, {20, 30}, {40, 50}, {80, 120}, }), newIDSet([]interval{{10, 45}, {90, 100}, {130, 150}}), &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{ interval{2, 5}, interval{8, 10}, interval{45, 50}, interval{80, 90}, interval{100, 120}, })}, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{ interval{2, 5}, interval{8, 50}, interval{80, 120}, interval{130, 150}, })}, []idtools.IDMap{ {ContainerID: 10, HostID: 2, Size: 3}, {ContainerID: 13, HostID: 8, Size: 2}, {ContainerID: 15, HostID: 20, Size: 10}, {ContainerID: 25, HostID: 40, Size: 10}, {ContainerID: 35, HostID: 80, Size: 10}, {ContainerID: 90, HostID: 90, Size: 10}, {ContainerID: 130, HostID: 100, Size: 20}, }, }, } func TestIDSetSubtract(t *testing.T) { for _, tt := range idSetOperatorsTestCases { t.Run(tt.name, func(t *testing.T) { var ix, iy []interval if tt.x != nil { ix = allIntervals(tt.x) } if tt.y != nil { iy = allIntervals(tt.y) } if got := tt.x.subtract(tt.y); !idSetsEqual(got, tt.subtractWant) { t.Errorf("idSet.subtract() = %v, want %v", got, tt.subtractWant) } // Make sure x and y are unchanged. if tt.x != nil { if jx := allIntervals(tt.x); !reflect.DeepEqual(ix, jx) { t.Errorf("x changed from %v to %v", ix, jx) } } if tt.y != nil { if jy := allIntervals(tt.y); !reflect.DeepEqual(iy, jy) { t.Errorf("y changed from %v to %v", iy, jy) } } }) } } func TestIDSetUnion(t *testing.T) { for _, tt := range idSetOperatorsTestCases { t.Run(tt.name, func(t *testing.T) { var ix, iy []interval if tt.x != nil { ix = allIntervals(tt.x) } if tt.y != nil { iy = allIntervals(tt.y) } if got := tt.x.union(tt.y); !idSetsEqual(got, tt.unionWant) { t.Errorf("idSet.union() = %v, want %v", got, tt.unionWant) } // Make sure x and y are unchanged. if tt.x != nil { if jx := allIntervals(tt.x); !reflect.DeepEqual(ix, jx) { t.Errorf("x changed from %v to %v", ix, jx) } } if tt.y != nil { if jy := allIntervals(tt.y); !reflect.DeepEqual(iy, jy) { t.Errorf("y changed from %v to %v", iy, jy) } } }) } } func TestIDSetSize(t *testing.T) { tests := []struct { name string set *idSet want int }{ {"Nil", nil, 0}, {"Empty", newIDSet([]interval{}), 0}, {"EmptyInterval", newIDSet([]interval{{3, 3}}), 0}, {"InvalidInterval", newIDSet([]interval{{5, 3}}), 0}, {"OneInterval", newIDSet([]interval{{3, 9}}), 6}, {"TwoIntervals", newIDSet([]interval{{3, 9}, {20, 25}}), 11}, {"TwoAdjacentIntervals", newIDSet([]interval{{3, 9}, {9, 20}}), 17}, {"TwoOverlappingIntervals", newIDSet([]interval{{3, 9}, {6, 20}}), 17}, {"TwoContainingIntervals", newIDSet([]interval{{3, 9}, {0, 20}}), 20}, {"ThreeIntervals", newIDSet([]interval{{3, 9}, {15, 20}, {30, 40}}), 21}, {"MultipleIntervals", newIDSet([]interval{{3, 9}, {15, 20}, {3, 0}, {6, 12}, {30, 40}}), 24}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.set.size(); got != tt.want { t.Errorf("idSet.size() = %v, want %v", got, tt.want) } }) } } func TestIDSetFindAvailable(t *testing.T) { tests := []struct { name string set *idSet n int want *idSet wantErr bool }{ { "NilIntervalFindZero", nil, 0, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "NilIntervalFindPositive", nil, 1, nil, true, }, { "NilIntervalFindNegative", nil, -1, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "EmptyIntervalFindZero", newIDSet([]interval{}), 0, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "EmptyIntervalFindPositive", newIDSet([]interval{}), 1, nil, true, }, { "EmptyIntervalFindNegative", newIDSet([]interval{}), -1, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "OneIntervalFindOK", newIDSet([]interval{{1, 5}}), 3, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 4}})}, false, }, { "OneIntervalFindNotEnough", newIDSet([]interval{{1, 5}}), 5, nil, true, }, { "OneIntervalFindZero", newIDSet([]interval{{1, 5}}), 0, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "OneIntervalFindNegative", newIDSet([]interval{{1, 5}}), -1, &idSet{set: intervalset.NewImmutableSet(nil)}, false, }, { "MultipleIntervalsFindOK", newIDSet([]interval{{1, 5}, {9, 15}, {20, 30}}), 15, &idSet{set: intervalset.NewImmutableSet([]intervalset.Interval{interval{1, 5}, interval{9, 15}, interval{20, 25}})}, false, }, { "MultipleIntervalsFindNotEnough", newIDSet([]interval{{1, 5}, {9, 15}, {20, 30}}), 25, nil, true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := tt.set.findAvailable(tt.n) if (err != nil) != tt.wantErr { t.Errorf("idSet.findAvailable() error = %v, wantErr %v", err, tt.wantErr) return } if !tt.wantErr && !idSetsEqual(got, tt.want) { t.Errorf("idSet.findAvailable() = %v, want %v", got, tt.want) } }) } } func TestIDSetZip(t *testing.T) { for _, tt := range idSetOperatorsTestCases { t.Run(tt.name, func(t *testing.T) { var ix, iy []interval if tt.x != nil { ix = allIntervals(tt.x) } if tt.y != nil { iy = allIntervals(tt.y) } if got := tt.x.zip(tt.y); !reflect.DeepEqual(got, tt.zipWant) { t.Errorf("idSet.zip() = %v, want %v", got, tt.unionWant) } // Make sure x and y are unchanged. if tt.x != nil { if jx := allIntervals(tt.x); !reflect.DeepEqual(ix, jx) { t.Errorf("x changed from %v to %v", ix, jx) } } if tt.y != nil { if jy := allIntervals(tt.y); !reflect.DeepEqual(iy, jy) { t.Errorf("y changed from %v to %v", iy, jy) } } }) } } func TestIntervalLength(t *testing.T) { tests := []struct { name string start int end int want int }{ {"ZeroLength", 3, 3, 0}, {"PositiveLength", 2, 10, 8}, {"NegativeLength", 10, 2, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { i := interval{ start: tt.start, end: tt.end, } if got := i.length(); got != tt.want { t.Errorf("interval.length() = %v, want %v", got, tt.want) } }) } } func TestIntervalIsZero(t *testing.T) { tests := []struct { name string start int end int want bool }{ {"ZeroLength", 3, 3, true}, {"PositiveLength", 2, 10, false}, {"NegativeLength", 10, 2, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { i := interval{ start: tt.start, end: tt.end, } if got := i.IsZero(); got != tt.want { t.Errorf("interval.IsZero() = %v, want %v", got, tt.want) } }) } } // assertIntervalSame asserts `got` equals to `want` considering zero check. If the wanted interval // is empty, we only want to assert IsZero() == true, instead of the exact number. func assertIntervalSame(t *testing.T, got intervalset.Interval, want *interval, name string) { t.Helper() if want == nil && !got.IsZero() { t.Errorf("%v = %v, want nil", name, got) } else if want != nil && !reflect.DeepEqual(got, *want) { t.Errorf("%v = %v, want %v", name, got, *want) } } var intervalTestCases = []struct { name string start, end int otherStart, otherEnd int intersectWant *interval beforeWant, reflectiveBeforeWant bool bisectWant, reflectiveBisectWant [2]*interval adjoinWant *interval encompassWant *interval }{ { "TwoZeroIntervals", 0, 0, 0, 0, nil, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, nil, }, { "ZeroIntervalAndInvalidInterval", 0, 0, 5, 3, nil, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, nil, }, { "ZeroIntervalAndInvalidIntervalIncludingZero", 0, 0, 5, -3, nil, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, nil, }, { "TwoIncludingInvalidIntervals", 3, -2, 5, -3, nil, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, nil, }, { "TwoInvalidIntervals", 8, 6, 5, -3, nil, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, nil, }, { "ZeroIntervalAndNormalInterval", 0, 0, 3, 5, nil, false, false, [2]*interval{nil, nil}, [2]*interval{{3, 5}, nil}, nil, &interval{3, 5}, }, { "ZeroIntervalAndNormalIntervalIncludingZero", 0, 0, -3, 5, nil, false, false, [2]*interval{nil, nil}, [2]*interval{{-3, 5}, nil}, nil, &interval{-3, 5}, }, { "InvalidIntervalAndNormalInterval", 5, 3, 6, 8, nil, false, false, [2]*interval{nil, nil}, [2]*interval{{6, 8}, nil}, nil, &interval{6, 8}, }, { "InvalidIntervalAndNormalIntervalEnclosing", 5, 3, 2, 6, nil, false, false, [2]*interval{nil, nil}, [2]*interval{{2, 6}, nil}, nil, &interval{2, 6}, }, { "InvalidIntervalAndNormalIntervalIntersecting", 5, 3, 4, 6, nil, false, false, [2]*interval{nil, nil}, [2]*interval{{4, 6}, nil}, nil, &interval{4, 6}, }, { "IntersectingIntervals", 5, 8, 6, 9, &interval{6, 8}, false, false, [2]*interval{{5, 6}, nil}, [2]*interval{nil, {8, 9}}, nil, &interval{5, 9}, }, { "AdjoinIntervals", 5, 8, 8, 12, nil, false, false, [2]*interval{{5, 8}, nil}, [2]*interval{nil, {8, 12}}, &interval{5, 12}, &interval{5, 12}, }, { "EnclosingIntervals", 5, 8, 4, 12, &interval{5, 8}, false, false, [2]*interval{nil, nil}, [2]*interval{{4, 5}, {8, 12}}, nil, &interval{4, 12}, }, { "EnclosingIntervalsMeetOneEnd", 5, 8, 5, 12, &interval{5, 8}, false, false, [2]*interval{nil, nil}, [2]*interval{nil, {8, 12}}, nil, &interval{5, 12}, }, { "EqualIntervals", 5, 8, 5, 8, &interval{5, 8}, false, false, [2]*interval{nil, nil}, [2]*interval{nil, nil}, nil, &interval{5, 8}, }, { "NonIntersectingIntervals", 3, 5, 8, 10, nil, true, false, [2]*interval{{3, 5}, nil}, [2]*interval{nil, {8, 10}}, nil, &interval{3, 10}, }, } func TestIntervalIntersect(t *testing.T) { for _, tt := range intervalTestCases { i := interval{tt.start, tt.end} j := interval{tt.otherStart, tt.otherEnd} t.Run(tt.name, func(t *testing.T) { assertIntervalSame(t, i.Intersect(j), tt.intersectWant, "interval.Intersect()") }) t.Run("Reflective_"+tt.name, func(t *testing.T) { assertIntervalSame(t, j.Intersect(i), tt.intersectWant, "interval.Intersect()") }) } } func TestIntervalBefore(t *testing.T) { for _, tt := range intervalTestCases { i := interval{tt.start, tt.end} j := interval{tt.otherStart, tt.otherEnd} t.Run(tt.name, func(t *testing.T) { if got := i.Before(j); got != tt.beforeWant { t.Errorf("interval.Before() = %v, want %v", got, tt.beforeWant) } }) t.Run("Reflective_"+tt.name, func(t *testing.T) { if got := j.Before(i); got != tt.reflectiveBeforeWant { t.Errorf("interval.Before() = %v, want %v", got, tt.reflectiveBeforeWant) } }) } } func TestIntervalBisect(t *testing.T) { for _, tt := range intervalTestCases { i := interval{tt.start, tt.end} j := interval{tt.otherStart, tt.otherEnd} t.Run(tt.name, func(t *testing.T) { x, y := i.Bisect(j) assertIntervalSame(t, x, tt.bisectWant[0], "interval.Bisect()[0]") assertIntervalSame(t, y, tt.bisectWant[1], "interval.Bisect()[1]") }) t.Run("Reflective_"+tt.name, func(t *testing.T) { x, y := j.Bisect(i) assertIntervalSame(t, x, tt.reflectiveBisectWant[0], "interval.Bisect()[0]") assertIntervalSame(t, y, tt.reflectiveBisectWant[1], "interval.Bisect()[1]") }) } } func TestIntervalAdjoin(t *testing.T) { for _, tt := range intervalTestCases { i := interval{tt.start, tt.end} j := interval{tt.otherStart, tt.otherEnd} t.Run(tt.name, func(t *testing.T) { assertIntervalSame(t, i.Adjoin(j), tt.adjoinWant, "interval.Adjoin()") }) t.Run("Reflective_"+tt.name, func(t *testing.T) { assertIntervalSame(t, j.Adjoin(i), tt.adjoinWant, "interval.Adjoin()") }) } } func TestIntervalEncompass(t *testing.T) { for _, tt := range intervalTestCases { i := interval{tt.start, tt.end} j := interval{tt.otherStart, tt.otherEnd} t.Run(tt.name, func(t *testing.T) { assertIntervalSame(t, i.Encompass(j), tt.encompassWant, "interval.Encompass()") }) t.Run("Reflective_"+tt.name, func(t *testing.T) { assertIntervalSame(t, j.Encompass(i), tt.encompassWant, "interval.Encompass()") }) } } func TestOverlappingMappings(t *testing.T) { mappings := []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 1000, Size: 65536}} if err := hasOverlappingRanges(mappings); err == nil { t.Errorf("mappings = %v, expected to be overlapping", mappings) } mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 65536, HostID: 5000, Size: 65536}} if err := hasOverlappingRanges(mappings); err == nil { t.Errorf("mappings = %v, expected to be overlapping", mappings) } mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 5000 + 65536, Size: 65536}} if err := hasOverlappingRanges(mappings); err == nil { t.Errorf("mappings = %v, expected to be overlapping", mappings) } mappings = []idtools.IDMap{{ContainerID: 0, HostID: 1000, Size: 65536}, {ContainerID: 0, HostID: 1000 + 65536, Size: 65536}} if err := hasOverlappingRanges(mappings); err == nil { t.Errorf("mappings = %v, expected to be overlapping", mappings) } mappings = []idtools.IDMap{{ContainerID: 0, HostID: 0, Size: 65536}, {ContainerID: 65536, HostID: 65536, Size: 65536}} if err := hasOverlappingRanges(mappings); err != nil { t.Errorf("mappings = %v, expected to not be overlapping", mappings) } mappings = []idtools.IDMap{{ContainerID: 0, HostID: 0, Size: 65536}, {ContainerID: 1 * 65536, HostID: 1 * 65536, Size: 65536}, {ContainerID: 2 * 65536, HostID: 2 * 65536, Size: 65536}} if err := hasOverlappingRanges(mappings); err != nil { t.Errorf("mappings = %v, expected to not be overlapping", mappings) } }