utils_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package docker
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker/engine"
  5. "github.com/dotcloud/docker/utils"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "path"
  10. "runtime"
  11. "strings"
  12. "testing"
  13. )
  14. // This file contains utility functions for docker's unit test suite.
  15. // It has to be named XXX_test.go, apparently, in other to access private functions
  16. // from other XXX_test.go functions.
  17. var globalTestID string
  18. // Create a temporary runtime suitable for unit testing.
  19. // Call t.Fatal() at the first error.
  20. func mkRuntime(f utils.Fataler) *Runtime {
  21. root, err := newTestDirectory(unitTestStoreBase)
  22. if err != nil {
  23. f.Fatal(err)
  24. }
  25. config := &DaemonConfig{
  26. Root: root,
  27. AutoRestart: false,
  28. }
  29. r, err := NewRuntimeFromDirectory(config)
  30. if err != nil {
  31. f.Fatal(err)
  32. }
  33. r.UpdateCapabilities(true)
  34. return r
  35. }
  36. func createNamedTestContainer(eng *engine.Engine, config *Config, f utils.Fataler, name string) (shortId string) {
  37. job := eng.Job("create", name)
  38. if err := job.ImportEnv(config); err != nil {
  39. f.Fatal(err)
  40. }
  41. job.StdoutParseString(&shortId)
  42. if err := job.Run(); err != nil {
  43. f.Fatal(err)
  44. }
  45. return
  46. }
  47. func createTestContainer(eng *engine.Engine, config *Config, f utils.Fataler) (shortId string) {
  48. return createNamedTestContainer(eng, config, f, "")
  49. }
  50. func mkServerFromEngine(eng *engine.Engine, t utils.Fataler) *Server {
  51. iSrv := eng.Hack_GetGlobalVar("httpapi.server")
  52. if iSrv == nil {
  53. panic("Legacy server field not set in engine")
  54. }
  55. srv, ok := iSrv.(*Server)
  56. if !ok {
  57. panic("Legacy server field in engine does not cast to *Server")
  58. }
  59. return srv
  60. }
  61. func NewTestEngine(t utils.Fataler) *engine.Engine {
  62. root, err := newTestDirectory(unitTestStoreBase)
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. eng, err := engine.New(root)
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. // Load default plugins
  71. // (This is manually copied and modified from main() until we have a more generic plugin system)
  72. job := eng.Job("initapi")
  73. job.Setenv("Root", root)
  74. job.SetenvBool("AutoRestart", false)
  75. if err := job.Run(); err != nil {
  76. t.Fatal(err)
  77. }
  78. return eng
  79. }
  80. func newTestDirectory(templateDir string) (dir string, err error) {
  81. if globalTestID == "" {
  82. globalTestID = GenerateID()[:4]
  83. }
  84. prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, getCallerName(2))
  85. if prefix == "" {
  86. prefix = "docker-test-"
  87. }
  88. dir, err = ioutil.TempDir("", prefix)
  89. if err = os.Remove(dir); err != nil {
  90. return
  91. }
  92. if err = utils.CopyDirectory(templateDir, dir); err != nil {
  93. return
  94. }
  95. return
  96. }
  97. func getCallerName(depth int) string {
  98. // Use the caller function name as a prefix.
  99. // This helps trace temp directories back to their test.
  100. pc, _, _, _ := runtime.Caller(depth + 1)
  101. callerLongName := runtime.FuncForPC(pc).Name()
  102. parts := strings.Split(callerLongName, ".")
  103. callerShortName := parts[len(parts)-1]
  104. return callerShortName
  105. }
  106. // Write `content` to the file at path `dst`, creating it if necessary,
  107. // as well as any missing directories.
  108. // The file is truncated if it already exists.
  109. // Call t.Fatal() at the first error.
  110. func writeFile(dst, content string, t *testing.T) {
  111. // Create subdirectories if necessary
  112. if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
  113. t.Fatal(err)
  114. }
  115. f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
  116. if err != nil {
  117. t.Fatal(err)
  118. }
  119. // Write content (truncate if it exists)
  120. if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
  121. t.Fatal(err)
  122. }
  123. }
  124. // Return the contents of file at path `src`.
  125. // Call t.Fatal() at the first error (including if the file doesn't exist)
  126. func readFile(src string, t *testing.T) (content string) {
  127. f, err := os.Open(src)
  128. if err != nil {
  129. t.Fatal(err)
  130. }
  131. data, err := ioutil.ReadAll(f)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. return string(data)
  136. }
  137. // Create a test container from the given runtime `r` and run arguments `args`.
  138. // If the image name is "_", (eg. []string{"-i", "-t", "_", "bash"}, it is
  139. // dynamically replaced by the current test image.
  140. // The caller is responsible for destroying the container.
  141. // Call t.Fatal() at the first error.
  142. func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, error) {
  143. config, hostConfig, _, err := ParseRun(args, nil)
  144. defer func() {
  145. if err != nil && t != nil {
  146. t.Fatal(err)
  147. }
  148. }()
  149. if err != nil {
  150. return nil, err
  151. }
  152. if config.Image == "_" {
  153. config.Image = GetTestImage(r).ID
  154. }
  155. c, _, err := r.Create(config, "")
  156. if err != nil {
  157. return nil, err
  158. }
  159. c.hostConfig = hostConfig
  160. return c, nil
  161. }
  162. // Create a test container, start it, wait for it to complete, destroy it,
  163. // and return its standard output as a string.
  164. // The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
  165. // If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
  166. func runContainer(r *Runtime, args []string, t *testing.T) (output string, err error) {
  167. defer func() {
  168. if err != nil && t != nil {
  169. t.Fatal(err)
  170. }
  171. }()
  172. container, err := mkContainer(r, args, t)
  173. if err != nil {
  174. return "", err
  175. }
  176. defer r.Destroy(container)
  177. stdout, err := container.StdoutPipe()
  178. if err != nil {
  179. return "", err
  180. }
  181. defer stdout.Close()
  182. if err := container.Start(); err != nil {
  183. return "", err
  184. }
  185. container.Wait()
  186. data, err := ioutil.ReadAll(stdout)
  187. if err != nil {
  188. return "", err
  189. }
  190. output = string(data)
  191. return
  192. }
  193. func TestCompareConfig(t *testing.T) {
  194. volumes1 := make(map[string]struct{})
  195. volumes1["/test1"] = struct{}{}
  196. config1 := Config{
  197. Dns: []string{"1.1.1.1", "2.2.2.2"},
  198. PortSpecs: []string{"1111:1111", "2222:2222"},
  199. Env: []string{"VAR1=1", "VAR2=2"},
  200. VolumesFrom: "11111111",
  201. Volumes: volumes1,
  202. }
  203. config2 := Config{
  204. Dns: []string{"0.0.0.0", "2.2.2.2"},
  205. PortSpecs: []string{"1111:1111", "2222:2222"},
  206. Env: []string{"VAR1=1", "VAR2=2"},
  207. VolumesFrom: "11111111",
  208. Volumes: volumes1,
  209. }
  210. config3 := Config{
  211. Dns: []string{"1.1.1.1", "2.2.2.2"},
  212. PortSpecs: []string{"0000:0000", "2222:2222"},
  213. Env: []string{"VAR1=1", "VAR2=2"},
  214. VolumesFrom: "11111111",
  215. Volumes: volumes1,
  216. }
  217. config4 := Config{
  218. Dns: []string{"1.1.1.1", "2.2.2.2"},
  219. PortSpecs: []string{"0000:0000", "2222:2222"},
  220. Env: []string{"VAR1=1", "VAR2=2"},
  221. VolumesFrom: "22222222",
  222. Volumes: volumes1,
  223. }
  224. volumes2 := make(map[string]struct{})
  225. volumes2["/test2"] = struct{}{}
  226. config5 := Config{
  227. Dns: []string{"1.1.1.1", "2.2.2.2"},
  228. PortSpecs: []string{"0000:0000", "2222:2222"},
  229. Env: []string{"VAR1=1", "VAR2=2"},
  230. VolumesFrom: "11111111",
  231. Volumes: volumes2,
  232. }
  233. if CompareConfig(&config1, &config2) {
  234. t.Fatalf("CompareConfig should return false, Dns are different")
  235. }
  236. if CompareConfig(&config1, &config3) {
  237. t.Fatalf("CompareConfig should return false, PortSpecs are different")
  238. }
  239. if CompareConfig(&config1, &config4) {
  240. t.Fatalf("CompareConfig should return false, VolumesFrom are different")
  241. }
  242. if CompareConfig(&config1, &config5) {
  243. t.Fatalf("CompareConfig should return false, Volumes are different")
  244. }
  245. if !CompareConfig(&config1, &config1) {
  246. t.Fatalf("CompareConfig should return true")
  247. }
  248. }
  249. func TestMergeConfig(t *testing.T) {
  250. volumesImage := make(map[string]struct{})
  251. volumesImage["/test1"] = struct{}{}
  252. volumesImage["/test2"] = struct{}{}
  253. configImage := &Config{
  254. Dns: []string{"1.1.1.1", "2.2.2.2"},
  255. PortSpecs: []string{"1111:1111", "2222:2222"},
  256. Env: []string{"VAR1=1", "VAR2=2"},
  257. VolumesFrom: "1111",
  258. Volumes: volumesImage,
  259. }
  260. volumesUser := make(map[string]struct{})
  261. volumesUser["/test3"] = struct{}{}
  262. configUser := &Config{
  263. Dns: []string{"3.3.3.3"},
  264. PortSpecs: []string{"3333:2222", "3333:3333"},
  265. Env: []string{"VAR2=3", "VAR3=3"},
  266. Volumes: volumesUser,
  267. }
  268. if err := MergeConfig(configUser, configImage); err != nil {
  269. t.Error(err)
  270. }
  271. if len(configUser.Dns) != 3 {
  272. t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
  273. }
  274. for _, dns := range configUser.Dns {
  275. if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
  276. t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
  277. }
  278. }
  279. if len(configUser.ExposedPorts) != 3 {
  280. t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
  281. }
  282. for portSpecs := range configUser.ExposedPorts {
  283. if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
  284. t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
  285. }
  286. }
  287. if len(configUser.Env) != 3 {
  288. t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
  289. }
  290. for _, env := range configUser.Env {
  291. if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
  292. t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
  293. }
  294. }
  295. if len(configUser.Volumes) != 3 {
  296. t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
  297. }
  298. for v := range configUser.Volumes {
  299. if v != "/test1" && v != "/test2" && v != "/test3" {
  300. t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
  301. }
  302. }
  303. if configUser.VolumesFrom != "1111" {
  304. t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
  305. }
  306. ports, _, err := parsePortSpecs([]string{"0000"})
  307. if err != nil {
  308. t.Error(err)
  309. }
  310. configImage2 := &Config{
  311. ExposedPorts: ports,
  312. }
  313. if err := MergeConfig(configUser, configImage2); err != nil {
  314. t.Error(err)
  315. }
  316. if len(configUser.ExposedPorts) != 4 {
  317. t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
  318. }
  319. for portSpecs := range configUser.ExposedPorts {
  320. if portSpecs.Port() != "0000" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
  321. t.Fatalf("Expected 0000 or 1111 or 2222 or 3333, found %s", portSpecs)
  322. }
  323. }
  324. }
  325. func TestParseLxcConfOpt(t *testing.T) {
  326. opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
  327. for _, o := range opts {
  328. k, v, err := parseLxcOpt(o)
  329. if err != nil {
  330. t.FailNow()
  331. }
  332. if k != "lxc.utsname" {
  333. t.Fail()
  334. }
  335. if v != "docker" {
  336. t.Fail()
  337. }
  338. }
  339. }
  340. func TestParseNetworkOptsPrivateOnly(t *testing.T) {
  341. ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. if len(ports) != 1 {
  346. t.Logf("Expected 1 got %d", len(ports))
  347. t.FailNow()
  348. }
  349. if len(bindings) != 1 {
  350. t.Logf("Expected 1 got %d", len(bindings))
  351. t.FailNow()
  352. }
  353. for k := range ports {
  354. if k.Proto() != "tcp" {
  355. t.Logf("Expected tcp got %s", k.Proto())
  356. t.Fail()
  357. }
  358. if k.Port() != "80" {
  359. t.Logf("Expected 80 got %s", k.Port())
  360. t.Fail()
  361. }
  362. b, exists := bindings[k]
  363. if !exists {
  364. t.Log("Binding does not exist")
  365. t.FailNow()
  366. }
  367. if len(b) != 1 {
  368. t.Logf("Expected 1 got %d", len(b))
  369. t.FailNow()
  370. }
  371. s := b[0]
  372. if s.HostPort != "" {
  373. t.Logf("Expected \"\" got %s", s.HostPort)
  374. t.Fail()
  375. }
  376. if s.HostIp != "192.168.1.100" {
  377. t.Fail()
  378. }
  379. }
  380. }
  381. func TestParseNetworkOptsPublic(t *testing.T) {
  382. ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
  383. if err != nil {
  384. t.Fatal(err)
  385. }
  386. if len(ports) != 1 {
  387. t.Logf("Expected 1 got %d", len(ports))
  388. t.FailNow()
  389. }
  390. if len(bindings) != 1 {
  391. t.Logf("Expected 1 got %d", len(bindings))
  392. t.FailNow()
  393. }
  394. for k := range ports {
  395. if k.Proto() != "tcp" {
  396. t.Logf("Expected tcp got %s", k.Proto())
  397. t.Fail()
  398. }
  399. if k.Port() != "80" {
  400. t.Logf("Expected 80 got %s", k.Port())
  401. t.Fail()
  402. }
  403. b, exists := bindings[k]
  404. if !exists {
  405. t.Log("Binding does not exist")
  406. t.FailNow()
  407. }
  408. if len(b) != 1 {
  409. t.Logf("Expected 1 got %d", len(b))
  410. t.FailNow()
  411. }
  412. s := b[0]
  413. if s.HostPort != "8080" {
  414. t.Logf("Expected 8080 got %s", s.HostPort)
  415. t.Fail()
  416. }
  417. if s.HostIp != "192.168.1.100" {
  418. t.Fail()
  419. }
  420. }
  421. }
  422. func TestParseNetworkOptsUdp(t *testing.T) {
  423. ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
  424. if err != nil {
  425. t.Fatal(err)
  426. }
  427. if len(ports) != 1 {
  428. t.Logf("Expected 1 got %d", len(ports))
  429. t.FailNow()
  430. }
  431. if len(bindings) != 1 {
  432. t.Logf("Expected 1 got %d", len(bindings))
  433. t.FailNow()
  434. }
  435. for k := range ports {
  436. if k.Proto() != "udp" {
  437. t.Logf("Expected udp got %s", k.Proto())
  438. t.Fail()
  439. }
  440. if k.Port() != "6000" {
  441. t.Logf("Expected 6000 got %s", k.Port())
  442. t.Fail()
  443. }
  444. b, exists := bindings[k]
  445. if !exists {
  446. t.Log("Binding does not exist")
  447. t.FailNow()
  448. }
  449. if len(b) != 1 {
  450. t.Logf("Expected 1 got %d", len(b))
  451. t.FailNow()
  452. }
  453. s := b[0]
  454. if s.HostPort != "" {
  455. t.Logf("Expected \"\" got %s", s.HostPort)
  456. t.Fail()
  457. }
  458. if s.HostIp != "192.168.1.100" {
  459. t.Fail()
  460. }
  461. }
  462. }