github.phpd.cn/thought-machine/please@v12.2.0+incompatible/src/core/utils_test.go (about)

     1  package core
     2  
     3  import (
     4  	"crypto/sha1"
     5  	"encoding/base64"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  
    13  	"cli"
    14  )
    15  
    16  var tenSecondsTime = 10 * time.Second
    17  var tenSeconds = cli.Duration(tenSecondsTime)
    18  
    19  func TestCollapseHash(t *testing.T) {
    20  	// Test that these two come out differently
    21  	input1 := [sha1.Size * 4]byte{}
    22  	input2 := [sha1.Size * 4]byte{}
    23  	for i := 0; i < sha1.Size; i++ {
    24  		input1[i] = byte(i)
    25  		input2[i] = byte(i * 2)
    26  	}
    27  	output1 := CollapseHash(input1[:])
    28  	output2 := CollapseHash(input2[:])
    29  	assert.NotEqual(t, output1, output2)
    30  }
    31  
    32  func TestCollapseHash2(t *testing.T) {
    33  	// Test of a couple of cases that weren't different...
    34  	input1, err1 := base64.URLEncoding.DecodeString("mByUsoTswXV2X_W6FHhBwJUCQM-YHJSyhOzBdXZf9boUeEHAlQJAz-DzaA7MCXxt5_FFws2WO51vKlqt-JThKzdEQn_bghpDDCuKOI9qGNI=")
    35  	input2, err2 := base64.URLEncoding.DecodeString("rSH0PS_dftB6KN_Jnu_jszhbxiutIfQ9L91-0Hoo38me7-OzOFvGK-DzaA7MCXxt5_FFws2WO51vKlqt-JThKzdEQn_bghpDDCuKOI9qGNI=")
    36  	assert.NoError(t, err1)
    37  	assert.NoError(t, err2)
    38  	output1 := CollapseHash(input1)
    39  	output2 := CollapseHash(input2)
    40  	assert.NotEqual(t, output1, output2)
    41  }
    42  
    43  func TestIterSources(t *testing.T) {
    44  	graph := buildGraph()
    45  	iterSources := func(label string) []SourcePair {
    46  		return toSlice(IterSources(graph, graph.TargetOrDie(ParseBuildLabel(label, ""))))
    47  	}
    48  
    49  	assert.Equal(t, []SourcePair{
    50  		{"src/core/target1.go", "plz-out/tmp/src/core/target1._build/src/core/target1.go"},
    51  	}, iterSources("//src/core:target1"))
    52  
    53  	assert.Equal(t, []SourcePair{
    54  		{"src/core/target2.go", "plz-out/tmp/src/core/target2._build/src/core/target2.go"},
    55  		{"plz-out/gen/src/core/target1.a", "plz-out/tmp/src/core/target2._build/src/core/target1.a"},
    56  	}, iterSources("//src/core:target2"))
    57  
    58  	assert.Equal(t, []SourcePair{
    59  		{"src/build/target1.go", "plz-out/tmp/src/build/target1._build/src/build/target1.go"},
    60  		{"plz-out/gen/src/core/target1.a", "plz-out/tmp/src/build/target1._build/src/core/target1.a"},
    61  	}, iterSources("//src/build:target1"))
    62  
    63  	assert.Equal(t, []SourcePair{
    64  		{"src/output/output1.go", "plz-out/tmp/src/output/output1._build/src/output/output1.go"},
    65  		{"plz-out/gen/src/build/target1.a", "plz-out/tmp/src/output/output1._build/src/build/target1.a"},
    66  	}, iterSources("//src/output:output1"))
    67  
    68  	assert.Equal(t, []SourcePair{
    69  		{"src/output/output1.go", "plz-out/tmp/src/output/output1._build/src/output/output1.go"},
    70  		{"plz-out/gen/src/build/target1.a", "plz-out/tmp/src/output/output1._build/src/build/target1.a"},
    71  	}, iterSources("//src/output:output1"))
    72  
    73  	assert.Equal(t, []SourcePair{
    74  		{"src/output/output2.go", "plz-out/tmp/src/output/output2._build/src/output/output2.go"},
    75  		{"plz-out/gen/src/core/target2.a", "plz-out/tmp/src/output/output2._build/src/core/target2.a"},
    76  		{"plz-out/gen/src/output/output1.a", "plz-out/tmp/src/output/output2._build/src/output/output1.a"},
    77  	}, iterSources("//src/output:output2"))
    78  
    79  	assert.Equal(t, []SourcePair{
    80  		{"src/parse/target1.go", "plz-out/tmp/src/parse/target1._build/src/parse/target1.go"},
    81  		{"plz-out/gen/src/core/target2.a", "plz-out/tmp/src/parse/target1._build/src/core/target2.a"},
    82  		{"plz-out/gen/src/core/target1.a", "plz-out/tmp/src/parse/target1._build/src/core/target1.a"},
    83  	}, iterSources("//src/parse:target1"))
    84  
    85  	assert.Equal(t, []SourcePair{
    86  		{"src/parse/target2.go", "plz-out/tmp/src/parse/target2._build/src/parse/target2.go"},
    87  		{"plz-out/gen/src/parse/target1.a", "plz-out/tmp/src/parse/target2._build/src/parse/target1.a"},
    88  	}, iterSources("//src/parse:target2"))
    89  }
    90  
    91  func TestInitialPackageSimple(t *testing.T) {
    92  	initialPackage = "src/core"
    93  	p := InitialPackage()
    94  	assert.Equal(t, []BuildLabel{{PackageName: "src/core", Name: "..."}}, p)
    95  }
    96  
    97  func TestInitialPackageIllegalLabel(t *testing.T) {
    98  	// Moves up a directory because the last component isn't a legal package name.
    99  	// This is not that common but does make our existing test work at least :)
   100  	initialPackage = "plz-out/tmp/test/query_alltargets_test._test"
   101  	p := InitialPackage()
   102  	assert.Equal(t, []BuildLabel{{PackageName: "plz-out/tmp/test", Name: "..."}}, p)
   103  }
   104  
   105  func TestInitialPackageRoot(t *testing.T) {
   106  	// Test that we don't get stuck in an infinite loop or do anything similarly weird
   107  	// when the input is empty.
   108  	initialPackage = ""
   109  	p := InitialPackage()
   110  	assert.Equal(t, []BuildLabel{{PackageName: "", Name: "..."}}, p)
   111  }
   112  
   113  func TestInitialPackageUpToRoot(t *testing.T) {
   114  	// Similar to above but when we don't start out at the root but back up to it.
   115  	initialPackage = "query_alltargets_test._test"
   116  	p := InitialPackage()
   117  	assert.Equal(t, []BuildLabel{{PackageName: "", Name: "..."}}, p)
   118  }
   119  
   120  func TestLookPath(t *testing.T) {
   121  	// Assume this will be present on the path somewhere (you've really got to have bash for plz)
   122  	path, err := LookPath("bash", []string{"/usr/local/bin", "/usr/bin", "/bin"})
   123  	assert.NoError(t, err)
   124  	assert.Contains(t, []string{"/usr/local/bin/bash", "/usr/bin/bash", "/bin/bash"}, path)
   125  	info, err := os.Stat(path)
   126  	assert.NoError(t, err)
   127  	assert.Equal(t, "bash", info.Name())
   128  }
   129  
   130  func TestLookPathColons(t *testing.T) {
   131  	// We support having colons inside the path elements because people might find that more natural.
   132  	path, err := LookPath("bash", []string{"/usr/local/bin:/usr/bin:/bin"})
   133  	assert.NoError(t, err)
   134  	assert.Contains(t, []string{"/usr/local/bin/bash", "/usr/bin/bash", "/bin/bash"}, path)
   135  	info, err := os.Stat(path)
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, "bash", info.Name())
   138  }
   139  
   140  func TestLookPathDoesntExist(t *testing.T) {
   141  	_, err := LookPath("wibblewobbleflibble", []string{"/usr/local/bin", "/usr/bin", "/bin"})
   142  	assert.Error(t, err)
   143  }
   144  
   145  func TestExecWithTimeout(t *testing.T) {
   146  	out, err := ExecWithTimeoutSimple(tenSeconds, "true")
   147  	assert.NoError(t, err)
   148  	assert.Equal(t, 0, len(out))
   149  }
   150  
   151  func TestExecWithTimeoutFailure(t *testing.T) {
   152  	out, err := ExecWithTimeoutSimple(tenSeconds, "false")
   153  	assert.Error(t, err)
   154  	assert.Equal(t, 0, len(out))
   155  }
   156  
   157  func TestExecWithTimeoutDeadline(t *testing.T) {
   158  	out, err := ExecWithTimeoutSimple(cli.Duration(1*time.Nanosecond), "sleep", "10")
   159  	assert.Error(t, err)
   160  	assert.True(t, strings.HasPrefix(err.Error(), "Timeout exceeded"))
   161  	assert.Equal(t, 0, len(out))
   162  }
   163  
   164  func TestExecWithTimeoutOutput(t *testing.T) {
   165  	state := NewDefaultBuildState()
   166  	out, stderr, err := ExecWithTimeoutShell(state, nil, "", nil, tenSecondsTime, tenSeconds, false, "echo hello", false)
   167  	assert.NoError(t, err)
   168  	assert.Equal(t, "hello\n", string(out))
   169  	assert.Equal(t, "hello\n", string(stderr))
   170  }
   171  
   172  func TestExecWithTimeoutStderr(t *testing.T) {
   173  	state := NewDefaultBuildState()
   174  	out, stderr, err := ExecWithTimeoutShell(state, nil, "", nil, tenSecondsTime, tenSeconds, false, "echo hello 1>&2", false)
   175  	assert.NoError(t, err)
   176  	assert.Equal(t, "", string(out))
   177  	assert.Equal(t, "hello\n", string(stderr))
   178  }
   179  
   180  func TestAsyncDeleteDir(t *testing.T) {
   181  	err := os.MkdirAll("test_dir/a/b/c", DirPermissions)
   182  	assert.NoError(t, err)
   183  	err = AsyncDeleteDir("test_dir")
   184  	assert.NoError(t, err)
   185  	for i := 0; i < 100; i++ {
   186  		if !PathExists("test_dir") {
   187  			return
   188  		}
   189  		time.Sleep(100 * time.Millisecond)
   190  	}
   191  	assert.False(t, PathExists("test_dir"))
   192  }
   193  
   194  // buildGraph builds a test graph which we use to test IterSources etc.
   195  func buildGraph() *BuildGraph {
   196  	graph := NewGraph()
   197  	mt := func(label string, deps ...string) *BuildTarget {
   198  		target := makeTarget(graph, label, deps...)
   199  		graph.AddTarget(target)
   200  		return target
   201  	}
   202  
   203  	mt("//src/core:target1")
   204  	mt("//src/core:target2", "//src/core:target1")
   205  	mt("//src/build:target1", "//src/core:target1")
   206  	mt("//src/output:output1", "//src/build:target1")
   207  	mt("//src/output:output2", "//src/output:output1", "//src/core:target2")
   208  	t1 := mt("//src/parse:target1", "//src/core:target2")
   209  	t1.NeedsTransitiveDependencies = true
   210  	t1.OutputIsComplete = true
   211  	mt("//src/parse:target2", "//src/parse:target1")
   212  
   213  	return graph
   214  }
   215  
   216  // makeTarget creates a new build target for us.
   217  func makeTarget(graph *BuildGraph, label string, deps ...string) *BuildTarget {
   218  	target := NewBuildTarget(ParseBuildLabel(label, ""))
   219  	for _, dep := range deps {
   220  		t := graph.TargetOrDie(ParseBuildLabel(dep, ""))
   221  		target.AddDependency(t.Label)
   222  		target.resolveDependency(target.Label, t)
   223  	}
   224  	target.Sources = append(target.Sources, FileLabel{
   225  		File:    target.Label.Name + ".go",
   226  		Package: target.Label.PackageName,
   227  	})
   228  	target.AddOutput(target.Label.Name + ".a")
   229  	return target
   230  }
   231  
   232  func toSlice(ch <-chan SourcePair) []SourcePair {
   233  	ret := []SourcePair{}
   234  	for x := range ch {
   235  		ret = append(ret, x)
   236  	}
   237  	return ret
   238  }