run_android_tests.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright (c) 2016, Google Inc.
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. package main
  15. import (
  16. "bytes"
  17. "encoding/json"
  18. "flag"
  19. "fmt"
  20. "io"
  21. "io/ioutil"
  22. "os"
  23. "os/exec"
  24. "path/filepath"
  25. "strconv"
  26. "strings"
  27. )
  28. var (
  29. buildDir = flag.String("build-dir", "build", "Specifies the build directory to push.")
  30. adbPath = flag.String("adb", "adb", "Specifies the adb binary to use. Defaults to looking in PATH.")
  31. device = flag.String("device", "", "Specifies the device or emulator. See adb's -s argument.")
  32. aarch64 = flag.Bool("aarch64", false, "Build the test runners for aarch64 instead of arm.")
  33. arm = flag.Int("arm", 7, "Which arm revision to build for.")
  34. suite = flag.String("suite", "all", "Specifies the test suites to run (all, unit, or ssl).")
  35. allTestsArgs = flag.String("all-tests-args", "", "Specifies space-separated arguments to pass to all_tests.go")
  36. runnerArgs = flag.String("runner-args", "", "Specifies space-separated arguments to pass to ssl/test/runner")
  37. jsonOutput = flag.String("json-output", "", "The file to output JSON results to.")
  38. )
  39. func enableUnitTests() bool {
  40. return *suite == "all" || *suite == "unit"
  41. }
  42. func enableSSLTests() bool {
  43. return *suite == "all" || *suite == "ssl"
  44. }
  45. func adb(args ...string) error {
  46. if len(*device) > 0 {
  47. args = append([]string{"-s", *device}, args...)
  48. }
  49. cmd := exec.Command(*adbPath, args...)
  50. cmd.Stdout = os.Stdout
  51. cmd.Stderr = os.Stderr
  52. return cmd.Run()
  53. }
  54. func adbShell(shellCmd string) (int, error) {
  55. var args []string
  56. if len(*device) > 0 {
  57. args = append([]string{"-s", *device}, args...)
  58. }
  59. args = append(args, "shell")
  60. const delimiter = "___EXIT_CODE___"
  61. // Older versions of adb and Android do not preserve the exit
  62. // code, so work around this.
  63. // https://code.google.com/p/android/issues/detail?id=3254
  64. shellCmd += "; echo " + delimiter + " $?"
  65. args = append(args, shellCmd)
  66. cmd := exec.Command(*adbPath, args...)
  67. stdout, err := cmd.StdoutPipe()
  68. if err != nil {
  69. return 0, err
  70. }
  71. cmd.Stderr = os.Stderr
  72. if err := cmd.Start(); err != nil {
  73. return 0, err
  74. }
  75. var stdoutBytes bytes.Buffer
  76. for {
  77. var buf [1024]byte
  78. n, err := stdout.Read(buf[:])
  79. stdoutBytes.Write(buf[:n])
  80. os.Stdout.Write(buf[:n])
  81. if err != nil {
  82. break
  83. }
  84. }
  85. if err := cmd.Wait(); err != nil {
  86. return 0, err
  87. }
  88. stdoutStr := stdoutBytes.String()
  89. idx := strings.LastIndex(stdoutStr, delimiter)
  90. if idx < 0 {
  91. return 0, fmt.Errorf("Could not find delimiter in output.")
  92. }
  93. return strconv.Atoi(strings.TrimSpace(stdoutStr[idx+len(delimiter):]))
  94. }
  95. func goTool(args ...string) error {
  96. cmd := exec.Command("go", args...)
  97. cmd.Stdout = os.Stdout
  98. cmd.Stderr = os.Stderr
  99. cmd.Env = os.Environ()
  100. if *aarch64 {
  101. cmd.Env = append(cmd.Env, "GOARCH=arm64")
  102. } else {
  103. cmd.Env = append(cmd.Env, "GOARCH=arm")
  104. cmd.Env = append(cmd.Env, fmt.Sprintf("GOARM=%d", *arm))
  105. }
  106. return cmd.Run()
  107. }
  108. // setWorkingDirectory walks up directories as needed until the current working
  109. // directory is the top of a BoringSSL checkout.
  110. func setWorkingDirectory() {
  111. for i := 0; i < 64; i++ {
  112. if _, err := os.Stat("BUILDING.md"); err == nil {
  113. return
  114. }
  115. os.Chdir("..")
  116. }
  117. panic("Couldn't find BUILDING.md in a parent directory!")
  118. }
  119. type test []string
  120. func parseTestConfig(filename string) ([]test, error) {
  121. in, err := os.Open(filename)
  122. if err != nil {
  123. return nil, err
  124. }
  125. defer in.Close()
  126. decoder := json.NewDecoder(in)
  127. var result []test
  128. if err := decoder.Decode(&result); err != nil {
  129. return nil, err
  130. }
  131. return result, nil
  132. }
  133. func copyFile(dst, src string) error {
  134. srcFile, err := os.Open(src)
  135. if err != nil {
  136. return err
  137. }
  138. defer srcFile.Close()
  139. srcInfo, err := srcFile.Stat()
  140. if err != nil {
  141. return err
  142. }
  143. dir := filepath.Dir(dst)
  144. if err := os.MkdirAll(dir, 0777); err != nil {
  145. return err
  146. }
  147. dstFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, srcInfo.Mode())
  148. if err != nil {
  149. return err
  150. }
  151. defer dstFile.Close()
  152. _, err = io.Copy(dstFile, srcFile)
  153. return err
  154. }
  155. func main() {
  156. flag.Parse()
  157. if *suite == "all" && *jsonOutput != "" {
  158. fmt.Printf("To use -json-output flag, select only one test suite with -suite.\n")
  159. os.Exit(1)
  160. }
  161. setWorkingDirectory()
  162. // Clear the target directory.
  163. if err := adb("shell", "rm -Rf /data/local/tmp/boringssl-tmp"); err != nil {
  164. fmt.Printf("Failed to clear target directory: %s\n", err)
  165. os.Exit(1)
  166. }
  167. // Stage everything in a temporary directory.
  168. tmpDir, err := ioutil.TempDir("", "boringssl-android")
  169. if err != nil {
  170. fmt.Printf("Error making temporary directory: %s\n", err)
  171. os.Exit(1)
  172. }
  173. defer os.RemoveAll(tmpDir)
  174. var binaries, files []string
  175. if enableUnitTests() {
  176. files = append(files,
  177. "util/all_tests.json",
  178. "BUILDING.md",
  179. )
  180. tests, err := parseTestConfig("util/all_tests.json")
  181. if err != nil {
  182. fmt.Printf("Failed to parse input: %s\n", err)
  183. os.Exit(1)
  184. }
  185. seenBinary := make(map[string]struct{})
  186. for _, test := range tests {
  187. if _, ok := seenBinary[test[0]]; !ok {
  188. binaries = append(binaries, test[0])
  189. seenBinary[test[0]] = struct{}{}
  190. }
  191. for _, arg := range test[1:] {
  192. if strings.Contains(arg, "/") {
  193. files = append(files, arg)
  194. }
  195. }
  196. }
  197. fmt.Printf("Building all_tests...\n")
  198. if err := goTool("build", "-o", filepath.Join(tmpDir, "util/all_tests"), "util/all_tests.go"); err != nil {
  199. fmt.Printf("Error building all_tests.go: %s\n", err)
  200. os.Exit(1)
  201. }
  202. }
  203. if enableSSLTests() {
  204. binaries = append(binaries, "ssl/test/bssl_shim")
  205. files = append(files,
  206. "BUILDING.md",
  207. "ssl/test/runner/cert.pem",
  208. "ssl/test/runner/channel_id_key.pem",
  209. "ssl/test/runner/ecdsa_p224_cert.pem",
  210. "ssl/test/runner/ecdsa_p224_key.pem",
  211. "ssl/test/runner/ecdsa_p256_cert.pem",
  212. "ssl/test/runner/ecdsa_p256_key.pem",
  213. "ssl/test/runner/ecdsa_p384_cert.pem",
  214. "ssl/test/runner/ecdsa_p384_key.pem",
  215. "ssl/test/runner/ecdsa_p521_cert.pem",
  216. "ssl/test/runner/ecdsa_p521_key.pem",
  217. "ssl/test/runner/ed25519_cert.pem",
  218. "ssl/test/runner/ed25519_key.pem",
  219. "ssl/test/runner/key.pem",
  220. "ssl/test/runner/rsa_1024_cert.pem",
  221. "ssl/test/runner/rsa_1024_key.pem",
  222. "ssl/test/runner/rsa_chain_cert.pem",
  223. "ssl/test/runner/rsa_chain_key.pem",
  224. "util/all_tests.json",
  225. )
  226. fmt.Printf("Building runner...\n")
  227. if err := goTool("test", "-c", "-o", filepath.Join(tmpDir, "ssl/test/runner/runner"), "./ssl/test/runner/"); err != nil {
  228. fmt.Printf("Error building runner: %s\n", err)
  229. os.Exit(1)
  230. }
  231. }
  232. fmt.Printf("Copying test binaries...\n")
  233. for _, binary := range binaries {
  234. if err := copyFile(filepath.Join(tmpDir, "build", binary), filepath.Join(*buildDir, binary)); err != nil {
  235. fmt.Printf("Failed to copy %s: %s\n", binary, err)
  236. os.Exit(1)
  237. }
  238. }
  239. fmt.Printf("Copying data files...\n")
  240. for _, file := range files {
  241. if err := copyFile(filepath.Join(tmpDir, file), file); err != nil {
  242. fmt.Printf("Failed to copy %s: %s\n", file, err)
  243. os.Exit(1)
  244. }
  245. }
  246. fmt.Printf("Uploading files...\n")
  247. if err := adb("push", "-p", tmpDir, "/data/local/tmp/boringssl-tmp"); err != nil {
  248. fmt.Printf("Failed to push runner: %s\n", err)
  249. os.Exit(1)
  250. }
  251. var unitTestExit int
  252. if enableUnitTests() {
  253. fmt.Printf("Running unit tests...\n")
  254. unitTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs))
  255. if err != nil {
  256. fmt.Printf("Failed to run unit tests: %s\n", err)
  257. os.Exit(1)
  258. }
  259. }
  260. var sslTestExit int
  261. if enableSSLTests() {
  262. fmt.Printf("Running SSL tests...\n")
  263. sslTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs))
  264. if err != nil {
  265. fmt.Printf("Failed to run SSL tests: %s\n", err)
  266. os.Exit(1)
  267. }
  268. }
  269. if *jsonOutput != "" {
  270. if err := adb("pull", "-p", "/data/local/tmp/boringssl-tmp/results.json", *jsonOutput); err != nil {
  271. fmt.Printf("Failed to extract results.json: %s\n", err)
  272. os.Exit(1)
  273. }
  274. }
  275. if unitTestExit != 0 {
  276. os.Exit(unitTestExit)
  277. }
  278. if sslTestExit != 0 {
  279. os.Exit(sslTestExit)
  280. }
  281. }