1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 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 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.transfer.s3.internal; 17 18 import static org.assertj.core.api.Assertions.assertThat; 19 import static org.assertj.core.api.Assertions.assertThatThrownBy; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.when; 23 24 import com.google.common.jimfs.Configuration; 25 import com.google.common.jimfs.Jimfs; 26 import java.io.IOException; 27 import java.io.UncheckedIOException; 28 import java.nio.charset.StandardCharsets; 29 import java.nio.file.FileSystem; 30 import java.nio.file.Files; 31 import java.nio.file.Path; 32 import java.nio.file.Paths; 33 import java.util.Arrays; 34 import java.util.Collection; 35 import java.util.List; 36 import java.util.concurrent.CancellationException; 37 import java.util.concurrent.CompletableFuture; 38 import java.util.concurrent.TimeUnit; 39 import java.util.function.Consumer; 40 import java.util.function.Function; 41 import java.util.stream.Collectors; 42 import org.junit.jupiter.api.AfterAll; 43 import org.junit.jupiter.api.AfterEach; 44 import org.junit.jupiter.api.BeforeAll; 45 import org.junit.jupiter.api.BeforeEach; 46 import org.junit.jupiter.api.Test; 47 import org.junit.jupiter.params.ParameterizedTest; 48 import org.junit.jupiter.params.provider.MethodSource; 49 import org.mockito.ArgumentCaptor; 50 import software.amazon.awssdk.core.exception.SdkClientException; 51 import software.amazon.awssdk.services.s3.internal.crt.S3MetaRequestPauseObservable; 52 import software.amazon.awssdk.services.s3.model.PutObjectRequest; 53 import software.amazon.awssdk.services.s3.model.PutObjectResponse; 54 import software.amazon.awssdk.testutils.FileUtils; 55 import software.amazon.awssdk.transfer.s3.config.TransferRequestOverrideConfiguration; 56 import software.amazon.awssdk.transfer.s3.internal.model.DefaultFileUpload; 57 import software.amazon.awssdk.transfer.s3.internal.progress.DefaultTransferProgress; 58 import software.amazon.awssdk.transfer.s3.internal.progress.DefaultTransferProgressSnapshot; 59 import software.amazon.awssdk.transfer.s3.model.CompletedDirectoryUpload; 60 import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload; 61 import software.amazon.awssdk.transfer.s3.model.DirectoryUpload; 62 import software.amazon.awssdk.transfer.s3.model.FileUpload; 63 import software.amazon.awssdk.transfer.s3.model.UploadDirectoryRequest; 64 import software.amazon.awssdk.transfer.s3.model.UploadFileRequest; 65 import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener; 66 import software.amazon.awssdk.transfer.s3.progress.TransferListener; 67 68 public class UploadDirectoryHelperTest { 69 private FileSystem jimfs; 70 private Path directory; 71 72 /** 73 * Local directory is needed to test symlinks because jimfs doesn't work well with symlinks 74 */ 75 private static Path localDirectory; 76 private Function<UploadFileRequest, FileUpload> singleUploadFunction; 77 private UploadDirectoryHelper uploadDirectoryHelper; 78 fileSystems()79 public static Collection<FileSystem> fileSystems() { 80 return Arrays.asList(Jimfs.newFileSystem(Configuration.unix()), 81 Jimfs.newFileSystem(Configuration.osX()), 82 Jimfs.newFileSystem(Configuration.windows())); 83 } 84 85 @BeforeAll setUp()86 public static void setUp() throws IOException { 87 localDirectory = createLocalTestDirectory(); 88 } 89 90 @AfterAll tearDown()91 public static void tearDown() throws IOException { 92 FileUtils.cleanUpTestDirectory(localDirectory); 93 } 94 95 @BeforeEach methodSetup()96 public void methodSetup() throws IOException { 97 jimfs = Jimfs.newFileSystem(); 98 directory = jimfs.getPath("test"); 99 Files.createDirectory(directory); 100 Files.createFile(jimfs.getPath("test/1")); 101 Files.createFile(jimfs.getPath("test/2")); 102 103 singleUploadFunction = mock(Function.class); 104 105 uploadDirectoryHelper = new UploadDirectoryHelper(TransferManagerConfiguration.builder().build(), singleUploadFunction); 106 } 107 108 @AfterEach methodCleanup()109 public void methodCleanup() throws IOException { 110 jimfs.close(); 111 } 112 113 @Test uploadDirectory_cancel_shouldCancelAllFutures()114 void uploadDirectory_cancel_shouldCancelAllFutures() { 115 CompletableFuture<CompletedFileUpload> future = new CompletableFuture<>(); 116 FileUpload fileUpload = newUpload(future); 117 118 CompletableFuture<CompletedFileUpload> future2 = new CompletableFuture<>(); 119 FileUpload fileUpload2 = newUpload(future2); 120 121 when(singleUploadFunction.apply(any(UploadFileRequest.class))).thenReturn(fileUpload, fileUpload2); 122 123 DirectoryUpload uploadDirectory = 124 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 125 .source(directory) 126 .bucket("bucket") 127 .build()); 128 129 uploadDirectory.completionFuture().cancel(true); 130 131 assertThatThrownBy(() -> future.get(1, TimeUnit.SECONDS)) 132 .isInstanceOf(CancellationException.class); 133 134 assertThatThrownBy(() -> future2.get(1, TimeUnit.SECONDS)) 135 .isInstanceOf(CancellationException.class); 136 } 137 138 @Test uploadDirectory_allUploadsSucceed_failedUploadsShouldBeEmpty()139 void uploadDirectory_allUploadsSucceed_failedUploadsShouldBeEmpty() throws Exception { 140 PutObjectResponse putObjectResponse = PutObjectResponse.builder().eTag("1234").build(); 141 CompletedFileUpload completedFileUpload = CompletedFileUpload.builder().response(putObjectResponse).build(); 142 CompletableFuture<CompletedFileUpload> successfulFuture = new CompletableFuture<>(); 143 144 FileUpload fileUpload = newUpload(successfulFuture); 145 successfulFuture.complete(completedFileUpload); 146 147 PutObjectResponse putObjectResponse2 = PutObjectResponse.builder().eTag("5678").build(); 148 CompletedFileUpload completedFileUpload2 = CompletedFileUpload.builder().response(putObjectResponse2).build(); 149 CompletableFuture<CompletedFileUpload> successfulFuture2 = new CompletableFuture<>(); 150 FileUpload fileUpload2 = newUpload(successfulFuture2); 151 successfulFuture2.complete(completedFileUpload2); 152 153 when(singleUploadFunction.apply(any(UploadFileRequest.class))).thenReturn(fileUpload, fileUpload2); 154 155 DirectoryUpload uploadDirectory = 156 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 157 .source(directory) 158 .bucket("bucket") 159 .build()); 160 161 CompletedDirectoryUpload completedDirectoryUpload = uploadDirectory.completionFuture().get(5, TimeUnit.SECONDS); 162 163 assertThat(completedDirectoryUpload.failedTransfers()).isEmpty(); 164 } 165 166 @Test uploadDirectory_partialSuccess_shouldProvideFailedUploads()167 void uploadDirectory_partialSuccess_shouldProvideFailedUploads() throws Exception { 168 PutObjectResponse putObjectResponse = PutObjectResponse.builder().eTag("1234").build(); 169 CompletedFileUpload completedFileUpload = CompletedFileUpload.builder().response(putObjectResponse).build(); 170 CompletableFuture<CompletedFileUpload> successfulFuture = new CompletableFuture<>(); 171 FileUpload fileUpload = newUpload(successfulFuture); 172 successfulFuture.complete(completedFileUpload); 173 174 SdkClientException exception = SdkClientException.create("failed"); 175 CompletableFuture<CompletedFileUpload> failedFuture = new CompletableFuture<>(); 176 FileUpload fileUpload2 = newUpload(failedFuture); 177 failedFuture.completeExceptionally(exception); 178 179 when(singleUploadFunction.apply(any(UploadFileRequest.class))).thenReturn(fileUpload, fileUpload2); 180 181 DirectoryUpload uploadDirectory = 182 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 183 .source(directory) 184 .bucket("bucket") 185 .build()); 186 187 CompletedDirectoryUpload completedDirectoryUpload = uploadDirectory.completionFuture().get(5, TimeUnit.SECONDS); 188 189 assertThat(completedDirectoryUpload.failedTransfers()).hasSize(1); 190 assertThat(completedDirectoryUpload.failedTransfers().iterator().next().exception()).isEqualTo(exception); 191 assertThat(completedDirectoryUpload.failedTransfers().iterator().next().request().source().toString()) 192 .isEqualTo("test" + directory.getFileSystem().getSeparator() + "2"); 193 } 194 195 @Test uploadDirectory_withRequestTransformer_usesRequestTransformer()196 void uploadDirectory_withRequestTransformer_usesRequestTransformer() throws Exception { 197 PutObjectResponse putObjectResponse = PutObjectResponse.builder().eTag("1234").build(); 198 CompletedFileUpload completedFileUpload = CompletedFileUpload.builder().response(putObjectResponse).build(); 199 CompletableFuture<CompletedFileUpload> successfulFuture = new CompletableFuture<>(); 200 201 FileUpload upload = newUpload(successfulFuture); 202 successfulFuture.complete(completedFileUpload); 203 204 PutObjectResponse putObjectResponse2 = PutObjectResponse.builder().eTag("5678").build(); 205 CompletedFileUpload completedFileUpload2 = CompletedFileUpload.builder().response(putObjectResponse2).build(); 206 CompletableFuture<CompletedFileUpload> successfulFuture2 = new CompletableFuture<>(); 207 FileUpload upload2 = newUpload(successfulFuture2); 208 successfulFuture2.complete(completedFileUpload2); 209 210 ArgumentCaptor<UploadFileRequest> uploadRequestCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 211 212 when(singleUploadFunction.apply(uploadRequestCaptor.capture())).thenReturn(upload, upload2); 213 214 Path newSource = Paths.get("/new/path"); 215 PutObjectRequest newPutObjectRequest = PutObjectRequest.builder().build(); 216 TransferRequestOverrideConfiguration newOverrideConfig = TransferRequestOverrideConfiguration.builder() 217 .build(); 218 List<TransferListener> listeners = Arrays.asList(LoggingTransferListener.create()); 219 220 Consumer<UploadFileRequest.Builder> uploadFileRequestTransformer = r -> r.source(newSource) 221 .putObjectRequest(newPutObjectRequest) 222 .transferListeners(listeners); 223 224 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 225 .source(directory) 226 .bucket("bucket") 227 .uploadFileRequestTransformer(uploadFileRequestTransformer) 228 .build()) 229 .completionFuture() 230 .get(5, TimeUnit.SECONDS); 231 232 List<UploadFileRequest> uploadRequests = uploadRequestCaptor.getAllValues(); 233 assertThat(uploadRequests).hasSize(2); 234 assertThat(uploadRequests).element(0).satisfies(r -> { 235 assertThat(r.source()).isEqualTo(newSource); 236 assertThat(r.putObjectRequest()).isEqualTo(newPutObjectRequest); 237 assertThat(r.transferListeners()).isEqualTo(listeners); 238 }); 239 assertThat(uploadRequests).element(1).satisfies(r -> { 240 assertThat(r.source()).isEqualTo(newSource); 241 assertThat(r.putObjectRequest()).isEqualTo(newPutObjectRequest); 242 assertThat(r.transferListeners()).isEqualTo(listeners); 243 }); 244 } 245 246 @ParameterizedTest 247 @MethodSource("fileSystems") uploadDirectory_defaultSetting_shouldRecursivelyUpload(FileSystem fileSystem)248 void uploadDirectory_defaultSetting_shouldRecursivelyUpload(FileSystem fileSystem) { 249 directory = createJimFsTestDirectory(fileSystem); 250 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 251 252 when(singleUploadFunction.apply(requestArgumentCaptor.capture())) 253 .thenReturn(completedUpload()); 254 DirectoryUpload uploadDirectory = 255 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 256 .source(directory) 257 .bucket("bucket") 258 .followSymbolicLinks(false) 259 .build()); 260 uploadDirectory.completionFuture().join(); 261 262 List<UploadFileRequest> actualRequests = requestArgumentCaptor.getAllValues(); 263 actualRequests.forEach(r -> assertThat(r.putObjectRequest().bucket()).isEqualTo("bucket")); 264 265 assertThat(actualRequests.size()).isEqualTo(3); 266 267 List<String> keys = 268 actualRequests.stream().map(u -> u.putObjectRequest().key()) 269 .collect(Collectors.toList()); 270 271 assertThat(keys).containsOnly("bar.txt", "foo/1.txt", "foo/2.txt"); 272 } 273 274 @Test uploadDirectory_depth1FollowSymlinkTrue_shouldOnlyUploadTopLevel()275 void uploadDirectory_depth1FollowSymlinkTrue_shouldOnlyUploadTopLevel() { 276 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 277 278 when(singleUploadFunction.apply(requestArgumentCaptor.capture())).thenReturn(completedUpload()); 279 DirectoryUpload uploadDirectory = 280 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 281 .source(localDirectory) 282 .bucket("bucket") 283 .maxDepth(1) 284 .followSymbolicLinks(true) 285 .build()); 286 uploadDirectory.completionFuture().join(); 287 288 List<UploadFileRequest> actualRequests = requestArgumentCaptor.getAllValues(); 289 List<String> keys = 290 actualRequests.stream().map(u -> u.putObjectRequest().key()) 291 .collect(Collectors.toList()); 292 293 assertThat(keys.size()).isEqualTo(2); 294 assertThat(keys).containsOnly("bar.txt", "symlink2"); 295 } 296 297 @Test uploadDirectory_FollowSymlinkTrue_shouldIncludeLinkedFiles()298 void uploadDirectory_FollowSymlinkTrue_shouldIncludeLinkedFiles() { 299 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 300 301 when(singleUploadFunction.apply(requestArgumentCaptor.capture())).thenReturn(completedUpload()); 302 DirectoryUpload uploadDirectory = 303 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 304 .source(localDirectory) 305 .bucket("bucket") 306 .followSymbolicLinks(true) 307 .build()); 308 uploadDirectory.completionFuture().join(); 309 310 List<UploadFileRequest> actualRequests = requestArgumentCaptor.getAllValues(); 311 actualRequests.forEach(r -> assertThat(r.putObjectRequest().bucket()).isEqualTo("bucket")); 312 313 List<String> keys = 314 actualRequests.stream().map(u -> u.putObjectRequest().key()) 315 .collect(Collectors.toList()); 316 317 assertThat(keys.size()).isEqualTo(5); 318 assertThat(keys).containsOnly("bar.txt", "foo/1.txt", "foo/2.txt", "symlink/2.txt", "symlink2"); 319 } 320 321 @ParameterizedTest 322 @MethodSource("fileSystems") uploadDirectory_withPrefix_keysShouldHavePrefix(FileSystem fileSystem)323 void uploadDirectory_withPrefix_keysShouldHavePrefix(FileSystem fileSystem) { 324 directory = createJimFsTestDirectory(fileSystem); 325 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 326 327 when(singleUploadFunction.apply(requestArgumentCaptor.capture())).thenReturn(completedUpload()); 328 DirectoryUpload uploadDirectory = 329 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 330 .source(directory) 331 .bucket("bucket") 332 .s3Prefix("yolo") 333 .build()); 334 uploadDirectory.completionFuture().join(); 335 336 List<String> keys = 337 requestArgumentCaptor.getAllValues().stream().map(u -> u.putObjectRequest().key()) 338 .collect(Collectors.toList()); 339 340 assertThat(keys.size()).isEqualTo(3); 341 keys.forEach(r -> assertThat(r).startsWith("yolo/")); 342 } 343 344 @ParameterizedTest 345 @MethodSource("fileSystems") uploadDirectory_withDelimiter_shouldHonor(FileSystem fileSystem)346 void uploadDirectory_withDelimiter_shouldHonor(FileSystem fileSystem) { 347 directory = createJimFsTestDirectory(fileSystem); 348 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 349 350 when(singleUploadFunction.apply(requestArgumentCaptor.capture())).thenReturn(completedUpload()); 351 DirectoryUpload uploadDirectory = 352 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 353 .source(directory) 354 .bucket("bucket") 355 .s3Delimiter(",") 356 .s3Prefix("yolo") 357 .build()); 358 uploadDirectory.completionFuture().join(); 359 360 List<String> keys = 361 requestArgumentCaptor.getAllValues().stream().map(u -> u.putObjectRequest().key()) 362 .collect(Collectors.toList()); 363 364 assertThat(keys.size()).isEqualTo(3); 365 assertThat(keys).containsOnly("yolo,foo,2.txt", "yolo,foo,1.txt", "yolo,bar.txt"); 366 } 367 368 @ParameterizedTest 369 @MethodSource("fileSystems") uploadDirectory_maxLengthOne_shouldOnlyUploadTopLevel(FileSystem fileSystem)370 void uploadDirectory_maxLengthOne_shouldOnlyUploadTopLevel(FileSystem fileSystem) { 371 directory = createJimFsTestDirectory(fileSystem); 372 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 373 374 when(singleUploadFunction.apply(requestArgumentCaptor.capture())) 375 .thenReturn(completedUpload()); 376 DirectoryUpload uploadDirectory = 377 uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 378 .source(directory) 379 .bucket("bucket") 380 .maxDepth(1) 381 .build()); 382 uploadDirectory.completionFuture().join(); 383 384 List<UploadFileRequest> actualRequests = requestArgumentCaptor.getAllValues(); 385 actualRequests.forEach(r -> assertThat(r.putObjectRequest().bucket()).isEqualTo("bucket")); 386 387 assertThat(actualRequests.size()).isEqualTo(1); 388 389 List<String> keys = 390 actualRequests.stream().map(u -> u.putObjectRequest().key()) 391 .collect(Collectors.toList()); 392 393 assertThat(keys).containsOnly("bar.txt"); 394 } 395 396 397 @ParameterizedTest 398 @MethodSource("fileSystems") uploadDirectory_directoryNotExist_shouldCompleteFutureExceptionally(FileSystem fileSystem)399 void uploadDirectory_directoryNotExist_shouldCompleteFutureExceptionally(FileSystem fileSystem) { 400 directory = createJimFsTestDirectory(fileSystem); 401 assertThatThrownBy(() -> uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder().source(Paths.get( 402 "randomstringneverexistas234ersaf1231")) 403 .bucket("bucketName").build()).completionFuture().join()) 404 .hasMessageContaining("does not exist").hasCauseInstanceOf(IllegalArgumentException.class); 405 } 406 407 @Test uploadDirectory_notDirectory_shouldCompleteFutureExceptionally()408 void uploadDirectory_notDirectory_shouldCompleteFutureExceptionally() { 409 assertThatThrownBy(() -> uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 410 .source(Paths.get(localDirectory.toString(), "symlink")) 411 .bucket("bucketName").build()).completionFuture().join()) 412 .hasMessageContaining("is not a directory").hasCauseInstanceOf(IllegalArgumentException.class); 413 } 414 415 @Test uploadDirectory_notDirectoryFollowSymlinkTrue_shouldCompleteSuccessfully()416 void uploadDirectory_notDirectoryFollowSymlinkTrue_shouldCompleteSuccessfully() { 417 ArgumentCaptor<UploadFileRequest> requestArgumentCaptor = ArgumentCaptor.forClass(UploadFileRequest.class); 418 419 when(singleUploadFunction.apply(requestArgumentCaptor.capture())).thenReturn(completedUpload()); 420 DirectoryUpload uploadDirectory = uploadDirectoryHelper.uploadDirectory(UploadDirectoryRequest.builder() 421 .followSymbolicLinks(true) 422 .source(Paths.get(localDirectory.toString(), "symlink")) 423 .bucket("bucket").build()); 424 425 uploadDirectory.completionFuture().join(); 426 427 List<UploadFileRequest> actualRequests = requestArgumentCaptor.getAllValues(); 428 actualRequests.forEach(r -> assertThat(r.putObjectRequest().bucket()).isEqualTo("bucket")); 429 430 assertThat(actualRequests.size()).isEqualTo(1); 431 432 List<String> keys = 433 actualRequests.stream().map(u -> u.putObjectRequest().key()) 434 .collect(Collectors.toList()); 435 436 assertThat(keys).containsOnly("2.txt"); 437 } 438 completedUpload()439 private DefaultFileUpload completedUpload() { 440 return new DefaultFileUpload(CompletableFuture.completedFuture(CompletedFileUpload.builder() 441 .response(PutObjectResponse.builder().build()) 442 .build()), 443 new DefaultTransferProgress(DefaultTransferProgressSnapshot.builder() 444 .transferredBytes(0L) 445 .build()), 446 UploadFileRequest.builder() 447 .source(Paths.get(".")).putObjectRequest(b -> b.bucket("bucket").key("key")) 448 .build()); 449 } 450 newUpload(CompletableFuture<CompletedFileUpload> future)451 private FileUpload newUpload(CompletableFuture<CompletedFileUpload> future) { 452 return new DefaultFileUpload(future, 453 new DefaultTransferProgress(DefaultTransferProgressSnapshot.builder() 454 .transferredBytes(0L) 455 .build()), 456 UploadFileRequest.builder() 457 .putObjectRequest(p -> p.key("key").bucket("bucket")).source(Paths.get( 458 "test.txt")) 459 .build()); 460 } 461 createJimFsTestDirectory(FileSystem fileSystem)462 private Path createJimFsTestDirectory(FileSystem fileSystem) { 463 464 try { 465 return createJmfsTestDirectory(fileSystem); 466 } catch (IOException exception) { 467 throw new UncheckedIOException(exception); 468 } 469 470 } 471 createLocalTestDirectory()472 private static Path createLocalTestDirectory() { 473 474 try { 475 return createLocalTestDirectoryWithSymLink(); 476 } catch (IOException exception) { 477 throw new UncheckedIOException(exception); 478 } 479 } 480 481 /** 482 * Create a test directory with the following structure - test1 - foo - 1.txt - 2.txt - bar.txt - symlink -> test2 - symlink2 483 * -> test3/4.txt - test2 - 2.txt - test3 - 4.txt 484 */ createLocalTestDirectoryWithSymLink()485 private static Path createLocalTestDirectoryWithSymLink() throws IOException { 486 Path directory = Files.createTempDirectory("test1"); 487 Path anotherDirectory = Files.createTempDirectory("test2"); 488 Path thirdDirectory = Files.createTempDirectory("test3"); 489 490 String directoryName = directory.toString(); 491 String anotherDirectoryName = anotherDirectory.toString(); 492 493 Files.createDirectory(Paths.get(directory + "/foo")); 494 495 Files.write(Paths.get(directoryName, "bar.txt"), "bar".getBytes(StandardCharsets.UTF_8)); 496 Files.write(Paths.get(directoryName, "foo/1.txt"), "1".getBytes(StandardCharsets.UTF_8)); 497 Files.write(Paths.get(directoryName, "foo/2.txt"), "2".getBytes(StandardCharsets.UTF_8)); 498 499 Files.write(Paths.get(anotherDirectoryName, "2.txt"), "2".getBytes(StandardCharsets.UTF_8)); 500 Files.write(Paths.get(thirdDirectory.toString(), "3.txt"), "3".getBytes(StandardCharsets.UTF_8)); 501 502 Files.createSymbolicLink(Paths.get(directoryName, "symlink"), anotherDirectory); 503 Files.createSymbolicLink(Paths.get(directoryName, "symlink2"), Paths.get(thirdDirectory.toString(), "3.txt")); 504 return directory; 505 } 506 507 /** 508 * Create a test directory with the following structure - test1 - foo - 1.txt - 2.txt - bar.txt 509 */ createJmfsTestDirectory(FileSystem jimfs)510 private Path createJmfsTestDirectory(FileSystem jimfs) throws IOException { 511 String directoryName = "test"; 512 Path directory = jimfs.getPath(directoryName); 513 514 Files.createDirectory(directory); 515 516 Files.createDirectory(jimfs.getPath(directoryName + "/foo")); 517 518 Files.write(jimfs.getPath(directoryName, "bar.txt"), "bar".getBytes(StandardCharsets.UTF_8)); 519 Files.write(jimfs.getPath(directoryName, "foo", "1.txt"), "1".getBytes(StandardCharsets.UTF_8)); 520 Files.write(jimfs.getPath(directoryName, "foo", "2.txt"), "2".getBytes(StandardCharsets.UTF_8)); 521 return directory; 522 } 523 } 524