Skip to content

testing: robustify "relative" case in TestChdir against oldDir symlinks #75995

@glycerine

Description

@glycerine

Go version

go1.25.3 linux/amd64

Output of go env in your module/workspace:

On Linux (Ubuntu 24.04), go1.25.3/amd64

the TestChdir test in the standard library testing package:

when testing from a directory that contains a symlink in its current
path, the test may raise a false alarm.

$ pwd
/usr/local/dev-go/go/src/testing
$ ls -al /usr |grep local
lrwxrwxrwx   1 root root    21 Jun  3 22:03 local -> /mnt/oldrog/usr/local

This fixes it:

--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -299,7 +299,13 @@ func TestChdir(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }

        // The "relative" test case relies on tmp not being a symlink.
        tmp, err := filepath.EvalSymlinks(t.TempDir())
        if err != nil {
                t.Fatal(err)
        }

-       rel, err := filepath.Rel(oldDir, tmp)
+       // The "relative" test case also relies on oldDir not containing symlinks.
+       oldDirNoSymLinks, err := filepath.EvalSymlinks(oldDir)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       rel, err := filepath.Rel(oldDirNoSymLinks, tmp)
        if err != nil {
                // If GOROOT is on C: volume and tmp is on the D: volume, there
  

Explanation: without the fix,

os.Getwd() returns '/usr/local/dev-go/go/src/testing' for oldDir.

however after resolving the symlinks in oldDir,
we obtain

oldDirNoSymLinks = '/mnt/oldrog/usr/local/dev-go/go/src/testing'

which means rel will have two more moves up on a fixed run.

rel='../../../../../../../../tmp/TestChdir2328321063/001'

With fix:

--- PASS: TestChdir (0.00s)
    --- PASS: TestChdir/absolute (0.00s)
    --- PASS: TestChdir/relative (0.00s)
    --- PASS: TestChdir/current_(absolute) (0.00s)
    --- PASS: TestChdir/current_(relative)_with_extra_os.Chdir (0.00s)

because:

filepath.Rel(oldDirNoSymLinks ='/mnt/oldrog/usr/local/dev-go/go/src/testing', tmp='/tmp/TestChdir1105991385/001') -> '../../../../../../../../tmp/TestChdir1105991385/001'

but without the fix, it fails, because it needs an additional '../..'
to get to the filesystem root.

=== RUN   TestChdir/relative
tc.name = 'relative'
tmp0 = '/tmp/TestChdir66365355/001' // raw output of t.TempDir()

 tmp = '/tmp/TestChdir66365355/001' // after tmp, err := filepath.EvalSymlinks(tmp0)

calling t.Chdir(tc.dir = '../../../../../../tmp/TestChdir66365355/001';  
 dir = '../../../../../../tmp/TestChdir66365355/001'
 vs cwd = '/usr/local/dev-go/go/src/testing'

--- FAIL: TestChdir (0.00s)
    --- PASS: TestChdir/absolute (0.00s)
    --- FAIL: TestChdir/relative (0.00s)
panic: chdir ../../../../../../tmp/TestChdir66365355/001: no such file or directory [recovered, repanicked]

goroutine 1661 [running]:
testing.tRunner.func1.2({0x608880, 0xc0006840f0})
        /usr/local/dev-go/go/src/testing/testing.go:1877 +0x237
testing.tRunner.func1()
        /usr/local/dev-go/go/src/testing/testing.go:1880 +0x35b
panic({0x608880?, 0xc0006840f0?})
        /mnt/oldrog/usr/local/dev-go/go/src/runtime/panic.go:783 +0x132
testing.(*common).Chdir(0xc000c83500, {0xc00032e090, 0x2b})
        /usr/local/dev-go/go/src/testing/testing.go:1463 +0x2c5
testing.(*T).Chdir(0x6987b0?, {0xc00032e090?, 0x64a437?})
        /usr/local/dev-go/go/src/testing/testing.go:1767 +0x45
testing_test.TestChdir.func1(0xc000c83500)
        /usr/local/dev-go/go/src/testing/testing_test.go:352 +0x32f
testing.tRunner(0xc000c83500, 0xc000196150)
        /usr/local/dev-go/go/src/testing/testing.go:1939 +0xea
created by testing.(*T).Run in goroutine 1687
        /usr/local/dev-go/go/src/testing/testing.go:2002 +0x465

~~~

What did you do?

see above

What did you see happen?

see above

What did you expect to see?

see above

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions