Home | History | Annotate | Download | only in work
      1 // Copyright 2016 The Go 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 work
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"io/ioutil"
     11 	"os"
     12 	"path/filepath"
     13 	"reflect"
     14 	"runtime"
     15 	"strings"
     16 	"testing"
     17 
     18 	"cmd/go/internal/base"
     19 	"cmd/go/internal/cfg"
     20 	"cmd/go/internal/load"
     21 )
     22 
     23 func TestRemoveDevNull(t *testing.T) {
     24 	fi, err := os.Lstat(os.DevNull)
     25 	if err != nil {
     26 		t.Skip(err)
     27 	}
     28 	if fi.Mode().IsRegular() {
     29 		t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
     30 	}
     31 	mayberemovefile(os.DevNull)
     32 	_, err = os.Lstat(os.DevNull)
     33 	if err != nil {
     34 		t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
     35 	}
     36 }
     37 
     38 func TestSplitPkgConfigOutput(t *testing.T) {
     39 	for _, test := range []struct {
     40 		in   []byte
     41 		want []string
     42 	}{
     43 		{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
     44 		{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
     45 		{[]byte(`broken flag\`), []string{"broken", "flag"}},
     46 		{[]byte("\textra     whitespace\r\n"), []string{"extra", "whitespace"}},
     47 		{[]byte("     \r\n      "), nil},
     48 	} {
     49 		got := splitPkgConfigOutput(test.in)
     50 		if !reflect.DeepEqual(got, test.want) {
     51 			t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
     52 		}
     53 	}
     54 }
     55 
     56 func TestSharedLibName(t *testing.T) {
     57 	// TODO(avdva) - make these values platform-specific
     58 	prefix := "lib"
     59 	suffix := ".so"
     60 	testData := []struct {
     61 		args      []string
     62 		pkgs      []*load.Package
     63 		expected  string
     64 		expectErr bool
     65 		rootedAt  string
     66 	}{
     67 		{
     68 			args:     []string{"std"},
     69 			pkgs:     []*load.Package{},
     70 			expected: "std",
     71 		},
     72 		{
     73 			args:     []string{"std", "cmd"},
     74 			pkgs:     []*load.Package{},
     75 			expected: "std,cmd",
     76 		},
     77 		{
     78 			args:     []string{},
     79 			pkgs:     []*load.Package{pkgImportPath("gopkg.in/somelib")},
     80 			expected: "gopkg.in-somelib",
     81 		},
     82 		{
     83 			args:     []string{"./..."},
     84 			pkgs:     []*load.Package{pkgImportPath("somelib")},
     85 			expected: "somelib",
     86 			rootedAt: "somelib",
     87 		},
     88 		{
     89 			args:     []string{"../somelib", "../somelib"},
     90 			pkgs:     []*load.Package{pkgImportPath("somelib")},
     91 			expected: "somelib",
     92 		},
     93 		{
     94 			args:     []string{"../lib1", "../lib2"},
     95 			pkgs:     []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
     96 			expected: "gopkg.in-lib1,gopkg.in-lib2",
     97 		},
     98 		{
     99 			args: []string{"./..."},
    100 			pkgs: []*load.Package{
    101 				pkgImportPath("gopkg.in/dir/lib1"),
    102 				pkgImportPath("gopkg.in/lib2"),
    103 				pkgImportPath("gopkg.in/lib3"),
    104 			},
    105 			expected: "gopkg.in",
    106 			rootedAt: "gopkg.in",
    107 		},
    108 		{
    109 			args:      []string{"std", "../lib2"},
    110 			pkgs:      []*load.Package{},
    111 			expectErr: true,
    112 		},
    113 		{
    114 			args:      []string{"all", "./"},
    115 			pkgs:      []*load.Package{},
    116 			expectErr: true,
    117 		},
    118 		{
    119 			args:      []string{"cmd", "fmt"},
    120 			pkgs:      []*load.Package{},
    121 			expectErr: true,
    122 		},
    123 	}
    124 	for _, data := range testData {
    125 		func() {
    126 			if data.rootedAt != "" {
    127 				tmpGopath, err := ioutil.TempDir("", "gopath")
    128 				if err != nil {
    129 					t.Fatal(err)
    130 				}
    131 				oldGopath := cfg.BuildContext.GOPATH
    132 				defer func() {
    133 					cfg.BuildContext.GOPATH = oldGopath
    134 					os.Chdir(base.Cwd)
    135 					err := os.RemoveAll(tmpGopath)
    136 					if err != nil {
    137 						t.Error(err)
    138 					}
    139 				}()
    140 				root := filepath.Join(tmpGopath, "src", data.rootedAt)
    141 				err = os.MkdirAll(root, 0755)
    142 				if err != nil {
    143 					t.Fatal(err)
    144 				}
    145 				cfg.BuildContext.GOPATH = tmpGopath
    146 				os.Chdir(root)
    147 			}
    148 			computed, err := libname(data.args, data.pkgs)
    149 			if err != nil {
    150 				if !data.expectErr {
    151 					t.Errorf("libname returned an error %q, expected a name", err.Error())
    152 				}
    153 			} else if data.expectErr {
    154 				t.Errorf("libname returned %q, expected an error", computed)
    155 			} else {
    156 				expected := prefix + data.expected + suffix
    157 				if expected != computed {
    158 					t.Errorf("libname returned %q, expected %q", computed, expected)
    159 				}
    160 			}
    161 		}()
    162 	}
    163 }
    164 
    165 func pkgImportPath(pkgpath string) *load.Package {
    166 	return &load.Package{
    167 		PackagePublic: load.PackagePublic{
    168 			ImportPath: pkgpath,
    169 		},
    170 	}
    171 }
    172 
    173 // When installing packages, the installed package directory should
    174 // respect the SetGID bit and group name of the destination
    175 // directory.
    176 // See https://golang.org/issue/18878.
    177 func TestRespectSetgidDir(t *testing.T) {
    178 	switch runtime.GOOS {
    179 	case "nacl":
    180 		t.Skip("can't set SetGID bit with chmod on nacl")
    181 	case "darwin":
    182 		if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
    183 			t.Skip("can't set SetGID bit with chmod on iOS")
    184 		}
    185 	}
    186 
    187 	var b Builder
    188 
    189 	// Check that `cp` is called instead of `mv` by looking at the output
    190 	// of `(*Builder).ShowCmd` afterwards as a sanity check.
    191 	cfg.BuildX = true
    192 	var cmdBuf bytes.Buffer
    193 	b.Print = func(a ...interface{}) (int, error) {
    194 		return cmdBuf.WriteString(fmt.Sprint(a...))
    195 	}
    196 
    197 	setgiddir, err := ioutil.TempDir("", "SetGroupID")
    198 	if err != nil {
    199 		t.Fatal(err)
    200 	}
    201 	defer os.RemoveAll(setgiddir)
    202 
    203 	if runtime.GOOS == "freebsd" {
    204 		err = os.Chown(setgiddir, os.Getuid(), os.Getgid())
    205 		if err != nil {
    206 			t.Fatal(err)
    207 		}
    208 	}
    209 
    210 	// Change setgiddir's permissions to include the SetGID bit.
    211 	if err := os.Chmod(setgiddir, 0755|os.ModeSetgid); err != nil {
    212 		t.Fatal(err)
    213 	}
    214 
    215 	pkgfile, err := ioutil.TempFile("", "pkgfile")
    216 	if err != nil {
    217 		t.Fatalf("ioutil.TempFile(\"\", \"pkgfile\"): %v", err)
    218 	}
    219 	defer os.Remove(pkgfile.Name())
    220 	defer pkgfile.Close()
    221 
    222 	dirGIDFile := filepath.Join(setgiddir, "setgid")
    223 	if err := b.moveOrCopyFile(nil, dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
    224 		t.Fatalf("moveOrCopyFile: %v", err)
    225 	}
    226 
    227 	got := strings.TrimSpace(cmdBuf.String())
    228 	want := b.fmtcmd("", "cp %s %s", pkgfile.Name(), dirGIDFile)
    229 	if got != want {
    230 		t.Fatalf("moveOrCopyFile(%q, %q): want %q, got %q", dirGIDFile, pkgfile.Name(), want, got)
    231 	}
    232 }
    233