utils_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. package integration
  2. import (
  3. "io"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "path"
  8. "runtime"
  9. "strings"
  10. "testing"
  11. "time"
  12. )
  13. func TestIsKilledFalseWithNonKilledProcess(t *testing.T) {
  14. lsCmd := exec.Command("ls")
  15. lsCmd.Start()
  16. // Wait for it to finish
  17. err := lsCmd.Wait()
  18. if IsKilled(err) {
  19. t.Fatalf("Expected the ls command to not be killed, was.")
  20. }
  21. }
  22. func TestIsKilledTrueWithKilledProcess(t *testing.T) {
  23. longCmd := exec.Command("top")
  24. // Start a command
  25. longCmd.Start()
  26. // Capture the error when *dying*
  27. done := make(chan error, 1)
  28. go func() {
  29. done <- longCmd.Wait()
  30. }()
  31. // Then kill it
  32. longCmd.Process.Kill()
  33. // Get the error
  34. err := <-done
  35. if !IsKilled(err) {
  36. t.Fatalf("Expected the command to be killed, was not.")
  37. }
  38. }
  39. func TestRunCommandWithOutput(t *testing.T) {
  40. echoHelloWorldCmd := exec.Command("echo", "hello", "world")
  41. out, exitCode, err := RunCommandWithOutput(echoHelloWorldCmd)
  42. expected := "hello world\n"
  43. if out != expected || exitCode != 0 || err != nil {
  44. t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expected, out, err, exitCode)
  45. }
  46. }
  47. func TestRunCommandWithOutputError(t *testing.T) {
  48. cmd := exec.Command("doesnotexists")
  49. out, exitCode, err := RunCommandWithOutput(cmd)
  50. expectedError := `exec: "doesnotexists": executable file not found in $PATH`
  51. if out != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
  52. t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expectedError, out, err, exitCode)
  53. }
  54. wrongLsCmd := exec.Command("ls", "-z")
  55. expected := `ls: invalid option -- 'z'
  56. Try 'ls --help' for more information.
  57. `
  58. out, exitCode, err = RunCommandWithOutput(wrongLsCmd)
  59. if out != expected || exitCode != 2 || err == nil || err.Error() != "exit status 2" {
  60. t.Fatalf("Expected command to output %s, got out:%s, err:%v with exitCode %v", expected, out, err, exitCode)
  61. }
  62. }
  63. func TestRunCommandWithStdoutStderr(t *testing.T) {
  64. echoHelloWorldCmd := exec.Command("echo", "hello", "world")
  65. stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(echoHelloWorldCmd)
  66. expected := "hello world\n"
  67. if stdout != expected || stderr != "" || exitCode != 0 || err != nil {
  68. t.Fatalf("Expected command to output %s, got stdout:%s, stderr:%s, err:%v with exitCode %v", expected, stdout, stderr, err, exitCode)
  69. }
  70. }
  71. func TestRunCommandWithStdoutStderrError(t *testing.T) {
  72. cmd := exec.Command("doesnotexists")
  73. stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(cmd)
  74. expectedError := `exec: "doesnotexists": executable file not found in $PATH`
  75. if stdout != "" || stderr != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
  76. t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", "", stdout, stderr, err, exitCode)
  77. }
  78. wrongLsCmd := exec.Command("ls", "-z")
  79. expected := `ls: invalid option -- 'z'
  80. Try 'ls --help' for more information.
  81. `
  82. stdout, stderr, exitCode, err = RunCommandWithStdoutStderr(wrongLsCmd)
  83. if stdout != "" && stderr != expected || exitCode != 2 || err == nil || err.Error() != "exit status 2" {
  84. t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", expectedError, stdout, stderr, err, exitCode)
  85. }
  86. }
  87. func TestRunCommandWithOutputForDurationFinished(t *testing.T) {
  88. cmd := exec.Command("ls")
  89. out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 50*time.Millisecond)
  90. if out == "" || exitCode != 0 || timedOut || err != nil {
  91. t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], timedOut:[%v], err:[%v]", out, exitCode, timedOut, err)
  92. }
  93. }
  94. func TestRunCommandWithOutputForDurationKilled(t *testing.T) {
  95. cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
  96. out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 500*time.Millisecond)
  97. ones := strings.Split(out, "\n")
  98. if len(ones) != 6 || exitCode != 0 || !timedOut || err != nil {
  99. t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out, but did not : out:[%s], exitCode:%d, timedOut:%v, err:%v", out, exitCode, timedOut, err)
  100. }
  101. }
  102. func TestRunCommandWithOutputForDurationErrors(t *testing.T) {
  103. cmd := exec.Command("ls")
  104. cmd.Stdout = os.Stdout
  105. if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
  106. t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
  107. }
  108. cmd = exec.Command("ls")
  109. cmd.Stderr = os.Stderr
  110. if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
  111. t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
  112. }
  113. }
  114. func TestRunCommandWithOutputAndTimeoutFinished(t *testing.T) {
  115. cmd := exec.Command("ls")
  116. out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 50*time.Millisecond)
  117. if out == "" || exitCode != 0 || err != nil {
  118. t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], err:[%v]", out, exitCode, err)
  119. }
  120. }
  121. func TestRunCommandWithOutputAndTimeoutKilled(t *testing.T) {
  122. cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
  123. out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 500*time.Millisecond)
  124. ones := strings.Split(out, "\n")
  125. if len(ones) != 6 || exitCode != 0 || err == nil || err.Error() != "command timed out" {
  126. t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out with an error 'command timed out', but did not : out:[%s], exitCode:%d, err:%v", out, exitCode, err)
  127. }
  128. }
  129. func TestRunCommandWithOutputAndTimeoutErrors(t *testing.T) {
  130. cmd := exec.Command("ls")
  131. cmd.Stdout = os.Stdout
  132. if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
  133. t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
  134. }
  135. cmd = exec.Command("ls")
  136. cmd.Stderr = os.Stderr
  137. if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
  138. t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
  139. }
  140. }
  141. func TestRunCommand(t *testing.T) {
  142. lsCmd := exec.Command("ls")
  143. exitCode, err := RunCommand(lsCmd)
  144. if exitCode != 0 || err != nil {
  145. t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
  146. }
  147. var expectedError string
  148. exitCode, err = RunCommand(exec.Command("doesnotexists"))
  149. expectedError = `exec: "doesnotexists": executable file not found in $PATH`
  150. if exitCode != 127 || err == nil || err.Error() != expectedError {
  151. t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
  152. }
  153. wrongLsCmd := exec.Command("ls", "-z")
  154. expected := 2
  155. expectedError = `exit status 2`
  156. exitCode, err = RunCommand(wrongLsCmd)
  157. if exitCode != expected || err == nil || err.Error() != expectedError {
  158. t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
  159. }
  160. }
  161. func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) {
  162. _, _, err := RunCommandPipelineWithOutput(exec.Command("ls"))
  163. expectedError := "pipeline does not have multiple cmds"
  164. if err == nil || err.Error() != expectedError {
  165. t.Fatalf("Expected an error with %s, got err:%s", expectedError, err)
  166. }
  167. }
  168. func TestRunCommandPipelineWithOutputErrors(t *testing.T) {
  169. cmd1 := exec.Command("ls")
  170. cmd1.Stdout = os.Stdout
  171. cmd2 := exec.Command("anything really")
  172. _, _, err := RunCommandPipelineWithOutput(cmd1, cmd2)
  173. if err == nil || err.Error() != "cannot set stdout pipe for anything really: exec: Stdout already set" {
  174. t.Fatalf("Expected an error, got %v", err)
  175. }
  176. cmdWithError := exec.Command("doesnotexists")
  177. cmdCat := exec.Command("cat")
  178. _, _, err = RunCommandPipelineWithOutput(cmdWithError, cmdCat)
  179. if err == nil || err.Error() != `starting doesnotexists failed with error: exec: "doesnotexists": executable file not found in $PATH` {
  180. t.Fatalf("Expected an error, got %v", err)
  181. }
  182. }
  183. func TestRunCommandPipelineWithOutput(t *testing.T) {
  184. cmds := []*exec.Cmd{
  185. // Print 2 characters
  186. exec.Command("echo", "-n", "11"),
  187. // Count the number or char from stdin (previous command)
  188. exec.Command("wc", "-m"),
  189. }
  190. out, exitCode, err := RunCommandPipelineWithOutput(cmds...)
  191. expectedOutput := "2\n"
  192. if out != expectedOutput || exitCode != 0 || err != nil {
  193. t.Fatalf("Expected %s for commands %v, got out:%s, exitCode:%d, err:%v", expectedOutput, cmds, out, exitCode, err)
  194. }
  195. }
  196. // Simple simple test as it is just a passthrough for json.Unmarshal
  197. func TestUnmarshalJSON(t *testing.T) {
  198. emptyResult := struct{}{}
  199. if err := UnmarshalJSON([]byte(""), &emptyResult); err == nil {
  200. t.Fatalf("Expected an error, got nothing")
  201. }
  202. result := struct{ Name string }{}
  203. if err := UnmarshalJSON([]byte(`{"name": "name"}`), &result); err != nil {
  204. t.Fatal(err)
  205. }
  206. if result.Name != "name" {
  207. t.Fatalf("Expected result.name to be 'name', was '%s'", result.Name)
  208. }
  209. }
  210. func TestConvertSliceOfStringsToMap(t *testing.T) {
  211. input := []string{"a", "b"}
  212. actual := ConvertSliceOfStringsToMap(input)
  213. for _, key := range input {
  214. if _, ok := actual[key]; !ok {
  215. t.Fatalf("Expected output to contains key %s, did not: %v", key, actual)
  216. }
  217. }
  218. }
  219. func TestCompareDirectoryEntries(t *testing.T) {
  220. tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-compare-directories")
  221. if err != nil {
  222. t.Fatal(err)
  223. }
  224. defer os.RemoveAll(tmpFolder)
  225. file1 := path.Join(tmpFolder, "file1")
  226. file2 := path.Join(tmpFolder, "file2")
  227. os.Create(file1)
  228. os.Create(file2)
  229. fi1, err := os.Stat(file1)
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. fi1bis, err := os.Stat(file1)
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. fi2, err := os.Stat(file2)
  238. if err != nil {
  239. t.Fatal(err)
  240. }
  241. cases := []struct {
  242. e1 []os.FileInfo
  243. e2 []os.FileInfo
  244. shouldError bool
  245. }{
  246. // Empty directories
  247. {
  248. []os.FileInfo{},
  249. []os.FileInfo{},
  250. false,
  251. },
  252. // Same FileInfos
  253. {
  254. []os.FileInfo{fi1},
  255. []os.FileInfo{fi1},
  256. false,
  257. },
  258. // Different FileInfos but same names
  259. {
  260. []os.FileInfo{fi1},
  261. []os.FileInfo{fi1bis},
  262. false,
  263. },
  264. // Different FileInfos, different names
  265. {
  266. []os.FileInfo{fi1},
  267. []os.FileInfo{fi2},
  268. true,
  269. },
  270. }
  271. for _, elt := range cases {
  272. err := CompareDirectoryEntries(elt.e1, elt.e2)
  273. if elt.shouldError && err == nil {
  274. t.Fatalf("Should have return an error, did not with %v and %v", elt.e1, elt.e2)
  275. }
  276. if !elt.shouldError && err != nil {
  277. t.Fatalf("Should have not returned an error, but did : %v with %v and %v", err, elt.e1, elt.e2)
  278. }
  279. }
  280. }
  281. // FIXME make an "unhappy path" test for ListTar without "panicing" :-)
  282. func TestListTar(t *testing.T) {
  283. tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-list-tar")
  284. if err != nil {
  285. t.Fatal(err)
  286. }
  287. defer os.RemoveAll(tmpFolder)
  288. // Let's create a Tar file
  289. srcFile := path.Join(tmpFolder, "src")
  290. tarFile := path.Join(tmpFolder, "src.tar")
  291. os.Create(srcFile)
  292. cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
  293. _, err = cmd.CombinedOutput()
  294. if err != nil {
  295. t.Fatal(err)
  296. }
  297. reader, err := os.Open(tarFile)
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. defer reader.Close()
  302. entries, err := ListTar(reader)
  303. if err != nil {
  304. t.Fatal(err)
  305. }
  306. if len(entries) != 1 && entries[0] != "src" {
  307. t.Fatalf("Expected a tar file with 1 entry (%s), got %v", srcFile, entries)
  308. }
  309. }
  310. func TestRandomTmpDirPath(t *testing.T) {
  311. path := RandomTmpDirPath("something", runtime.GOOS)
  312. prefix := "/tmp/something"
  313. if runtime.GOOS == "windows" {
  314. prefix = os.Getenv("TEMP") + `\something`
  315. }
  316. expectedSize := len(prefix) + 11
  317. if !strings.HasPrefix(path, prefix) {
  318. t.Fatalf("Expected generated path to have '%s' as prefix, got %s'", prefix, path)
  319. }
  320. if len(path) != expectedSize {
  321. t.Fatalf("Expected generated path to be %d, got %d", expectedSize, len(path))
  322. }
  323. }
  324. func TestConsumeWithSpeed(t *testing.T) {
  325. reader := strings.NewReader("1234567890")
  326. chunksize := 2
  327. bytes1, err := ConsumeWithSpeed(reader, chunksize, 1*time.Millisecond, nil)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. if bytes1 != 10 {
  332. t.Fatalf("Expected to have read 10 bytes, got %d", bytes1)
  333. }
  334. }
  335. func TestConsumeWithSpeedWithStop(t *testing.T) {
  336. reader := strings.NewReader("1234567890")
  337. chunksize := 2
  338. stopIt := make(chan bool)
  339. go func() {
  340. time.Sleep(1 * time.Millisecond)
  341. stopIt <- true
  342. }()
  343. bytes1, err := ConsumeWithSpeed(reader, chunksize, 2*time.Millisecond, stopIt)
  344. if err != nil {
  345. t.Fatal(err)
  346. }
  347. if bytes1 != 2 {
  348. t.Fatalf("Expected to have read 2 bytes, got %d", bytes1)
  349. }
  350. }
  351. func TestParseCgroupPathsEmpty(t *testing.T) {
  352. cgroupMap := ParseCgroupPaths("")
  353. if len(cgroupMap) != 0 {
  354. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  355. }
  356. cgroupMap = ParseCgroupPaths("\n")
  357. if len(cgroupMap) != 0 {
  358. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  359. }
  360. cgroupMap = ParseCgroupPaths("something:else\nagain:here")
  361. if len(cgroupMap) != 0 {
  362. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  363. }
  364. }
  365. func TestParseCgroupPaths(t *testing.T) {
  366. cgroupMap := ParseCgroupPaths("2:memory:/a\n1:cpuset:/b")
  367. if len(cgroupMap) != 2 {
  368. t.Fatalf("Expected a map with 2 entries, got %v", cgroupMap)
  369. }
  370. if value, ok := cgroupMap["memory"]; !ok || value != "/a" {
  371. t.Fatalf("Expected cgroupMap to contains an entry for 'memory' with value '/a', got %v", cgroupMap)
  372. }
  373. if value, ok := cgroupMap["cpuset"]; !ok || value != "/b" {
  374. t.Fatalf("Expected cgroupMap to contains an entry for 'cpuset' with value '/b', got %v", cgroupMap)
  375. }
  376. }
  377. func TestChannelBufferTimeout(t *testing.T) {
  378. expected := "11"
  379. buf := &ChannelBuffer{make(chan []byte, 1)}
  380. defer buf.Close()
  381. go func() {
  382. time.Sleep(100 * time.Millisecond)
  383. io.Copy(buf, strings.NewReader(expected))
  384. }()
  385. // Wait long enough
  386. b := make([]byte, 2)
  387. _, err := buf.ReadTimeout(b, 50*time.Millisecond)
  388. if err == nil && err.Error() != "timeout reading from channel" {
  389. t.Fatalf("Expected an error, got %s", err)
  390. }
  391. // Wait for the end :)
  392. time.Sleep(150 * time.Millisecond)
  393. }
  394. func TestChannelBuffer(t *testing.T) {
  395. expected := "11"
  396. buf := &ChannelBuffer{make(chan []byte, 1)}
  397. defer buf.Close()
  398. go func() {
  399. time.Sleep(100 * time.Millisecond)
  400. io.Copy(buf, strings.NewReader(expected))
  401. }()
  402. // Wait long enough
  403. b := make([]byte, 2)
  404. _, err := buf.ReadTimeout(b, 200*time.Millisecond)
  405. if err != nil {
  406. t.Fatal(err)
  407. }
  408. if string(b) != expected {
  409. t.Fatalf("Expected '%s', got '%s'", expected, string(b))
  410. }
  411. }
  412. // FIXME doesn't work
  413. // func TestRunAtDifferentDate(t *testing.T) {
  414. // var date string
  415. // // Layout for date. MMDDhhmmYYYY
  416. // const timeLayout = "20060102"
  417. // expectedDate := "20100201"
  418. // theDate, err := time.Parse(timeLayout, expectedDate)
  419. // if err != nil {
  420. // t.Fatal(err)
  421. // }
  422. // RunAtDifferentDate(theDate, func() {
  423. // cmd := exec.Command("date", "+%Y%M%d")
  424. // out, err := cmd.Output()
  425. // if err != nil {
  426. // t.Fatal(err)
  427. // }
  428. // date = string(out)
  429. // })
  430. // }