You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

326 lines
8.5 KiB

  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/key.pem",
  218. "ssl/test/runner/rsa_1024_cert.pem",
  219. "ssl/test/runner/rsa_1024_key.pem",
  220. "ssl/test/runner/rsa_chain_cert.pem",
  221. "ssl/test/runner/rsa_chain_key.pem",
  222. "util/all_tests.json",
  223. )
  224. fmt.Printf("Building runner...\n")
  225. if err := goTool("test", "-c", "-o", filepath.Join(tmpDir, "ssl/test/runner/runner"), "./ssl/test/runner/"); err != nil {
  226. fmt.Printf("Error building runner: %s\n", err)
  227. os.Exit(1)
  228. }
  229. }
  230. fmt.Printf("Copying test binaries...\n")
  231. for _, binary := range binaries {
  232. if err := copyFile(filepath.Join(tmpDir, "build", binary), filepath.Join(*buildDir, binary)); err != nil {
  233. fmt.Printf("Failed to copy %s: %s\n", binary, err)
  234. os.Exit(1)
  235. }
  236. }
  237. fmt.Printf("Copying data files...\n")
  238. for _, file := range files {
  239. if err := copyFile(filepath.Join(tmpDir, file), file); err != nil {
  240. fmt.Printf("Failed to copy %s: %s\n", file, err)
  241. os.Exit(1)
  242. }
  243. }
  244. fmt.Printf("Uploading files...\n")
  245. if err := adb("push", "-p", tmpDir, "/data/local/tmp/boringssl-tmp"); err != nil {
  246. fmt.Printf("Failed to push runner: %s\n", err)
  247. os.Exit(1)
  248. }
  249. var unitTestExit int
  250. if enableUnitTests() {
  251. fmt.Printf("Running unit tests...\n")
  252. unitTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs))
  253. if err != nil {
  254. fmt.Printf("Failed to run unit tests: %s\n", err)
  255. os.Exit(1)
  256. }
  257. }
  258. var sslTestExit int
  259. if enableSSLTests() {
  260. fmt.Printf("Running SSL tests...\n")
  261. sslTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs))
  262. if err != nil {
  263. fmt.Printf("Failed to run SSL tests: %s\n", err)
  264. os.Exit(1)
  265. }
  266. }
  267. if *jsonOutput != "" {
  268. if err := adb("pull", "-p", "/data/local/tmp/boringssl-tmp/results.json", *jsonOutput); err != nil {
  269. fmt.Printf("Failed to extract results.json: %s\n", err)
  270. os.Exit(1)
  271. }
  272. }
  273. if unitTestExit != 0 {
  274. os.Exit(unitTestExit)
  275. }
  276. if sslTestExit != 0 {
  277. os.Exit(sslTestExit)
  278. }
  279. }