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  }