Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 632162c

Browse files
committedMar 8, 2019
misc/android: enable many more tests on GOOS=android
Android tests are built on the host and run on the device. To do that, the exec wrapper copies the test binary and testdata to the device. To enable many more tests, make the copied environment more like the host: - Copy all of pkg from GOROOT, not just the android pkg directory. - Copy any parent testdata directories as well as the package's own. - Copy *.go files from the package directory. This enables misc/cgo/stdio and misc/cgo/life tests that were invisible before so disable them explicitly. - Always copy the GOROOT, even for tests outside GOROOT. This is expensive but only done once per make.bash. - Build the go tool for the device and put it in PATH. Set GOCACHE to a writable directory and disable cgo. While here, use a single directory for all the exec wrapper files and delete that once per make.bash as well. In total, this CL enables many tests in the subrepos that would need skips without it, in particular the x/tools tests. Fixes #11452 Updates #23824 Updates #11811 Change-Id: I2e50d8b57db9bc4637f25272a5360c8b2cf4e627 Reviewed-on: https://go-review.googlesource.com/c/go/+/165797 Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent d3dd258 commit 632162c

File tree

3 files changed

+80
-33
lines changed

3 files changed

+80
-33
lines changed
 

‎misc/android/go_android_exec.go

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ func run(args ...string) string {
5151
}
5252

5353
const (
54-
deviceGoroot = "/data/local/tmp/goroot"
55-
deviceGopath = "/data/local/tmp/gopath"
54+
deviceRoot = "/data/local/tmp/go_exec_android"
55+
deviceGoroot = deviceRoot + "/goroot"
5656
)
5757

