cmd/go: move part of gotoolchain_net to verylongtest

There is a case in gotoolchain_net that tries to download a real
GOTOOLCHAIN from the network. Move it to verylongtest so that it doesn't
affect the normal cmd/go test suite.

Also modify scripttest.RunTest to make files writable so that we can
clean up modcaches with readonly files.

For #80243

Change-Id: I3148fb07249358c7471dae7a7e1b97d76a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/796020
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Matloob <matloob@google.com>
Auto-Submit: Michael Matloob <matloob@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/src/cmd/go/internal/verylongtest/script_test.go b/src/cmd/go/internal/verylongtest/script_test.go
index baf8ebd..4b58ff1 100644
--- a/src/cmd/go/internal/verylongtest/script_test.go
+++ b/src/cmd/go/internal/verylongtest/script_test.go
@@ -8,7 +8,10 @@
 	"cmd/internal/script"
 	"cmd/internal/script/scripttest"
 	"internal/testenv"
+	"io/fs"
+	"os"
 	"os/exec"
+	"path/filepath"
 	"runtime"
 	"testing"
 )
@@ -22,6 +25,15 @@
 	testenv.SkipIfShortAndSlow(t)
 
 	engine, env := scripttest.NewEngine(t, nil)
+	modcache := filepath.Join(t.TempDir(), "modcache")
+	env = append(env, "GOMODCACHE="+modcache)
+	// Remove write only permissions on GOMODCACHE so we can clear its files.
+	t.Cleanup(func() {
+		filepath.WalkDir(modcache, func(path string, info fs.DirEntry, err error) error {
+			os.Chmod(path, 0777)
+			return nil
+		})
+	})
 	env = append(env, "GOROOT="+runtime.GOROOT())
 	engine.Conds["net"] = script.PrefixCondition("can connect to external network host <suffix>", hasNet)
 	engine.Conds["git"] = script.OnceCondition("the 'git' executable exists and provides the standard CLI", hasWorkingGit)
diff --git a/src/cmd/go/internal/verylongtest/testdata/script/gotoolchain_net.txt b/src/cmd/go/internal/verylongtest/testdata/script/gotoolchain_net.txt
new file mode 100644
index 0000000..44435af8
--- /dev/null
+++ b/src/cmd/go/internal/verylongtest/testdata/script/gotoolchain_net.txt
@@ -0,0 +1,26 @@
+# Test downloading a real GOTOOLCHAIN from the network.
+
+[short] skip
+[!net:golang.org] skip
+[!net:proxy.golang.org] skip
+[!net:sum.golang.org] skip
+[!GOOS:darwin] [!GOOS:windows] [!GOOS:linux] skip
+[!GOARCH:amd64] [!GOARCH:arm64] skip
+
+env GOPROXY=proxy.golang.org
+env GOSUMDB=sum.golang.org
+env GOTOOLCHAIN=go1.20.1
+
+	# Avoid resolving a "go1.20.1" from the user's real $PATH.
+	# That would not only cause the "downloading go1.20.1" message
+	# to be suppressed, but may spuriously fail:
+	# golang.org/dl/go1.20.1 expects to find its GOROOT in $HOME/sdk,
+	# but we set HOME=/no-home.
+env GOPATH=$WORK/go
+env HOME=/no-home
+env PATH=
+env path=
+
+go version
+stderr '^go: downloading go1.20.1 '
+stdout go1.20.1
diff --git a/src/cmd/go/testdata/script/gotoolchain_net.txt b/src/cmd/go/testdata/script/gotoolchain_net.txt
index 1d6473c..6edabcb 100644
--- a/src/cmd/go/testdata/script/gotoolchain_net.txt
+++ b/src/cmd/go/testdata/script/gotoolchain_net.txt
@@ -45,26 +45,3 @@
 stderr 'panic: use of network' # test catches network access
 env GOSUMDB=$oldsumdb
 
-# Test a real GOTOOLCHAIN
-[short] skip
-[!net:golang.org] skip
-[!net:sum.golang.org] skip
-[!GOOS:darwin] [!GOOS:windows] [!GOOS:linux] skip
-[!GOARCH:amd64] [!GOARCH:arm64] skip
-
-env GOPROXY=
-[go-builder] env GOSUMDB=
-[!go-builder] env GOSUMDB=sum.golang.org  # Set explicitly in case GOROOT/go.env is modified.
-env GOTOOLCHAIN=go1.20.1
-
-	# Avoid resolving a "go1.20.1" from the user's real $PATH.
-	# That would not only cause the "downloading go1.20.1" message
-	# to be suppressed, but may spuriously fail:
-	# golang.org/dl/go1.20.1 expects to find its GOROOT in $HOME/sdk,
-	# but the script environment sets HOME=/no-home.
-env PATH=
-env path=
-
-go version
-stderr '^go: downloading go1.20.1 '
-stdout go1.20.1
diff --git a/src/cmd/internal/script/scripttest/run.go b/src/cmd/internal/script/scripttest/run.go
index 76956a5..ecd91b8 100644
--- a/src/cmd/internal/script/scripttest/run.go
+++ b/src/cmd/internal/script/scripttest/run.go
@@ -12,6 +12,7 @@
 	"fmt"
 	"internal/testenv"
 	"internal/txtar"
+	"io/fs"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -254,6 +255,11 @@
 				t.Fatal(err)
 			}
 
+			// Call fixPermissions at the end of the test case in case
+			// it uses the go modcache, which writes read-only files.
+			// fixPermissions fixes up the permissions so a later removal can succeed.
+			defer fixPermissions(t, workdir)
+
 			// Unpack archive.
 			a, err := txtar.ParseFile(file)
 			if err != nil {
@@ -278,6 +284,21 @@
 	}
 }
 
+func fixPermissions(t *testing.T, dir string) {
+	t.Helper()
+
+	// module cache has 0444 directories;
+	// make them writable in order to remove content.
+	filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
+		// chmod not only directories, but also things that we couldn't even stat
+		// due to permission errors: they may also be unreadable directories.
+		if err != nil || info.IsDir() {
+			os.Chmod(path, 0777)
+		}
+		return nil
+	})
+}
+
 // InitScriptDirs sets up directories for executing a script test.
 //
 //   - WORK (env var) is set to the current working directory.