/**
* Copyright 2016 StreamSets Inc.
*
* Licensed under the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.streamsets.pipeline.lib.io;
import com.streamsets.pipeline.lib.executor.SafeScheduledExecutorService;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.internal.util.reflection.Whitebox;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestDirectoryPathCreationWatcher {
private class DirectoryCreationWorker implements Runnable {
List<Path> remainingPathsToCreate;
boolean shouldShuffle;
DirectoryCreationWorker(Collection<Path> paths, boolean shouldShuffle) {
this.remainingPathsToCreate = Collections.synchronizedList(new ArrayList<Path>(paths));
this.shouldShuffle = shouldShuffle;
}
List<Path> getRemainingPathsToCreate() {
return this.remainingPathsToCreate;
}
@Override
public void run() {
if (!remainingPathsToCreate.isEmpty()) {
if (shouldShuffle) {
Collections.shuffle(remainingPathsToCreate);
}
Path path = remainingPathsToCreate.remove(0);
try {
Files.createDirectories(path);
} catch (IOException e) {
Assert.fail(e.getMessage());
}
}
}
}
private void checkCorrectness(Collection<Path> paths, Set<Path> foundPaths, ScheduledExecutorService executor) {
Assert.assertEquals("All Paths are not found", paths.size(), foundPaths.size());
Assert.assertTrue("Found Unwanted Paths", foundPaths.containsAll(paths));
Assert.assertTrue("Executor should be null after shut down", executor == null);
}
@Test
public void testSynchronousDirectoryFinder() throws Exception {
String testDataDir = "target" + File.separatorChar + UUID.randomUUID().toString();
Files.createDirectories(Paths.get(testDataDir));
final Collection<Path> paths = Arrays.asList(
Paths.get(testDataDir + File.separatorChar + "d1"),
Paths.get(testDataDir + File.separatorChar + "d2"),
Paths.get(testDataDir + File.separatorChar + "d3"),
Paths.get(testDataDir + File.separatorChar + "d4"),
Paths.get(testDataDir + File.separatorChar + "d5"),
Paths.get(testDataDir + File.separatorChar + "d6"),
Paths.get(testDataDir + File.separatorChar + "d7"),
Paths.get(testDataDir + File.separatorChar + "d8")
);
DirectoryPathCreationWatcher watcher = new DirectoryPathCreationWatcher(paths, 0);
DirectoryCreationWorker worker = new DirectoryCreationWorker(paths, true);
for (int i =0; i < paths.size(); i++) {
worker.run();
}
Set<Path> foundPaths = watcher.find();
checkCorrectness(paths, foundPaths, (ScheduledExecutorService)Whitebox.getInternalState(watcher, "executor"));
}
@Test
public void testAsyncDirFinderAllDirsAtOnce() throws Exception {
String testDataDir = "target" + File.separatorChar + UUID.randomUUID().toString();
Files.createDirectories(Paths.get(testDataDir));
final Collection<Path> paths = Arrays.asList(
Paths.get(testDataDir + File.separatorChar + "d1"),
Paths.get(testDataDir + File.separatorChar + "d2"),
Paths.get(testDataDir + File.separatorChar + "d3"),
Paths.get(testDataDir + File.separatorChar + "d4"),
Paths.get(testDataDir + File.separatorChar + "d5"),
Paths.get(testDataDir + File.separatorChar + "d6"),
Paths.get(testDataDir + File.separatorChar + "d7"),
Paths.get(testDataDir + File.separatorChar + "d8")
);
DirectoryPathCreationWatcher watcher = new DirectoryPathCreationWatcher(paths, 1);
DirectoryCreationWorker worker = new DirectoryCreationWorker(paths, true);
for (int i =0; i < paths.size(); i++) {
worker.run();
}
Thread.sleep(paths.size() * 1000);
Set<Path> foundPaths = watcher.find();
checkCorrectness(paths, foundPaths, (ScheduledExecutorService)Whitebox.getInternalState(watcher, "executor"));
}
@Test
public void testAsyncDirFinderDirsCreatedPeriodically() throws Exception {
String testDataDir = "target" + File.separatorChar + UUID.randomUUID().toString();
Files.createDirectories(Paths.get(testDataDir));
final Collection<Path> paths = Arrays.asList(
Paths.get(testDataDir + File.separatorChar + "d1"),
Paths.get(testDataDir + File.separatorChar + "d2"),
Paths.get(testDataDir + File.separatorChar + "d3"),
Paths.get(testDataDir + File.separatorChar + "d4"),
Paths.get(testDataDir + File.separatorChar + "d5"),
Paths.get(testDataDir + File.separatorChar + "d6"),
Paths.get(testDataDir + File.separatorChar + "d7"),
Paths.get(testDataDir + File.separatorChar + "d8"),
Paths.get(testDataDir + File.separatorChar + "d1" + File.separatorChar + "d11"),
Paths.get(testDataDir + File.separatorChar + "d1" + File.separatorChar + "d12"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d21" + File.separatorChar + "d211"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d22" + File.separatorChar + "d221"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d23" + File.separatorChar + "d231"),
Paths.get(testDataDir + File.separatorChar + "d3" + File.separatorChar + "d31"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111" + File.separatorChar + "d41111")
);
DirectoryPathCreationWatcher watcher = new DirectoryPathCreationWatcher(paths, 1);
ScheduledExecutorService directoryCreationExecutor = new SafeScheduledExecutorService(1, "Directory Creator");
DirectoryCreationWorker worker = new DirectoryCreationWorker(paths, false);
directoryCreationExecutor.scheduleAtFixedRate(worker, 0, 100, TimeUnit.MILLISECONDS);
Set<Path> foundPaths = new HashSet<Path>();
while (!worker.getRemainingPathsToCreate().isEmpty()) {
Set<Path> foundPathsTillNow = watcher.find();
foundPaths.addAll(foundPathsTillNow);
Thread.sleep(100);
}
directoryCreationExecutor.shutdownNow();
directoryCreationExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
Thread.sleep(paths.size() * 100 + 1000);
//Just to find the last set of detected directories.
foundPaths.addAll(watcher.find());
checkCorrectness(paths, foundPaths, (ScheduledExecutorService)Whitebox.getInternalState(watcher, "executor"));
}
@Test
public void testAsyncDirFinderShuffledDirsCreatedPeriodically() throws Exception {
String testDataDir = "target" + File.separatorChar + UUID.randomUUID().toString();
Files.createDirectories(Paths.get(testDataDir));
final Collection<Path> paths = Arrays.asList(
Paths.get(testDataDir + File.separatorChar + "d1"),
Paths.get(testDataDir + File.separatorChar + "d2"),
Paths.get(testDataDir + File.separatorChar + "d3"),
Paths.get(testDataDir + File.separatorChar + "d4"),
Paths.get(testDataDir + File.separatorChar + "d5"),
Paths.get(testDataDir + File.separatorChar + "d6"),
Paths.get(testDataDir + File.separatorChar + "d7"),
Paths.get(testDataDir + File.separatorChar + "d8"),
Paths.get(testDataDir + File.separatorChar + "d1" + File.separatorChar + "d11"),
Paths.get(testDataDir + File.separatorChar + "d1" + File.separatorChar + "d12"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d21" + File.separatorChar + "d211"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d22" + File.separatorChar + "d221"),
Paths.get(testDataDir + File.separatorChar + "d2" + File.separatorChar + "d23" + File.separatorChar + "d231"),
Paths.get(testDataDir + File.separatorChar + "d3" + File.separatorChar + "d31"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4112"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111" + File.separatorChar + "d41111"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111" + File.separatorChar + "d41112"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111" + File.separatorChar + "d41111" + File.separatorChar + "d411111"),
Paths.get(testDataDir + File.separatorChar + "d4" + File.separatorChar + "d41" + File.separatorChar + "d411"
+ File.separatorChar + "d4111" + File.separatorChar + "d41112" + File.separatorChar + "d411111")
);
DirectoryPathCreationWatcher watcher = new DirectoryPathCreationWatcher(paths, 1);
ScheduledExecutorService directoryCreationExecutor = new SafeScheduledExecutorService(1, "Directory Creator");
DirectoryCreationWorker worker = new DirectoryCreationWorker(paths, true);
directoryCreationExecutor.scheduleAtFixedRate(worker, 0, 100, TimeUnit.MILLISECONDS);
Set<Path> foundPaths = new HashSet<Path>();
while (!worker.getRemainingPathsToCreate().isEmpty()) {
Set<Path> foundPathsTillNow = watcher.find();
foundPaths.addAll(foundPathsTillNow);
Thread.sleep(100);
}
directoryCreationExecutor.shutdownNow();
directoryCreationExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
Thread.sleep(paths.size() * 100 + 1000);
//Just to find the last set of detected directories.
foundPaths.addAll(watcher.find());
checkCorrectness(paths, foundPaths, (ScheduledExecutorService)Whitebox.getInternalState(watcher, "executor"));
}
}