docker_cli_build_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "testing"
  9. )
  10. func TestBuildCacheADD(t *testing.T) {
  11. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildCacheADD", "1")
  12. buildCmd := exec.Command(dockerBinary, "build", "-t", "testcacheadd1", ".")
  13. buildCmd.Dir = buildDirectory
  14. exitCode, err := runCommand(buildCmd)
  15. errorOut(err, t, fmt.Sprintf("build failed to complete: %v", err))
  16. if err != nil || exitCode != 0 {
  17. t.Fatal("failed to build the image")
  18. }
  19. buildDirectory = filepath.Join(workingDirectory, "build_tests", "TestBuildCacheADD", "2")
  20. buildCmd = exec.Command(dockerBinary, "build", "-t", "testcacheadd2", ".")
  21. buildCmd.Dir = buildDirectory
  22. out, exitCode, err := runCommandWithOutput(buildCmd)
  23. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  24. if err != nil || exitCode != 0 {
  25. t.Fatal("failed to build the image")
  26. }
  27. if strings.Contains(out, "Using cache") {
  28. t.Fatal("2nd build used cache on ADD, it shouldn't")
  29. }
  30. deleteImages("testcacheadd1")
  31. deleteImages("testcacheadd2")
  32. logDone("build - build two images with ADD")
  33. }
  34. func TestBuildSixtySteps(t *testing.T) {
  35. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildSixtySteps")
  36. buildCmd := exec.Command(dockerBinary, "build", "-t", "foobuildsixtysteps", ".")
  37. buildCmd.Dir = buildDirectory
  38. out, exitCode, err := runCommandWithOutput(buildCmd)
  39. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  40. if err != nil || exitCode != 0 {
  41. t.Fatal("failed to build the image")
  42. }
  43. deleteImages("foobuildsixtysteps")
  44. logDone("build - build an image with sixty build steps")
  45. }
  46. func TestAddSingleFileToRoot(t *testing.T) {
  47. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd", "SingleFileToRoot")
  48. f, err := os.OpenFile(filepath.Join(buildDirectory, "test_file"), os.O_CREATE, 0644)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. f.Close()
  53. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", ".")
  54. buildCmd.Dir = buildDirectory
  55. out, exitCode, err := runCommandWithOutput(buildCmd)
  56. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  57. if err != nil || exitCode != 0 {
  58. t.Fatal("failed to build the image")
  59. }
  60. deleteImages("testaddimg")
  61. logDone("build - add single file to root")
  62. }
  63. func TestAddSingleFileToExistDir(t *testing.T) {
  64. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
  65. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "SingleFileToExistDir")
  66. buildCmd.Dir = buildDirectory
  67. out, exitCode, err := runCommandWithOutput(buildCmd)
  68. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  69. if err != nil || exitCode != 0 {
  70. t.Fatal("failed to build the image")
  71. }
  72. deleteImages("testaddimg")
  73. logDone("build - add single file to existing dir")
  74. }
  75. func TestAddSingleFileToNonExistDir(t *testing.T) {
  76. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
  77. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "SingleFileToNonExistDir")
  78. buildCmd.Dir = buildDirectory
  79. out, exitCode, err := runCommandWithOutput(buildCmd)
  80. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  81. if err != nil || exitCode != 0 {
  82. t.Fatal("failed to build the image")
  83. }
  84. deleteImages("testaddimg")
  85. logDone("build - add single file to non-existing dir")
  86. }
  87. func TestAddDirContentToRoot(t *testing.T) {
  88. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
  89. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "DirContentToRoot")
  90. buildCmd.Dir = buildDirectory
  91. out, exitCode, err := runCommandWithOutput(buildCmd)
  92. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  93. if err != nil || exitCode != 0 {
  94. t.Fatal("failed to build the image")
  95. }
  96. deleteImages("testaddimg")
  97. logDone("build - add directory contents to root")
  98. }
  99. func TestAddDirContentToExistDir(t *testing.T) {
  100. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
  101. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "DirContentToExistDir")
  102. buildCmd.Dir = buildDirectory
  103. out, exitCode, err := runCommandWithOutput(buildCmd)
  104. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  105. if err != nil || exitCode != 0 {
  106. t.Fatal("failed to build the image")
  107. }
  108. deleteImages("testaddimg")
  109. logDone("build - add directory contents to existing dir")
  110. }
  111. func TestAddWholeDirToRoot(t *testing.T) {
  112. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd", "WholeDirToRoot")
  113. test_dir := filepath.Join(buildDirectory, "test_dir")
  114. if err := os.MkdirAll(test_dir, 0755); err != nil {
  115. t.Fatal(err)
  116. }
  117. f, err := os.OpenFile(filepath.Join(test_dir, "test_file"), os.O_CREATE, 0644)
  118. if err != nil {
  119. t.Fatal(err)
  120. }
  121. f.Close()
  122. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", ".")
  123. buildCmd.Dir = buildDirectory
  124. out, exitCode, err := runCommandWithOutput(buildCmd)
  125. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  126. if err != nil || exitCode != 0 {
  127. t.Fatal("failed to build the image")
  128. }
  129. deleteImages("testaddimg")
  130. logDone("build - add whole directory to root")
  131. }
  132. func TestAddEtcToRoot(t *testing.T) {
  133. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestAdd")
  134. buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", "EtcToRoot")
  135. buildCmd.Dir = buildDirectory
  136. out, exitCode, err := runCommandWithOutput(buildCmd)
  137. errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
  138. if err != nil || exitCode != 0 {
  139. t.Fatal("failed to build the image")
  140. }
  141. deleteImages("testaddimg")
  142. logDone("build - add etc directory to root")
  143. }
  144. // Issue #5270 - ensure we throw a better error than "unexpected EOF"
  145. // when we can't access files in the context.
  146. func TestBuildWithInaccessibleFilesInContext(t *testing.T) {
  147. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildWithInaccessibleFilesInContext")
  148. {
  149. // This is used to ensure we detect inaccessible files early during build in the cli client
  150. pathToInaccessibleFileBuildDirectory := filepath.Join(buildDirectory, "inaccessiblefile")
  151. pathToFileWithoutReadAccess := filepath.Join(pathToInaccessibleFileBuildDirectory, "fileWithoutReadAccess")
  152. err := os.Chown(pathToFileWithoutReadAccess, 0, 0)
  153. errorOut(err, t, fmt.Sprintf("failed to chown file to root: %s", err))
  154. err = os.Chmod(pathToFileWithoutReadAccess, 0700)
  155. errorOut(err, t, fmt.Sprintf("failed to chmod file to 700: %s", err))
  156. buildCommandStatement := fmt.Sprintf("%s build -t inaccessiblefiles .", dockerBinary)
  157. buildCmd := exec.Command("su", "unprivilegeduser", "-c", buildCommandStatement)
  158. buildCmd.Dir = pathToInaccessibleFileBuildDirectory
  159. out, exitCode, err := runCommandWithOutput(buildCmd)
  160. if err == nil || exitCode == 0 {
  161. t.Fatalf("build should have failed: %s %s", err, out)
  162. }
  163. // check if we've detected the failure before we started building
  164. if !strings.Contains(out, "no permission to read from ") {
  165. t.Fatalf("output should've contained the string: no permission to read from but contained: %s", out)
  166. }
  167. if !strings.Contains(out, "Error checking context is accessible") {
  168. t.Fatalf("output should've contained the string: Error checking context is accessible")
  169. }
  170. }
  171. {
  172. // This is used to ensure we detect inaccessible directories early during build in the cli client
  173. pathToInaccessibleDirectoryBuildDirectory := filepath.Join(buildDirectory, "inaccessibledirectory")
  174. pathToDirectoryWithoutReadAccess := filepath.Join(pathToInaccessibleDirectoryBuildDirectory, "directoryWeCantStat")
  175. pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
  176. err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0)
  177. errorOut(err, t, fmt.Sprintf("failed to chown directory to root: %s", err))
  178. err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444)
  179. errorOut(err, t, fmt.Sprintf("failed to chmod directory to 755: %s", err))
  180. err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700)
  181. errorOut(err, t, fmt.Sprintf("failed to chmod file to 444: %s", err))
  182. buildCommandStatement := fmt.Sprintf("%s build -t inaccessiblefiles .", dockerBinary)
  183. buildCmd := exec.Command("su", "unprivilegeduser", "-c", buildCommandStatement)
  184. buildCmd.Dir = pathToInaccessibleDirectoryBuildDirectory
  185. out, exitCode, err := runCommandWithOutput(buildCmd)
  186. if err == nil || exitCode == 0 {
  187. t.Fatalf("build should have failed: %s %s", err, out)
  188. }
  189. // check if we've detected the failure before we started building
  190. if !strings.Contains(out, "can't stat") {
  191. t.Fatalf("output should've contained the string: can't access %s", out)
  192. }
  193. if !strings.Contains(out, "Error checking context is accessible") {
  194. t.Fatalf("output should've contained the string: Error checking context is accessible")
  195. }
  196. }
  197. {
  198. // This is used to ensure we don't follow links when checking if everything in the context is accessible
  199. // This test doesn't require that we run commands as an unprivileged user
  200. pathToDirectoryWhichContainsLinks := filepath.Join(buildDirectory, "linksdirectory")
  201. buildCmd := exec.Command(dockerBinary, "build", "-t", "testlinksok", ".")
  202. buildCmd.Dir = pathToDirectoryWhichContainsLinks
  203. out, exitCode, err := runCommandWithOutput(buildCmd)
  204. if err != nil || exitCode != 0 {
  205. t.Fatalf("build should have worked: %s %s", err, out)
  206. }
  207. deleteImages("testlinksok")
  208. }
  209. deleteImages("inaccessiblefiles")
  210. logDone("build - ADD from context with inaccessible files must fail")
  211. logDone("build - ADD from context with accessible links must work")
  212. }
  213. func TestBuildForceRm(t *testing.T) {
  214. containerCountBefore, err := getContainerCount()
  215. if err != nil {
  216. t.Fatalf("failed to get the container count: %s", err)
  217. }
  218. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildForceRm")
  219. buildCmd := exec.Command(dockerBinary, "build", "--force-rm", ".")
  220. buildCmd.Dir = buildDirectory
  221. _, exitCode, err := runCommandWithOutput(buildCmd)
  222. if err == nil || exitCode == 0 {
  223. t.Fatal("failed to build the image")
  224. }
  225. containerCountAfter, err := getContainerCount()
  226. if err != nil {
  227. t.Fatalf("failed to get the container count: %s", err)
  228. }
  229. if containerCountBefore != containerCountAfter {
  230. t.Fatalf("--force-rm shouldn't have left containers behind")
  231. }
  232. logDone("build - ensure --force-rm doesn't leave containers behind")
  233. }
  234. func TestBuildRm(t *testing.T) {
  235. {
  236. containerCountBefore, err := getContainerCount()
  237. if err != nil {
  238. t.Fatalf("failed to get the container count: %s", err)
  239. }
  240. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildRm")
  241. buildCmd := exec.Command(dockerBinary, "build", "--rm", "-t", "testbuildrm", ".")
  242. buildCmd.Dir = buildDirectory
  243. _, exitCode, err := runCommandWithOutput(buildCmd)
  244. if err != nil || exitCode != 0 {
  245. t.Fatal("failed to build the image")
  246. }
  247. containerCountAfter, err := getContainerCount()
  248. if err != nil {
  249. t.Fatalf("failed to get the container count: %s", err)
  250. }
  251. if containerCountBefore != containerCountAfter {
  252. t.Fatalf("-rm shouldn't have left containers behind")
  253. }
  254. deleteImages("testbuildrm")
  255. }
  256. {
  257. containerCountBefore, err := getContainerCount()
  258. if err != nil {
  259. t.Fatalf("failed to get the container count: %s", err)
  260. }
  261. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildRm")
  262. buildCmd := exec.Command(dockerBinary, "build", "-t", "testbuildrm", ".")
  263. buildCmd.Dir = buildDirectory
  264. _, exitCode, err := runCommandWithOutput(buildCmd)
  265. if err != nil || exitCode != 0 {
  266. t.Fatal("failed to build the image")
  267. }
  268. containerCountAfter, err := getContainerCount()
  269. if err != nil {
  270. t.Fatalf("failed to get the container count: %s", err)
  271. }
  272. if containerCountBefore != containerCountAfter {
  273. t.Fatalf("--rm shouldn't have left containers behind")
  274. }
  275. deleteImages("testbuildrm")
  276. }
  277. {
  278. containerCountBefore, err := getContainerCount()
  279. if err != nil {
  280. t.Fatalf("failed to get the container count: %s", err)
  281. }
  282. buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildRm")
  283. buildCmd := exec.Command(dockerBinary, "build", "--rm=false", "-t", "testbuildrm", ".")
  284. buildCmd.Dir = buildDirectory
  285. _, exitCode, err := runCommandWithOutput(buildCmd)
  286. if err != nil || exitCode != 0 {
  287. t.Fatal("failed to build the image")
  288. }
  289. containerCountAfter, err := getContainerCount()
  290. if err != nil {
  291. t.Fatalf("failed to get the container count: %s", err)
  292. }
  293. if containerCountBefore == containerCountAfter {
  294. t.Fatalf("--rm=false should have left containers behind")
  295. }
  296. deleteAllContainers()
  297. deleteImages("testbuildrm")
  298. }
  299. logDone("build - ensure --rm doesn't leave containers behind and that --rm=true is the default")
  300. logDone("build - ensure --rm=false overrides the default")
  301. }
  302. // TODO: TestCaching
  303. // TODO: TestADDCacheInvalidation