/*
* Licensed to 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 gobblin.util;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import gobblin.util.filesystem.PathAlterationListener;
import gobblin.util.filesystem.PathAlterationListenerAdaptor;
import gobblin.util.filesystem.PathAlterationObserverScheduler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Semaphore;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.fs.Path;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import gobblin.configuration.ConfigurationKeys;
/**
* Unit tests for {@link SchedulerUtils}.
* Note that the entities involved in unit tests
* are only from local file system (Compatible with java.io.File Class)
*/
@Test(groups = {"gobblin.util"})
public class SchedulerUtilsTest {
// For general type of File system
private File jobConfigDir;
private File subDir1;
private File subDir11;
private File subDir2;
@BeforeClass
public void setUp()
throws IOException {
this.jobConfigDir = java.nio.file.Files.createTempDirectory(
String.format("gobblin-test_%s_job-conf", this.getClass().getSimpleName())).toFile();
FileUtils.forceDeleteOnExit(this.jobConfigDir);
this.subDir1 = new File(this.jobConfigDir, "test1");
this.subDir11 = new File(this.subDir1, "test11");
this.subDir2 = new File(this.jobConfigDir, "test2");
this.subDir1.mkdirs();
this.subDir11.mkdirs();
this.subDir2.mkdirs();
Properties rootProps = new Properties();
rootProps.setProperty("k1", "a1");
rootProps.setProperty("k2", "a2");
// test-job-conf-dir/root.properties
rootProps.store(new FileWriter(new File(this.jobConfigDir, "root.properties")), "");
Properties props1 = new Properties();
props1.setProperty("k1", "b1");
props1.setProperty("k3", "a3");
// test-job-conf-dir/test1/test.properties
props1.store(new FileWriter(new File(this.subDir1, "test.properties")), "");
Properties jobProps1 = new Properties();
jobProps1.setProperty("k1", "c1");
jobProps1.setProperty("k3", "b3");
jobProps1.setProperty("k6", "a6");
// test-job-conf-dir/test1/test11.pull
jobProps1.store(new FileWriter(new File(this.subDir1, "test11.pull")), "");
Properties jobProps2 = new Properties();
jobProps2.setProperty("k7", "a7");
// test-job-conf-dir/test1/test12.PULL
jobProps2.store(new FileWriter(new File(this.subDir1, "test12.PULL")), "");
Properties jobProps3 = new Properties();
jobProps3.setProperty("k1", "d1");
jobProps3.setProperty("k8", "a8");
jobProps3.setProperty("k9", "${k8}");
// test-job-conf-dir/test1/test11/test111.pull
jobProps3.store(new FileWriter(new File(this.subDir11, "test111.pull")), "");
Properties props2 = new Properties();
props2.setProperty("k2", "b2");
props2.setProperty("k5", "a5");
// test-job-conf-dir/test2/test.properties
props2.store(new FileWriter(new File(this.subDir2, "test.PROPERTIES")), "");
Properties jobProps4 = new Properties();
jobProps4.setProperty("k5", "b5");
// test-job-conf-dir/test2/test21.PULL
jobProps4.store(new FileWriter(new File(this.subDir2, "test21.PULL")), "");
}
@Test
public void testloadGenericJobConfigs()
throws ConfigurationException, IOException {
Properties properties = new Properties();
properties.setProperty(ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY, this.jobConfigDir.getAbsolutePath());
List<Properties> jobConfigs = SchedulerUtils.loadGenericJobConfigs(properties);
Assert.assertEquals(jobConfigs.size(), 4);
// test-job-conf-dir/test1/test11/test111.pull
Properties jobProps1 = getJobConfigForFile(jobConfigs, "test111.pull");
Assert.assertEquals(jobProps1.stringPropertyNames().size(), 7);
Assert.assertTrue(jobProps1.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_DIR_KEY) || jobProps1.containsKey(
ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY));
Assert.assertTrue(jobProps1.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY));
Assert.assertEquals(jobProps1.getProperty("k1"), "d1");
Assert.assertEquals(jobProps1.getProperty("k2"), "a2");
Assert.assertEquals(jobProps1.getProperty("k3"), "a3");
Assert.assertEquals(jobProps1.getProperty("k8"), "a8");
Assert.assertEquals(jobProps1.getProperty("k9"), "a8");
// test-job-conf-dir/test1/test11.pull
Properties jobProps2 = getJobConfigForFile(jobConfigs, "test11.pull");
Assert.assertEquals(jobProps2.stringPropertyNames().size(), 6);
Assert.assertTrue(jobProps2.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_DIR_KEY) || jobProps1.containsKey(
ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY));
Assert.assertTrue(jobProps2.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY));
Assert.assertEquals(jobProps2.getProperty("k1"), "c1");
Assert.assertEquals(jobProps2.getProperty("k2"), "a2");
Assert.assertEquals(jobProps2.getProperty("k3"), "b3");
Assert.assertEquals(jobProps2.getProperty("k6"), "a6");
// test-job-conf-dir/test1/test12.PULL
Properties jobProps3 = getJobConfigForFile(jobConfigs, "test12.PULL");
Assert.assertEquals(jobProps3.stringPropertyNames().size(), 6);
Assert.assertTrue(jobProps3.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_DIR_KEY) || jobProps1.containsKey(
ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY));
Assert.assertTrue(jobProps3.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY));
Assert.assertEquals(jobProps3.getProperty("k1"), "b1");
Assert.assertEquals(jobProps3.getProperty("k2"), "a2");
Assert.assertEquals(jobProps3.getProperty("k3"), "a3");
Assert.assertEquals(jobProps3.getProperty("k7"), "a7");
// test-job-conf-dir/test2/test21.PULL
Properties jobProps4 = getJobConfigForFile(jobConfigs, "test21.PULL");
Assert.assertEquals(jobProps4.stringPropertyNames().size(), 5);
Assert.assertTrue(jobProps4.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_DIR_KEY) || jobProps1.containsKey(
ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY));
Assert.assertTrue(jobProps4.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY));
Assert.assertEquals(jobProps4.getProperty("k1"), "a1");
Assert.assertEquals(jobProps4.getProperty("k2"), "b2");
Assert.assertEquals(jobProps4.getProperty("k5"), "b5");
}
@Test
public void testLoadJobConfigsForCommonPropsFile()
throws ConfigurationException, IOException {
Path commonPropsPath = new Path(this.subDir1.getAbsolutePath() + "/test.properties");
Properties properties = new Properties();
properties.setProperty(ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY, this.jobConfigDir.getAbsolutePath());
List<Properties> jobConfigs = SchedulerUtils.loadGenericJobConfigs(properties, commonPropsPath,
new Path(this.jobConfigDir.getAbsolutePath()));
Assert.assertEquals(jobConfigs.size(), 3);
// test-job-conf-dir/test1/test11/test111.pull
Properties jobProps1 = getJobConfigForFile(jobConfigs, "test111.pull");
Assert.assertEquals(jobProps1.stringPropertyNames().size(), 7);
Assert.assertEquals(jobProps1.getProperty("k1"), "d1");
Assert.assertEquals(jobProps1.getProperty("k2"), "a2");
Assert.assertEquals(jobProps1.getProperty("k3"), "a3");
Assert.assertEquals(jobProps1.getProperty("k8"), "a8");
Assert.assertEquals(jobProps1.getProperty("k9"), "a8");
// test-job-conf-dir/test1/test11.pull
Properties jobProps2 = getJobConfigForFile(jobConfigs, "test11.pull");
Assert.assertEquals(jobProps2.stringPropertyNames().size(), 6);
Assert.assertEquals(jobProps2.getProperty("k1"), "c1");
Assert.assertEquals(jobProps2.getProperty("k2"), "a2");
Assert.assertEquals(jobProps2.getProperty("k3"), "b3");
Assert.assertEquals(jobProps2.getProperty("k6"), "a6");
// test-job-conf-dir/test1/test12.PULL
Properties jobProps3 = getJobConfigForFile(jobConfigs, "test12.PULL");
Assert.assertEquals(jobProps3.stringPropertyNames().size(), 6);
Assert.assertEquals(jobProps3.getProperty("k1"), "b1");
Assert.assertEquals(jobProps3.getProperty("k2"), "a2");
Assert.assertEquals(jobProps3.getProperty("k3"), "a3");
Assert.assertEquals(jobProps3.getProperty("k7"), "a7");
}
@Test
public void testloadGenericJobConfig()
throws ConfigurationException, IOException {
Path jobConfigPath = new Path(this.subDir11.getAbsolutePath(), "test111.pull");
Properties properties = new Properties();
properties.setProperty(ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY, this.jobConfigDir.getAbsolutePath());
Properties jobProps =
SchedulerUtils.loadGenericJobConfig(properties, jobConfigPath, new Path(this.jobConfigDir.getAbsolutePath()));
Assert.assertEquals(jobProps.stringPropertyNames().size(), 7);
Assert.assertTrue(jobProps.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_DIR_KEY) || jobProps.containsKey(
ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY));
Assert.assertTrue(jobProps.containsKey(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY));
Assert.assertEquals(jobProps.getProperty("k1"), "d1");
Assert.assertEquals(jobProps.getProperty("k2"), "a2");
Assert.assertEquals(jobProps.getProperty("k3"), "a3");
Assert.assertEquals(jobProps.getProperty("k8"), "a8");
Assert.assertEquals(jobProps.getProperty("k9"), "a8");
}
@Test(dependsOnMethods = {"testLoadJobConfigsForCommonPropsFile", "testloadGenericJobConfig"})
public void testPathAlterationObserver()
throws Exception {
PathAlterationObserverScheduler monitor = new PathAlterationObserverScheduler(1000);
final Set<Path> fileAltered = Sets.newHashSet();
final Semaphore semaphore = new Semaphore(0);
PathAlterationListener listener = new PathAlterationListenerAdaptor() {
@Override
public void onFileCreate(Path path) {
fileAltered.add(path);
semaphore.release();
}
@Override
public void onFileChange(Path path) {
fileAltered.add(path);
semaphore.release();
}
};
SchedulerUtils.addPathAlterationObserver(monitor, listener, new Path(this.jobConfigDir.getPath()));
try {
monitor.start();
// Give the monitor some time to start
Thread.sleep(1000);
File jobConfigFile = new File(this.subDir11, "test111.pull");
Files.touch(jobConfigFile);
File commonPropsFile = new File(this.subDir1, "test.properties");
Files.touch(commonPropsFile);
File newJobConfigFile = new File(this.subDir11, "test112.pull");
Files.append("k1=v1", newJobConfigFile, ConfigurationKeys.DEFAULT_CHARSET_ENCODING);
semaphore.acquire(3);
Assert.assertEquals(fileAltered.size(), 3);
Assert.assertTrue(fileAltered.contains(new Path("file:" + jobConfigFile)));
Assert.assertTrue(fileAltered.contains(new Path("file:" + commonPropsFile)));
Assert.assertTrue(fileAltered.contains(new Path("file:" + newJobConfigFile)));
} finally {
monitor.stop();
}
}
@Test
public void testTemplateLoad() throws Exception {
Path path = new Path(getClass().getClassLoader().getResource("schedulerUtilsTest").getFile());
Properties pullFile =
SchedulerUtils.loadGenericJobConfig(new Properties(), new Path(path, "templated.pull"), path);
Assert.assertEquals(pullFile.getProperty("gobblin.dataset.pattern"), "pattern");
Assert.assertEquals(pullFile.getProperty("job.name"), "GobblinDatabaseCopyTest");
List<Properties> jobConfigs = SchedulerUtils.loadGenericJobConfigs(new Properties(), new Path(path, "templated.pull"), path);
Properties pullFile2 = getJobConfigForFile(jobConfigs, "templated.pull");
Assert.assertEquals(pullFile2.getProperty("gobblin.dataset.pattern"), "pattern");
Assert.assertEquals(pullFile2.getProperty("job.name"), "GobblinDatabaseCopyTest");
Properties props = new Properties();
props.put(ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY, path.toString());
List<Properties> jobConfigs3 = SchedulerUtils.loadGenericJobConfigs(props);
Properties pullFile3 = getJobConfigForFile(jobConfigs3, "templated.pull");
Assert.assertEquals(pullFile3.getProperty("gobblin.dataset.pattern"), "pattern");
Assert.assertEquals(pullFile3.getProperty("job.name"), "GobblinDatabaseCopyTest");
}
@AfterClass
public void tearDown()
throws IOException {
if (this.jobConfigDir != null) {
FileUtils.forceDelete(this.jobConfigDir);
}
}
private Properties getJobConfigForFile(List<Properties> jobConfigs, String fileName) {
for (Properties jobConfig : jobConfigs) {
if (jobConfig.getProperty(ConfigurationKeys.JOB_CONFIG_FILE_PATH_KEY).endsWith(fileName)) {
return jobConfig;
}
}
return null;
}
}