/* * 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.service.modules.core; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.hadoop.fs.Path; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.typesafe.config.Config; import gobblin.configuration.ConfigurationKeys; import gobblin.runtime.api.FlowSpec; import gobblin.runtime.api.JobSpec; import gobblin.runtime.api.Spec; import gobblin.runtime.api.SpecExecutorInstanceProducer; import gobblin.runtime.api.TopologySpec; import gobblin.runtime.spec_executorInstance.InMemorySpecExecutorInstanceProducer; import gobblin.service.ServiceConfigKeys; import gobblin.service.modules.flow.IdentityFlowToJobSpecCompiler; import gobblin.util.ConfigUtils; import gobblin.util.PathUtils; public class IdentityFlowToJobSpecCompilerTest { private static final Logger logger = LoggerFactory.getLogger(IdentityFlowToJobSpecCompilerTest.class); private static final String TEST_TEMPLATE_CATALOG_PATH = "/tmp/gobblinTestTemplateCatalog_" + System.currentTimeMillis(); private static final String TEST_TEMPLATE_CATALOG_URI = "file://" + TEST_TEMPLATE_CATALOG_PATH; private static final String TEST_TEMPLATE_NAME = "test.template"; private static final String TEST_TEMPLATE_URI = "FS:///test.template"; private static final String TEST_SOURCE_NAME = "testSource"; private static final String TEST_SINK_NAME = "testSink"; private static final String TEST_FLOW_GROUP = "testFlowGroup"; private static final String TEST_FLOW_NAME = "testFlowName"; private static final String SPEC_STORE_PARENT_DIR = "/tmp/orchestrator/"; private static final String SPEC_DESCRIPTION = "Test Orchestrator"; private static final String SPEC_VERSION = "1"; private static final String TOPOLOGY_SPEC_STORE_DIR = "/tmp/orchestrator/topologyTestSpecStore_" + System.currentTimeMillis(); private static final String FLOW_SPEC_STORE_DIR = "/tmp/orchestrator/flowTestSpecStore_" + System.currentTimeMillis(); private IdentityFlowToJobSpecCompiler compilerWithTemplateCalague; private IdentityFlowToJobSpecCompiler compilerWithoutTemplateCalague; @BeforeClass public void setup() throws Exception { // Create dir for template catalog setupDir(TEST_TEMPLATE_CATALOG_PATH); // Create template to use in test List<String> templateEntries = new ArrayList<>(); templateEntries.add("testProperty1 = \"testValue1\""); templateEntries.add("testProperty2 = \"test.Value1\""); templateEntries.add("testProperty3 = 100"); FileUtils.writeLines(new File(TEST_TEMPLATE_CATALOG_PATH + "/" + TEST_TEMPLATE_NAME), templateEntries); // Initialize compiler with template catalog Properties compilerWithTemplateCatalogProperties = new Properties(); compilerWithTemplateCatalogProperties.setProperty(ServiceConfigKeys.TEMPLATE_CATALOGS_FULLY_QUALIFIED_PATH_KEY, TEST_TEMPLATE_CATALOG_URI); this.compilerWithTemplateCalague = new IdentityFlowToJobSpecCompiler(ConfigUtils.propertiesToConfig(compilerWithTemplateCatalogProperties)); // Add a topology to compiler this.compilerWithTemplateCalague.onAddSpec(initTopologySpec()); // Initialize compiler without template catalog this.compilerWithoutTemplateCalague = new IdentityFlowToJobSpecCompiler(ConfigUtils.propertiesToConfig(new Properties())); // Add a topology to compiler this.compilerWithoutTemplateCalague.onAddSpec(initTopologySpec()); } private void setupDir(String dir) throws Exception { FileUtils.forceMkdir(new File(dir)); } private void cleanUpDir(String dir) throws Exception { File specStoreDir = new File(dir); if (specStoreDir.exists()) { FileUtils.deleteDirectory(specStoreDir); } } private TopologySpec initTopologySpec() { Properties properties = new Properties(); properties.put("specStore.fs.dir", TOPOLOGY_SPEC_STORE_DIR); properties.put("specExecInstance.capabilities", TEST_SOURCE_NAME + ":" + TEST_SINK_NAME); Config config = ConfigUtils.propertiesToConfig(properties); SpecExecutorInstanceProducer specExecutorInstanceProducer = new InMemorySpecExecutorInstanceProducer(config); TopologySpec.Builder topologySpecBuilder = TopologySpec.builder(computeTopologySpecURI(SPEC_STORE_PARENT_DIR, TOPOLOGY_SPEC_STORE_DIR)) .withConfig(config) .withDescription(SPEC_DESCRIPTION) .withVersion(SPEC_VERSION) .withSpecExecutorInstanceProducer(specExecutorInstanceProducer); return topologySpecBuilder.build(); } private FlowSpec initFlowSpec() { return initFlowSpec(TEST_FLOW_GROUP, TEST_FLOW_NAME, TEST_SOURCE_NAME, TEST_SINK_NAME); } private FlowSpec initFlowSpec(String flowGroup, String flowName, String source, String destination) { Properties properties = new Properties(); properties.put(ConfigurationKeys.JOB_SCHEDULE_KEY, "* * * * *"); properties.put(ConfigurationKeys.FLOW_GROUP_KEY, flowGroup); properties.put(ConfigurationKeys.FLOW_NAME_KEY, flowName); properties.put(ServiceConfigKeys.FLOW_SOURCE_IDENTIFIER_KEY, source); properties.put(ServiceConfigKeys.FLOW_DESTINATION_IDENTIFIER_KEY, destination); Config config = ConfigUtils.propertiesToConfig(properties); FlowSpec.Builder flowSpecBuilder = null; try { flowSpecBuilder = FlowSpec.builder(computeTopologySpecURI(SPEC_STORE_PARENT_DIR, FLOW_SPEC_STORE_DIR)) .withConfig(config) .withDescription("dummy description") .withVersion("1") .withTemplate(new URI(TEST_TEMPLATE_URI)); } catch (URISyntaxException e) { throw new RuntimeException(e); } return flowSpecBuilder.build(); } public URI computeTopologySpecURI(String parent, String current) { // Make sure this is relative return PathUtils.relativizePath(new Path(current), new Path(parent)).toUri(); } @AfterClass public void cleanUp() throws Exception { // Cleanup Template Catalog try { cleanUpDir(TEST_TEMPLATE_CATALOG_PATH); } catch (Exception e) { logger.warn("Could not completely cleanup Template catalog dir"); } // Cleanup ToplogySpec Dir try { cleanUpDir(TOPOLOGY_SPEC_STORE_DIR); } catch (Exception e) { logger.warn("Could not completely cleanup ToplogySpec catalog dir"); } // Cleanup FlowSpec Dir try { cleanUpDir(FLOW_SPEC_STORE_DIR); } catch (Exception e) { logger.warn("Could not completely cleanup FlowSpec catalog dir"); } } @Test public void testCompilerWithTemplateCatalog() { FlowSpec flowSpec = initFlowSpec(); // Run compiler on flowSpec Map<Spec, SpecExecutorInstanceProducer> specExecutorMapping = this.compilerWithTemplateCalague.compileFlow(flowSpec); // Assert pre-requisites Assert.assertNotNull(specExecutorMapping, "Expected non null mapping."); Assert.assertTrue(specExecutorMapping.size() == 1, "Exepected 1 executor for FlowSpec."); // Assert FlowSpec compilation Spec spec = specExecutorMapping.keySet().iterator().next(); Assert.assertTrue(spec instanceof JobSpec, "Expected JobSpec compiled from FlowSpec."); // Assert JobSpec properties JobSpec jobSpec = (JobSpec) spec; Assert.assertEquals(jobSpec.getConfig().getString("testProperty1"), "testValue1"); Assert.assertEquals(jobSpec.getConfig().getString("testProperty2"), "test.Value1"); Assert.assertEquals(jobSpec.getConfig().getString("testProperty3"), "100"); Assert.assertEquals(jobSpec.getConfig().getString(ServiceConfigKeys.FLOW_SOURCE_IDENTIFIER_KEY), TEST_SOURCE_NAME); Assert.assertFalse(jobSpec.getConfig().hasPath(ConfigurationKeys.JOB_SCHEDULE_KEY)); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.JOB_NAME_KEY), TEST_FLOW_NAME); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.JOB_GROUP_KEY), TEST_FLOW_GROUP); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.FLOW_NAME_KEY), TEST_FLOW_NAME); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.FLOW_GROUP_KEY), TEST_FLOW_GROUP); Assert.assertTrue(jobSpec.getConfig().hasPath(ConfigurationKeys.FLOW_EXECUTION_ID_KEY)); } @Test public void testCompilerWithoutTemplateCatalog() { FlowSpec flowSpec = initFlowSpec(); // Run compiler on flowSpec Map<Spec, SpecExecutorInstanceProducer> specExecutorMapping = this.compilerWithoutTemplateCalague.compileFlow(flowSpec); // Assert pre-requisites Assert.assertNotNull(specExecutorMapping, "Expected non null mapping."); Assert.assertTrue(specExecutorMapping.size() == 1, "Exepected 1 executor for FlowSpec."); // Assert FlowSpec compilation Spec spec = specExecutorMapping.keySet().iterator().next(); Assert.assertTrue(spec instanceof JobSpec, "Expected JobSpec compiled from FlowSpec."); // Assert JobSpec properties JobSpec jobSpec = (JobSpec) spec; Assert.assertTrue(!jobSpec.getConfig().hasPath("testProperty1")); Assert.assertTrue(!jobSpec.getConfig().hasPath("testProperty2")); Assert.assertTrue(!jobSpec.getConfig().hasPath("testProperty3")); Assert.assertEquals(jobSpec.getConfig().getString(ServiceConfigKeys.FLOW_SOURCE_IDENTIFIER_KEY), TEST_SOURCE_NAME); Assert.assertFalse(jobSpec.getConfig().hasPath(ConfigurationKeys.JOB_SCHEDULE_KEY)); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.JOB_NAME_KEY), TEST_FLOW_NAME); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.JOB_GROUP_KEY), TEST_FLOW_GROUP); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.FLOW_NAME_KEY), TEST_FLOW_NAME); Assert.assertEquals(jobSpec.getConfig().getString(ConfigurationKeys.FLOW_GROUP_KEY), TEST_FLOW_GROUP); Assert.assertTrue(jobSpec.getConfig().hasPath(ConfigurationKeys.FLOW_EXECUTION_ID_KEY)); } @Test public void testNoJobSpecCompilation() { FlowSpec flowSpec = initFlowSpec(TEST_FLOW_GROUP, TEST_FLOW_NAME, "unsupportedSource", "unsupportedSink"); // Run compiler on flowSpec Map<Spec, SpecExecutorInstanceProducer> specExecutorMapping = this.compilerWithTemplateCalague.compileFlow(flowSpec); // Assert pre-requisites Assert.assertNotNull(specExecutorMapping, "Expected non null mapping."); Assert.assertTrue(specExecutorMapping.size() == 0, "Exepected 1 executor for FlowSpec."); } }