go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/common/run_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 common 16 17 import ( 18 "sort" 19 "testing" 20 "time" 21 22 . "github.com/smartystreets/goconvey/convey" 23 . "go.chromium.org/luci/common/testing/assertions" 24 ) 25 26 func TestID(t *testing.T) { 27 t.Parallel() 28 29 Convey("ID works", t, func() { 30 id := MakeRunID("infra", endOfTheWorld.Add(-time.Minute), 1, []byte{65, 15}) 31 So(id, ShouldEqual, RunID("infra/0000000060000-1-410f")) 32 // Assert separately to ensure # of digits doesn't change, 33 // as this will break sorting order with IDs makde before. 34 So(id.InverseTS(), ShouldHaveLength, 13) 35 So(id.InverseTS(), ShouldResemble, "0000000060000") 36 So(id.LUCIProject(), ShouldResemble, "infra") 37 So(id.AttemptKey(), ShouldResemble, "410f") 38 39 Convey("lexical ordering is oldest last", func() { 40 earlierId := MakeRunID("infra", endOfTheWorld.Add(-time.Hour), 2, []byte{31, 44}) 41 So(earlierId, ShouldEqual, RunID("infra/0000003600000-2-1f2c")) 42 So(earlierId, ShouldBeGreaterThan, id) 43 }) 44 45 Convey("works for recent date", func() { 46 earlierId := MakeRunID("infra", time.Date(2020, 01, 01, 1, 1, 1, 2, time.UTC), 1, []byte{31, 44}) 47 So(earlierId, ShouldEqual, RunID("infra/9045130335854-1-1f2c")) 48 So(earlierId, ShouldBeGreaterThan, id) 49 }) 50 51 Convey("panics if computers survive after endOfTheWorld", func() { 52 So(func() { 53 MakeRunID("infra", endOfTheWorld.Add(time.Millisecond), 1, []byte{31, 44}) 54 }, ShouldPanic) 55 }) 56 57 Convey("panics if time machine is invented", func() { 58 // Load Hill Valley's presumed timezone. 59 la, err := time.LoadLocation("America/Los_Angeles") 60 So(err, ShouldBeNil) 61 So(func() { 62 MakeRunID("infra", time.Date(1955, time.November, 5, 6, 15, 0, 0, la), 1, []byte{31, 44}) 63 }, ShouldPanic) 64 }) 65 66 Convey("PublicID", func() { 67 publicID := id.PublicID() 68 So(publicID, ShouldEqual, "projects/infra/runs/0000000060000-1-410f") 69 id2, err := FromPublicRunID(publicID) 70 So(err, ShouldBeNil) 71 So(id2, ShouldResemble, id) 72 73 Convey("panics if ID is invalid", func() { 74 So(func() { RunID("something good").PublicID() }, ShouldPanic) 75 }) 76 77 Convey("errors if Public ID is invalid", func() { 78 _, err := FromPublicRunID("0000000060000-1-410f") 79 So(err, ShouldErrLike, "must be in the form") 80 _, err = FromPublicRunID("infra/0000000060000-1-410f") 81 So(err, ShouldErrLike, "must be in the form") 82 _, err = FromPublicRunID("pRoJeCtS/infra/runs/0000000060000-1-410f") 83 So(err, ShouldErrLike, "must be in the form") 84 _, err = FromPublicRunID("projects/infra/RuNs/0000000060000-1-410f") 85 So(err, ShouldErrLike, "must be in the form") 86 }) 87 }) 88 89 Convey("Vallidate", func() { 90 id := MakeRunID("infra", time.Date(2020, 01, 01, 1, 1, 1, 2, time.UTC), 1, []byte{31, 44}) 91 So(id.Validate(), ShouldBeNil) 92 minimal := RunID("i/1-1-a") 93 So(minimal.Validate(), ShouldBeNil) 94 95 So(RunID("i/1-1-").Validate(), ShouldErrLike, "digest") 96 So(RunID("i/1-1").Validate(), ShouldErrLike, "version") 97 So(RunID("i/1").Validate(), ShouldErrLike, "InverseTS") 98 So(RunID("/1-1-a").Validate(), ShouldErrLike, "project") 99 100 So(RunID("+/1-1-a").Validate(), ShouldErrLike, "invalid character at 0 (+)") 101 So(RunID("a/a-1-a").Validate(), ShouldErrLike, "InverseTS") 102 So(RunID("a/1-b-a").Validate(), ShouldErrLike, "version") 103 }) 104 }) 105 } 106 107 func TestIDs(t *testing.T) { 108 t.Parallel() 109 110 Convey("IDs WithoutSorted works", t, func() { 111 So(MakeRunIDs().WithoutSorted(MakeRunIDs("1")), ShouldResemble, MakeRunIDs()) 112 So(RunIDs(nil).WithoutSorted(MakeRunIDs("1")), ShouldBeNil) 113 114 ids := MakeRunIDs("5", "8", "2") 115 sort.Sort(ids) 116 So(ids, ShouldResemble, MakeRunIDs("2", "5", "8")) 117 118 So(ids.Equal(MakeRunIDs("2", "5", "8")), ShouldBeTrue) 119 So(ids.Equal(MakeRunIDs("2", "5", "8", "8")), ShouldBeFalse) 120 121 assertSameSlice(ids.WithoutSorted(nil), ids) 122 So(ids, ShouldResemble, MakeRunIDs("2", "5", "8")) 123 124 assertSameSlice(ids.WithoutSorted(MakeRunIDs("1", "3", "9")), ids) 125 So(ids, ShouldResemble, MakeRunIDs("2", "5", "8")) 126 127 So(ids.WithoutSorted(MakeRunIDs("1", "5", "9")), ShouldResemble, MakeRunIDs("2", "8")) 128 So(ids, ShouldResemble, MakeRunIDs("2", "5", "8")) 129 130 So(ids.WithoutSorted(MakeRunIDs("1", "5", "5", "7")), ShouldResemble, MakeRunIDs("2", "8")) 131 So(ids, ShouldResemble, MakeRunIDs("2", "5", "8")) 132 }) 133 134 Convey("IDs InsertSorted & ContainsSorted works", t, func() { 135 ids := MakeRunIDs() 136 137 So(ids.ContainsSorted(RunID("5")), ShouldBeFalse) 138 ids.InsertSorted(RunID("5")) 139 So(ids, ShouldResemble, MakeRunIDs("5")) 140 So(ids.ContainsSorted(RunID("5")), ShouldBeTrue) 141 142 So(ids.ContainsSorted(RunID("2")), ShouldBeFalse) 143 ids.InsertSorted(RunID("2")) 144 So(ids, ShouldResemble, MakeRunIDs("2", "5")) 145 So(ids.ContainsSorted(RunID("2")), ShouldBeTrue) 146 147 So(ids.ContainsSorted(RunID("3")), ShouldBeFalse) 148 ids.InsertSorted(RunID("3")) 149 So(ids, ShouldResemble, MakeRunIDs("2", "3", "5")) 150 So(ids.ContainsSorted(RunID("3")), ShouldBeTrue) 151 }) 152 153 Convey("IDs DelSorted works", t, func() { 154 ids := MakeRunIDs() 155 So(ids.DelSorted(RunID("1")), ShouldBeFalse) 156 157 ids = MakeRunIDs("2", "3", "5") 158 So(ids.DelSorted(RunID("1")), ShouldBeFalse) 159 So(ids.DelSorted(RunID("10")), ShouldBeFalse) 160 So(ids.DelSorted(RunID("3")), ShouldBeTrue) 161 So(ids, ShouldResemble, MakeRunIDs("2", "5")) 162 So(ids.DelSorted(RunID("5")), ShouldBeTrue) 163 So(ids, ShouldResemble, MakeRunIDs("2")) 164 So(ids.DelSorted(RunID("2")), ShouldBeTrue) 165 So(ids, ShouldResemble, MakeRunIDs()) 166 }) 167 168 Convey("IDs DifferenceSorted works", t, func() { 169 ids := MakeRunIDs() 170 So(ids.DifferenceSorted(MakeRunIDs("1")), ShouldBeEmpty) 171 172 ids = MakeRunIDs("2", "3", "5") 173 So(ids.DifferenceSorted(nil), ShouldResemble, MakeRunIDs("2", "3", "5")) 174 So(ids.DifferenceSorted(MakeRunIDs()), ShouldResemble, MakeRunIDs("2", "3", "5")) 175 So(ids.DifferenceSorted(MakeRunIDs("3")), ShouldResemble, MakeRunIDs("2", "5")) 176 So(ids.DifferenceSorted(MakeRunIDs("4")), ShouldResemble, MakeRunIDs("2", "3", "5")) 177 So(ids.DifferenceSorted(MakeRunIDs("1", "3", "4")), ShouldResemble, MakeRunIDs("2", "5")) 178 So(ids.DifferenceSorted(MakeRunIDs("1", "2", "3", "4", "5")), ShouldBeEmpty) 179 }) 180 } 181 182 func assertSameSlice(a, b RunIDs) { 183 // Go doesn't allow comparing slices, so compare their contents and ensure 184 // pointers to the first element are the same. 185 So(a, ShouldResemble, b) 186 So(&a[0], ShouldEqual, &b[0]) 187 }