5858
func main() {
@@ -77,35 +77,44 @@ func main() {
7777
// wait for sys.boot_completed.
7878
run("wait-for-device", "exec-out", "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;")
7979

80+
// Done once per make.bash.
81+
adbCopyGoroot()
82+
8083
// Prepare a temporary directory that will be cleaned up at the end.
81-
deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d",
82-
filepath.Base(os.Args[1]), os.Getpid())
83-
run("exec-out", "mkdir", "-p", deviceGotmp)
84+
// Binary names can conflict.
85+
// E.g. template.test from the {html,text}/template packages.
86+
binName := filepath.Base(os.Args[1])
87+
deviceGotmp := fmt.Sprintf(deviceRoot+"/%s-%d", binName, os.Getpid())
88+
deviceGopath := deviceGotmp + "/gopath"
89+
defer run("exec-out", "rm", "-rf", deviceGotmp) // Clean up.
8490

8591
// Determine the package by examining the current working
8692
// directory, which will look something like
8793
// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
8894
// We extract everything after the $GOROOT or $GOPATH to run on the
8995
// same relative directory on the target device.
9096
subdir, inGoRoot := subdir()
91-
deviceCwd := filepath.Join(deviceGoroot, subdir)
92-
if !inGoRoot {
93-
deviceCwd = filepath.Join(deviceGopath, subdir)
97+
deviceCwd := filepath.Join(deviceGopath, subdir)
98+
if inGoRoot {
99+
deviceCwd = filepath.Join(deviceGoroot, subdir)
94100
} else {
95-
adbSyncGoroot()
101+
run("exec-out", "mkdir", "-p", deviceCwd)
102+
adbCopyTestdata(deviceCwd, subdir)
103+
104+
// Copy .go files from the package.
105+
goFiles, err := filepath.Glob("*.go")
106+
if err != nil {
107+
log.Fatal(err)
108+
}
109+
if len(goFiles) > 0 {
110+
args := append(append([]string{"push"}, goFiles...), deviceCwd)
111+
run(args...)
112+
}
96113
}
97-
run("exec-out", "mkdir", "-p", deviceCwd)
98114

99-
// Binary names can conflict.
100-
// E.g. template.test from the {html,text}/template packages.
101-
binName := fmt.Sprintf("%s-%d", filepath.Base(os.Args[1]), os.Getpid())
102115
deviceBin := fmt.Sprintf("%s/%s", deviceGotmp, binName)
103116
run("push", os.Args[1], deviceBin)
104117

105-
if _, err := os.Stat("testdata"); err == nil {
106-
run("push", "--sync", "testdata", deviceCwd)
107-
}
108-
109118
// Forward SIGQUIT from the go command to show backtraces from
110119
// the binary instead of from this wrapper.
111120
quit := make(chan os.Signal, 1)
@@ -125,15 +134,16 @@ func main() {
125134
cmd := `export TMPDIR="` + deviceGotmp + `"` +
126135
`; export GOROOT="` + deviceGoroot + `"` +
127136
`; export GOPATH="` + deviceGopath + `"` +
137+
`; export CGO_ENABLED=0` +
138+
`; export GOCACHE="` + deviceRoot + `/gocache"` +
139+
`; export PATH=$PATH:"` + deviceGoroot + `/bin"` +
128140
`; cd "` + deviceCwd + `"` +
129141
"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
130142
"; echo -n " + exitstr + "$?"
131143
output := run("exec-out", cmd)
132144
signal.Reset(syscall.SIGQUIT)
133145
close(quit)
134146

135-
run("exec-out", "rm", "-rf", deviceGotmp) // Clean up.
136-
137147
exitIdx := strings.LastIndex(output, exitstr)
138148
if exitIdx == -1 {
139149
log.Fatalf("no exit code: %q", output)
@@ -186,17 +196,42 @@ func subdir() (pkgpath string, underGoRoot bool) {
186196
return "", false
187197
}
188198

189-
// adbSyncGoroot ensures that files necessary for testing the Go standard
190-
// packages are present on the attached device.
191-
func adbSyncGoroot() {
199+
// adbCopyTestdata copies testdata directories from subdir to deviceCwd
200+
// on the device.
201+
// It is common for tests to reach out into testdata from parent
202+
// packages, so copy testdata directories all the way up to the root
203+
// of subdir.
204+
func adbCopyTestdata(deviceCwd, subdir string) {
205+
dir := ""
206+
for {
207+
testdata := filepath.Join(dir, "testdata")
208+
if _, err := os.Stat(testdata); err == nil {
209+
devicePath := filepath.Join(deviceCwd, dir)
210+
run("exec-out", "mkdir", "-p", devicePath)
211+
run("push", testdata, devicePath)
212+
}
213+
if subdir == "." {
214+
break
215+
}
216+
subdir = filepath.Dir(subdir)
217+
dir = filepath.Join(dir, "..")
218+
}
219+
}
220+
221+
// adbCopyGoroot clears deviceRoot for previous versions of GOROOT, GOPATH
222+
// and temporary data. Then, it copies relevant parts of GOROOT to the device,
223+
// including the go tool built for android.
224+
// A lock file ensures this only happens once, even with concurrent exec
225+
// wrappers.
226+
func adbCopyGoroot() {
192227
// Also known by cmd/dist. The bootstrap command deletes the file.
193228
statPath := filepath.Join(os.TempDir(), "go_android_exec-adb-sync-status")
194229
stat, err := os.OpenFile(statPath, os.O_CREATE|os.O_RDWR, 0666)
195230
if err != nil {
196231
log.Fatal(err)
197232
}
198233
defer stat.Close()
199-
// Serialize check and syncing.
234+
// Serialize check and copying.
200235
if err := syscall.Flock(int(stat.Fd()), syscall.LOCK_EX); err != nil {
201236
log.Fatal(err)
202237
}
@@ -207,23 +242,29 @@ func adbSyncGoroot() {
207242
if string(s) == "done" {
208243
return
209244
}
210-
devRoot := "/data/local/tmp/goroot"
211-
run("exec-out", "rm", "-rf", devRoot)
212-
run("exec-out", "mkdir", "-p", devRoot+"/pkg")
245+
// Delete GOROOT, GOPATH and any leftover test data.
246+
run("exec-out", "rm", "-rf", deviceRoot)
247+
deviceBin := filepath.Join(deviceGoroot, "bin")
248+
run("exec-out", "mkdir", "-p", deviceBin)
213249
goroot := runtime.GOROOT()
250+
// Build go for android.
214251
goCmd := filepath.Join(goroot, "bin", "go")
215-
runtimea, err := exec.Command(goCmd, "list", "-f", "{{.Target}}", "runtime").Output()
252+
tmpGo, err := ioutil.TempFile("", "go_android_exec-cmd-go-*")
216253
if err != nil {
217254
log.Fatal(err)
218255
}
219-
pkgdir := filepath.Dir(string(runtimea))
220-
if pkgdir == "" {
221-
log.Fatal("could not find android pkg dir")
256+
tmpGo.Close()
257+
defer os.Remove(tmpGo.Name())
258+
259+
if out, err := exec.Command(goCmd, "build", "-o", tmpGo.Name(), "cmd/go").CombinedOutput(); err != nil {
260+
log.Fatalf("failed to build go tool for device: %s\n%v", out, err)
222261
}
223-
for _, dir := range []string{"src", "test", "lib"} {
224-
run("push", filepath.Join(goroot, dir), filepath.Join(devRoot))
262+
deviceGo := filepath.Join(deviceBin, "go")
263+
run("push", tmpGo.Name(), deviceGo)
264+
for _, dir := range []string{"pkg", "src", "test", "lib", "api"} {
265+
run("push", filepath.Join(goroot, dir), filepath.Join(deviceGoroot))
225266
}
226-
run("push", filepath.Join(pkgdir), filepath.Join(devRoot, "pkg/"))
267+
227268
if _, err := stat.Write([]byte("done")); err != nil {
228269
log.Fatal(err)
229270
}

‎misc/cgo/life/life_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ func testMain(m *testing.M) int {
4646
}
4747

4848
func TestTestRun(t *testing.T) {
49+
if os.Getenv("GOOS") == "android" {
50+
t.Skip("the go tool runs with CGO_ENABLED=0 on the android device")
51+
}
4952
out, err := exec.Command("go", "env", "GOROOT").Output()
5053
if err != nil {
5154
t.Fatal(err)

‎misc/cgo/stdio/stdio_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ func testMain(m *testing.M) int {
4646
}
4747

4848
func TestTestRun(t *testing.T) {
49+
if os.Getenv("GOOS") == "android" {
50+
t.Skip("subpackage stdio is not available on android")
51+
}
4952
out, err := exec.Command("go", "env", "GOROOT").Output()
5053
if err != nil {
5154
t.Fatal(err)

0 commit comments

Comments
 (0)
Please sign in to comment.