github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/os/os_test.go (about) 1 package os 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "runtime" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/tilt-dev/tilt/internal/tiltfile/io" 15 "github.com/tilt-dev/tilt/internal/tiltfile/starkit" 16 ) 17 18 func TestEnviron(t *testing.T) { 19 f := NewFixture(t) 20 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 21 22 f.File("Tiltfile", ` 23 print(os.environ['FAKE_ENV_VARIABLE']) 24 print(os.environ.get('FAKE_ENV_VARIABLE')) 25 `) 26 27 _, err := f.ExecFile("Tiltfile") 28 assert.NoError(t, err) 29 assert.Equal(t, "fakeValue\nfakeValue\n", f.PrintOutput()) 30 } 31 32 func TestGetenv(t *testing.T) { 33 f := NewFixture(t) 34 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 35 36 f.File("Tiltfile", ` 37 print(os.getenv('FAKE_ENV_VARIABLE')) 38 print(os.getenv('FAKE_ENV_VARIABLE', 'foo')) 39 print(os.getenv('FAKE_ENV_VARIABLE_UNSET', 'bar')) 40 `) 41 42 _, err := f.ExecFile("Tiltfile") 43 assert.NoError(t, err) 44 assert.Equal(t, "fakeValue\nfakeValue\nbar\n", f.PrintOutput()) 45 } 46 47 func TestPutenv(t *testing.T) { 48 f := NewFixture(t) 49 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 50 51 f.File("Tiltfile", ` 52 os.putenv('FAKE_ENV_VARIABLE', 'fakeValue2') 53 print(os.getenv('FAKE_ENV_VARIABLE')) 54 `) 55 56 _, err := f.ExecFile("Tiltfile") 57 assert.NoError(t, err) 58 assert.Equal(t, "fakeValue2\n", f.PrintOutput()) 59 assert.Equal(t, "fakeValue2", os.Getenv("FAKE_ENV_VARIABLE")) 60 } 61 62 func TestPutenvByDict(t *testing.T) { 63 f := NewFixture(t) 64 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 65 66 f.File("Tiltfile", ` 67 os.environ['FAKE_ENV_VARIABLE'] = 'fakeValueByDict' 68 print(os.getenv('FAKE_ENV_VARIABLE')) 69 `) 70 71 _, err := f.ExecFile("Tiltfile") 72 assert.NoError(t, err) 73 assert.Equal(t, "fakeValueByDict\n", f.PrintOutput()) 74 assert.Equal(t, "fakeValueByDict", os.Getenv("FAKE_ENV_VARIABLE")) 75 } 76 77 func TestUnsetenv(t *testing.T) { 78 f := NewFixture(t) 79 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 80 81 f.File("Tiltfile", ` 82 os.unsetenv('FAKE_ENV_VARIABLE') 83 print(os.getenv('FAKE_ENV_VARIABLE', 'unused')) 84 `) 85 86 _, err := f.ExecFile("Tiltfile") 87 assert.NoError(t, err) 88 assert.Equal(t, "unused\n", f.PrintOutput()) 89 90 _, found := os.LookupEnv("FAKE_ENV_VARIABLE") 91 assert.False(t, found) 92 } 93 94 func TestUnsetenvAsDict(t *testing.T) { 95 f := NewFixture(t) 96 t.Setenv("FAKE_ENV_VARIABLE", "fakeValue") 97 98 f.File("Tiltfile", ` 99 os.environ.pop('FAKE_ENV_VARIABLE') 100 print(os.getenv('FAKE_ENV_VARIABLE', 'unused')) 101 `) 102 103 _, err := f.ExecFile("Tiltfile") 104 assert.NoError(t, err) 105 assert.Equal(t, "unused\n", f.PrintOutput()) 106 107 _, found := os.LookupEnv("FAKE_ENV_VARIABLE") 108 assert.False(t, found) 109 } 110 111 func TestGetCwd(t *testing.T) { 112 f := NewFixture(t) 113 114 f.File("Tiltfile", ` 115 print(os.getcwd()) 116 `) 117 118 _, err := f.ExecFile("Tiltfile") 119 assert.NoError(t, err) 120 assert.Equal(t, fmt.Sprintf("%s\n", f.Path()), f.PrintOutput()) 121 } 122 123 func TestGetCwdLoad(t *testing.T) { 124 f := NewFixture(t) 125 126 f.File("foo/Tiltfile", ` 127 cwd = os.getcwd() 128 `) 129 f.File("Tiltfile", ` 130 load('./foo/Tiltfile', 'cwd') 131 print(cwd) 132 `) 133 134 _, err := f.ExecFile("Tiltfile") 135 assert.NoError(t, err) 136 assert.Equal(t, fmt.Sprintf("%s\n", f.JoinPath("foo")), f.PrintOutput()) 137 } 138 139 func TestGetCwdLoadFunction(t *testing.T) { 140 f := NewFixture(t) 141 142 f.File("foo/Tiltfile", ` 143 def get_cwd_wrapper(): 144 return os.getcwd() 145 `) 146 f.File("Tiltfile", ` 147 load('./foo/Tiltfile', 'get_cwd_wrapper') 148 print(get_cwd_wrapper()) 149 `) 150 151 _, err := f.ExecFile("Tiltfile") 152 assert.NoError(t, err) 153 assert.Equal(t, fmt.Sprintf("%s\n", f.Path()), f.PrintOutput()) 154 } 155 156 func TestAbspath(t *testing.T) { 157 f := NewFixture(t) 158 f.UseRealFS() 159 160 f.File("foo/Tiltfile", ` 161 path = os.path.abspath('.') 162 `) 163 f.File("Tiltfile", ` 164 load('./foo/Tiltfile', 'path') 165 print(path) 166 `) 167 168 _, err := f.ExecFile("Tiltfile") 169 require.NoError(t, err) 170 assert.Equal(t, fmt.Sprintf("%s\n", f.JoinPath("foo")), f.PrintOutput()) 171 } 172 173 func TestAbspathSymlinks(t *testing.T) { 174 if runtime.GOOS == "windows" { 175 t.Skip("no user-land symlink support on windows") 176 } 177 178 f := NewFixture(t) 179 f.UseRealFS() 180 181 f.File("foo/Tiltfile", ` 182 path = os.path.abspath('.') 183 `) 184 f.Symlink("foo", "bar") 185 f.File("Tiltfile", ` 186 load('./bar/Tiltfile', 'path') 187 print(path) 188 `) 189 190 _, err := f.ExecFile("Tiltfile") 191 require.NoError(t, err) 192 assert.Equal(t, fmt.Sprintf("%s\n", f.JoinPath("bar")), f.PrintOutput()) 193 } 194 195 // NOTE(maia): `relpath` tests use raw strings (`r'stuff'`) so that Windows tests pass 196 // (otherwise Starlark sees invalid escape sequences in Windows filespaths and gets mad) 197 // Also, we use filepath.Rel to get expected path so it works on all OS's. 198 func TestRelpathDefaultCWD(t *testing.T) { 199 f := NewFixture(t) 200 f.UseRealFS() 201 202 targpath := f.JoinPath("beep/boop") 203 expected, err := filepath.Rel(f.Path(), targpath) 204 assert.NoError(t, err) 205 206 f.File("Tiltfile", fmt.Sprintf(` 207 print(os.path.relpath(r'%s')) 208 `, targpath)) 209 210 _, err = f.ExecFile("Tiltfile") 211 require.NoError(t, err) 212 assert.Equal(t, expected, strings.TrimSpace(f.PrintOutput())) 213 } 214 215 func TestRelpathToDifferentDir(t *testing.T) { 216 f := NewFixture(t) 217 f.UseRealFS() 218 219 targpath := f.JoinPath("beep/boop") 220 basepath := f.JoinPath("beep/") 221 expected, err := filepath.Rel(basepath, targpath) 222 assert.NoError(t, err) 223 224 f.File("Tiltfile", fmt.Sprintf(` 225 print(os.path.relpath(r'%s', r'%s')) 226 `, targpath, basepath)) 227 228 _, err = f.ExecFile("Tiltfile") 229 require.NoError(t, err) 230 assert.Equal(t, expected, strings.TrimSpace(f.PrintOutput())) 231 } 232 233 func TestRelpathImpossible(t *testing.T) { 234 f := NewFixture(t) 235 f.UseRealFS() 236 237 f.File("Tiltfile", ` 238 print(os.path.relpath('some/nonsense/path')) 239 `) 240 _, err := f.ExecFile("Tiltfile") 241 require.Error(t, err) 242 assert.Contains(t, err.Error(), "can't make some/nonsense/path relative to") 243 } 244 245 func TestRelpathUpADir(t *testing.T) { 246 f := NewFixture(t) 247 f.UseRealFS() 248 249 targpath := f.JoinPath("beep/boop") 250 basepath := f.JoinPath("foo") 251 expected, err := filepath.Rel(basepath, targpath) 252 assert.NoError(t, err) 253 254 f.File("foo/Tiltfile", fmt.Sprintf(` 255 print(os.path.relpath(r'%s')) 256 `, f.JoinPath("beep/boop"))) 257 258 _, err = f.ExecFile("foo/Tiltfile") 259 require.NoError(t, err) 260 assert.Equal(t, expected, strings.TrimSpace(f.PrintOutput())) 261 } 262 263 func TestRelpathLoad(t *testing.T) { 264 f := NewFixture(t) 265 f.UseRealFS() 266 267 targpath := f.JoinPath("foo/beep/boop") 268 basepath := f.JoinPath("foo") 269 expected, err := filepath.Rel(basepath, targpath) 270 assert.NoError(t, err) 271 272 f.File("foo/Tiltfile", fmt.Sprintf(` 273 path = os.path.relpath(r'%s') 274 `, f.JoinPath("foo/beep/boop"))) 275 276 f.File("Tiltfile", ` 277 load('./foo/Tiltfile', 'path') 278 print(path) 279 `) 280 _, err = f.ExecFile("Tiltfile") 281 require.NoError(t, err) 282 assert.Equal(t, expected, strings.TrimSpace(f.PrintOutput())) 283 } 284 285 func TestBasename(t *testing.T) { 286 f := NewFixture(t) 287 f.UseRealFS() 288 289 f.File("foo/Tiltfile", ` 290 path = os.path.basename(os.path.abspath('.')) 291 `) 292 f.File("Tiltfile", ` 293 load('./foo/Tiltfile', 'path') 294 print(path) 295 `) 296 297 _, err := f.ExecFile("Tiltfile") 298 require.NoError(t, err) 299 assert.Equal(t, "foo\n", f.PrintOutput()) 300 } 301 302 func TestDirname(t *testing.T) { 303 f := NewFixture(t) 304 f.UseRealFS() 305 306 f.File("foo/Tiltfile", ` 307 path = os.path.dirname(os.path.abspath('.')) 308 `) 309 f.File("Tiltfile", ` 310 load('./foo/Tiltfile', 'path') 311 print(path) 312 `) 313 314 _, err := f.ExecFile("Tiltfile") 315 require.NoError(t, err) 316 assert.Equal(t, f.Path()+"\n", f.PrintOutput()) 317 } 318 319 func TestExists(t *testing.T) { 320 f := NewFixture(t) 321 f.UseRealFS() 322 323 f.File("foo/Tiltfile", ` 324 result1 = os.path.exists('foo/Tiltfile') 325 result2 = os.path.exists('./Tiltfile') 326 result3 = os.path.exists('../Tiltfile') 327 result4 = os.path.exists('../foo') 328 result5 = os.path.exists('../bar') 329 `) 330 f.File("Tiltfile", ` 331 load('./foo/Tiltfile', 'result1', 'result2', 'result3', 'result4', 'result5') 332 print(result1) 333 print(result2) 334 print(result3) 335 print(result4) 336 print(result5) 337 `) 338 339 _, err := f.ExecFile("Tiltfile") 340 require.NoError(t, err) 341 assert.Equal(t, "False\nTrue\nTrue\nTrue\nFalse\n", f.PrintOutput()) 342 } 343 344 func TestPermissionDenied(t *testing.T) { 345 if runtime.GOOS != "linux" { 346 t.Skip("Test relies on Unix /root permissions") 347 } 348 f := NewFixture(t) 349 f.UseRealFS() 350 351 f.File("Tiltfile", ` 352 print(os.path.exists('/root/x')) 353 `) 354 355 model, err := f.ExecFile("Tiltfile") 356 require.NoError(t, err) 357 assert.Equal(t, "False\n", f.PrintOutput()) 358 359 readState := io.MustState(model) 360 assert.Equal(t, []string{f.JoinPath("Tiltfile")}, readState.Paths) 361 } 362 363 func TestPathExistsDir(t *testing.T) { 364 if runtime.GOOS != "linux" { 365 t.Skip("Test relies on Unix /root permissions") 366 } 367 f := NewFixture(t) 368 f.UseRealFS() 369 370 f.File(f.JoinPath("subdir", "inner", "a.txt"), "hello") 371 f.File("Tiltfile", ` 372 print(os.path.exists('subdir')) 373 `) 374 375 model, err := f.ExecFile("Tiltfile") 376 require.NoError(t, err) 377 assert.Equal(t, "True\n", f.PrintOutput()) 378 379 // Verify that we're not watching the subdir recursively. 380 readState := io.MustState(model) 381 assert.Equal(t, []string{f.JoinPath("Tiltfile")}, readState.Paths) 382 } 383 384 func TestRealpath(t *testing.T) { 385 f := NewFixture(t) 386 387 f.File("Tiltfile", ` 388 print(os.path.realpath('.')) 389 `) 390 391 _, err := f.ExecFile("Tiltfile") 392 require.NoError(t, err) 393 assert.Equal(t, fmt.Sprintf("%s\n", f.Path()), f.PrintOutput()) 394 } 395 396 func TestRealpathSymlink(t *testing.T) { 397 if runtime.GOOS == "windows" { 398 t.Skip("no user-land symlink support on windows") 399 } 400 f := NewFixture(t) 401 f.UseRealFS() 402 403 f.File("foo/Tiltfile", ` 404 path = os.path.realpath('.') 405 `) 406 f.Symlink("foo", "bar") 407 f.File("Tiltfile", ` 408 load('./bar/Tiltfile', 'path') 409 print(path) 410 `) 411 412 _, err := f.ExecFile("Tiltfile") 413 require.NoError(t, err) 414 415 // on MacOS, /tmp is a symlink to /private/tmp. If we don't eval the expected path, 416 // we get an error because /tmp != /private/tmp 417 expected, err := filepath.EvalSymlinks(f.JoinPath("foo")) 418 require.NoError(t, err) 419 assert.Equal(t, fmt.Sprintf("%s\n", expected), f.PrintOutput()) 420 } 421 422 func TestName(t *testing.T) { 423 f := NewFixture(t) 424 f.File("Tiltfile", ` 425 print(os.name) 426 `) 427 428 _, err := f.ExecFile("Tiltfile") 429 require.NoError(t, err) 430 431 assert.Equal(t, fmt.Sprintf("%s\n", osName()), f.PrintOutput()) 432 } 433 434 func TestJoin(t *testing.T) { 435 f := NewFixture(t) 436 f.File("Tiltfile", ` 437 print(os.path.join("foo", "bar", "baz")) 438 `) 439 440 _, err := f.ExecFile("Tiltfile") 441 require.NoError(t, err) 442 443 assert.Equal(t, fmt.Sprintf("%s\n", filepath.Join("foo", "bar", "baz")), f.PrintOutput()) 444 } 445 446 func NewFixture(tb testing.TB) *starkit.Fixture { 447 return starkit.NewFixture(tb, NewPlugin(), io.NewPlugin()) 448 }