k8s.io/kubernetes@v1.29.3/pkg/volume/util/subpath/subpath_windows_test.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2017 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package subpath 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "os/exec" 27 "path/filepath" 28 "testing" 29 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func makeLink(link, target string) error { 34 if output, err := exec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput(); err != nil { 35 return fmt.Errorf("mklink failed: %v, link(%q) target(%q) output: %q", err, link, target, string(output)) 36 } 37 return nil 38 } 39 40 func TestDoSafeMakeDir(t *testing.T) { 41 base, err := ioutil.TempDir("", "TestDoSafeMakeDir") 42 if err != nil { 43 t.Fatalf(err.Error()) 44 } 45 46 defer os.RemoveAll(base) 47 48 testingVolumePath := filepath.Join(base, "testingVolumePath") 49 os.MkdirAll(testingVolumePath, 0755) 50 defer os.RemoveAll(testingVolumePath) 51 52 tests := []struct { 53 volumePath string 54 subPath string 55 expectError bool 56 symlinkTarget string 57 }{ 58 { 59 volumePath: testingVolumePath, 60 subPath: ``, 61 expectError: true, 62 symlinkTarget: "", 63 }, 64 { 65 volumePath: testingVolumePath, 66 subPath: filepath.Join(testingVolumePath, `x`), 67 expectError: false, 68 symlinkTarget: "", 69 }, 70 { 71 volumePath: testingVolumePath, 72 subPath: filepath.Join(testingVolumePath, `a\b\c\d`), 73 expectError: false, 74 symlinkTarget: "", 75 }, 76 { 77 volumePath: testingVolumePath, 78 subPath: filepath.Join(testingVolumePath, `symlink`), 79 expectError: false, 80 symlinkTarget: base, 81 }, 82 { 83 volumePath: testingVolumePath, 84 subPath: filepath.Join(testingVolumePath, `symlink\c\d`), 85 expectError: true, 86 symlinkTarget: "", 87 }, 88 { 89 volumePath: testingVolumePath, 90 subPath: filepath.Join(testingVolumePath, `symlink\y926`), 91 expectError: true, 92 symlinkTarget: "", 93 }, 94 { 95 volumePath: testingVolumePath, 96 subPath: filepath.Join(testingVolumePath, `a\b\symlink`), 97 expectError: false, 98 symlinkTarget: base, 99 }, 100 { 101 volumePath: testingVolumePath, 102 subPath: filepath.Join(testingVolumePath, `a\x\symlink`), 103 expectError: false, 104 symlinkTarget: filepath.Join(testingVolumePath, `a`), 105 }, 106 } 107 108 for _, test := range tests { 109 if len(test.volumePath) > 0 && len(test.subPath) > 0 && len(test.symlinkTarget) > 0 { 110 // make all parent sub directories 111 if parent := filepath.Dir(test.subPath); parent != "." { 112 os.MkdirAll(parent, 0755) 113 } 114 115 // make last element as symlink 116 linkPath := test.subPath 117 if _, err := os.Stat(linkPath); err != nil && os.IsNotExist(err) { 118 if err := makeLink(linkPath, test.symlinkTarget); err != nil { 119 t.Fatalf("unexpected error: %v", fmt.Errorf("mklink link(%q) target(%q) error: %q", linkPath, test.symlinkTarget, err)) 120 } 121 } 122 } 123 124 err := doSafeMakeDir(test.subPath, test.volumePath, os.FileMode(0755)) 125 if test.expectError { 126 assert.NotNil(t, err, "Expect error during doSafeMakeDir(%s, %s)", test.subPath, test.volumePath) 127 continue 128 } 129 assert.Nil(t, err, "Expect no error during doSafeMakeDir(%s, %s)", test.subPath, test.volumePath) 130 if _, err := os.Stat(test.subPath); os.IsNotExist(err) { 131 t.Errorf("subPath should exists after doSafeMakeDir(%s, %s)", test.subPath, test.volumePath) 132 } 133 } 134 } 135 136 func TestLockAndCheckSubPath(t *testing.T) { 137 base, err := ioutil.TempDir("", "TestLockAndCheckSubPath") 138 if err != nil { 139 t.Fatalf(err.Error()) 140 } 141 142 defer os.RemoveAll(base) 143 144 testingVolumePath := filepath.Join(base, "testingVolumePath") 145 146 tests := []struct { 147 volumePath string 148 subPath string 149 expectedHandleCount int 150 expectError bool 151 symlinkTarget string 152 }{ 153 { 154 volumePath: `c:\`, 155 subPath: ``, 156 expectedHandleCount: 0, 157 expectError: false, 158 symlinkTarget: "", 159 }, 160 { 161 volumePath: ``, 162 subPath: `a`, 163 expectedHandleCount: 0, 164 expectError: false, 165 symlinkTarget: "", 166 }, 167 { 168 volumePath: testingVolumePath, 169 subPath: filepath.Join(testingVolumePath, `a`), 170 expectedHandleCount: 1, 171 expectError: false, 172 symlinkTarget: "", 173 }, 174 { 175 volumePath: testingVolumePath, 176 subPath: filepath.Join(testingVolumePath, `a\b\c\d`), 177 expectedHandleCount: 4, 178 expectError: false, 179 symlinkTarget: "", 180 }, 181 { 182 volumePath: testingVolumePath, 183 subPath: filepath.Join(testingVolumePath, `symlink`), 184 expectedHandleCount: 0, 185 expectError: true, 186 symlinkTarget: base, 187 }, 188 { 189 volumePath: testingVolumePath, 190 subPath: filepath.Join(testingVolumePath, `a\b\c\symlink`), 191 expectedHandleCount: 0, 192 expectError: true, 193 symlinkTarget: base, 194 }, 195 { 196 volumePath: testingVolumePath, 197 subPath: filepath.Join(testingVolumePath, `a\b\c\d\symlink`), 198 expectedHandleCount: 2, 199 expectError: false, 200 symlinkTarget: filepath.Join(testingVolumePath, `a\b`), 201 }, 202 } 203 204 for _, test := range tests { 205 if len(test.volumePath) > 0 && len(test.subPath) > 0 { 206 os.MkdirAll(test.volumePath, 0755) 207 if len(test.symlinkTarget) == 0 { 208 // make all intermediate sub directories 209 os.MkdirAll(test.subPath, 0755) 210 } else { 211 // make all parent sub directories 212 if parent := filepath.Dir(test.subPath); parent != "." { 213 os.MkdirAll(parent, 0755) 214 } 215 216 // make last element as symlink 217 linkPath := test.subPath 218 if _, err := os.Stat(linkPath); err != nil && os.IsNotExist(err) { 219 if err := makeLink(linkPath, test.symlinkTarget); err != nil { 220 t.Fatalf("unexpected error: %v", fmt.Errorf("mklink link(%q) target(%q) error: %q", linkPath, test.symlinkTarget, err)) 221 } 222 } 223 } 224 } 225 226 fileHandles, err := lockAndCheckSubPath(test.volumePath, test.subPath) 227 unlockPath(fileHandles) 228 assert.Equal(t, test.expectedHandleCount, len(fileHandles)) 229 if test.expectError { 230 assert.NotNil(t, err, "Expect error during LockAndCheckSubPath(%s, %s)", test.volumePath, test.subPath) 231 continue 232 } 233 assert.Nil(t, err, "Expect no error during LockAndCheckSubPath(%s, %s)", test.volumePath, test.subPath) 234 } 235 236 // remove dir will happen after closing all file handles 237 assert.Nil(t, os.RemoveAll(testingVolumePath), "Expect no error during remove dir %s", testingVolumePath) 238 } 239 240 func TestLockAndCheckSubPathWithoutSymlink(t *testing.T) { 241 base, err := ioutil.TempDir("", "TestLockAndCheckSubPathWithoutSymlink") 242 if err != nil { 243 t.Fatalf(err.Error()) 244 } 245 246 defer os.RemoveAll(base) 247 248 testingVolumePath := filepath.Join(base, "testingVolumePath") 249 250 tests := []struct { 251 volumePath string 252 subPath string 253 expectedHandleCount int 254 expectError bool 255 symlinkTarget string 256 }{ 257 { 258 volumePath: `c:\`, 259 subPath: ``, 260 expectedHandleCount: 0, 261 expectError: false, 262 symlinkTarget: "", 263 }, 264 { 265 volumePath: ``, 266 subPath: `a`, 267 expectedHandleCount: 0, 268 expectError: false, 269 symlinkTarget: "", 270 }, 271 { 272 volumePath: testingVolumePath, 273 subPath: filepath.Join(testingVolumePath, `a`), 274 expectedHandleCount: 1, 275 expectError: false, 276 symlinkTarget: "", 277 }, 278 { 279 volumePath: testingVolumePath, 280 subPath: filepath.Join(testingVolumePath, `a\b\c\d`), 281 expectedHandleCount: 4, 282 expectError: false, 283 symlinkTarget: "", 284 }, 285 { 286 volumePath: testingVolumePath, 287 subPath: filepath.Join(testingVolumePath, `symlink`), 288 expectedHandleCount: 1, 289 expectError: true, 290 symlinkTarget: base, 291 }, 292 { 293 volumePath: testingVolumePath, 294 subPath: filepath.Join(testingVolumePath, `a\b\c\symlink`), 295 expectedHandleCount: 4, 296 expectError: true, 297 symlinkTarget: base, 298 }, 299 { 300 volumePath: testingVolumePath, 301 subPath: filepath.Join(testingVolumePath, `a\b\c\d\symlink`), 302 expectedHandleCount: 5, 303 expectError: true, 304 symlinkTarget: filepath.Join(testingVolumePath, `a\b`), 305 }, 306 } 307 308 for _, test := range tests { 309 if len(test.volumePath) > 0 && len(test.subPath) > 0 { 310 os.MkdirAll(test.volumePath, 0755) 311 if len(test.symlinkTarget) == 0 { 312 // make all intermediate sub directories 313 os.MkdirAll(test.subPath, 0755) 314 } else { 315 // make all parent sub directories 316 if parent := filepath.Dir(test.subPath); parent != "." { 317 os.MkdirAll(parent, 0755) 318 } 319 320 // make last element as symlink 321 linkPath := test.subPath 322 if _, err := os.Stat(linkPath); err != nil && os.IsNotExist(err) { 323 if err := makeLink(linkPath, test.symlinkTarget); err != nil { 324 t.Fatalf("unexpected error: %v", fmt.Errorf("mklink link(%q) target(%q) error: %q", linkPath, test.symlinkTarget, err)) 325 } 326 } 327 } 328 } 329 330 fileHandles, err := lockAndCheckSubPathWithoutSymlink(test.volumePath, test.subPath) 331 unlockPath(fileHandles) 332 assert.Equal(t, test.expectedHandleCount, len(fileHandles)) 333 if test.expectError { 334 assert.NotNil(t, err, "Expect error during LockAndCheckSubPath(%s, %s)", test.volumePath, test.subPath) 335 continue 336 } 337 assert.Nil(t, err, "Expect no error during LockAndCheckSubPath(%s, %s)", test.volumePath, test.subPath) 338 } 339 340 // remove dir will happen after closing all file handles 341 assert.Nil(t, os.RemoveAll(testingVolumePath), "Expect no error during remove dir %s", testingVolumePath) 342 } 343 344 func TestFindExistingPrefix(t *testing.T) { 345 base, err := ioutil.TempDir("", "TestFindExistingPrefix") 346 if err != nil { 347 t.Fatalf(err.Error()) 348 } 349 350 defer os.RemoveAll(base) 351 352 testingVolumePath := filepath.Join(base, "testingVolumePath") 353 354 tests := []struct { 355 base string 356 pathname string 357 expectError bool 358 expectedExistingPath string 359 expectedToCreateDirs []string 360 createSubPathBeforeTest bool 361 }{ 362 { 363 base: `c:\tmp\a`, 364 pathname: `c:\tmp\b`, 365 expectError: true, 366 expectedExistingPath: "", 367 expectedToCreateDirs: []string{}, 368 createSubPathBeforeTest: false, 369 }, 370 { 371 base: ``, 372 pathname: `c:\tmp\b`, 373 expectError: true, 374 expectedExistingPath: "", 375 expectedToCreateDirs: []string{}, 376 createSubPathBeforeTest: false, 377 }, 378 { 379 base: `c:\tmp\a`, 380 pathname: `d:\tmp\b`, 381 expectError: true, 382 expectedExistingPath: "", 383 expectedToCreateDirs: []string{}, 384 createSubPathBeforeTest: false, 385 }, 386 { 387 base: testingVolumePath, 388 pathname: testingVolumePath, 389 expectError: false, 390 expectedExistingPath: testingVolumePath, 391 expectedToCreateDirs: []string{}, 392 createSubPathBeforeTest: false, 393 }, 394 { 395 base: testingVolumePath, 396 pathname: filepath.Join(testingVolumePath, `a\b`), 397 expectError: false, 398 expectedExistingPath: filepath.Join(testingVolumePath, `a\b`), 399 expectedToCreateDirs: []string{}, 400 createSubPathBeforeTest: true, 401 }, 402 { 403 base: testingVolumePath, 404 pathname: filepath.Join(testingVolumePath, `a\b\c\`), 405 expectError: false, 406 expectedExistingPath: filepath.Join(testingVolumePath, `a\b`), 407 expectedToCreateDirs: []string{`c`}, 408 createSubPathBeforeTest: false, 409 }, 410 { 411 base: testingVolumePath, 412 pathname: filepath.Join(testingVolumePath, `a\b\c\d`), 413 expectError: false, 414 expectedExistingPath: filepath.Join(testingVolumePath, `a\b`), 415 expectedToCreateDirs: []string{`c`, `d`}, 416 createSubPathBeforeTest: false, 417 }, 418 } 419 420 for _, test := range tests { 421 if test.createSubPathBeforeTest { 422 os.MkdirAll(test.pathname, 0755) 423 } 424 425 existingPath, toCreate, err := findExistingPrefix(test.base, test.pathname) 426 if test.expectError { 427 assert.NotNil(t, err, "Expect error during findExistingPrefix(%s, %s)", test.base, test.pathname) 428 continue 429 } 430 assert.Nil(t, err, "Expect no error during findExistingPrefix(%s, %s)", test.base, test.pathname) 431 432 assert.Equal(t, test.expectedExistingPath, existingPath, "Expect result not equal with findExistingPrefix(%s, %s) return: %q, expected: %q", 433 test.base, test.pathname, existingPath, test.expectedExistingPath) 434 435 assert.Equal(t, test.expectedToCreateDirs, toCreate, "Expect result not equal with findExistingPrefix(%s, %s) return: %q, expected: %q", 436 test.base, test.pathname, toCreate, test.expectedToCreateDirs) 437 438 } 439 // remove dir will happen after closing all file handles 440 assert.Nil(t, os.RemoveAll(testingVolumePath), "Expect no error during remove dir %s", testingVolumePath) 441 } 442 443 func TestIsDriveLetterorEmptyPath(t *testing.T) { 444 tests := []struct { 445 path string 446 expectedResult bool 447 }{ 448 { 449 path: ``, 450 expectedResult: true, 451 }, 452 { 453 path: `\tmp`, 454 expectedResult: false, 455 }, 456 { 457 path: `c:\tmp`, 458 expectedResult: false, 459 }, 460 { 461 path: `c:\\`, 462 expectedResult: true, 463 }, 464 { 465 path: `c:\`, 466 expectedResult: true, 467 }, 468 { 469 path: `c:`, 470 expectedResult: true, 471 }, 472 } 473 474 for _, test := range tests { 475 result := isDriveLetterorEmptyPath(test.path) 476 assert.Equal(t, test.expectedResult, result, "Expect result not equal with isDriveLetterorEmptyPath(%s) return: %t, expected: %t", 477 test.path, result, test.expectedResult) 478 } 479 }