go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/buildbucket/appengine/internal/buildid/buildid_test.go (about) 1 // Copyright 2020 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package buildid 16 17 import ( 18 "context" 19 "math/rand" 20 "testing" 21 "time" 22 23 "go.chromium.org/luci/common/data/rand/mathrand" 24 25 . "github.com/smartystreets/goconvey/convey" 26 ) 27 28 func TestNewBuildIDs(t *testing.T) { 29 t.Parallel() 30 31 Convey("NewBuildIDs", t, func() { 32 ctx := mathrand.Set(context.Background(), rand.New(rand.NewSource(0))) 33 t := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) 34 So(1<<16, ShouldEqual, 65536) 35 36 Convey("zero", func() { 37 ids := NewBuildIDs(ctx, t, 0) 38 So(ids, ShouldBeEmpty) 39 }) 40 41 Convey("one", func() { 42 ids := NewBuildIDs(ctx, t, 1) 43 So(ids, ShouldResemble, []int64{ 44 0x7DB4463C7FF2FFA1, 45 }) 46 So(ids[0]>>63, ShouldEqual, 0) 47 So(ids[0]&0x0FFFFFFFFFFFFFFF>>buildIDTimeSuffixLen, ShouldEqual, 941745227775) 48 So(ids[0]&0x0000000000000001, ShouldEqual, buildIDVersion) 49 }) 50 51 Convey("two", func() { 52 ids := NewBuildIDs(ctx, t, 2) 53 So(ids, ShouldResemble, []int64{ 54 0x7DB4463C7FFA8F71, 55 0x7DB4463C7FFA8F61, 56 }) 57 So(ids[0]>>63, ShouldEqual, 0) 58 So(ids[0]&0x0000000000000001, ShouldEqual, buildIDVersion) 59 So(ids[0]&0x0FFFFFFFFFFFFFFF>>buildIDTimeSuffixLen, ShouldEqual, 941745227775) 60 So(ids[1]>>63, ShouldEqual, 0) 61 So(ids[1]&0x0000000000000001, ShouldEqual, buildIDVersion) 62 So(ids[1]&0x0FFFFFFFFFFFFFFF>>buildIDTimeSuffixLen, ShouldEqual, 941745227775) 63 }) 64 65 Convey("many", func() { 66 for i := 0; i < 2^16; i++ { 67 ids := NewBuildIDs(ctx, t, i) 68 So(ids, ShouldHaveLength, i) 69 prev := BuildIDMax 70 for _, id := range ids { 71 // Ensure strictly decreasing. 72 So(id, ShouldBeLessThan, prev) 73 prev = id 74 // Ensure positive. 75 So(id>>63, ShouldEqual, 0) 76 // Ensure time component. 77 So(id&0x0FFFFFFFFFFFFFFF>>buildIDTimeSuffixLen, ShouldEqual, 941745227775) 78 // Ensure version. 79 So(id&0x000000000000000F, ShouldEqual, buildIDVersion) 80 } 81 } 82 }) 83 }) 84 } 85 86 func TestIDRange(t *testing.T) { 87 t.Parallel() 88 89 Convey("IDRange", t, func() { 90 Convey("valid time", func() { 91 timeLow := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) 92 timeHigh := timeLow.Add(timeResolution * 10000) 93 idLow, idHigh := IDRange(timeLow, timeHigh) 94 95 inRange := func(t time.Time, suffix int64) bool { 96 buildID := idTimeSegment(t) | suffix 97 return idLow <= buildID && buildID < idHigh 98 } 99 ones := (int64(1) << buildIDTimeSuffixLen) - 1 100 101 // Ensure that min and max possible build IDs are within 102 // the range up to the timeResolution. 103 for _, suffix := range []int64{0, ones} { 104 So(inRange(timeLow.Add(-timeResolution), suffix), ShouldBeFalse) 105 So(inRange(timeLow, suffix), ShouldBeTrue) 106 So(inRange(timeLow.Add(timeResolution), suffix), ShouldBeTrue) 107 108 So(inRange(timeHigh.Add(-timeResolution), suffix), ShouldBeTrue) 109 So(inRange(timeHigh, suffix), ShouldBeFalse) 110 So(inRange(timeHigh.Add(timeResolution), suffix), ShouldBeFalse) 111 } 112 }) 113 114 Convey("invalid time", func() { 115 timeLow := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) 116 timeHigh := timeLow.Add(timeResolution * 10000) 117 idLow, idHigh := IDRange(timeLow, timeHigh) 118 So(idLow, ShouldEqual, 0) 119 So(idHigh, ShouldEqual, 0) 120 }) 121 }) 122 } 123 124 func TestIDTimeSegment(t *testing.T) { 125 t.Parallel() 126 127 Convey("idTimeSegment", t, func() { 128 Convey("after the start of the word time", func() { 129 id := idTimeSegment(beginningOfTheWorld.Add(timeResolution)) 130 So(id, ShouldEqual, 0x7FFFFFFFFFE00000) 131 }) 132 133 Convey("at the start of the word time", func() { 134 id := idTimeSegment(beginningOfTheWorld) 135 So(id, ShouldEqual, 0x7FFFFFFFFFF00000) 136 }) 137 138 Convey("before the start of the word time", func() { 139 t := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) 140 id := idTimeSegment(t) 141 So(id, ShouldEqual, 0) 142 }) 143 }) 144 } 145 146 func TestMayContainBuilds(t *testing.T) { 147 t.Parallel() 148 149 Convey("normal", t, func() { 150 low := time.Date(2011, 1, 1, 0, 0, 0, 0, time.UTC) 151 high := time.Date(2011, 2, 1, 0, 0, 0, 0, time.UTC) 152 So(MayContainBuilds(low, high), ShouldBeTrue) 153 }) 154 155 Convey("low time is larger than high time", t, func() { 156 low := time.Date(2011, 2, 1, 0, 0, 0, 0, time.UTC) 157 high := time.Date(2011, 1, 1, 0, 0, 0, 0, time.UTC) 158 So(MayContainBuilds(low, high), ShouldBeFalse) 159 }) 160 161 Convey("low and high time are nil", t, func() { 162 low := time.Time{} 163 high := time.Time{} 164 So(MayContainBuilds(low, high), ShouldBeTrue) 165 }) 166 167 Convey("high time is less than beginningOfTheWorld", t, func() { 168 low := time.Date(2011, 2, 1, 0, 0, 0, 0, time.UTC) 169 high := beginningOfTheWorld.Add(-1) 170 So(MayContainBuilds(low, high), ShouldBeFalse) 171 }) 172 }