volume_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package volume
  2. import (
  3. "runtime"
  4. "strings"
  5. "testing"
  6. )
  7. func TestParseMountSpec(t *testing.T) {
  8. var (
  9. valid []string
  10. invalid map[string]string
  11. )
  12. if runtime.GOOS == "windows" {
  13. valid = []string{
  14. `d:\`,
  15. `d:`,
  16. `d:\path`,
  17. `d:\path with space`,
  18. // TODO Windows post TP5 - readonly support `d:\pathandmode:ro`,
  19. `c:\:d:\`,
  20. `c:\windows\:d:`,
  21. `c:\windows:d:\s p a c e`,
  22. `c:\windows:d:\s p a c e:RW`,
  23. `c:\program files:d:\s p a c e i n h o s t d i r`,
  24. `0123456789name:d:`,
  25. `MiXeDcAsEnAmE:d:`,
  26. `name:D:`,
  27. `name:D::rW`,
  28. `name:D::RW`,
  29. // TODO Windows post TP5 - readonly support `name:D::RO`,
  30. `c:/:d:/forward/slashes/are/good/too`,
  31. // TODO Windows post TP5 - readonly support `c:/:d:/including with/spaces:ro`,
  32. `c:\Windows`, // With capital
  33. `c:\Program Files (x86)`, // With capitals and brackets
  34. }
  35. invalid = map[string]string{
  36. ``: "Invalid volume specification: ",
  37. `.`: "Invalid volume specification: ",
  38. `..\`: "Invalid volume specification: ",
  39. `c:\:..\`: "Invalid volume specification: ",
  40. `c:\:d:\:xyzzy`: "Invalid volume specification: ",
  41. `c:`: "cannot be c:",
  42. `c:\`: `cannot be c:\`,
  43. `c:\notexist:d:`: `The system cannot find the file specified`,
  44. `c:\windows\system32\ntdll.dll:d:`: `Source 'c:\windows\system32\ntdll.dll' is not a directory`,
  45. `name<:d:`: `Invalid volume specification`,
  46. `name>:d:`: `Invalid volume specification`,
  47. `name::d:`: `Invalid volume specification`,
  48. `name":d:`: `Invalid volume specification`,
  49. `name\:d:`: `Invalid volume specification`,
  50. `name*:d:`: `Invalid volume specification`,
  51. `name|:d:`: `Invalid volume specification`,
  52. `name?:d:`: `Invalid volume specification`,
  53. `name/:d:`: `Invalid volume specification`,
  54. `d:\pathandmode:rw`: `Invalid volume specification`,
  55. `con:d:`: `cannot be a reserved word for Windows filenames`,
  56. `PRN:d:`: `cannot be a reserved word for Windows filenames`,
  57. `aUx:d:`: `cannot be a reserved word for Windows filenames`,
  58. `nul:d:`: `cannot be a reserved word for Windows filenames`,
  59. `com1:d:`: `cannot be a reserved word for Windows filenames`,
  60. `com2:d:`: `cannot be a reserved word for Windows filenames`,
  61. `com3:d:`: `cannot be a reserved word for Windows filenames`,
  62. `com4:d:`: `cannot be a reserved word for Windows filenames`,
  63. `com5:d:`: `cannot be a reserved word for Windows filenames`,
  64. `com6:d:`: `cannot be a reserved word for Windows filenames`,
  65. `com7:d:`: `cannot be a reserved word for Windows filenames`,
  66. `com8:d:`: `cannot be a reserved word for Windows filenames`,
  67. `com9:d:`: `cannot be a reserved word for Windows filenames`,
  68. `lpt1:d:`: `cannot be a reserved word for Windows filenames`,
  69. `lpt2:d:`: `cannot be a reserved word for Windows filenames`,
  70. `lpt3:d:`: `cannot be a reserved word for Windows filenames`,
  71. `lpt4:d:`: `cannot be a reserved word for Windows filenames`,
  72. `lpt5:d:`: `cannot be a reserved word for Windows filenames`,
  73. `lpt6:d:`: `cannot be a reserved word for Windows filenames`,
  74. `lpt7:d:`: `cannot be a reserved word for Windows filenames`,
  75. `lpt8:d:`: `cannot be a reserved word for Windows filenames`,
  76. `lpt9:d:`: `cannot be a reserved word for Windows filenames`,
  77. }
  78. } else {
  79. valid = []string{
  80. "/home",
  81. "/home:/home",
  82. "/home:/something/else",
  83. "/with space",
  84. "/home:/with space",
  85. "relative:/absolute-path",
  86. "hostPath:/containerPath:ro",
  87. "/hostPath:/containerPath:rw",
  88. "/rw:/ro",
  89. }
  90. invalid = map[string]string{
  91. "": "Invalid volume specification",
  92. "./": "Invalid volume destination",
  93. "../": "Invalid volume destination",
  94. "/:../": "Invalid volume destination",
  95. "/:path": "Invalid volume destination",
  96. ":": "Invalid volume specification",
  97. "/tmp:": "Invalid volume destination",
  98. ":test": "Invalid volume specification",
  99. ":/test": "Invalid volume specification",
  100. "tmp:": "Invalid volume destination",
  101. ":test:": "Invalid volume specification",
  102. "::": "Invalid volume specification",
  103. ":::": "Invalid volume specification",
  104. "/tmp:::": "Invalid volume specification",
  105. ":/tmp::": "Invalid volume specification",
  106. "/path:rw": "Invalid volume specification",
  107. "/path:ro": "Invalid volume specification",
  108. "/rw:rw": "Invalid volume specification",
  109. "path:ro": "Invalid volume specification",
  110. "/path:/path:sw": `invalid mode: sw`,
  111. "/path:/path:rwz": `invalid mode: rwz`,
  112. }
  113. }
  114. for _, path := range valid {
  115. if _, err := ParseMountSpec(path, "local"); err != nil {
  116. t.Fatalf("ParseMountSpec(`%q`) should succeed: error %q", path, err)
  117. }
  118. }
  119. for path, expectedError := range invalid {
  120. if _, err := ParseMountSpec(path, "local"); err == nil {
  121. t.Fatalf("ParseMountSpec(`%q`) should have failed validation. Err %v", path, err)
  122. } else {
  123. if !strings.Contains(err.Error(), expectedError) {
  124. t.Fatalf("ParseMountSpec(`%q`) error should contain %q, got %v", path, expectedError, err.Error())
  125. }
  126. }
  127. }
  128. }
  129. // testParseMountSpec is a structure used by TestParseMountSpecSplit for
  130. // specifying test cases for the ParseMountSpec() function.
  131. type testParseMountSpec struct {
  132. bind string
  133. driver string
  134. expDest string
  135. expSource string
  136. expName string
  137. expDriver string
  138. expRW bool
  139. fail bool
  140. }
  141. func TestParseMountSpecSplit(t *testing.T) {
  142. var cases []testParseMountSpec
  143. if runtime.GOOS == "windows" {
  144. cases = []testParseMountSpec{
  145. {`c:\:d:`, "local", `d:`, `c:\`, ``, "", true, false},
  146. {`c:\:d:\`, "local", `d:\`, `c:\`, ``, "", true, false},
  147. // TODO Windows post TP5 - Add readonly support {`c:\:d:\:ro`, "local", `d:\`, `c:\`, ``, "", false, false},
  148. {`c:\:d:\:rw`, "local", `d:\`, `c:\`, ``, "", true, false},
  149. {`c:\:d:\:foo`, "local", `d:\`, `c:\`, ``, "", false, true},
  150. {`name:d::rw`, "local", `d:`, ``, `name`, "local", true, false},
  151. {`name:d:`, "local", `d:`, ``, `name`, "local", true, false},
  152. // TODO Windows post TP5 - Add readonly support {`name:d::ro`, "local", `d:`, ``, `name`, "local", false, false},
  153. {`name:c:`, "", ``, ``, ``, "", true, true},
  154. {`driver/name:c:`, "", ``, ``, ``, "", true, true},
  155. }
  156. } else {
  157. cases = []testParseMountSpec{
  158. {"/tmp:/tmp1", "", "/tmp1", "/tmp", "", "", true, false},
  159. {"/tmp:/tmp2:ro", "", "/tmp2", "/tmp", "", "", false, false},
  160. {"/tmp:/tmp3:rw", "", "/tmp3", "/tmp", "", "", true, false},
  161. {"/tmp:/tmp4:foo", "", "", "", "", "", false, true},
  162. {"name:/named1", "", "/named1", "", "name", "", true, false},
  163. {"name:/named2", "external", "/named2", "", "name", "external", true, false},
  164. {"name:/named3:ro", "local", "/named3", "", "name", "local", false, false},
  165. {"local/name:/tmp:rw", "", "/tmp", "", "local/name", "", true, false},
  166. {"/tmp:tmp", "", "", "", "", "", true, true},
  167. }
  168. }
  169. for _, c := range cases {
  170. m, err := ParseMountSpec(c.bind, c.driver)
  171. if c.fail {
  172. if err == nil {
  173. t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
  174. }
  175. continue
  176. }
  177. if m == nil || err != nil {
  178. t.Fatalf("ParseMountSpec failed for spec %s driver %s error %v\n", c.bind, c.driver, err.Error())
  179. continue
  180. }
  181. if m.Destination != c.expDest {
  182. t.Fatalf("Expected destination %s, was %s, for spec %s\n", c.expDest, m.Destination, c.bind)
  183. }
  184. if m.Source != c.expSource {
  185. t.Fatalf("Expected source %s, was %s, for spec %s\n", c.expSource, m.Source, c.bind)
  186. }
  187. if m.Name != c.expName {
  188. t.Fatalf("Expected name %s, was %s for spec %s\n", c.expName, m.Name, c.bind)
  189. }
  190. if m.Driver != c.expDriver {
  191. t.Fatalf("Expected driver %s, was %s, for spec %s\n", c.expDriver, m.Driver, c.bind)
  192. }
  193. if m.RW != c.expRW {
  194. t.Fatalf("Expected RW %v, was %v for spec %s\n", c.expRW, m.RW, c.bind)
  195. }
  196. }
  197. }