go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cipd/common/iid_test.go (about) 1 // Copyright 2018 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 "fmt" 19 "strings" 20 "testing" 21 22 api "go.chromium.org/luci/cipd/api/cipd/v1" 23 24 . "github.com/smartystreets/goconvey/convey" 25 . "go.chromium.org/luci/common/testing/assertions" 26 ) 27 28 func TestValidateInstanceID(t *testing.T) { 29 t.Parallel() 30 31 good := []string{ 32 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 33 "0123456789abcdefaaaaaaaaaaaaaaaaaaaaaaaa", 34 "B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUC", 35 "-dXsPJ3XDdzO3GLNqekTAmNfIXtE697vame6_4_HNUkC", 36 "ytsp2xXp26LpDqWLjKOUmpGorZXaEJGryJO1-Nkp5t0C", 37 } 38 for _, iid := range good { 39 Convey(fmt.Sprintf("Works with %q", iid), t, func() { 40 So(ValidateInstanceID(iid, KnownHash), ShouldBeNil) 41 So(ValidateInstanceID(iid, AnyHash), ShouldBeNil) 42 }) 43 } 44 45 bad := []string{ 46 "", 47 "€aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 48 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 49 "gaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 50 "AAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 51 "B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajM==", // no padding allowed 52 "/7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUC", // should be URL encoding, NOT std 53 "B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUA", // unspecified hash algo 54 "AAAAAAAAAAAAAAAAAAAAAAAAAAAC", // bad digest len for an algo 55 } 56 for _, iid := range bad { 57 Convey(fmt.Sprintf("Fails with %q", iid), t, func() { 58 So(ValidateInstanceID(iid, KnownHash), ShouldNotBeNil) 59 So(ValidateInstanceID(iid, AnyHash), ShouldNotBeNil) 60 }) 61 } 62 63 unknown := []string{ 64 "B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUD", // unrecognized hash algo 65 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // happens to be looking like unknown hash algo 66 } 67 for _, iid := range unknown { 68 Convey(fmt.Sprintf("Works with %q", iid), t, func() { 69 So(ValidateInstanceID(iid, KnownHash), ShouldNotBeNil) 70 So(ValidateInstanceID(iid, AnyHash), ShouldBeNil) 71 }) 72 } 73 } 74 75 func TestValidateObjectRef(t *testing.T) { 76 t.Parallel() 77 78 Convey("SHA1", t, func() { 79 So(ValidateObjectRef(&api.ObjectRef{ 80 HashAlgo: api.HashAlgo_SHA1, 81 HexDigest: "0123456789abcdef0123456789abcdef00000000", 82 }, KnownHash), ShouldBeNil) 83 84 So(ValidateObjectRef(&api.ObjectRef{ 85 HashAlgo: api.HashAlgo_SHA1, 86 HexDigest: "abcd", 87 }, KnownHash), ShouldErrLike, "expecting 40 chars, got 4") 88 89 So(ValidateObjectRef(&api.ObjectRef{ 90 HashAlgo: api.HashAlgo_SHA1, 91 HexDigest: strings.Repeat("A", 40), // uppercase are forbidden 92 }, KnownHash), ShouldErrLike, "wrong char") 93 }) 94 95 Convey("SHA256", t, func() { 96 So(ValidateObjectRef(&api.ObjectRef{ 97 HashAlgo: api.HashAlgo_SHA256, 98 HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447", 99 }, KnownHash), ShouldBeNil) 100 101 So(ValidateObjectRef(&api.ObjectRef{ 102 HashAlgo: api.HashAlgo_SHA256, 103 HexDigest: "abcd", 104 }, KnownHash), ShouldErrLike, "expecting 64 chars, got 4") 105 106 So(ValidateObjectRef(&api.ObjectRef{ 107 HashAlgo: api.HashAlgo_SHA256, 108 HexDigest: strings.Repeat("A", 64), // uppercase are forbidden 109 }, KnownHash), ShouldErrLike, "wrong char") 110 }) 111 112 Convey("Some future hash in KnownHash mode", t, func() { 113 So(ValidateObjectRef(&api.ObjectRef{ 114 HashAlgo: 33, 115 HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447", 116 }, KnownHash), ShouldErrLike, "unsupported hash algorithm 33") 117 }) 118 119 Convey("Some future hash in AnyHash mode", t, func() { 120 So(ValidateObjectRef(&api.ObjectRef{ 121 HashAlgo: 33, 122 HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447", 123 }, AnyHash), ShouldBeNil) 124 125 // Still checks that the hex digest looks like a digest. 126 So(ValidateObjectRef(&api.ObjectRef{ 127 HashAlgo: 33, 128 HexDigest: "abc", 129 }, KnownHash), ShouldErrLike, "uneven number of symbols") 130 131 So(ValidateObjectRef(&api.ObjectRef{ 132 HashAlgo: 33, 133 HexDigest: strings.Repeat("A", 64), // uppercase are forbidden 134 }, KnownHash), ShouldErrLike, "wrong char") 135 }) 136 137 Convey("Bad args", t, func() { 138 So(ValidateObjectRef(nil, AnyHash), ShouldErrLike, "not provided") 139 So(ValidateObjectRef(&api.ObjectRef{HashAlgo: 0}, AnyHash), ShouldErrLike, "unspecified hash algo") 140 }) 141 } 142 143 func TestRefIIDConversion(t *testing.T) { 144 t.Parallel() 145 146 Convey("SHA1 works", t, func() { 147 sha1hex := strings.Repeat("a", 40) 148 sha1iid := sha1hex // iid and hex digest coincide for SHA1 149 150 So(ObjectRefToInstanceID(&api.ObjectRef{ 151 HashAlgo: api.HashAlgo_SHA1, 152 HexDigest: sha1hex, 153 }), ShouldEqual, sha1iid) 154 155 So(InstanceIDToObjectRef(sha1iid), ShouldResembleProto, &api.ObjectRef{ 156 HashAlgo: api.HashAlgo_SHA1, 157 HexDigest: sha1hex, 158 }) 159 }) 160 161 Convey("SHA256 works", t, func() { 162 sha256hex := "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447" 163 sha256iid := "qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A-4XSmaGSpEcC" 164 165 So(ObjectRefToInstanceID(&api.ObjectRef{ 166 HashAlgo: api.HashAlgo_SHA256, 167 HexDigest: sha256hex, 168 }), ShouldEqual, sha256iid) 169 170 So(InstanceIDToObjectRef(sha256iid), ShouldResembleProto, &api.ObjectRef{ 171 HashAlgo: api.HashAlgo_SHA256, 172 HexDigest: sha256hex, 173 }) 174 }) 175 176 Convey("Some future unknown hash", t, func() { 177 hex := strings.Repeat("a", 60) 178 iid := "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqIQ" 179 180 So(ObjectRefToInstanceID(&api.ObjectRef{ 181 HashAlgo: 33, 182 HexDigest: hex, 183 }), ShouldEqual, iid) 184 185 So(InstanceIDToObjectRef(iid), ShouldResembleProto, &api.ObjectRef{ 186 HashAlgo: 33, 187 HexDigest: hex, 188 }) 189 }) 190 191 Convey("Wrong length in InstanceIDToObjectRef", t, func() { 192 So(func() { 193 InstanceIDToObjectRef("aaaa") 194 }, ShouldPanicLike, "not a valid size for an encoded digest") 195 }) 196 197 Convey("Bad format in InstanceIDToObjectRef", t, func() { 198 So(func() { 199 InstanceIDToObjectRef("qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A-?XSmaGSpEcC") 200 }, ShouldPanicLike, "illegal base64 data") 201 }) 202 }