context_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. package builder
  2. import (
  3. "archive/tar"
  4. "bytes"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "path/filepath"
  9. "runtime"
  10. "strings"
  11. "testing"
  12. "github.com/docker/docker/pkg/archive"
  13. )
  14. const (
  15. dockerfileTestName = "Dockerfile-test"
  16. dockerfileContent = "FROM busybox"
  17. )
  18. var prepareEmpty = func(t *testing.T) string {
  19. return ""
  20. }
  21. var prepareNoFiles = func(t *testing.T) string {
  22. contextDir, err := ioutil.TempDir("", "builder-context-test")
  23. if err != nil {
  24. t.Fatalf("Error when creating temporary directory: %s", err)
  25. }
  26. return contextDir
  27. }
  28. var prepareOneFile = func(t *testing.T) string {
  29. contextDir, err := ioutil.TempDir("", "builder-context-test")
  30. if err != nil {
  31. t.Fatalf("Error when creating temporary directory: %s", err)
  32. }
  33. dockerfileFilename := filepath.Join(contextDir, dockerfileTestName)
  34. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  35. if err != nil {
  36. t.Fatalf("Error with writing to file: %s", err)
  37. }
  38. return contextDir
  39. }
  40. func testValidateContextDirectory(t *testing.T, prepare func(t *testing.T) string, excludes []string) {
  41. contextDir := prepare(t)
  42. defer os.RemoveAll(contextDir)
  43. err := ValidateContextDirectory(contextDir, excludes)
  44. if err != nil {
  45. t.Fatalf("Error should be nil, got: %s", err)
  46. }
  47. }
  48. func TestGetContextFromLocalDirNoDockerfile(t *testing.T) {
  49. contextDir, err := ioutil.TempDir("", "builder-context-test")
  50. defer os.RemoveAll(contextDir)
  51. if err != nil {
  52. t.Fatalf("Error with creating temporary directory: %s", err)
  53. }
  54. absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, "")
  55. if err == nil {
  56. t.Fatalf("Error should not be nil")
  57. }
  58. if absContextDir != "" {
  59. t.Fatalf("Absolute directory path should be empty, got: %s", absContextDir)
  60. }
  61. if relDockerfile != "" {
  62. t.Fatalf("Relative path to Dockerfile should be empty, got: %s", relDockerfile)
  63. }
  64. }
  65. func TestGetContextFromLocalDirNotExistingDir(t *testing.T) {
  66. contextDir, err := ioutil.TempDir("", "builder-context-test")
  67. if err != nil {
  68. t.Fatalf("Error with creating temporary directory: %s", err)
  69. }
  70. defer os.RemoveAll(contextDir)
  71. fakePath := filepath.Join(contextDir, "fake")
  72. absContextDir, relDockerfile, err := GetContextFromLocalDir(fakePath, "")
  73. if err == nil {
  74. t.Fatalf("Error should not be nil")
  75. }
  76. if absContextDir != "" {
  77. t.Fatalf("Absolute directory path should be empty, got: %s", absContextDir)
  78. }
  79. if relDockerfile != "" {
  80. t.Fatalf("Relative path to Dockerfile should be empty, got: %s", relDockerfile)
  81. }
  82. }
  83. func TestGetContextFromLocalDirNotExistingDockerfile(t *testing.T) {
  84. contextDir, err := ioutil.TempDir("", "builder-context-test")
  85. if err != nil {
  86. t.Fatalf("Error with creating temporary directory: %s", err)
  87. }
  88. defer os.RemoveAll(contextDir)
  89. fakePath := filepath.Join(contextDir, "fake")
  90. absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, fakePath)
  91. if err == nil {
  92. t.Fatalf("Error should not be nil")
  93. }
  94. if absContextDir != "" {
  95. t.Fatalf("Absolute directory path should be empty, got: %s", absContextDir)
  96. }
  97. if relDockerfile != "" {
  98. t.Fatalf("Relative path to Dockerfile should be empty, got: %s", relDockerfile)
  99. }
  100. }
  101. func TestGetContextFromLocalDirWithNoDirectory(t *testing.T) {
  102. contextDir, err := ioutil.TempDir("", "builder-context-test")
  103. if err != nil {
  104. t.Fatalf("Error with creating temporary directory: %s", err)
  105. }
  106. defer os.RemoveAll(contextDir)
  107. dockerfileFilename := filepath.Join(contextDir, DefaultDockerfileName)
  108. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  109. if err != nil {
  110. t.Fatalf("Error when writing file (%s) contents: %s", dockerfileFilename, err)
  111. }
  112. workingDirectory, err := os.Getwd()
  113. if err != nil {
  114. t.Fatalf("Error when retrieving working directory: %s", err)
  115. }
  116. defer os.Chdir(workingDirectory)
  117. err = os.Chdir(contextDir)
  118. if err != nil {
  119. t.Fatalf("Error when changing directory to %s: %s", contextDir, err)
  120. }
  121. absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, "")
  122. if err != nil {
  123. t.Fatalf("Error when getting context from local dir: %s", err)
  124. }
  125. if absContextDir != contextDir {
  126. t.Fatalf("Absolute directory path should be equal to %s, got: %s", contextDir, absContextDir)
  127. }
  128. if relDockerfile != DefaultDockerfileName {
  129. t.Fatalf("Relative path to dockerfile should be equal to %s, got: %s", DefaultDockerfileName, relDockerfile)
  130. }
  131. }
  132. func TestGetContextFromLocalDirWithDockerfile(t *testing.T) {
  133. contextDir, err := ioutil.TempDir("", "builder-context-test")
  134. if err != nil {
  135. t.Fatalf("Error with creating temporary directory: %s", err)
  136. }
  137. defer os.RemoveAll(contextDir)
  138. dockerfileFilename := filepath.Join(contextDir, DefaultDockerfileName)
  139. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  140. if err != nil {
  141. t.Fatalf("Error when writing file (%s) contents: %s", dockerfileFilename, err)
  142. }
  143. absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, "")
  144. if err != nil {
  145. t.Fatalf("Error when getting context from local dir: %s", err)
  146. }
  147. if absContextDir != contextDir {
  148. t.Fatalf("Absolute directory path should be equal to %s, got: %s", contextDir, absContextDir)
  149. }
  150. if relDockerfile != DefaultDockerfileName {
  151. t.Fatalf("Relative path to dockerfile should be equal to %s, got: %s", DefaultDockerfileName, relDockerfile)
  152. }
  153. }
  154. func TestGetContextFromLocalDirLocalFile(t *testing.T) {
  155. contextDir, err := ioutil.TempDir("", "builder-context-test")
  156. if err != nil {
  157. t.Fatalf("Error with creating temporary directory: %s", err)
  158. }
  159. defer os.RemoveAll(contextDir)
  160. dockerfileFilename := filepath.Join(contextDir, DefaultDockerfileName)
  161. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  162. if err != nil {
  163. t.Fatalf("Error when writing file (%s) contents: %s", dockerfileFilename, err)
  164. }
  165. testFilename := filepath.Join(contextDir, "tmpTest")
  166. testContent := "test"
  167. err = ioutil.WriteFile(testFilename, []byte(testContent), 0777)
  168. if err != nil {
  169. t.Fatalf("Error when writing file (%s) contents: %s", testFilename, err)
  170. }
  171. absContextDir, relDockerfile, err := GetContextFromLocalDir(testFilename, "")
  172. if err == nil {
  173. t.Fatalf("Error should not be nil")
  174. }
  175. if absContextDir != "" {
  176. t.Fatalf("Absolute directory path should be empty, got: %s", absContextDir)
  177. }
  178. if relDockerfile != "" {
  179. t.Fatalf("Relative path to Dockerfile should be empty, got: %s", relDockerfile)
  180. }
  181. }
  182. func TestGetContextFromLocalDirWithCustomDockerfile(t *testing.T) {
  183. contextDir, err := ioutil.TempDir("", "builder-context-test")
  184. if err != nil {
  185. t.Fatalf("Error with creating temporary directory: %s", err)
  186. }
  187. defer os.RemoveAll(contextDir)
  188. workingDirectory, err := os.Getwd()
  189. if err != nil {
  190. t.Fatalf("Error when retrieving working directory: %s", err)
  191. }
  192. defer os.Chdir(workingDirectory)
  193. err = os.Chdir(contextDir)
  194. if err != nil {
  195. t.Fatalf("Error when changing directory to %s: %s", contextDir, err)
  196. }
  197. dockerfileFilename := filepath.Join(contextDir, dockerfileTestName)
  198. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  199. if err != nil {
  200. t.Fatalf("Error when writing file (%s) contents: %s", dockerfileFilename, err)
  201. }
  202. absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, dockerfileTestName)
  203. if err != nil {
  204. t.Fatalf("Error when getting context from local dir: %s", err)
  205. }
  206. if absContextDir != contextDir {
  207. t.Fatalf("Absolute directory path should be equal to %s, got: %s", contextDir, absContextDir)
  208. }
  209. if relDockerfile != dockerfileTestName {
  210. t.Fatalf("Relative path to dockerfile should be equal to %s, got: %s", dockerfileTestName, relDockerfile)
  211. }
  212. }
  213. func TestGetContextFromReaderString(t *testing.T) {
  214. tarArchive, relDockerfile, err := GetContextFromReader(ioutil.NopCloser(strings.NewReader(dockerfileContent)), "")
  215. if err != nil {
  216. t.Fatalf("Error when executing GetContextFromReader: %s", err)
  217. }
  218. tarReader := tar.NewReader(tarArchive)
  219. _, err = tarReader.Next()
  220. if err != nil {
  221. t.Fatalf("Error when reading tar archive: %s", err)
  222. }
  223. buff := new(bytes.Buffer)
  224. buff.ReadFrom(tarReader)
  225. contents := buff.String()
  226. _, err = tarReader.Next()
  227. if err != io.EOF {
  228. t.Fatalf("Tar stream too long: %s", err)
  229. }
  230. if err = tarArchive.Close(); err != nil {
  231. t.Fatalf("Error when closing tar stream: %s", err)
  232. }
  233. if dockerfileContent != contents {
  234. t.Fatalf("Uncompressed tar archive does not equal: %s, got: %s", dockerfileContent, contents)
  235. }
  236. if relDockerfile != DefaultDockerfileName {
  237. t.Fatalf("Relative path not equals %s, got: %s", DefaultDockerfileName, relDockerfile)
  238. }
  239. }
  240. func TestGetContextFromReaderTar(t *testing.T) {
  241. contextDir, err := ioutil.TempDir("", "builder-context-test")
  242. if err != nil {
  243. t.Fatalf("Error with creating temporary directory: %s", err)
  244. }
  245. defer os.RemoveAll(contextDir)
  246. dockerfileFilename := filepath.Join(contextDir, dockerfileTestName)
  247. err = ioutil.WriteFile(dockerfileFilename, []byte(dockerfileContent), 0777)
  248. if err != nil {
  249. t.Fatalf("Error when writing file (%s) contents: %s", dockerfileFilename, err)
  250. }
  251. tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
  252. if err != nil {
  253. t.Fatalf("Error when creating tar: %s", err)
  254. }
  255. tarArchive, relDockerfile, err := GetContextFromReader(tarStream, dockerfileTestName)
  256. if err != nil {
  257. t.Fatalf("Error when executing GetContextFromReader: %s", err)
  258. }
  259. tarReader := tar.NewReader(tarArchive)
  260. header, err := tarReader.Next()
  261. if err != nil {
  262. t.Fatalf("Error when reading tar archive: %s", err)
  263. }
  264. if header.Name != dockerfileTestName {
  265. t.Fatalf("Dockerfile name should be: %s, got: %s", dockerfileTestName, header.Name)
  266. }
  267. buff := new(bytes.Buffer)
  268. buff.ReadFrom(tarReader)
  269. contents := buff.String()
  270. _, err = tarReader.Next()
  271. if err != io.EOF {
  272. t.Fatalf("Tar stream too long: %s", err)
  273. }
  274. if err = tarArchive.Close(); err != nil {
  275. t.Fatalf("Error when closing tar stream: %s", err)
  276. }
  277. if dockerfileContent != contents {
  278. t.Fatalf("Uncompressed tar archive does not equal: %s, got: %s", dockerfileContent, contents)
  279. }
  280. if relDockerfile != dockerfileTestName {
  281. t.Fatalf("Relative path not equals %s, got: %s", dockerfileTestName, relDockerfile)
  282. }
  283. }
  284. func TestValidateContextDirectoryEmptyContext(t *testing.T) {
  285. // This isn't a valid test on Windows. See https://play.golang.org/p/RR6z6jxR81.
  286. // The test will ultimately end up calling filepath.Abs(""). On Windows,
  287. // golang will error. On Linux, golang will return /. Due to there being
  288. // drive letters on Windows, this is probably the correct behaviour for
  289. // Windows.
  290. if runtime.GOOS == "windows" {
  291. t.Skip("Invalid test on Windows")
  292. }
  293. testValidateContextDirectory(t, prepareEmpty, []string{})
  294. }
  295. func TestValidateContextDirectoryContextWithNoFiles(t *testing.T) {
  296. testValidateContextDirectory(t, prepareNoFiles, []string{})
  297. }
  298. func TestValidateContextDirectoryWithOneFile(t *testing.T) {
  299. testValidateContextDirectory(t, prepareOneFile, []string{})
  300. }
  301. func TestValidateContextDirectoryWithOneFileExcludes(t *testing.T) {
  302. testValidateContextDirectory(t, prepareOneFile, []string{dockerfileTestName})
  303. }