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 }