buildfile_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  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. {
  127. `
  128. from {IMAGE}
  129. env FOO BAR
  130. run [ "$FOO" = "BAR" ]
  131. `,
  132. nil,
  133. nil,
  134. },
  135. {
  136. `
  137. from {IMAGE}
  138. ENTRYPOINT /bin/echo
  139. CMD Hello world
  140. `,
  141. nil,
  142. nil,
  143. },
  144. {
  145. `
  146. from {IMAGE}
  147. VOLUME /test
  148. CMD Hello world
  149. `,
  150. nil,
  151. nil,
  152. },
  153. {
  154. `
  155. from {IMAGE}
  156. env FOO /foo/baz
  157. env BAR /bar
  158. env BAZ $BAR
  159. env FOOPATH $PATH:$FOO
  160. run [ "$BAR" = "$BAZ" ]
  161. run [ "$FOOPATH" = "$PATH:/foo/baz" ]
  162. `,
  163. nil,
  164. nil,
  165. },
  166. {
  167. `
  168. from {IMAGE}
  169. env FOO /bar
  170. env TEST testdir
  171. env BAZ /foobar
  172. add testfile $BAZ/
  173. add $TEST $FOO
  174. run [ "$(cat /foobar/testfile)" = "test1" ]
  175. run [ "$(cat /bar/withfile)" = "test2" ]
  176. `,
  177. [][2]string{
  178. {"testfile", "test1"},
  179. {"testdir/withfile", "test2"},
  180. },
  181. nil,
  182. },
  183. }
  184. // FIXME: test building with 2 successive overlapping ADD commands
  185. func constructDockerfile(template string, ip net.IP, port string) string {
  186. serverAddr := fmt.Sprintf("%s:%s", ip, port)
  187. replacer := strings.NewReplacer("{IMAGE}", unitTestImageID, "{SERVERADDR}", serverAddr)
  188. return replacer.Replace(template)
  189. }
  190. func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
  191. mux := http.NewServeMux()
  192. for _, file := range files {
  193. name, contents := file[0], file[1]
  194. mux.HandleFunc(name, func(w http.ResponseWriter, r *http.Request) {
  195. w.Write([]byte(contents))
  196. })
  197. }
  198. // This is how httptest.NewServer sets up a net.Listener, except that our listener must accept remote
  199. // connections (from the container).
  200. listener, err := net.Listen("tcp", ":0")
  201. if err != nil {
  202. return nil, err
  203. }
  204. s := httptest.NewUnstartedServer(mux)
  205. s.Listener = listener
  206. s.Start()
  207. return s, nil
  208. }
  209. func TestBuild(t *testing.T) {
  210. for _, ctx := range testContexts {
  211. _, err := buildImage(ctx, t, nil, true)
  212. if err != nil {
  213. t.Fatal(err)
  214. }
  215. }
  216. }
  217. func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, useCache bool) (*docker.Image, error) {
  218. if eng == nil {
  219. eng = NewTestEngine(t)
  220. runtime := mkRuntimeFromEngine(eng, t)
  221. // FIXME: we might not need runtime, why not simply nuke
  222. // the engine?
  223. defer nuke(runtime)
  224. }
  225. srv := mkServerFromEngine(eng, t)
  226. httpServer, err := mkTestingFileServer(context.remoteFiles)
  227. if err != nil {
  228. t.Fatal(err)
  229. }
  230. defer httpServer.Close()
  231. idx := strings.LastIndex(httpServer.URL, ":")
  232. if idx < 0 {
  233. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  234. }
  235. port := httpServer.URL[idx+1:]
  236. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  237. if iIP == nil {
  238. t.Fatal("Legacy bridgeIP field not set in engine")
  239. }
  240. ip, ok := iIP.(net.IP)
  241. if !ok {
  242. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  243. }
  244. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  245. buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  246. id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
  247. if err != nil {
  248. return nil, err
  249. }
  250. return srv.ImageInspect(id)
  251. }
  252. func TestVolume(t *testing.T) {
  253. img, err := buildImage(testContextTemplate{`
  254. from {IMAGE}
  255. volume /test
  256. cmd Hello world
  257. `, nil, nil}, t, nil, true)
  258. if err != nil {
  259. t.Fatal(err)
  260. }
  261. if len(img.Config.Volumes) == 0 {
  262. t.Fail()
  263. }
  264. for key := range img.Config.Volumes {
  265. if key != "/test" {
  266. t.Fail()
  267. }
  268. }
  269. }
  270. func TestBuildMaintainer(t *testing.T) {
  271. img, err := buildImage(testContextTemplate{`
  272. from {IMAGE}
  273. maintainer dockerio
  274. `, nil, nil}, t, nil, true)
  275. if err != nil {
  276. t.Fatal(err)
  277. }
  278. if img.Author != "dockerio" {
  279. t.Fail()
  280. }
  281. }
  282. func TestBuildUser(t *testing.T) {
  283. img, err := buildImage(testContextTemplate{`
  284. from {IMAGE}
  285. user dockerio
  286. `, nil, nil}, t, nil, true)
  287. if err != nil {
  288. t.Fatal(err)
  289. }
  290. if img.Config.User != "dockerio" {
  291. t.Fail()
  292. }
  293. }
  294. func TestBuildEnv(t *testing.T) {
  295. img, err := buildImage(testContextTemplate{`
  296. from {IMAGE}
  297. env port 4243
  298. `,
  299. nil, nil}, t, nil, true)
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. hasEnv := false
  304. for _, envVar := range img.Config.Env {
  305. if envVar == "port=4243" {
  306. hasEnv = true
  307. break
  308. }
  309. }
  310. if !hasEnv {
  311. t.Fail()
  312. }
  313. }
  314. func TestBuildCmd(t *testing.T) {
  315. img, err := buildImage(testContextTemplate{`
  316. from {IMAGE}
  317. cmd ["/bin/echo", "Hello World"]
  318. `,
  319. nil, nil}, t, nil, true)
  320. if err != nil {
  321. t.Fatal(err)
  322. }
  323. if img.Config.Cmd[0] != "/bin/echo" {
  324. t.Log(img.Config.Cmd[0])
  325. t.Fail()
  326. }
  327. if img.Config.Cmd[1] != "Hello World" {
  328. t.Log(img.Config.Cmd[1])
  329. t.Fail()
  330. }
  331. }
  332. func TestBuildExpose(t *testing.T) {
  333. img, err := buildImage(testContextTemplate{`
  334. from {IMAGE}
  335. expose 4243
  336. `,
  337. nil, nil}, t, nil, true)
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. if img.Config.PortSpecs[0] != "4243" {
  342. t.Fail()
  343. }
  344. }
  345. func TestBuildEntrypoint(t *testing.T) {
  346. img, err := buildImage(testContextTemplate{`
  347. from {IMAGE}
  348. entrypoint ["/bin/echo"]
  349. `,
  350. nil, nil}, t, nil, true)
  351. if err != nil {
  352. t.Fatal(err)
  353. }
  354. if img.Config.Entrypoint[0] != "/bin/echo" {
  355. t.Log(img.Config.Entrypoint[0])
  356. t.Fail()
  357. }
  358. }
  359. // testing #1405 - config.Cmd does not get cleaned up if
  360. // utilizing cache
  361. func TestBuildEntrypointRunCleanup(t *testing.T) {
  362. eng := NewTestEngine(t)
  363. defer nuke(mkRuntimeFromEngine(eng, t))
  364. img, err := buildImage(testContextTemplate{`
  365. from {IMAGE}
  366. run echo "hello"
  367. `,
  368. nil, nil}, t, eng, true)
  369. if err != nil {
  370. t.Fatal(err)
  371. }
  372. img, err = buildImage(testContextTemplate{`
  373. from {IMAGE}
  374. run echo "hello"
  375. add foo /foo
  376. entrypoint ["/bin/echo"]
  377. `,
  378. [][2]string{{"foo", "HEYO"}}, nil}, t, eng, true)
  379. if err != nil {
  380. t.Fatal(err)
  381. }
  382. if len(img.Config.Cmd) != 0 {
  383. t.Fail()
  384. }
  385. }
  386. func checkCacheBehavior(t *testing.T, template testContextTemplate, expectHit bool) (imageId string) {
  387. eng := NewTestEngine(t)
  388. defer nuke(mkRuntimeFromEngine(eng, t))
  389. img, err := buildImage(template, t, eng, true)
  390. if err != nil {
  391. t.Fatal(err)
  392. }
  393. imageId = img.ID
  394. img, err = buildImage(template, t, eng, expectHit)
  395. if err != nil {
  396. t.Fatal(err)
  397. }
  398. if hit := imageId == img.ID; hit != expectHit {
  399. t.Fatalf("Cache misbehavior, got hit=%t, expected hit=%t: (first: %s, second %s)", hit, expectHit, imageId, img.ID)
  400. }
  401. return
  402. }
  403. func checkCacheBehaviorFromEngime(t *testing.T, template testContextTemplate, expectHit bool, eng *engine.Engine) (imageId string) {
  404. img, err := buildImage(template, t, eng, true)
  405. if err != nil {
  406. t.Fatal(err)
  407. }
  408. imageId = img.ID
  409. img, err = buildImage(template, t, eng, expectHit)
  410. if err != nil {
  411. t.Fatal(err)
  412. }
  413. if hit := imageId == img.ID; hit != expectHit {
  414. t.Fatalf("Cache misbehavior, got hit=%t, expected hit=%t: (first: %s, second %s)", hit, expectHit, imageId, img.ID)
  415. }
  416. return
  417. }
  418. func TestBuildImageWithCache(t *testing.T) {
  419. template := testContextTemplate{`
  420. from {IMAGE}
  421. maintainer dockerio
  422. `,
  423. nil, nil}
  424. checkCacheBehavior(t, template, true)
  425. }
  426. func TestBuildImageWithoutCache(t *testing.T) {
  427. template := testContextTemplate{`
  428. from {IMAGE}
  429. maintainer dockerio
  430. `,
  431. nil, nil}
  432. checkCacheBehavior(t, template, false)
  433. }
  434. func TestBuildADDLocalFileWithCache(t *testing.T) {
  435. template := testContextTemplate{`
  436. from {IMAGE}
  437. maintainer dockerio
  438. run echo "first"
  439. add foo /usr/lib/bla/bar
  440. run [ "$(cat /usr/lib/bla/bar)" = "hello" ]
  441. run echo "second"
  442. add . /src/
  443. run [ "$(cat /src/foo)" = "hello" ]
  444. `,
  445. [][2]string{
  446. {"foo", "hello"},
  447. },
  448. nil}
  449. eng := NewTestEngine(t)
  450. defer nuke(mkRuntimeFromEngine(eng, t))
  451. id1 := checkCacheBehaviorFromEngime(t, template, true, eng)
  452. template.files = append(template.files, [2]string{"bar", "hello2"})
  453. id2 := checkCacheBehaviorFromEngime(t, template, true, eng)
  454. if id1 == id2 {
  455. t.Fatal("The cache should have been invalided but hasn't.")
  456. }
  457. id3 := checkCacheBehaviorFromEngime(t, template, true, eng)
  458. if id2 != id3 {
  459. t.Fatal("The cache should have been used but hasn't.")
  460. }
  461. template.files[1][1] = "hello3"
  462. id4 := checkCacheBehaviorFromEngime(t, template, true, eng)
  463. if id3 == id4 {
  464. t.Fatal("The cache should have been invalided but hasn't.")
  465. }
  466. template.dockerfile += `
  467. add ./bar /src2/
  468. run ls /src2/bar
  469. `
  470. id5 := checkCacheBehaviorFromEngime(t, template, true, eng)
  471. if id4 == id5 {
  472. t.Fatal("The cache should have been invalided but hasn't.")
  473. }
  474. template.files[1][1] = "hello4"
  475. id6 := checkCacheBehaviorFromEngime(t, template, true, eng)
  476. if id5 == id6 {
  477. t.Fatal("The cache should have been invalided but hasn't.")
  478. }
  479. template.dockerfile += `
  480. add bar /src2/bar2
  481. add /bar /src2/bar3
  482. run ls /src2/bar2 /src2/bar3
  483. `
  484. id7 := checkCacheBehaviorFromEngime(t, template, true, eng)
  485. if id6 == id7 {
  486. t.Fatal("The cache should have been invalided but hasn't.")
  487. }
  488. template.files[1][1] = "hello5"
  489. id8 := checkCacheBehaviorFromEngime(t, template, true, eng)
  490. if id7 == id8 {
  491. t.Fatal("The cache should have been invalided but hasn't.")
  492. }
  493. }
  494. func TestBuildADDLocalFileWithoutCache(t *testing.T) {
  495. template := testContextTemplate{`
  496. from {IMAGE}
  497. maintainer dockerio
  498. run echo "first"
  499. add foo /usr/lib/bla/bar
  500. run echo "second"
  501. `,
  502. [][2]string{{"foo", "hello"}},
  503. nil}
  504. checkCacheBehavior(t, template, false)
  505. }
  506. func TestBuildADDRemoteFileWithCache(t *testing.T) {
  507. template := testContextTemplate{`
  508. from {IMAGE}
  509. maintainer dockerio
  510. run echo "first"
  511. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  512. run echo "second"
  513. `,
  514. nil,
  515. [][2]string{{"/baz", "world!"}}}
  516. checkCacheBehavior(t, template, true)
  517. }
  518. func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
  519. template := testContextTemplate{`
  520. from {IMAGE}
  521. maintainer dockerio
  522. run echo "first"
  523. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  524. run echo "second"
  525. `,
  526. nil,
  527. [][2]string{{"/baz", "world!"}}}
  528. checkCacheBehavior(t, template, false)
  529. }
  530. func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
  531. template := testContextTemplate{`
  532. from {IMAGE}
  533. maintainer dockerio
  534. run echo "first"
  535. add foo /usr/lib/bla/bar
  536. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  537. run echo "second"
  538. `,
  539. [][2]string{{"foo", "hello"}},
  540. [][2]string{{"/baz", "world!"}}}
  541. checkCacheBehavior(t, template, true)
  542. }
  543. func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
  544. template := testContextTemplate{`
  545. from {IMAGE}
  546. maintainer dockerio
  547. run echo "first"
  548. add foo /usr/lib/bla/bar
  549. add http://{SERVERADDR}/baz /usr/lib/baz/quux
  550. run echo "second"
  551. `,
  552. [][2]string{{"foo", "hello"}},
  553. [][2]string{{"/baz", "world!"}}}
  554. checkCacheBehavior(t, template, false)
  555. }
  556. func TestForbiddenContextPath(t *testing.T) {
  557. eng := NewTestEngine(t)
  558. defer nuke(mkRuntimeFromEngine(eng, t))
  559. srv := mkServerFromEngine(eng, t)
  560. context := testContextTemplate{`
  561. from {IMAGE}
  562. maintainer dockerio
  563. add ../../ test/
  564. `,
  565. [][2]string{{"test.txt", "test1"}, {"other.txt", "other"}}, nil}
  566. httpServer, err := mkTestingFileServer(context.remoteFiles)
  567. if err != nil {
  568. t.Fatal(err)
  569. }
  570. defer httpServer.Close()
  571. idx := strings.LastIndex(httpServer.URL, ":")
  572. if idx < 0 {
  573. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  574. }
  575. port := httpServer.URL[idx+1:]
  576. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  577. if iIP == nil {
  578. t.Fatal("Legacy bridgeIP field not set in engine")
  579. }
  580. ip, ok := iIP.(net.IP)
  581. if !ok {
  582. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  583. }
  584. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  585. buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  586. _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
  587. if err == nil {
  588. t.Log("Error should not be nil")
  589. t.Fail()
  590. }
  591. if err.Error() != "Forbidden path outside the build context: ../../ (/)" {
  592. t.Logf("Error message is not expected: %s", err.Error())
  593. t.Fail()
  594. }
  595. }
  596. func TestBuildADDFileNotFound(t *testing.T) {
  597. eng := NewTestEngine(t)
  598. defer nuke(mkRuntimeFromEngine(eng, t))
  599. context := testContextTemplate{`
  600. from {IMAGE}
  601. add foo /usr/local/bar
  602. `,
  603. nil, nil}
  604. httpServer, err := mkTestingFileServer(context.remoteFiles)
  605. if err != nil {
  606. t.Fatal(err)
  607. }
  608. defer httpServer.Close()
  609. idx := strings.LastIndex(httpServer.URL, ":")
  610. if idx < 0 {
  611. t.Fatalf("could not get port from test http server address %s", httpServer.URL)
  612. }
  613. port := httpServer.URL[idx+1:]
  614. iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
  615. if iIP == nil {
  616. t.Fatal("Legacy bridgeIP field not set in engine")
  617. }
  618. ip, ok := iIP.(net.IP)
  619. if !ok {
  620. panic("Legacy bridgeIP field in engine does not cast to net.IP")
  621. }
  622. dockerfile := constructDockerfile(context.dockerfile, ip, port)
  623. buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil)
  624. _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
  625. if err == nil {
  626. t.Log("Error should not be nil")
  627. t.Fail()
  628. }
  629. if err.Error() != "foo: no such file or directory" {
  630. t.Logf("Error message is not expected: %s", err.Error())
  631. t.Fail()
  632. }
  633. }
  634. func TestBuildInheritance(t *testing.T) {
  635. eng := NewTestEngine(t)
  636. defer nuke(mkRuntimeFromEngine(eng, t))
  637. img, err := buildImage(testContextTemplate{`
  638. from {IMAGE}
  639. expose 4243
  640. `,
  641. nil, nil}, t, eng, true)
  642. if err != nil {
  643. t.Fatal(err)
  644. }
  645. img2, _ := buildImage(testContextTemplate{fmt.Sprintf(`
  646. from %s
  647. entrypoint ["/bin/echo"]
  648. `, img.ID),
  649. nil, nil}, t, eng, true)
  650. if err != nil {
  651. t.Fatal(err)
  652. }
  653. // from child
  654. if img2.Config.Entrypoint[0] != "/bin/echo" {
  655. t.Fail()
  656. }
  657. // from parent
  658. if img.Config.PortSpecs[0] != "4243" {
  659. t.Fail()
  660. }
  661. }
  662. func TestBuildFails(t *testing.T) {
  663. _, err := buildImage(testContextTemplate{`
  664. from {IMAGE}
  665. run sh -c "exit 23"
  666. `,
  667. nil, nil}, t, nil, true)
  668. if err == nil {
  669. t.Fatal("Error should not be nil")
  670. }
  671. sterr, ok := err.(*utils.JSONError)
  672. if !ok {
  673. t.Fatalf("Error should be utils.JSONError")
  674. }
  675. if sterr.Code != 23 {
  676. t.Fatalf("StatusCode %d unexpected, should be 23", sterr.Code)
  677. }
  678. }
  679. func TestBuildFailsDockerfileEmpty(t *testing.T) {
  680. _, err := buildImage(testContextTemplate{``, nil, nil}, t, nil, true)
  681. if err != docker.ErrDockerfileEmpty {
  682. t.Fatal("Expected: %v, got: %v", docker.ErrDockerfileEmpty, err)
  683. }
  684. }