buildfile_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. package docker
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker"
  5. "github.com/dotcloud/docker/archive"
  6. "github.com/dotcloud/docker/engine"
  7. "github.com/dotcloud/docker/utils"
  8. "io/ioutil"
  9. "net"
  10. "net/http"
  11. "net/http/httptest"
  12. "strings"
  13. "testing"
  14. )
  15. // mkTestContext generates a build context from the contents of the provided dockerfile.
  16. // This context is suitable for use as an argument to BuildFile.Build()
  17. func mkTestContext(dockerfile string, files [][2]string, t *testing.T) archive.Archive {
  18. context, err := docker.MkBuildContext(dockerfile, files)
  19. if err != nil {
  20. t.Fatal(err)
  21. }
  22. return context
  23. }
  24. // A testContextTemplate describes a build context and how to test it
  25. type testContextTemplate struct {
  26. // Contents of the Dockerfile
  27. dockerfile string
  28. // Additional files in the context, eg [][2]string{"./passwd", "gordon"}
  29. files [][2]string
  30. // Additional remote files to host on a local HTTP server.
  31. remoteFiles [][2]string
  32. }
  33. // A table of all the contexts to build and test.
  34. // A new docker runtime will be created and torn down for each context.
  35. var testContexts = []testContextTemplate{
  36. {
  37. `
  38. from {IMAGE}
  39. run sh -c 'echo root:testpass > /tmp/passwd'
  40. run mkdir -p /var/run/sshd
  41. run [ "$(cat /tmp/passwd)" = "root:testpass" ]
  42. run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
  43. `,
  44. nil,
  45. nil,
  46. },
  47. // Exactly the same as above, except uses a line split with a \ to test
  48. // multiline support.
  49. {
  50. `
  51. from {IMAGE}
  52. run sh -c 'echo root:testpass \
  53. > /tmp/passwd'
  54. run mkdir -p /var/run/sshd
  55. run [ "$(cat /tmp/passwd)" = "root:testpass" ]
  56. run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
  57. `,
  58. nil,
  59. nil,
  60. },
  61. // Line containing literal "\n"
  62. {
  63. `
  64. from {IMAGE}
  65. run sh -c 'echo root:testpass > /tmp/passwd'
  66. run echo "foo \n bar"; echo "baz"
  67. run mkdir -p /var/run/sshd
  68. run [ "$(cat /tmp/passwd)" = "root:testpass" ]
  69. run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
  70. `,
  71. nil,
  72. nil,
  73. },
  74. {
  75. `
  76. from {IMAGE}
  77. add foo /usr/lib/bla/bar
  78. run [ "$(cat /usr/lib/bla/bar)" = 'hello' ]
  79. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  80. run [ "$(cat /usr/lib/baz/quux)" = 'world!' ]
  81. `,
  82. [][2]string{{"foo", "hello"}},
  83. [][2]string{{"/baz", "world!"}},
  84. },
  85. {
  86. `
  87. from {IMAGE}
  88. add f /
  89. run [ "$(cat /f)" = "hello" ]
  90. add f /abc
  91. run [ "$(cat /abc)" = "hello" ]
  92. add f /x/y/z
  93. run [ "$(cat /x/y/z)" = "hello" ]
  94. add f /x/y/d/
  95. run [ "$(cat /x/y/d/f)" = "hello" ]
  96. add d /
  97. run [ "$(cat /ga)" = "bu" ]
  98. add d /somewhere
  99. run [ "$(cat /somewhere/ga)" = "bu" ]
  100. add d /anotherplace/
  101. run [ "$(cat /anotherplace/ga)" = "bu" ]
  102. add d /somewheeeere/over/the/rainbooow
  103. run [ "$(cat /somewheeeere/over/the/rainbooow/ga)" = "bu" ]
  104. `,
  105. [][2]string{
  106. {"f", "hello"},
  107. {"d/ga", "bu"},
  108. },
  109. nil,
  110. },
  111. {
  112. `
  113. from {IMAGE}
  114. add http://{SERVERADDR}/x /a/b/c
  115. run [ "$(cat /a/b/c)" = "hello" ]
  116. add http://{SERVERADDR}/x?foo=bar /
  117. run [ "$(cat /x)" = "hello" ]
  118. add http://{SERVERADDR}/x /d/
  119. run [ "$(cat /d/x)" = "hello" ]
  120. add http://{SERVERADDR} /e
  121. run [ "$(cat /e)" = "blah" ]
  122. `,
  123. nil,
  124. [][2]string{{"/x", "hello"}, {"/", "blah"}},
  125. },
  126. // Comments, shebangs, and executability, oh my!
  127. {
  128. `
  129. FROM {IMAGE}
  130. # This is an ordinary comment.
  131. RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh
  132. RUN [ ! -x /hello.sh ]
  133. RUN chmod +x /hello.sh
  134. RUN [ -x /hello.sh ]
  135. RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
  136. RUN [ "$(/hello.sh)" = "hello world" ]
  137. `,
  138. nil,
  139. nil,
  140. },
  141. // Environment variable
  142. {
  143. `
  144. from {IMAGE}
  145. env FOO BAR
  146. run [ "$FOO" = "BAR" ]
  147. `,
  148. nil,
  149. nil,
  150. },
  151. // Environment overwriting
  152. {
  153. `
  154. from {IMAGE}
  155. env FOO BAR
  156. run [ "$FOO" = "BAR" ]
  157. env FOO BAZ
  158. run [ "$FOO" = "BAZ" ]
  159. `,
  160. nil,
  161. nil,
  162. },
  163. {
  164. `
  165. from {IMAGE}
  166. ENTRYPOINT /bin/echo
  167. CMD Hello world
  168. `,
  169. nil,
  170. nil,
  171. },
  172. {
  173. `
  174. from {IMAGE}
  175. VOLUME /test
  176. CMD Hello world
  177. `,
  178. nil,
  179. nil,
  180. },
  181. {
  182. `
  183. from {IMAGE}
  184. env FOO /foo/baz
  185. env BAR /bar
  186. env BAZ $BAR
  187. env FOOPATH $PATH:$FOO
  188. run [ "$BAR" = "$BAZ" ]
  189. run [ "$FOOPATH" = "$PATH:/foo/baz" ]
  190. `,
  191. nil,
  192. nil,
  193. },
  194. {
  195. `
  196. from {IMAGE}
  197. env FOO /bar
  198. env TEST testdir
  199. env BAZ /foobar
  200. add testfile $BAZ/
  201. add $TEST $FOO
  202. run [ "$(cat /foobar/testfile)" = "test1" ]
  203. run [ "$(cat /bar/withfile)" = "test2" ]
  204. `,
  205. [][2]string{
  206. {"testfile", "test1"},
  207. {"testdir/withfile", "test2"},
  208. },
  209. nil,
  210. },
  211. }
  212. // FIXME: test building with 2 successive overlapping ADD commands
  213. func constructDockerfile(template string, ip net.IP, port string) string {
  214. serverAddr := fmt.Sprintf("%s:%s", ip, port)
  215. replacer := strings.NewReplacer("{IMAGE}", unitTestImageID, "{SERVERADDR}", serverAddr)
  216. return replacer.Replace(template)
  217. }
  218. func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
  219. mux := http.NewServeMux()
  220. for _, file := range files {
  221. name, contents := file[0], file[1]
  222. mux.HandleFunc(name, func(w http.ResponseWriter, r *http.Request) {
  223. w.Write([]byte(contents))
  224. })
  225. }
  226. // This is how httptest.NewServer sets up a net.Listener, except that our listener must accept remote
  227. // connections (from the container).
  228. listener, err := net.Listen("tcp", ":0")
  229. if err != nil {
  230. return nil, err
  231. }
  232. s := httptest.NewUnstartedServer(mux)
  233. s.Listener = listener
  234. s.Start()
  235. return s, nil
  236. }
  237. func TestBuild(t *testing.T) {
  238. for _, ctx := range testContexts {
  239. _, err := buildImage(ctx, t, nil, true)
  240. if err != nil {
  241. t.Fatal(err)
  242. }
  243. }
  244. }
  245. func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, useCache bool) (*docker.Image, error) {
  246. if eng == nil {
  247. eng = NewTestEngine(t)
  248. runtime := mkRuntimeFromEngine(eng, t)
  249. // FIXME: we might not need runtime, why not simply nuke
  250. // the engine?
  251. defer nuke(runtime)
  252. }
  253. srv := mkServerFromEngine(eng, t)
  254. httpServer, err := mkTestingFileServer(context.remoteFiles)
  255. if err != nil {
  256. t.Fatal(err)
  257. }
  258. defer httpServer.Close()
  259. idx := strings.LastIndex(httpServer.URL, ":")
  260. if idx < 0 {
  261. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  262. }
  263. port := httpServer.URL[idx+1:]
  264. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  265. if iIP == nil {
  266. t.Fatal("Legacy bridgeIP field not set in engine")
  267. }
  268. ip, ok := iIP.(net.IP)
  269. if !ok {
  270. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  271. }
  272. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  273. buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  274. id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
  275. if err != nil {
  276. return nil, err
  277. }
  278. return srv.ImageInspect(id)
  279. }
  280. func TestVolume(t *testing.T) {
  281. img, err := buildImage(testContextTemplate{`
  282. from {IMAGE}
  283. volume /test
  284. cmd Hello world
  285. `, nil, nil}, t, nil, true)
  286. if err != nil {
  287. t.Fatal(err)
  288. }
  289. if len(img.Config.Volumes) == 0 {
  290. t.Fail()
  291. }
  292. for key := range img.Config.Volumes {
  293. if key != "/test" {
  294. t.Fail()
  295. }
  296. }
  297. }
  298. func TestBuildMaintainer(t *testing.T) {
  299. img, err := buildImage(testContextTemplate{`
  300. from {IMAGE}
  301. maintainer dockerio
  302. `, nil, nil}, t, nil, true)
  303. if err != nil {
  304. t.Fatal(err)
  305. }
  306. if img.Author != "dockerio" {
  307. t.Fail()
  308. }
  309. }
  310. func TestBuildUser(t *testing.T) {
  311. img, err := buildImage(testContextTemplate{`
  312. from {IMAGE}
  313. user dockerio
  314. `, nil, nil}, t, nil, true)
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. if img.Config.User != "dockerio" {
  319. t.Fail()
  320. }
  321. }
  322. func TestBuildEnv(t *testing.T) {
  323. img, err := buildImage(testContextTemplate{`
  324. from {IMAGE}
  325. env port 4243
  326. `,
  327. nil, nil}, t, nil, true)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. hasEnv := false
  332. for _, envVar := range img.Config.Env {
  333. if envVar == "port=4243" {
  334. hasEnv = true
  335. break
  336. }
  337. }
  338. if !hasEnv {
  339. t.Fail()
  340. }
  341. }
  342. func TestBuildCmd(t *testing.T) {
  343. img, err := buildImage(testContextTemplate{`
  344. from {IMAGE}
  345. cmd ["/bin/echo", "Hello World"]
  346. `,
  347. nil, nil}, t, nil, true)
  348. if err != nil {
  349. t.Fatal(err)
  350. }
  351. if img.Config.Cmd[0] != "/bin/echo" {
  352. t.Log(img.Config.Cmd[0])
  353. t.Fail()
  354. }
  355. if img.Config.Cmd[1] != "Hello World" {
  356. t.Log(img.Config.Cmd[1])
  357. t.Fail()
  358. }
  359. }
  360. func TestBuildExpose(t *testing.T) {
  361. img, err := buildImage(testContextTemplate{`
  362. from {IMAGE}
  363. expose 4243
  364. `,
  365. nil, nil}, t, nil, true)
  366. if err != nil {
  367. t.Fatal(err)
  368. }
  369. if img.Config.PortSpecs[0] != "4243" {
  370. t.Fail()
  371. }
  372. }
  373. func TestBuildEntrypoint(t *testing.T) {
  374. img, err := buildImage(testContextTemplate{`
  375. from {IMAGE}
  376. entrypoint ["/bin/echo"]
  377. `,
  378. nil, nil}, t, nil, true)
  379. if err != nil {
  380. t.Fatal(err)
  381. }
  382. if img.Config.Entrypoint[0] != "/bin/echo" {
  383. t.Log(img.Config.Entrypoint[0])
  384. t.Fail()
  385. }
  386. }
  387. // testing #1405 - config.Cmd does not get cleaned up if
  388. // utilizing cache
  389. func TestBuildEntrypointRunCleanup(t *testing.T) {
  390. eng := NewTestEngine(t)
  391. defer nuke(mkRuntimeFromEngine(eng, t))
  392. img, err := buildImage(testContextTemplate{`
  393. from {IMAGE}
  394. run echo "hello"
  395. `,
  396. nil, nil}, t, eng, true)
  397. if err != nil {
  398. t.Fatal(err)
  399. }
  400. img, err = buildImage(testContextTemplate{`
  401. from {IMAGE}
  402. run echo "hello"
  403. add foo /foo
  404. entrypoint ["/bin/echo"]
  405. `,
  406. [][2]string{{"foo", "HEYO"}}, nil}, t, eng, true)
  407. if err != nil {
  408. t.Fatal(err)
  409. }
  410. if len(img.Config.Cmd) != 0 {
  411. t.Fail()
  412. }
  413. }
  414. func checkCacheBehavior(t *testing.T, template testContextTemplate, expectHit bool) (imageId string) {
  415. eng := NewTestEngine(t)
  416. defer nuke(mkRuntimeFromEngine(eng, t))
  417. img, err := buildImage(template, t, eng, true)
  418. if err != nil {
  419. t.Fatal(err)
  420. }
  421. imageId = img.ID
  422. img, err = buildImage(template, t, eng, expectHit)
  423. if err != nil {
  424. t.Fatal(err)
  425. }
  426. if hit := imageId == img.ID; hit != expectHit {
  427. t.Fatalf("Cache misbehavior, got hit=%t, expected hit=%t: (first: %s, second %s)", hit, expectHit, imageId, img.ID)
  428. }
  429. return
  430. }
  431. func checkCacheBehaviorFromEngime(t *testing.T, template testContextTemplate, expectHit bool, eng *engine.Engine) (imageId string) {
  432. img, err := buildImage(template, t, eng, true)
  433. if err != nil {
  434. t.Fatal(err)
  435. }
  436. imageId = img.ID
  437. img, err = buildImage(template, t, eng, expectHit)
  438. if err != nil {
  439. t.Fatal(err)
  440. }
  441. if hit := imageId == img.ID; hit != expectHit {
  442. t.Fatalf("Cache misbehavior, got hit=%t, expected hit=%t: (first: %s, second %s)", hit, expectHit, imageId, img.ID)
  443. }
  444. return
  445. }
  446. func TestBuildImageWithCache(t *testing.T) {
  447. template := testContextTemplate{`
  448. from {IMAGE}
  449. maintainer dockerio
  450. `,
  451. nil, nil}
  452. checkCacheBehavior(t, template, true)
  453. }
  454. func TestBuildImageWithoutCache(t *testing.T) {
  455. template := testContextTemplate{`
  456. from {IMAGE}
  457. maintainer dockerio
  458. `,
  459. nil, nil}
  460. checkCacheBehavior(t, template, false)
  461. }
  462. func TestBuildADDLocalFileWithCache(t *testing.T) {
  463. template := testContextTemplate{`
  464. from {IMAGE}
  465. maintainer dockerio
  466. run echo "first"
  467. add foo /usr/lib/bla/bar
  468. run [ "$(cat /usr/lib/bla/bar)" = "hello" ]
  469. run echo "second"
  470. add . /src/
  471. run [ "$(cat /src/foo)" = "hello" ]
  472. `,
  473. [][2]string{
  474. {"foo", "hello"},
  475. },
  476. nil}
  477. eng := NewTestEngine(t)
  478. defer nuke(mkRuntimeFromEngine(eng, t))
  479. id1 := checkCacheBehaviorFromEngime(t, template, true, eng)
  480. template.files = append(template.files, [2]string{"bar", "hello2"})
  481. id2 := checkCacheBehaviorFromEngime(t, template, true, eng)
  482. if id1 == id2 {
  483. t.Fatal("The cache should have been invalided but hasn't.")
  484. }
  485. id3 := checkCacheBehaviorFromEngime(t, template, true, eng)
  486. if id2 != id3 {
  487. t.Fatal("The cache should have been used but hasn't.")
  488. }
  489. template.files[1][1] = "hello3"
  490. id4 := checkCacheBehaviorFromEngime(t, template, true, eng)
  491. if id3 == id4 {
  492. t.Fatal("The cache should have been invalided but hasn't.")
  493. }
  494. template.dockerfile += `
  495. add ./bar /src2/
  496. run ls /src2/bar
  497. `
  498. id5 := checkCacheBehaviorFromEngime(t, template, true, eng)
  499. if id4 == id5 {
  500. t.Fatal("The cache should have been invalided but hasn't.")
  501. }
  502. template.files[1][1] = "hello4"
  503. id6 := checkCacheBehaviorFromEngime(t, template, true, eng)
  504. if id5 == id6 {
  505. t.Fatal("The cache should have been invalided but hasn't.")
  506. }
  507. template.dockerfile += `
  508. add bar /src2/bar2
  509. add /bar /src2/bar3
  510. run ls /src2/bar2 /src2/bar3
  511. `
  512. id7 := checkCacheBehaviorFromEngime(t, template, true, eng)
  513. if id6 == id7 {
  514. t.Fatal("The cache should have been invalided but hasn't.")
  515. }
  516. template.files[1][1] = "hello5"
  517. id8 := checkCacheBehaviorFromEngime(t, template, true, eng)
  518. if id7 == id8 {
  519. t.Fatal("The cache should have been invalided but hasn't.")
  520. }
  521. }
  522. func TestBuildADDLocalFileWithoutCache(t *testing.T) {
  523. template := testContextTemplate{`
  524. from {IMAGE}
  525. maintainer dockerio
  526. run echo "first"
  527. add foo /usr/lib/bla/bar
  528. run echo "second"
  529. `,
  530. [][2]string{{"foo", "hello"}},
  531. nil}
  532. checkCacheBehavior(t, template, false)
  533. }
  534. func TestBuildADDCurrentDirectoryWithCache(t *testing.T) {
  535. template := testContextTemplate{`
  536. from {IMAGE}
  537. maintainer dockerio
  538. add . /usr/lib/bla
  539. `,
  540. nil, nil}
  541. checkCacheBehavior(t, template, true)
  542. }
  543. func TestBuildADDCurrentDirectoryWithoutCache(t *testing.T) {
  544. template := testContextTemplate{`
  545. from {IMAGE}
  546. maintainer dockerio
  547. add . /usr/lib/bla
  548. `,
  549. nil, nil}
  550. checkCacheBehavior(t, template, false)
  551. }
  552. func TestBuildADDRemoteFileWithCache(t *testing.T) {
  553. template := testContextTemplate{`
  554. from {IMAGE}
  555. maintainer dockerio
  556. run echo "first"
  557. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  558. run echo "second"
  559. `,
  560. nil,
  561. [][2]string{{"/baz", "world!"}}}
  562. checkCacheBehavior(t, template, true)
  563. }
  564. func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
  565. template := testContextTemplate{`
  566. from {IMAGE}
  567. maintainer dockerio
  568. run echo "first"
  569. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  570. run echo "second"
  571. `,
  572. nil,
  573. [][2]string{{"/baz", "world!"}}}
  574. checkCacheBehavior(t, template, false)
  575. }
  576. func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
  577. template := testContextTemplate{`
  578. from {IMAGE}
  579. maintainer dockerio
  580. run echo "first"
  581. add foo /usr/lib/bla/bar
  582. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  583. run echo "second"
  584. `,
  585. [][2]string{{"foo", "hello"}},
  586. [][2]string{{"/baz", "world!"}}}
  587. checkCacheBehavior(t, template, true)
  588. }
  589. func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
  590. template := testContextTemplate{`
  591. from {IMAGE}
  592. maintainer dockerio
  593. run echo "first"
  594. add foo /usr/lib/bla/bar
  595. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  596. run echo "second"
  597. `,
  598. [][2]string{{"foo", "hello"}},
  599. [][2]string{{"/baz", "world!"}}}
  600. checkCacheBehavior(t, template, false)
  601. }
  602. func TestForbiddenContextPath(t *testing.T) {
  603. eng := NewTestEngine(t)
  604. defer nuke(mkRuntimeFromEngine(eng, t))
  605. srv := mkServerFromEngine(eng, t)
  606. context := testContextTemplate{`
  607. from {IMAGE}
  608. maintainer dockerio
  609. add ../../ test/
  610. `,
  611. [][2]string{{"test.txt", "test1"}, {"other.txt", "other"}}, nil}
  612. httpServer, err := mkTestingFileServer(context.remoteFiles)
  613. if err != nil {
  614. t.Fatal(err)
  615. }
  616. defer httpServer.Close()
  617. idx := strings.LastIndex(httpServer.URL, ":")
  618. if idx < 0 {
  619. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  620. }
  621. port := httpServer.URL[idx+1:]
  622. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  623. if iIP == nil {
  624. t.Fatal("Legacy bridgeIP field not set in engine")
  625. }
  626. ip, ok := iIP.(net.IP)
  627. if !ok {
  628. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  629. }
  630. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  631. buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  632. _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
  633. if err == nil {
  634. t.Log("Error should not be nil")
  635. t.Fail()
  636. }
  637. if err.Error() != "Forbidden path outside the build context: ../../ (/)" {
  638. t.Logf("Error message is not expected: %s", err.Error())
  639. t.Fail()
  640. }
  641. }
  642. func TestBuildADDFileNotFound(t *testing.T) {
  643. eng := NewTestEngine(t)
  644. defer nuke(mkRuntimeFromEngine(eng, t))
  645. context := testContextTemplate{`
  646. from {IMAGE}
  647. add foo /usr/local/bar
  648. `,
  649. nil, nil}
  650. httpServer, err := mkTestingFileServer(context.remoteFiles)
  651. if err != nil {
  652. t.Fatal(err)
  653. }
  654. defer httpServer.Close()
  655. idx := strings.LastIndex(httpServer.URL, ":")
  656. if idx < 0 {
  657. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  658. }
  659. port := httpServer.URL[idx+1:]
  660. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  661. if iIP == nil {
  662. t.Fatal("Legacy bridgeIP field not set in engine")
  663. }
  664. ip, ok := iIP.(net.IP)
  665. if !ok {
  666. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  667. }
  668. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  669. buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  670. _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
  671. if err == nil {
  672. t.Log("Error should not be nil")
  673. t.Fail()
  674. }
  675. if err.Error() != "foo: no such file or directory" {
  676. t.Logf("Error message is not expected: %s", err.Error())
  677. t.Fail()
  678. }
  679. }
  680. func TestBuildInheritance(t *testing.T) {
  681. eng := NewTestEngine(t)
  682. defer nuke(mkRuntimeFromEngine(eng, t))
  683. img, err := buildImage(testContextTemplate{`
  684. from {IMAGE}
  685. expose 4243
  686. `,
  687. nil, nil}, t, eng, true)
  688. if err != nil {
  689. t.Fatal(err)
  690. }
  691. img2, _ := buildImage(testContextTemplate{fmt.Sprintf(`
  692. from %s
  693. entrypoint ["/bin/echo"]
  694. `, img.ID),
  695. nil, nil}, t, eng, true)
  696. if err != nil {
  697. t.Fatal(err)
  698. }
  699. // from child
  700. if img2.Config.Entrypoint[0] != "/bin/echo" {
  701. t.Fail()
  702. }
  703. // from parent
  704. if img.Config.PortSpecs[0] != "4243" {
  705. t.Fail()
  706. }
  707. }
  708. func TestBuildFails(t *testing.T) {
  709. _, err := buildImage(testContextTemplate{`
  710. from {IMAGE}
  711. run sh -c "exit 23"
  712. `,
  713. nil, nil}, t, nil, true)
  714. if err == nil {
  715. t.Fatal("Error should not be nil")
  716. }
  717. sterr, ok := err.(*utils.JSONError)
  718. if !ok {
  719. t.Fatalf("Error should be utils.JSONError")
  720. }
  721. if sterr.Code != 23 {
  722. t.Fatalf("StatusCode %d unexpected, should be 23", sterr.Code)
  723. }
  724. }
  725. func TestBuildFailsDockerfileEmpty(t *testing.T) {
  726. _, err := buildImage(testContextTemplate{``, nil, nil}, t, nil, true)
  727. if err != docker.ErrDockerfileEmpty {
  728. t.Fatal("Expected: %v, got: %v", docker.ErrDockerfileEmpty, err)
  729. }
  730. }