github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/cipd/cipd_test.go (about) 1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cipd 6 7 import ( 8 "bytes" 9 "encoding/hex" 10 "io/ioutil" 11 "os" 12 "path" 13 "reflect" 14 "sort" 15 "strings" 16 "testing" 17 18 "github.com/btwiuse/jiri/jiritest/xtest" 19 ) 20 21 const ( 22 // Some random valid cipd version tags from infra/tools/cipd 23 cipdVersionForTestA = "git_revision:00e2d8b49a4e7505d1c71f19d15c9e7c5b9245a5" 24 cipdVersionForTestB = "git_revision:8fac632847b1ce0de3b57d16d0f2193625f4a4f0" 25 // package path and versions for ACL tests 26 cipdPkgPathA = "gn/gn/${platform}" 27 cipdPkgVersionA = "git_revision:bdb0fd02324b120cacde634a9235405061c8ea06" 28 cipdPkgPathB = "notexist/notexist" 29 cipdPkgVersionB = "git_revision:bdb0fd02324b120cacde634a9235405061c8ea06" 30 ) 31 32 var ( 33 // Digests generated by cipd selfupdate-roll ... 34 digestMapA = map[string]string{ 35 "linux-amd64": "df37ffc2588e345a31ca790d773b6136fedbd2efbf9a34cb735dd34b6891c16c", 36 "linux-arm64": "650f2a045f8587062a16299a650aa24ba5c5c0652585a2d9bd56594369d5f99e", 37 "linux-armv6l": "61b657c860ddc39d3286ced073c843852b1dafc0222af0bdc22ad988b289d733", 38 "mac-amd64": "4d015791ed6f03f305cf6a5a673a447e5c47ff5fdb701f43f99fba9ca73e61f8", 39 } 40 digestMapB = map[string]string{ 41 "linux-amd64": "bdc971fd2895c3771e0709d2a3ec5fcace69c59a3a9f9dc33ab76fbc2f777d40", 42 "linux-arm64": "e1d6aadc9bfc155e9088aa3de39b9d3311c7359f398f372b5ad1c308e25edfeb", 43 "linux-armv6l": "3ad97b47ecc1b358c8ebd1b0307087d354433d88f24bf8ece096fb05452837f9", 44 "mac-amd64": "167edadf7c7c019a40b9f7869a4c05b2d9834427dad68e295442ef9ebce88dba", 45 } 46 instanceIDMap = map[string]string{ 47 "gn/gn/linux-amd64": "0uGjKAZkJXPZjtYktgEwHiNbwsut_qRsk7ZCGGxi82IC", 48 "gn/gn/mac-amd64": "rN2F641yR4Bj-H1q8OwC_RiqRpUYxy3hryzRfPER9wcC", 49 } 50 ) 51 52 // TestFetchBinary tests fetchiBinary method by fetching a set of 53 // cipd binaries. This test requires network access 54 func TestFetchBinary(t *testing.T) { 55 tmpDir, err := ioutil.TempDir("", "jiri-test") 56 if err != nil { 57 t.Error("failed to create temp dir for testing") 58 } 59 defer os.RemoveAll(tmpDir) 60 61 tests := []struct { 62 version string 63 digest map[string]string 64 }{ 65 {cipdVersionForTestA, digestMapA}, 66 {cipdVersionForTestB, digestMapB}, 67 } 68 69 for i, test := range tests { 70 for platform, digest := range test.digest { 71 cipdPath := path.Join(tmpDir, "cipd"+platform+test.version) 72 if err := fetchBinary(cipdPath, platform, test.version, digest); err != nil { 73 t.Errorf("test %d failed while retrieving cipd binary for platform %q on version %q with digest %q: %v", i, platform, test.version, digest, err) 74 } 75 } 76 } 77 } 78 79 func TestCipdVersion(t *testing.T) { 80 // Assume cipd version is always a git commit hash for now 81 versionStr := string(cipdVersion) 82 if len(versionStr) != len("git_revision:00e2d8b49a4e7505d1c71f19d15c9e7c5b9245a5") || 83 !strings.HasPrefix(versionStr, "git_revision:") { 84 t.Errorf("unsupported cipd version tag: %q", versionStr) 85 } 86 versionHash := versionStr[len("git_revision:"):] 87 if _, err := hex.DecodeString(versionHash); err != nil { 88 t.Errorf("unsupported cipd version tag: %q", versionStr) 89 } 90 } 91 92 func TestFetchDigest(t *testing.T) { 93 tests := []string{ 94 "linux-amd64", 95 "linux-arm64", 96 "linux-armv6l", 97 "mac-amd64", 98 } 99 100 for _, platform := range tests { 101 digest, _, err := fetchDigest(platform) 102 if err != nil { 103 t.Errorf("failed to retrieve cipd digest for platform %q due to error: %v", platform, err) 104 } 105 if _, err := hex.DecodeString(digest); err != nil { 106 t.Errorf("digest %q is not a valid hex string for platform %q", digest, platform) 107 } 108 } 109 } 110 111 func TestSelfUpdate(t *testing.T) { 112 tmpDir, err := ioutil.TempDir("", "jiri-test") 113 if err != nil { 114 t.Error("failed to create temp dir for testing") 115 } 116 defer os.RemoveAll(tmpDir) 117 // Bootstrap cipd to version A 118 cipdPath := path.Join(tmpDir, "cipd") 119 if err := fetchBinary(cipdPath, CipdPlatform.String(), cipdVersionForTestA, digestMapA[CipdPlatform.String()]); err != nil { 120 t.Errorf("failed to bootstrap cipd with version %q: %v", cipdVersionForTestA, err) 121 } 122 // Perform cipd self update to version B 123 if err := selfUpdate(cipdPath, cipdVersionForTestB); err != nil { 124 t.Errorf("failed to perform cipd self update: %v", err) 125 } 126 // Verify self updated cipd 127 cipdData, err := ioutil.ReadFile(cipdPath) 128 if err != nil { 129 t.Errorf("failed to read self-updated cipd binary: %v", err) 130 } 131 verified, err := verifyDigest(cipdData, digestMapB[CipdPlatform.String()]) 132 if err != nil { 133 t.Errorf("digest failed verification for platform %q on version %q", CipdPlatform.String(), cipdVersionForTestB) 134 } 135 if !verified { 136 t.Errorf("self-updated cipd failed integrity test") 137 } 138 } 139 140 func TestBootsrap(t *testing.T) { 141 fakex, cleanup := xtest.NewX(t) 142 defer cleanup() 143 cipdPath, err := Bootstrap(fakex.CIPDPath()) 144 if cipdPath == "" { 145 t.Errorf("bootstrap returned an empty path") 146 } 147 fileInfo, err := os.Stat(cipdPath) 148 if err != nil { 149 if os.IsNotExist(err) { 150 t.Errorf("bootstrap failed, cipd binary was not found at %q", cipdPath) 151 } 152 t.Errorf("bootstrap failed, could not access cipd binary at %q due to error %v", cipdPath, err) 153 } 154 if fileInfo.Mode()&0111 == 0 { 155 t.Errorf("bootstrap failed, cipd binary at %q is not executable", cipdBinary) 156 } 157 } 158 159 func TestEnsure(t *testing.T) { 160 fakex, cleanup := xtest.NewX(t) 161 defer cleanup() 162 cipdPath, err := Bootstrap(fakex.CIPDPath()) 163 if err != nil { 164 t.Errorf("bootstrap failed due to error: %v", err) 165 } 166 defer os.Remove(cipdPath) 167 // Write test ensure file 168 testEnsureFile, err := ioutil.TempFile("", "test_jiri*.ensure") 169 if err != nil { 170 t.Errorf("failed to create test ensure file: %v", err) 171 } 172 defer testEnsureFile.Close() 173 defer os.Remove(testEnsureFile.Name()) 174 _, err = testEnsureFile.Write([]byte(` 175 $ParanoidMode CheckPresence 176 177 # GN 178 gn/gn/${platform} git_revision:bdb0fd02324b120cacde634a9235405061c8ea06 179 `)) 180 if err != nil { 181 t.Errorf("failed to write test ensure file: %v", err) 182 } 183 testEnsureFile.Sync() 184 tmpDir, err := ioutil.TempDir("", "jiri-test") 185 if err != nil { 186 t.Error("failed to creat temp dir for testing") 187 } 188 defer os.RemoveAll(tmpDir) 189 // Invoke Ensure on test ensure file 190 if err := Ensure(fakex, testEnsureFile.Name(), tmpDir, 30); err != nil { 191 t.Errorf("ensure failed due to error: %v", err) 192 } 193 // Check the existence downloaded package 194 gnPath := path.Join(tmpDir, "gn") 195 if _, err := os.Stat(gnPath); err != nil { 196 if os.IsNotExist(err) { 197 t.Errorf("fetched cipd package is not found at %q", gnPath) 198 } 199 t.Errorf("failed to execute os.Stat() on fetched cipd package due to error: %v", err) 200 } 201 } 202 203 func TestCheckACL(t *testing.T) { 204 fakex, cleanup := xtest.NewX(t) 205 defer cleanup() 206 cipdPath, err := Bootstrap(fakex.CIPDPath()) 207 if err != nil { 208 t.Errorf("bootstrap failed due to error: %v", err) 209 } 210 defer os.Remove(cipdPath) 211 212 pkgMap := make(map[string]bool) 213 pkgMap[cipdPkgPathA] = false 214 pkgMap[cipdPkgPathB] = false 215 if err := CheckPackageACL(fakex, pkgMap); err != nil { 216 t.Errorf("CheckPackageACL failed due to error: %v", err) 217 } 218 219 if !pkgMap[cipdPkgPathA] { 220 t.Errorf("pkg %q should be accessible, but it is not accessible by cipd", cipdPkgPathA) 221 } 222 223 if pkgMap[cipdPkgPathB] { 224 t.Errorf("pkg %q should not be accessible, but it is accessible by cipd", cipdPkgPathB) 225 } 226 227 } 228 229 func TestResolve(t *testing.T) { 230 fakex, cleanup := xtest.NewX(t) 231 defer cleanup() 232 cipdPath, err := Bootstrap(fakex.CIPDPath()) 233 if err != nil { 234 t.Errorf("bootstrap failed due to error: %v", err) 235 } 236 defer os.Remove(cipdPath) 237 238 // Write test ensure file 239 testEnsureFile, err := ioutil.TempFile("", "test_jiri*.ensure") 240 if err != nil { 241 t.Errorf("failed to create test ensure file: %v", err) 242 } 243 defer testEnsureFile.Close() 244 ensureFileName := testEnsureFile.Name() 245 defer os.Remove(ensureFileName) 246 versionFileName := ensureFileName[:len(ensureFileName)-len(".ensure")] + ".version" 247 var ensureBuf bytes.Buffer 248 ensureBuf.WriteString("$ResolvedVersions " + versionFileName + "\n") 249 ensureBuf.WriteString(` 250 $ParanoidMode CheckPresence 251 $VerifiedPlatform linux-amd64 252 $VerifiedPlatform mac-amd64 253 254 # GN 255 gn/gn/${platform} git_revision:bdb0fd02324b120cacde634a9235405061c8ea06 256 `) 257 _, err = testEnsureFile.Write(ensureBuf.Bytes()) 258 if err != nil { 259 t.Errorf("failed to write test ensure file: %v", err) 260 } 261 262 testEnsureFile.Sync() 263 instances, err := Resolve(fakex, testEnsureFile.Name()) 264 if err != nil { 265 t.Errorf("resolve failed due to error: %v", err) 266 } 267 for _, instance := range instances { 268 if val, ok := instanceIDMap[instance.PackageName]; ok { 269 if val != instance.InstanceID { 270 t.Errorf("instance id %q for package %q does not match the record %q", 271 instance.InstanceID, instance.PackageName, val) 272 } 273 } else { 274 t.Errorf("package %q is not found in record", instance.PackageName) 275 } 276 } 277 } 278 279 func TestExpand(t *testing.T) { 280 platforms := []Platform{ 281 Platform{"linux", "amd64"}, 282 Platform{"linux", "arm64"}, 283 Platform{"mac", "amd64"}, 284 } 285 286 tests := map[string][]string{ 287 "gn/gn/${platform}": []string{"gn/gn/linux-amd64", "gn/gn/linux-arm64", "gn/gn/mac-amd64"}, 288 "fuchsia/sysroot/${os=linux}-${arch}": []string{"fuchsia/sysroot/linux-amd64", "fuchsia/sysroot/linux-arm64"}, 289 "infra/ninja/linux-amd64": []string{"infra/ninja/linux-amd64"}, 290 } 291 292 for k, p := range tests { 293 pkgs, err := Expand(k, platforms) 294 if err != nil { 295 t.Errorf("Expand faild on path %q due to error: %v", p, err) 296 } 297 sort.Strings(p) 298 sort.Strings(pkgs) 299 if !reflect.DeepEqual(p, pkgs) { 300 t.Errorf("test on %q failed: expecting %v, got %v", k, p, pkgs) 301 } 302 } 303 } 304 305 func TestMustExpand(t *testing.T) { 306 tests := map[string]bool{ 307 "fuchsia/clang/${platform}": true, 308 "fuchsia/clang/${os}-${arch}": true, 309 "fuchsia/clang/${os=linux}-${arch=amd64}": true, 310 "fuchsia/clang/linux-amd64": false, 311 } 312 for k, v := range tests { 313 if MustExpand(k) != v { 314 t.Errorf("MustExpand failed on package %q, expecting %v got %v", k, v, MustExpand(k)) 315 } 316 } 317 } 318 319 func TestDecl(t *testing.T) { 320 platforms := []Platform{ 321 Platform{"linux", "amd64"}, 322 Platform{"linux", "arm64"}, 323 Platform{"mac", "amd64"}, 324 } 325 326 tests := map[string]string{ 327 "fuchsia/clang/${platform}": "fuchsia/clang/${platform=linux-amd64,linux-arm64,mac-amd64}", 328 "fuchsia/clang/${os}-${arch}": "fuchsia/clang/${os=linux,mac}-${arch=amd64,arm64}", 329 "fuchsia/clang/${os=linux}-${arch}": "fuchsia/clang/${os=linux}-${arch=amd64,arm64}", 330 "fuchsia/clang/${os=linux}-${arch=amd64}": "fuchsia/clang/${os=linux}-${arch=amd64}", 331 "fuchsia/clang/linux-amd64": "fuchsia/clang/linux-amd64", 332 } 333 334 for k, v := range tests { 335 cipdPath, err := Decl(k, platforms) 336 if err != nil { 337 t.Errorf("Decl failed on cipdPath %q due to error: %v", k, err) 338 } 339 if cipdPath != v { 340 t.Errorf("test on %q failed: expecting %q, got %q", k, v, cipdPath) 341 } 342 } 343 } 344 345 func TestFloatingRefs(t *testing.T) { 346 fakex, cleanup := xtest.NewX(t) 347 defer cleanup() 348 cipdPath, err := Bootstrap(fakex.CIPDPath()) 349 if err != nil { 350 t.Errorf("bootstrap failed due to error: %v", err) 351 } 352 defer os.Remove(cipdPath) 353 testExpects := map[PackageInstance]bool{ 354 PackageInstance{ 355 PackageName: "gn/gn/${platform}", 356 VersionTag: "latest", 357 }: true, 358 PackageInstance{ 359 PackageName: "gn/gn/${platform}", 360 VersionTag: "git_revision:bdb0fd02324b120cacde634a9235405061c8ea06", 361 }: false, 362 } 363 364 platformMap := make(map[PackageInstance][]Platform) 365 for k := range testExpects { 366 platformMap[k] = DefaultPlatforms() 367 } 368 369 tests := make(map[PackageInstance]bool) 370 for k, v := range testExpects { 371 tests[k] = v 372 } 373 374 if err := CheckFloatingRefs(fakex, tests, platformMap); err != nil { 375 t.Errorf("CheckFloatingRefs failed due to error: %v", err) 376 return 377 } 378 379 for k, v := range tests { 380 if v != testExpects[k] { 381 t.Errorf("expecting %v, got %v for test %q", testExpects[k], v, k.PackageName) 382 } 383 } 384 }