mount_windows_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // +build windows
  2. /*
  3. Copyright 2017 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package mount
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "os/exec"
  20. "path/filepath"
  21. "strings"
  22. "testing"
  23. "github.com/stretchr/testify/assert"
  24. )
  25. func TestNormalizeWindowsPath(t *testing.T) {
  26. path := `/var/lib/kubelet/pods/146f8428-83e7-11e7-8dd4-000d3a31dac4/volumes/kubernetes.io~azure-disk`
  27. normalizedPath := normalizeWindowsPath(path)
  28. if normalizedPath != `c:\var\lib\kubelet\pods\146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk` {
  29. t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath)
  30. }
  31. path = `/var/lib/kubelet/pods/146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk`
  32. normalizedPath = normalizeWindowsPath(path)
  33. if normalizedPath != `c:\var\lib\kubelet\pods\146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk` {
  34. t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath)
  35. }
  36. path = `/`
  37. normalizedPath = normalizeWindowsPath(path)
  38. if normalizedPath != `c:\` {
  39. t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath)
  40. }
  41. }
  42. func TestValidateDiskNumber(t *testing.T) {
  43. diskNum := "0"
  44. if err := ValidateDiskNumber(diskNum); err != nil {
  45. t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
  46. }
  47. diskNum = "99"
  48. if err := ValidateDiskNumber(diskNum); err != nil {
  49. t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
  50. }
  51. diskNum = "ab"
  52. if err := ValidateDiskNumber(diskNum); err == nil {
  53. t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
  54. }
  55. diskNum = "100"
  56. if err := ValidateDiskNumber(diskNum); err == nil {
  57. t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
  58. }
  59. }
  60. func makeLink(link, target string) error {
  61. if output, err := exec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput(); err != nil {
  62. return fmt.Errorf("mklink failed: %v, link(%q) target(%q) output: %q", err, link, target, string(output))
  63. }
  64. return nil
  65. }
  66. func removeLink(link string) error {
  67. if output, err := exec.Command("cmd", "/c", "rmdir", link).CombinedOutput(); err != nil {
  68. return fmt.Errorf("rmdir failed: %v, output: %q", err, string(output))
  69. }
  70. return nil
  71. }
  72. func setEquivalent(set1, set2 []string) bool {
  73. map1 := make(map[string]bool)
  74. map2 := make(map[string]bool)
  75. for _, s := range set1 {
  76. map1[s] = true
  77. }
  78. for _, s := range set2 {
  79. map2[s] = true
  80. }
  81. for s := range map1 {
  82. if !map2[s] {
  83. return false
  84. }
  85. }
  86. for s := range map2 {
  87. if !map1[s] {
  88. return false
  89. }
  90. }
  91. return true
  92. }
  93. // this func must run in admin mode, otherwise it will fail
  94. func TestGetMountRefs(t *testing.T) {
  95. tests := []struct {
  96. mountPath string
  97. expectedRefs []string
  98. }{
  99. {
  100. mountPath: `c:\windows`,
  101. expectedRefs: []string{`c:\windows`},
  102. },
  103. {
  104. mountPath: `c:\doesnotexist`,
  105. expectedRefs: []string{},
  106. },
  107. }
  108. mounter := Mounter{"fake/path"}
  109. for _, test := range tests {
  110. if refs, err := mounter.GetMountRefs(test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
  111. t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", test.mountPath, refs, err, test.expectedRefs)
  112. }
  113. }
  114. }
  115. func TestPathWithinBase(t *testing.T) {
  116. tests := []struct {
  117. fullPath string
  118. basePath string
  119. expectedResult bool
  120. }{
  121. {
  122. fullPath: `c:\tmp\a\b\c`,
  123. basePath: `c:\tmp`,
  124. expectedResult: true,
  125. },
  126. {
  127. fullPath: `c:\tmp1`,
  128. basePath: `c:\tmp2`,
  129. expectedResult: false,
  130. },
  131. {
  132. fullPath: `c:\tmp`,
  133. basePath: `c:\tmp`,
  134. expectedResult: true,
  135. },
  136. {
  137. fullPath: `c:\tmp`,
  138. basePath: `c:\tmp\a\b\c`,
  139. expectedResult: false,
  140. },
  141. {
  142. fullPath: `c:\kubelet\pods\uuid\volumes\kubernetes.io~configmap\config\..timestamp\file.txt`,
  143. basePath: `c:\kubelet\pods\uuid\volumes\kubernetes.io~configmap\config`,
  144. expectedResult: true,
  145. },
  146. }
  147. for _, test := range tests {
  148. result := PathWithinBase(test.fullPath, test.basePath)
  149. assert.Equal(t, result, test.expectedResult, "Expect result not equal with PathWithinBase(%s, %s) return: %q, expected: %q",
  150. test.fullPath, test.basePath, result, test.expectedResult)
  151. }
  152. }
  153. func TestGetFileType(t *testing.T) {
  154. mounter := New("fake/path")
  155. testCase := []struct {
  156. name string
  157. expectedType FileType
  158. setUp func() (string, string, error)
  159. }{
  160. {
  161. "Directory Test",
  162. FileTypeDirectory,
  163. func() (string, string, error) {
  164. tempDir, err := ioutil.TempDir("", "test-get-filetype-")
  165. return tempDir, tempDir, err
  166. },
  167. },
  168. {
  169. "File Test",
  170. FileTypeFile,
  171. func() (string, string, error) {
  172. tempFile, err := ioutil.TempFile("", "test-get-filetype")
  173. if err != nil {
  174. return "", "", err
  175. }
  176. tempFile.Close()
  177. return tempFile.Name(), tempFile.Name(), nil
  178. },
  179. },
  180. }
  181. for idx, tc := range testCase {
  182. path, cleanUpPath, err := tc.setUp()
  183. if err != nil {
  184. t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
  185. }
  186. if len(cleanUpPath) > 0 {
  187. defer os.RemoveAll(cleanUpPath)
  188. }
  189. fileType, err := mounter.GetFileType(path)
  190. if err != nil {
  191. t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
  192. }
  193. if fileType != tc.expectedType {
  194. t.Fatalf("[%d-%s] expected %s, but got %s", idx, tc.name, tc.expectedType, fileType)
  195. }
  196. }
  197. }
  198. func TestIsLikelyNotMountPoint(t *testing.T) {
  199. mounter := Mounter{"fake/path"}
  200. tests := []struct {
  201. fileName string
  202. targetLinkName string
  203. setUp func(base, fileName, targetLinkName string) error
  204. expectedResult bool
  205. expectError bool
  206. }{
  207. {
  208. "Dir",
  209. "",
  210. func(base, fileName, targetLinkName string) error {
  211. return os.Mkdir(filepath.Join(base, fileName), 0750)
  212. },
  213. true,
  214. false,
  215. },
  216. {
  217. "InvalidDir",
  218. "",
  219. func(base, fileName, targetLinkName string) error {
  220. return nil
  221. },
  222. true,
  223. true,
  224. },
  225. {
  226. "ValidSymLink",
  227. "targetSymLink",
  228. func(base, fileName, targetLinkName string) error {
  229. targeLinkPath := filepath.Join(base, targetLinkName)
  230. if err := os.Mkdir(targeLinkPath, 0750); err != nil {
  231. return err
  232. }
  233. filePath := filepath.Join(base, fileName)
  234. if err := makeLink(filePath, targeLinkPath); err != nil {
  235. return err
  236. }
  237. return nil
  238. },
  239. false,
  240. false,
  241. },
  242. {
  243. "InvalidSymLink",
  244. "targetSymLink2",
  245. func(base, fileName, targetLinkName string) error {
  246. targeLinkPath := filepath.Join(base, targetLinkName)
  247. if err := os.Mkdir(targeLinkPath, 0750); err != nil {
  248. return err
  249. }
  250. filePath := filepath.Join(base, fileName)
  251. if err := makeLink(filePath, targeLinkPath); err != nil {
  252. return err
  253. }
  254. return removeLink(targeLinkPath)
  255. },
  256. true,
  257. false,
  258. },
  259. }
  260. for _, test := range tests {
  261. base, err := ioutil.TempDir("", test.fileName)
  262. if err != nil {
  263. t.Fatalf(err.Error())
  264. }
  265. defer os.RemoveAll(base)
  266. if err := test.setUp(base, test.fileName, test.targetLinkName); err != nil {
  267. t.Fatalf("unexpected error in setUp(%s, %s): %v", test.fileName, test.targetLinkName, err)
  268. }
  269. filePath := filepath.Join(base, test.fileName)
  270. result, err := mounter.IsLikelyNotMountPoint(filePath)
  271. assert.Equal(t, result, test.expectedResult, "Expect result not equal with IsLikelyNotMountPoint(%s) return: %q, expected: %q",
  272. filePath, result, test.expectedResult)
  273. if test.expectError {
  274. assert.NotNil(t, err, "Expect error during IsLikelyNotMountPoint(%s)", filePath)
  275. } else {
  276. assert.Nil(t, err, "Expect error is nil during IsLikelyNotMountPoint(%s)", filePath)
  277. }
  278. }
  279. }
  280. func TestFormatAndMount(t *testing.T) {
  281. fakeMounter := ErrorMounter{&FakeMounter{}, 0, nil}
  282. execCallback := func(cmd string, args ...string) ([]byte, error) {
  283. for j := range args {
  284. if strings.Contains(args[j], "Get-Disk -Number") {
  285. return []byte("0"), nil
  286. }
  287. if strings.Contains(args[j], "Get-Partition -DiskNumber") {
  288. return []byte("0"), nil
  289. }
  290. if strings.Contains(args[j], "mklink") {
  291. return nil, nil
  292. }
  293. }
  294. return nil, fmt.Errorf("Unexpected cmd %s, args %v", cmd, args)
  295. }
  296. fakeExec := NewFakeExec(execCallback)
  297. mounter := SafeFormatAndMount{
  298. Interface: &fakeMounter,
  299. Exec: fakeExec,
  300. }
  301. tests := []struct {
  302. device string
  303. target string
  304. fstype string
  305. mountOptions []string
  306. expectError bool
  307. }{
  308. {
  309. "0",
  310. "disk",
  311. "NTFS",
  312. []string{},
  313. false,
  314. },
  315. {
  316. "0",
  317. "disk",
  318. "",
  319. []string{},
  320. false,
  321. },
  322. {
  323. "invalidDevice",
  324. "disk",
  325. "NTFS",
  326. []string{},
  327. true,
  328. },
  329. }
  330. for _, test := range tests {
  331. base, err := ioutil.TempDir("", test.device)
  332. if err != nil {
  333. t.Fatalf(err.Error())
  334. }
  335. defer os.RemoveAll(base)
  336. target := filepath.Join(base, test.target)
  337. err = mounter.FormatAndMount(test.device, target, test.fstype, test.mountOptions)
  338. if test.expectError {
  339. assert.NotNil(t, err, "Expect error during FormatAndMount(%s, %s, %s, %v)", test.device, test.target, test.fstype, test.mountOptions)
  340. } else {
  341. assert.Nil(t, err, "Expect error is nil during FormatAndMount(%s, %s, %s, %v)", test.device, test.target, test.fstype, test.mountOptions)
  342. }
  343. }
  344. }
  345. func TestNewSMBMapping(t *testing.T) {
  346. tests := []struct {
  347. username string
  348. password string
  349. remotepath string
  350. expectError bool
  351. }{
  352. {
  353. "",
  354. "password",
  355. `\\remotepath`,
  356. true,
  357. },
  358. {
  359. "username",
  360. "",
  361. `\\remotepath`,
  362. true,
  363. },
  364. {
  365. "username",
  366. "password",
  367. "",
  368. true,
  369. },
  370. }
  371. for _, test := range tests {
  372. _, err := newSMBMapping(test.username, test.password, test.remotepath)
  373. if test.expectError {
  374. assert.NotNil(t, err, "Expect error during newSMBMapping(%s, %s, %s, %v)", test.username, test.password, test.remotepath)
  375. } else {
  376. assert.Nil(t, err, "Expect error is nil during newSMBMapping(%s, %s, %s, %v)", test.username, test.password, test.remotepath)
  377. }
  378. }
  379. }