utils_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. package testutil
  2. import (
  3. "io"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "testing"
  11. "time"
  12. )
  13. func TestIsKilledFalseWithNonKilledProcess(t *testing.T) {
  14. var lsCmd *exec.Cmd
  15. if runtime.GOOS != "windows" {
  16. lsCmd = exec.Command("ls")
  17. } else {
  18. lsCmd = exec.Command("cmd", "/c", "dir")
  19. }
  20. err := lsCmd.Run()
  21. if IsKilled(err) {
  22. t.Fatalf("Expected the ls command to not be killed, was.")
  23. }
  24. }
  25. func TestIsKilledTrueWithKilledProcess(t *testing.T) {
  26. var longCmd *exec.Cmd
  27. if runtime.GOOS != "windows" {
  28. longCmd = exec.Command("top")
  29. } else {
  30. longCmd = exec.Command("powershell", "while ($true) { sleep 1 }")
  31. }
  32. // Start a command
  33. err := longCmd.Start()
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. // Capture the error when *dying*
  38. done := make(chan error, 1)
  39. go func() {
  40. done <- longCmd.Wait()
  41. }()
  42. // Then kill it
  43. longCmd.Process.Kill()
  44. // Get the error
  45. err = <-done
  46. if !IsKilled(err) {
  47. t.Fatalf("Expected the command to be killed, was not.")
  48. }
  49. }
  50. func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) {
  51. _, _, err := RunCommandPipelineWithOutput(exec.Command("ls"))
  52. expectedError := "pipeline does not have multiple cmds"
  53. if err == nil || err.Error() != expectedError {
  54. t.Fatalf("Expected an error with %s, got err:%s", expectedError, err)
  55. }
  56. }
  57. func TestRunCommandPipelineWithOutputErrors(t *testing.T) {
  58. p := "$PATH"
  59. if runtime.GOOS == "windows" {
  60. p = "%PATH%"
  61. }
  62. cmd1 := exec.Command("ls")
  63. cmd1.Stdout = os.Stdout
  64. cmd2 := exec.Command("anything really")
  65. _, _, err := RunCommandPipelineWithOutput(cmd1, cmd2)
  66. if err == nil || err.Error() != "cannot set stdout pipe for anything really: exec: Stdout already set" {
  67. t.Fatalf("Expected an error, got %v", err)
  68. }
  69. cmdWithError := exec.Command("doesnotexists")
  70. cmdCat := exec.Command("cat")
  71. _, _, err = RunCommandPipelineWithOutput(cmdWithError, cmdCat)
  72. if err == nil || err.Error() != `starting doesnotexists failed with error: exec: "doesnotexists": executable file not found in `+p {
  73. t.Fatalf("Expected an error, got %v", err)
  74. }
  75. }
  76. func TestRunCommandPipelineWithOutput(t *testing.T) {
  77. //TODO: Should run on Solaris
  78. if runtime.GOOS == "solaris" {
  79. t.Skip()
  80. }
  81. cmds := []*exec.Cmd{
  82. // Print 2 characters
  83. exec.Command("echo", "-n", "11"),
  84. // Count the number or char from stdin (previous command)
  85. exec.Command("wc", "-m"),
  86. }
  87. out, exitCode, err := RunCommandPipelineWithOutput(cmds...)
  88. expectedOutput := "2\n"
  89. if out != expectedOutput || exitCode != 0 || err != nil {
  90. t.Fatalf("Expected %s for commands %v, got out:%s, exitCode:%d, err:%v", expectedOutput, cmds, out, exitCode, err)
  91. }
  92. }
  93. func TestConvertSliceOfStringsToMap(t *testing.T) {
  94. input := []string{"a", "b"}
  95. actual := ConvertSliceOfStringsToMap(input)
  96. for _, key := range input {
  97. if _, ok := actual[key]; !ok {
  98. t.Fatalf("Expected output to contains key %s, did not: %v", key, actual)
  99. }
  100. }
  101. }
  102. func TestCompareDirectoryEntries(t *testing.T) {
  103. tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-compare-directories")
  104. if err != nil {
  105. t.Fatal(err)
  106. }
  107. defer os.RemoveAll(tmpFolder)
  108. file1 := filepath.Join(tmpFolder, "file1")
  109. file2 := filepath.Join(tmpFolder, "file2")
  110. os.Create(file1)
  111. os.Create(file2)
  112. fi1, err := os.Stat(file1)
  113. if err != nil {
  114. t.Fatal(err)
  115. }
  116. fi1bis, err := os.Stat(file1)
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. fi2, err := os.Stat(file2)
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. cases := []struct {
  125. e1 []os.FileInfo
  126. e2 []os.FileInfo
  127. shouldError bool
  128. }{
  129. // Empty directories
  130. {
  131. []os.FileInfo{},
  132. []os.FileInfo{},
  133. false,
  134. },
  135. // Same FileInfos
  136. {
  137. []os.FileInfo{fi1},
  138. []os.FileInfo{fi1},
  139. false,
  140. },
  141. // Different FileInfos but same names
  142. {
  143. []os.FileInfo{fi1},
  144. []os.FileInfo{fi1bis},
  145. false,
  146. },
  147. // Different FileInfos, different names
  148. {
  149. []os.FileInfo{fi1},
  150. []os.FileInfo{fi2},
  151. true,
  152. },
  153. }
  154. for _, elt := range cases {
  155. err := CompareDirectoryEntries(elt.e1, elt.e2)
  156. if elt.shouldError && err == nil {
  157. t.Fatalf("Should have return an error, did not with %v and %v", elt.e1, elt.e2)
  158. }
  159. if !elt.shouldError && err != nil {
  160. t.Fatalf("Should have not returned an error, but did : %v with %v and %v", err, elt.e1, elt.e2)
  161. }
  162. }
  163. }
  164. // FIXME make an "unhappy path" test for ListTar without "panicking" :-)
  165. func TestListTar(t *testing.T) {
  166. // TODO Windows: Figure out why this fails. Should be portable.
  167. if runtime.GOOS == "windows" {
  168. t.Skip("Failing on Windows - needs further investigation")
  169. }
  170. tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-list-tar")
  171. if err != nil {
  172. t.Fatal(err)
  173. }
  174. defer os.RemoveAll(tmpFolder)
  175. // Let's create a Tar file
  176. srcFile := filepath.Join(tmpFolder, "src")
  177. tarFile := filepath.Join(tmpFolder, "src.tar")
  178. os.Create(srcFile)
  179. cmd := exec.Command("sh", "-c", "tar cf "+tarFile+" "+srcFile)
  180. _, err = cmd.CombinedOutput()
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. reader, err := os.Open(tarFile)
  185. if err != nil {
  186. t.Fatal(err)
  187. }
  188. defer reader.Close()
  189. entries, err := ListTar(reader)
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. if len(entries) != 1 && entries[0] != "src" {
  194. t.Fatalf("Expected a tar file with 1 entry (%s), got %v", srcFile, entries)
  195. }
  196. }
  197. func TestRandomTmpDirPath(t *testing.T) {
  198. path := RandomTmpDirPath("something", runtime.GOOS)
  199. prefix := "/tmp/something"
  200. if runtime.GOOS == "windows" {
  201. prefix = os.Getenv("TEMP") + `\something`
  202. }
  203. expectedSize := len(prefix) + 11
  204. if !strings.HasPrefix(path, prefix) {
  205. t.Fatalf("Expected generated path to have '%s' as prefix, got %s'", prefix, path)
  206. }
  207. if len(path) != expectedSize {
  208. t.Fatalf("Expected generated path to be %d, got %d", expectedSize, len(path))
  209. }
  210. }
  211. func TestConsumeWithSpeed(t *testing.T) {
  212. reader := strings.NewReader("1234567890")
  213. chunksize := 2
  214. bytes1, err := ConsumeWithSpeed(reader, chunksize, 10*time.Millisecond, nil)
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. if bytes1 != 10 {
  219. t.Fatalf("Expected to have read 10 bytes, got %d", bytes1)
  220. }
  221. }
  222. func TestConsumeWithSpeedWithStop(t *testing.T) {
  223. reader := strings.NewReader("1234567890")
  224. chunksize := 2
  225. stopIt := make(chan bool)
  226. go func() {
  227. time.Sleep(1 * time.Millisecond)
  228. stopIt <- true
  229. }()
  230. bytes1, err := ConsumeWithSpeed(reader, chunksize, 20*time.Millisecond, stopIt)
  231. if err != nil {
  232. t.Fatal(err)
  233. }
  234. if bytes1 != 2 {
  235. t.Fatalf("Expected to have read 2 bytes, got %d", bytes1)
  236. }
  237. }
  238. func TestParseCgroupPathsEmpty(t *testing.T) {
  239. cgroupMap := ParseCgroupPaths("")
  240. if len(cgroupMap) != 0 {
  241. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  242. }
  243. cgroupMap = ParseCgroupPaths("\n")
  244. if len(cgroupMap) != 0 {
  245. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  246. }
  247. cgroupMap = ParseCgroupPaths("something:else\nagain:here")
  248. if len(cgroupMap) != 0 {
  249. t.Fatalf("Expected an empty map, got %v", cgroupMap)
  250. }
  251. }
  252. func TestParseCgroupPaths(t *testing.T) {
  253. cgroupMap := ParseCgroupPaths("2:memory:/a\n1:cpuset:/b")
  254. if len(cgroupMap) != 2 {
  255. t.Fatalf("Expected a map with 2 entries, got %v", cgroupMap)
  256. }
  257. if value, ok := cgroupMap["memory"]; !ok || value != "/a" {
  258. t.Fatalf("Expected cgroupMap to contains an entry for 'memory' with value '/a', got %v", cgroupMap)
  259. }
  260. if value, ok := cgroupMap["cpuset"]; !ok || value != "/b" {
  261. t.Fatalf("Expected cgroupMap to contains an entry for 'cpuset' with value '/b', got %v", cgroupMap)
  262. }
  263. }
  264. func TestChannelBufferTimeout(t *testing.T) {
  265. expected := "11"
  266. buf := &ChannelBuffer{make(chan []byte, 1)}
  267. defer buf.Close()
  268. done := make(chan struct{}, 1)
  269. go func() {
  270. time.Sleep(100 * time.Millisecond)
  271. io.Copy(buf, strings.NewReader(expected))
  272. done <- struct{}{}
  273. }()
  274. // Wait long enough
  275. b := make([]byte, 2)
  276. _, err := buf.ReadTimeout(b, 50*time.Millisecond)
  277. if err == nil && err.Error() != "timeout reading from channel" {
  278. t.Fatalf("Expected an error, got %s", err)
  279. }
  280. <-done
  281. }
  282. func TestChannelBuffer(t *testing.T) {
  283. expected := "11"
  284. buf := &ChannelBuffer{make(chan []byte, 1)}
  285. defer buf.Close()
  286. go func() {
  287. time.Sleep(100 * time.Millisecond)
  288. io.Copy(buf, strings.NewReader(expected))
  289. }()
  290. // Wait long enough
  291. b := make([]byte, 2)
  292. _, err := buf.ReadTimeout(b, 200*time.Millisecond)
  293. if err != nil {
  294. t.Fatal(err)
  295. }
  296. if string(b) != expected {
  297. t.Fatalf("Expected '%s', got '%s'", expected, string(b))
  298. }
  299. }