You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ji...@apache.org on 2016/12/22 19:31:28 UTC
[02/51] [abbrv] hadoop git commit: YARN-5513. Move Java only tests
from slider develop to yarn-native-services. Contributed by Gour Saha
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestAgentProviderService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestAgentProviderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestAgentProviderService.java
new file mode 100644
index 0000000..7fceac7
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestAgentProviderService.java
@@ -0,0 +1,60 @@
+/*
+ * 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 org.apache.slider.server.appmaster.web.rest.publisher;
+
+import org.apache.hadoop.yarn.api.records.Container;
+import org.apache.slider.common.tools.SliderFileSystem;
+import org.apache.slider.providers.agent.AgentProviderService;
+import org.apache.slider.server.appmaster.actions.QueueAccess;
+import org.apache.slider.server.appmaster.state.StateAccessForProviders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class TestAgentProviderService extends AgentProviderService {
+ protected static final Logger log =
+ LoggerFactory.getLogger(TestAgentProviderService.class);
+
+ public TestAgentProviderService() {
+ super();
+ log.info("TestAgentProviderService created");
+ }
+
+ @Override
+ public void bind(StateAccessForProviders stateAccessor,
+ QueueAccess queueAccess,
+ List<Container> liveContainers) {
+ super.bind(stateAccessor, queueAccess, liveContainers);
+ Map<String,String> dummyProps = new HashMap<String, String>();
+ dummyProps.put("prop1", "val1");
+ dummyProps.put("prop2", "val2");
+ log.info("publishing dummy-site.xml with values {}", dummyProps);
+ publishApplicationInstanceData("dummy-site", "dummy configuration",
+ dummyProps.entrySet());
+ // publishing global config for testing purposes
+ publishApplicationInstanceData("global", "global configuration",
+ stateAccessor.getAppConfSnapshot()
+ .getGlobalOptions().entrySet());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestSliderProviderFactory.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestSliderProviderFactory.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestSliderProviderFactory.java
new file mode 100644
index 0000000..f49e15a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/publisher/TestSliderProviderFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.slider.server.appmaster.web.rest.publisher;
+
+import org.apache.slider.providers.ProviderService;
+import org.apache.slider.providers.agent.AgentProviderFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class TestSliderProviderFactory extends AgentProviderFactory{
+ protected static final Logger log =
+ LoggerFactory.getLogger(TestSliderProviderFactory.class);
+
+ public TestSliderProviderFactory() {
+ log.info("Created TestSliderProviderFactory");
+ }
+
+ @Override
+ public ProviderService createServerProvider() {
+ log.info("Creating TestAgentProviderService");
+ return new TestAgentProviderService();
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/servicemonitor/TestPortProbe.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/servicemonitor/TestPortProbe.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/servicemonitor/TestPortProbe.java
new file mode 100644
index 0000000..a93ec57
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/servicemonitor/TestPortProbe.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.slider.server.servicemonitor;
+
+import org.junit.Assert;
+import org.apache.hadoop.conf.Configuration;
+import org.junit.Test;
+
+public class TestPortProbe extends Assert {
+ /**
+ * Assert that a port probe failed if the port is closed
+ * @throws Throwable
+ */
+ @Test
+ public void testPortProbeFailsClosedPort() throws Throwable {
+ PortProbe probe = new PortProbe("127.0.0.1", 65500, 100, "", new Configuration());
+ probe.init();
+ ProbeStatus status = probe.ping(true);
+ assertFalse("Expected a failure but got successful result: " + status,
+ status.isSuccess());
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestCertificateManager.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestCertificateManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestCertificateManager.java
new file mode 100644
index 0000000..7a4a586
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestCertificateManager.java
@@ -0,0 +1,540 @@
+/*
+ * 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 org.apache.slider.server.services.security;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.alias.CredentialProvider;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
+import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
+import org.apache.slider.Slider;
+import org.apache.slider.common.SliderKeys;
+import org.apache.slider.common.SliderXmlConfKeys;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.core.conf.MapOperations;
+import org.apache.slider.core.exceptions.SliderException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ */
+public class TestCertificateManager {
+ @Rule
+ public TemporaryFolder workDir = new TemporaryFolder();
+ private File secDir;
+ private CertificateManager certMan;
+
+ @Before
+ public void setup() throws Exception {
+ certMan = new CertificateManager();
+ MapOperations compOperations = new MapOperations();
+ secDir = new File(workDir.getRoot(), SliderKeys.SECURITY_DIR);
+ File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME);
+ compOperations.put(SliderXmlConfKeys.KEY_KEYSTORE_LOCATION,
+ keystoreFile.getAbsolutePath());
+ certMan.initialize(compOperations, "cahost", null, null);
+ }
+
+ @Test
+ public void testServerCertificateGenerated() throws Exception {
+ File serverCrt = new File(secDir, SliderKeys.CRT_FILE_NAME);
+ Assert.assertTrue("Server CRD does not exist:" + serverCrt,
+ serverCrt.exists());
+ }
+
+ @Test
+ public void testAMKeystoreGenerated() throws Exception {
+ File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME);
+ Assert.assertTrue("Keystore does not exist: " + keystoreFile,
+ keystoreFile.exists());
+ InputStream is = null;
+ try {
+
+ is = new FileInputStream(keystoreFile);
+ KeyStore keystore = KeyStore.getInstance("pkcs12");
+ String password = SecurityUtils.getKeystorePass();
+ keystore.load(is, password.toCharArray());
+
+ Certificate certificate = keystore.getCertificate(
+ keystore.aliases().nextElement());
+ Assert.assertNotNull(certificate);
+
+ if (certificate instanceof X509Certificate) {
+ X509Certificate x509cert = (X509Certificate) certificate;
+
+ // Get subject
+ Principal principal = x509cert.getSubjectDN();
+ String subjectDn = principal.getName();
+ Assert.assertEquals("wrong DN",
+ "CN=cahost",
+ subjectDn);
+
+ // Get issuer
+ principal = x509cert.getIssuerDN();
+ String issuerDn = principal.getName();
+ Assert.assertEquals("wrong Issuer DN",
+ "CN=cahost",
+ issuerDn);
+ }
+ } finally {
+ if(null != is) {
+ is.close();
+ }
+ }
+ }
+
+ @Test
+ public void testContainerCertificateGeneration() throws Exception {
+ certMan.generateContainerCertificate("testhost", "container1");
+ Assert.assertTrue("container certificate not generated",
+ new File(secDir, "container1.crt").exists());
+ }
+
+ @Test
+ public void testContainerKeystoreGeneration() throws Exception {
+ SecurityStore keystoreFile = certMan.generateContainerKeystore("testhost",
+ "container1",
+ "component1",
+ "password");
+ validateKeystore(keystoreFile.getFile(), "testhost", "cahost");
+ }
+
+ private void validateKeystore(File keystoreFile, String certHostname,
+ String issuerHostname)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+ Assert.assertTrue("container keystore not generated",
+ keystoreFile.exists());
+
+ InputStream is = null;
+ try {
+
+ is = new FileInputStream(keystoreFile);
+ KeyStore keystore = KeyStore.getInstance("pkcs12");
+ String password = "password";
+ keystore.load(is, password.toCharArray());
+
+ Certificate certificate = keystore.getCertificate(
+ keystore.aliases().nextElement());
+ Assert.assertNotNull(certificate);
+
+ if (certificate instanceof X509Certificate) {
+ X509Certificate x509cert = (X509Certificate) certificate;
+
+ // Get subject
+ Principal principal = x509cert.getSubjectDN();
+ String subjectDn = principal.getName();
+ Assert.assertEquals("wrong DN", "CN=" + certHostname + ", OU=container1",
+ subjectDn);
+
+ // Get issuer
+ principal = x509cert.getIssuerDN();
+ String issuerDn = principal.getName();
+ Assert.assertEquals("wrong Issuer DN",
+ "CN=" + issuerHostname,
+ issuerDn);
+ }
+ } finally {
+ if(null != is) {
+ is.close();
+ }
+ }
+ }
+
+ @Test
+ public void testContainerKeystoreGenerationViaStoresGenerator() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = new MapOperations();
+ instanceDefinition.getAppConf().components.put("component1", compOps);
+ compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY,
+ "app1.component1.password.property");
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+ instanceDefinition.getAppConf().global.put(
+ "app1.component1.password.property", "password");
+ instanceDefinition.resolve();
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ validateKeystore(files[0].getFile(), "testhost", "cahost");
+ }
+
+ @Test
+ public void testContainerKeystoreGenerationViaStoresGeneratorUsingGlobalProps() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = new MapOperations();
+ instanceDefinition.getAppConf().components.put("component1", compOps);
+ compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY,
+ "app1.component1.password.property");
+ instanceDefinition.getAppConf().global.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+ compOps.put(
+ "app1.component1.password.property", "password");
+ instanceDefinition.resolve();
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ validateKeystore(files[0].getFile(), "testhost", "cahost");
+ }
+
+ @Test
+ public void testContainerKeystoreGenerationViaStoresGeneratorOverrideGlobalSetting() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = setupComponentOptions(true, null,
+ "app1.component1.password.property",
+ null, null);
+ instanceDefinition.getAppConf().components.put("component1", compOps);
+ instanceDefinition.getAppConf().global.put(
+ "app1.component1.password.property", "password");
+ instanceDefinition.getAppConf().global.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "false");
+ instanceDefinition.resolve();
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ validateKeystore(files[0].getFile(), "testhost", "cahost");
+ }
+
+ @Test
+ public void testContainerTrusttoreGeneration() throws Exception {
+ SecurityStore keystoreFile =
+ certMan.generateContainerKeystore("testhost",
+ "container1",
+ "component1",
+ "keypass");
+ Assert.assertTrue("container keystore not generated",
+ keystoreFile.getFile().exists());
+ SecurityStore truststoreFile =
+ certMan.generateContainerTruststore("container1",
+ "component1", "trustpass"
+ );
+ Assert.assertTrue("container truststore not generated",
+ truststoreFile.getFile().exists());
+
+ validateTruststore(keystoreFile.getFile(), truststoreFile.getFile());
+ }
+
+ @Test
+ public void testContainerGenerationUsingStoresGeneratorNoTruststore() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = new MapOperations();
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+ compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_KEY,
+ "test.keystore.password");
+
+ setupCredentials(instanceDefinition, "test.keystore.password", null);
+
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ File keystoreFile = CertificateManager.getContainerKeystoreFilePath(
+ "container1", "component1");
+ Assert.assertTrue("container keystore not generated",
+ keystoreFile.exists());
+
+ Assert.assertTrue("keystore not in returned list",
+ Arrays.asList(files).contains(new SecurityStore(keystoreFile,
+ SecurityStore.StoreType.keystore)));
+ File truststoreFile =
+ CertificateManager.getContainerTruststoreFilePath("component1",
+ "container1");
+ Assert.assertFalse("container truststore generated",
+ truststoreFile.exists());
+ Assert.assertFalse("truststore in returned list",
+ Arrays.asList(files).contains(new SecurityStore(truststoreFile,
+ SecurityStore.StoreType.truststore)));
+
+ }
+
+ @Test
+ public void testContainerGenerationUsingStoresGeneratorJustTruststoreWithDefaultAlias() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = setupComponentOptions(true);
+
+ setupCredentials(instanceDefinition, null,
+ SliderKeys.COMP_TRUSTSTORE_PASSWORD_ALIAS_DEFAULT);
+
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ File keystoreFile = CertificateManager.getContainerKeystoreFilePath(
+ "container1", "component1");
+ Assert.assertFalse("container keystore generated",
+ keystoreFile.exists());
+ Assert.assertFalse("keystore in returned list",
+ Arrays.asList(files).contains(keystoreFile));
+ File truststoreFile =
+ CertificateManager.getContainerTruststoreFilePath("component1",
+ "container1");
+ Assert.assertTrue("container truststore not generated",
+ truststoreFile.exists());
+ Assert.assertTrue("truststore not in returned list",
+ Arrays.asList(files).contains(new SecurityStore(truststoreFile,
+ SecurityStore.StoreType.truststore)));
+
+ }
+
+ @Test
+ public void testContainerTrusttoreGenerationUsingStoresGenerator() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = setupComponentOptions(true,
+ "test.keystore.password",
+ null,
+ "test.truststore.password",
+ null);
+
+ setupCredentials(instanceDefinition, "test.keystore.password",
+ "test.truststore.password");
+
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 2, files.length);
+ File keystoreFile = CertificateManager.getContainerKeystoreFilePath(
+ "container1", "component1");
+ Assert.assertTrue("container keystore not generated",
+ keystoreFile.exists());
+ Assert.assertTrue("keystore not in returned list",
+ Arrays.asList(files).contains(new SecurityStore(keystoreFile,
+ SecurityStore.StoreType.keystore)));
+ File truststoreFile =
+ CertificateManager.getContainerTruststoreFilePath("component1",
+ "container1");
+ Assert.assertTrue("container truststore not generated",
+ truststoreFile.exists());
+ Assert.assertTrue("truststore not in returned list",
+ Arrays.asList(files).contains(new SecurityStore(truststoreFile,
+ SecurityStore.StoreType.truststore)));
+
+ validateTruststore(keystoreFile, truststoreFile);
+ }
+
+ private void setupCredentials(AggregateConf instanceDefinition,
+ String keyAlias, String trustAlias)
+ throws Exception {
+ Configuration conf = new Configuration();
+ final Path jksPath = new Path(SecurityUtils.getSecurityDir(), "test.jks");
+ final String ourUrl =
+ JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri();
+
+ File file = new File(SecurityUtils.getSecurityDir(), "test.jks");
+ file.delete();
+ conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl);
+
+ instanceDefinition.getAppConf().credentials.put(ourUrl, new ArrayList<String>());
+
+ CredentialProvider provider =
+ CredentialProviderFactory.getProviders(conf).get(0);
+
+ // create new aliases
+ try {
+
+ if (keyAlias != null) {
+ char[] storepass = {'k', 'e', 'y', 'p', 'a', 's', 's'};
+ provider.createCredentialEntry(
+ keyAlias, storepass);
+ }
+
+ if (trustAlias != null) {
+ char[] trustpass = {'t', 'r', 'u', 's', 't', 'p', 'a', 's', 's'};
+ provider.createCredentialEntry(
+ trustAlias, trustpass);
+ }
+
+ // write out so that it can be found in checks
+ provider.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ private MapOperations setupComponentOptions(boolean storesRequired) {
+ return this.setupComponentOptions(storesRequired, null, null, null, null);
+ }
+
+ private MapOperations setupComponentOptions(boolean storesRequired,
+ String keyAlias,
+ String keyPwd,
+ String trustAlias,
+ String trustPwd) {
+ MapOperations compOps = new MapOperations();
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY,
+ Boolean.toString(storesRequired));
+ if (keyAlias != null) {
+ compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_KEY,
+ "test.keystore.password");
+ }
+ if (trustAlias != null) {
+ compOps.put(SliderKeys.COMP_TRUSTSTORE_PASSWORD_ALIAS_KEY,
+ "test.truststore.password");
+ }
+ if (keyPwd != null) {
+ compOps.put(SliderKeys.COMP_KEYSTORE_PASSWORD_PROPERTY_KEY,
+ keyPwd);
+ }
+ if (trustPwd != null) {
+ compOps.put(SliderKeys.COMP_TRUSTSTORE_PASSWORD_PROPERTY_KEY,
+ trustPwd);
+ }
+ return compOps;
+ }
+
+ @Test
+ public void testContainerStoresGenerationKeystoreOnly() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = new MapOperations();
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+
+ setupCredentials(instanceDefinition,
+ SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_DEFAULT, null);
+
+ SecurityStore[]
+ files = StoresGenerator.generateSecurityStores("testhost",
+ "container1",
+ "component1",
+ instanceDefinition,
+ compOps);
+ assertEquals("wrong number of stores", 1, files.length);
+ File keystoreFile = CertificateManager.getContainerKeystoreFilePath(
+ "container1", "component1");
+ Assert.assertTrue("container keystore not generated",
+ keystoreFile.exists());
+ Assert.assertTrue("keystore not in returned list",
+ Arrays.asList(files).contains(new SecurityStore(keystoreFile,
+ SecurityStore.StoreType.keystore)));
+ File truststoreFile =
+ CertificateManager.getContainerTruststoreFilePath("component1",
+ "container1");
+ Assert.assertFalse("container truststore generated",
+ truststoreFile.exists());
+ Assert.assertFalse("truststore in returned list",
+ Arrays.asList(files).contains(new SecurityStore(truststoreFile,
+ SecurityStore.StoreType.truststore)));
+
+ }
+
+ @Test
+ public void testContainerStoresGenerationMisconfiguration() throws Exception {
+ AggregateConf instanceDefinition = new AggregateConf();
+ MapOperations compOps = new MapOperations();
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+
+ setupCredentials(instanceDefinition, "cant.be.found", null);
+
+ try {
+ StoresGenerator.generateSecurityStores("testhost", "container1",
+ "component1", instanceDefinition,
+ compOps);
+ Assert.fail("SliderException should have been generated");
+ } catch (SliderException e) {
+ // ignore - should be thrown
+ }
+ }
+
+ private void validateTruststore(File keystoreFile, File truststoreFile)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+ InputStream keyis = null;
+ InputStream trustis = null;
+ try {
+
+ // create keystore
+ keyis = new FileInputStream(keystoreFile);
+ KeyStore keystore = KeyStore.getInstance("pkcs12");
+ String password = "keypass";
+ keystore.load(keyis, password.toCharArray());
+
+ // obtain server cert
+ Certificate certificate = keystore.getCertificate(
+ keystore.aliases().nextElement());
+ Assert.assertNotNull(certificate);
+
+ // create trust store from generated trust store file
+ trustis = new FileInputStream(truststoreFile);
+ KeyStore truststore = KeyStore.getInstance("pkcs12");
+ password = "trustpass";
+ truststore.load(trustis, password.toCharArray());
+
+ // validate keystore cert using trust store
+ TrustManagerFactory
+ trustManagerFactory =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(truststore);
+
+ for (TrustManager trustManager: trustManagerFactory.getTrustManagers()) {
+ if (trustManager instanceof X509TrustManager) {
+ X509TrustManager x509TrustManager = (X509TrustManager)trustManager;
+ x509TrustManager.checkServerTrusted(
+ new X509Certificate[] {(X509Certificate) certificate},
+ "RSA_EXPORT");
+ }
+ }
+
+ } finally {
+ if(null != keyis) {
+ keyis.close();
+ }
+ if(null != trustis) {
+ trustis.close();
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java
new file mode 100644
index 0000000..2e2ffce
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java
@@ -0,0 +1,156 @@
+/*
+ * 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 org.apache.slider.server.services.security;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.alias.CredentialProvider;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
+import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
+import org.apache.slider.common.SliderKeys;
+import org.apache.slider.common.SliderXmlConfKeys;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.core.conf.MapOperations;
+import org.apache.slider.core.exceptions.SliderException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ */
+public class TestMultiThreadedStoreGeneration {
+
+ public static final int NUM_THREADS = 30;
+ @Rule
+ public TemporaryFolder workDir = new TemporaryFolder();;
+
+ private void setupCredentials(AggregateConf instanceDefinition,
+ String keyAlias, String trustAlias)
+ throws Exception {
+ Configuration conf = new Configuration();
+ final Path jksPath = new Path(SecurityUtils.getSecurityDir(), "test.jks");
+ final String ourUrl =
+ JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri();
+
+ File file = new File(SecurityUtils.getSecurityDir(), "test.jks");
+ file.delete();
+ conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl);
+
+ instanceDefinition.getAppConf().credentials.put(ourUrl, new ArrayList<String>());
+
+ CredentialProvider provider =
+ CredentialProviderFactory.getProviders(conf).get(0);
+
+ // create new aliases
+ try {
+
+ if (keyAlias != null) {
+ char[] storepass = {'k', 'e', 'y', 'p', 'a', 's', 's'};
+ provider.createCredentialEntry(
+ keyAlias, storepass);
+ }
+
+ if (trustAlias != null) {
+ char[] trustpass = {'t', 'r', 'u', 's', 't', 'p', 'a', 's', 's'};
+ provider.createCredentialEntry(
+ trustAlias, trustpass);
+ }
+
+ // write out so that it can be found in checks
+ provider.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+
+ @Test
+ public void testMultiThreadedStoreGeneration() throws Exception {
+
+ CertificateManager certMan = new CertificateManager();
+ MapOperations compOperations = new MapOperations();
+ File secDir = new File(workDir.getRoot(), SliderKeys.SECURITY_DIR);
+ File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME);
+ compOperations.put(SliderXmlConfKeys.KEY_KEYSTORE_LOCATION,
+ keystoreFile.getAbsolutePath());
+ certMan.initialize(compOperations, "cahost", null, null);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final List<SecurityStore> stores = new ArrayList<>();
+ List<Thread> threads = new ArrayList<>();
+ final AggregateConf instanceDefinition = new AggregateConf();
+
+ setupCredentials(instanceDefinition,
+ SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_DEFAULT, null);
+ final MapOperations compOps = new MapOperations();
+ compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true");
+
+ for (int i=0; i<NUM_THREADS; ++i) {
+ final int finalI = i;
+ Runnable runner = new Runnable() {
+ public void run() {
+ System.out.println ("----> In run");
+ try {
+ latch.await();
+ SecurityStore[] stores1 = StoresGenerator.generateSecurityStores(
+ "testhost",
+ "container" + finalI,
+ "component" + finalI,
+ instanceDefinition,
+ compOps);
+ System.out.println ("----> stores1" + stores1);
+ List<SecurityStore>
+ securityStores =
+ Arrays.asList(stores1);
+ stores.addAll(securityStores);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (SliderException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ Thread thread = new Thread(runner, "TestThread" + i);
+ threads.add(thread);
+ thread.start();
+ }
+ latch.countDown();
+ for (Thread t : threads) {
+ t.join();
+ }
+
+ for (int i=0; i < NUM_THREADS; i++) {
+ assertTrue("keystore " + i + " not generated", stores.get(i).getFile().exists());
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/MockService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/MockService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/MockService.java
new file mode 100644
index 0000000..588f621
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/MockService.java
@@ -0,0 +1,80 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.service.AbstractService;
+import org.apache.hadoop.service.ServiceStateException;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MockService extends AbstractService {
+ private final boolean fail;
+ private final int lifespan;
+ private final ExecutorService executorService =
+ Executors.newSingleThreadExecutor();
+
+ MockService() {
+ this("mock", false, -1);
+ }
+
+ MockService(String name, boolean fail, int lifespan) {
+ super(name);
+ this.fail = fail;
+ this.lifespan = lifespan;
+ }
+
+ @Override
+ protected void serviceStart() throws Exception {
+ //act on the lifespan here
+ if (lifespan > 0) {
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(lifespan);
+ } catch (InterruptedException ignored) {
+
+ }
+ finish();
+ }
+ });
+ } else {
+ if (lifespan == 0) {
+ finish();
+ } else {
+ //continue until told not to
+ }
+ }
+ }
+
+ void finish() {
+ if (fail) {
+ ServiceStateException e =
+ new ServiceStateException(getName() + " failed");
+
+ noteFailure(e);
+ stop();
+ throw e;
+ } else {
+ stop();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ParentWorkflowTestBase.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ParentWorkflowTestBase.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ParentWorkflowTestBase.java
new file mode 100644
index 0000000..a11a1cf
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ParentWorkflowTestBase.java
@@ -0,0 +1,70 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.service.Service;
+
+/**
+ * Extends {@link WorkflowServiceTestBase} with parent-specific operations
+ * and logic to build up and run the parent service
+ */
+public abstract class ParentWorkflowTestBase extends WorkflowServiceTestBase {
+
+ /**
+ * Wait a second for the service parent to stop
+ * @param parent the service to wait for
+ */
+ protected void waitForParentToStop(ServiceParent parent) {
+ waitForParentToStop(parent, 1000);
+ }
+
+ /**
+ * Wait for the service parent to stop
+ * @param parent the service to wait for
+ * @param timeout time in milliseconds
+ */
+ protected void waitForParentToStop(ServiceParent parent, int timeout) {
+ boolean stop = parent.waitForServiceToStop(timeout);
+ if (!stop) {
+ logState(parent);
+ fail("Service failed to stop : after " + timeout + " millis " + parent);
+ }
+ }
+
+ /**
+ * Subclasses are require to implement this and return an instance of a
+ * ServiceParent
+ * @param services a possibly empty list of services
+ * @return an inited -but -not-started- service parent instance
+ */
+ protected abstract ServiceParent buildService(Service... services);
+
+ /**
+ * Use {@link #buildService(Service...)} to create service and then start it
+ * @param services
+ * @return
+ */
+ protected ServiceParent startService(Service... services) {
+ ServiceParent parent = buildService(services);
+ //expect service to start and stay started
+ parent.start();
+ return parent;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
new file mode 100644
index 0000000..4a19417
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.util.Shell;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A source of commands, with the goal being to allow for adding different
+ * implementations for different platforms
+ */
+public class ProcessCommandFactory {
+
+ protected ProcessCommandFactory() {
+ }
+
+ /**
+ * The command to list a directory
+ * @param dir directory
+ * @return commands
+ */
+ public List<String> ls(File dir) {
+ List<String> commands;
+ if (!Shell.WINDOWS) {
+ commands = Arrays.asList("ls","-1", dir.getAbsolutePath());
+ } else {
+ commands = Arrays.asList("cmd", "/c", "dir", dir.getAbsolutePath());
+ }
+ return commands;
+ }
+
+ /**
+ * Echo some text to stdout
+ * @param text text
+ * @return commands
+ */
+ public List<String> echo(String text) {
+ List<String> commands = new ArrayList<String>(5);
+ commands.add("echo");
+ commands.add(text);
+ return commands;
+ }
+
+ /**
+ * print env variables
+ * @return commands
+ */
+ public List<String> env() {
+ List<String> commands;
+ if (!Shell.WINDOWS) {
+ commands = Arrays.asList("env");
+ } else {
+ commands = Arrays.asList("cmd", "/c", "set");
+ }
+ return commands;
+ }
+
+ /**
+ * execute a command that returns with an error code that will
+ * be converted into a number
+ * @return commands
+ */
+ public List<String> exitFalse() {
+ List<String> commands = new ArrayList<String>(2);
+ commands.add("false");
+ return commands;
+ }
+
+ /**
+ * Create a process command factory for this OS
+ * @return
+ */
+ public static ProcessCommandFactory createProcessCommandFactory() {
+ return new ProcessCommandFactory();
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/SimpleRunnable.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/SimpleRunnable.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/SimpleRunnable.java
new file mode 100644
index 0000000..1f330f4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/SimpleRunnable.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+/**
+ * Test runnable that can be made to exit, or throw an exception
+ * during its run
+ */
+class SimpleRunnable implements Runnable {
+ boolean throwException = false;
+
+
+ SimpleRunnable() {
+ }
+
+ SimpleRunnable(boolean throwException) {
+ this.throwException = throwException;
+ }
+
+ @Override
+ public synchronized void run() {
+ try {
+ if (throwException) {
+ throw new RuntimeException("SimpleRunnable");
+ }
+ } finally {
+ this.notify();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowClosingService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowClosingService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowClosingService.java
new file mode 100644
index 0000000..39516b7
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowClosingService.java
@@ -0,0 +1,116 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.conf.Configuration;
+import org.junit.Test;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public class TestWorkflowClosingService extends WorkflowServiceTestBase {
+
+ @Test
+ public void testSimpleClose() throws Throwable {
+ ClosingService<OpenClose> svc = instance(false);
+ OpenClose openClose = svc.getCloseable();
+ assertFalse(openClose.closed);
+ svc.stop();
+ assertTrue(openClose.closed);
+ }
+
+ @Test
+ public void testNullClose() throws Throwable {
+ ClosingService<OpenClose> svc = new ClosingService<OpenClose>("", null);
+ svc.init(new Configuration());
+ svc.start();
+ assertNull(svc.getCloseable());
+ svc.stop();
+ }
+
+ @Test
+ public void testFailingClose() throws Throwable {
+ ClosingService<OpenClose> svc = instance(false);
+ OpenClose openClose = svc.getCloseable();
+ openClose.raiseExceptionOnClose = true;
+ svc.stop();
+ assertTrue(openClose.closed);
+ Throwable cause = svc.getFailureCause();
+ assertNotNull(cause);
+
+ //retry should be a no-op
+ svc.close();
+ }
+
+ @Test
+ public void testDoubleClose() throws Throwable {
+ ClosingService<OpenClose> svc = instance(false);
+ OpenClose openClose = svc.getCloseable();
+ openClose.raiseExceptionOnClose = true;
+ svc.stop();
+ assertTrue(openClose.closed);
+ Throwable cause = svc.getFailureCause();
+ assertNotNull(cause);
+ openClose.closed = false;
+ svc.stop();
+ assertEquals(cause, svc.getFailureCause());
+ }
+
+ /**
+ * This does not recurse forever, as the service has already entered the
+ * STOPPED state before the inner close tries to stop it -that operation
+ * is a no-op
+ * @throws Throwable
+ */
+ @Test
+ public void testCloseSelf() throws Throwable {
+ ClosingService<ClosingService> svc =
+ new ClosingService<ClosingService>("");
+ svc.setCloseable(svc);
+ svc.stop();
+ }
+
+
+ private ClosingService<OpenClose> instance(boolean raiseExceptionOnClose) {
+ ClosingService<OpenClose> svc = new ClosingService<OpenClose>(new OpenClose(
+ raiseExceptionOnClose));
+ svc.init(new Configuration());
+ svc.start();
+ return svc;
+ }
+
+ private static class OpenClose implements Closeable {
+ public boolean closed = false;
+ public boolean raiseExceptionOnClose;
+
+ private OpenClose(boolean raiseExceptionOnClose) {
+ this.raiseExceptionOnClose = raiseExceptionOnClose;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ closed = true;
+ if (raiseExceptionOnClose) {
+ throw new IOException("OpenClose");
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowCompositeService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowCompositeService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowCompositeService.java
new file mode 100644
index 0000000..5780149
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowCompositeService.java
@@ -0,0 +1,113 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.service.Service;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestWorkflowCompositeService extends ParentWorkflowTestBase {
+ private static final Logger
+ log = LoggerFactory.getLogger(TestWorkflowCompositeService.class);
+
+ @Test
+ public void testSingleChild() throws Throwable {
+ Service parent = startService(new MockService());
+ parent.stop();
+ }
+
+ @Test
+ public void testSingleChildTerminating() throws Throwable {
+ ServiceParent parent =
+ startService(new MockService("1", false, 100));
+ waitForParentToStop(parent);
+ }
+
+ @Test
+ public void testSingleChildFailing() throws Throwable {
+ ServiceParent parent =
+ startService(new MockService("1", true, 100));
+ waitForParentToStop(parent);
+ assert parent.getFailureCause() != null;
+ }
+
+ @Test
+ public void testTwoChildren() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = startService(one, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ }
+
+ @Test
+ public void testCallableChild() throws Throwable {
+
+ MockService one = new MockService("one", false, 100);
+ CallableHandler handler = new CallableHandler("hello");
+ WorkflowCallbackService<String> ens =
+ new WorkflowCallbackService<String>("handler", handler, 100, true);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = startService(one, ens, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(ens);
+ assertStopped(two);
+ assertTrue(handler.notified);
+ String s = ens.getScheduledFuture().get();
+ assertEquals("hello", s);
+ }
+
+ @Test
+ public void testNestedComposite() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = buildService(one, two);
+ ServiceParent outer = startService(parent);
+ assertTrue(outer.waitForServiceToStop(1000));
+ assertStopped(one);
+ assertStopped(two);
+ }
+
+ @Test
+ public void testFailingComposite() throws Throwable {
+ MockService one = new MockService("one", true, 10);
+ MockService two = new MockService("two", false, 1000);
+ ServiceParent parent = startService(one, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ assertNotNull(one.getFailureCause());
+ assertNotNull(parent.getFailureCause());
+ assertEquals(one.getFailureCause(), parent.getFailureCause());
+ }
+
+ @Override
+ public ServiceParent buildService(Service... services) {
+ ServiceParent parent =
+ new WorkflowCompositeService("test", services);
+ parent.init(new Configuration());
+ return parent;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowExecutorService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowExecutorService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowExecutorService.java
new file mode 100644
index 0000000..dc160d9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowExecutorService.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.junit.Test;
+
+import java.util.concurrent.ExecutorService;
+
+
+/**
+ * Basic tests for executor service
+ */
+public class TestWorkflowExecutorService extends WorkflowServiceTestBase {
+
+ @Test
+ public void testAsyncRun() throws Throwable {
+
+ ExecutorSvc svc = run(new ExecutorSvc());
+ ServiceTerminatingRunnable runnable = new ServiceTerminatingRunnable(svc,
+ new SimpleRunnable());
+
+ // synchronous in-thread execution
+ svc.execute(runnable);
+ Thread.sleep(1000);
+ assertStopped(svc);
+ }
+
+ @Test
+ public void testFailureRun() throws Throwable {
+
+ ExecutorSvc svc = run(new ExecutorSvc());
+ ServiceTerminatingRunnable runnable = new ServiceTerminatingRunnable(svc,
+ new SimpleRunnable(true));
+
+ // synchronous in-thread execution
+ svc.execute(runnable);
+ Thread.sleep(1000);
+ assertStopped(svc);
+ assertNotNull(runnable.getException());
+ }
+
+ private static class ExecutorSvc
+ extends WorkflowExecutorService<ExecutorService> {
+ private ExecutorSvc() {
+ super("ExecutorService",
+ ServiceThreadFactory.singleThreadExecutor("test", true));
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowRpcService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowRpcService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowRpcService.java
new file mode 100644
index 0000000..38cd9e1
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowRpcService.java
@@ -0,0 +1,107 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.ipc.Server;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+public class TestWorkflowRpcService extends WorkflowServiceTestBase {
+
+ @Test
+ public void testCreateMockRPCService() throws Throwable {
+ MockRPC rpc = new MockRPC();
+ rpc.start();
+ assertTrue(rpc.started);
+ rpc.getListenerAddress();
+ rpc.stop();
+ assertTrue(rpc.stopped);
+ }
+
+ @Test
+ public void testLifecycle() throws Throwable {
+ MockRPC rpc = new MockRPC();
+ WorkflowRpcService svc = new WorkflowRpcService("test", rpc);
+ run(svc);
+ assertTrue(rpc.started);
+ svc.getConnectAddress();
+ svc.stop();
+ assertTrue(rpc.stopped);
+ }
+
+ @Test
+ public void testStartFailure() throws Throwable {
+ MockRPC rpc = new MockRPC();
+ rpc.failOnStart = true;
+ WorkflowRpcService svc = new WorkflowRpcService("test", rpc);
+ svc.init(new Configuration());
+ try {
+ svc.start();
+ fail("expected an exception");
+ } catch (RuntimeException e) {
+ assertEquals("failOnStart", e.getMessage());
+ }
+ svc.stop();
+ assertTrue(rpc.stopped);
+ }
+
+ private static class MockRPC extends Server {
+
+ public boolean stopped;
+ public boolean started;
+ public boolean failOnStart;
+
+ private MockRPC() throws IOException {
+ super("localhost", 0, null, 1, new Configuration());
+ }
+
+ @Override
+ public synchronized void start() {
+ if (failOnStart) {
+ throw new RuntimeException("failOnStart");
+ }
+ started = true;
+ super.start();
+ }
+
+ @Override
+ public synchronized void stop() {
+ stopped = true;
+ super.stop();
+ }
+
+ @Override
+ public synchronized InetSocketAddress getListenerAddress() {
+ return super.getListenerAddress();
+ }
+
+ @Override
+ public Writable call(RPC.RpcKind rpcKind,
+ String protocol,
+ Writable param,
+ long receiveTime) throws Exception {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowSequenceService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowSequenceService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowSequenceService.java
new file mode 100644
index 0000000..581e3ed
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowSequenceService.java
@@ -0,0 +1,151 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.service.Service;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestWorkflowSequenceService extends ParentWorkflowTestBase {
+ private static final Logger
+ log = LoggerFactory.getLogger(TestWorkflowSequenceService.class);
+
+ @Test
+ public void testSingleSequence() throws Throwable {
+ ServiceParent parent = startService(new MockService());
+ parent.stop();
+ }
+
+ @Test
+ public void testEmptySequence() throws Throwable {
+ ServiceParent parent = startService();
+ waitForParentToStop(parent);
+ }
+
+ @Test
+ public void testSequence() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = startService(one, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ assert ((WorkflowSequenceService) parent).getPreviousService().equals(two);
+ }
+
+ @Test
+ public void testCallableChild() throws Throwable {
+
+ MockService one = new MockService("one", false, 100);
+ CallableHandler handler = new CallableHandler("hello");
+ WorkflowCallbackService<String> ens =
+ new WorkflowCallbackService<String>("handler", handler, 100, true);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = startService(one, ens, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(ens);
+ assertStopped(two);
+ assertTrue(handler.notified);
+ String s = ens.getScheduledFuture().get();
+ assertEquals("hello", s);
+ }
+
+
+ @Test
+ public void testFailingSequence() throws Throwable {
+ MockService one = new MockService("one", true, 100);
+ MockService two = new MockService("two", false, 100);
+ WorkflowSequenceService parent =
+ (WorkflowSequenceService) startService(one, two);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertInState(two, Service.STATE.NOTINITED);
+ assertEquals(one, parent.getPreviousService());
+ }
+
+
+ @Test
+ public void testFailInStartNext() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", true, 0);
+ MockService three = new MockService("3", false, 0);
+ ServiceParent parent = startService(one, two, three);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ Throwable failureCause = two.getFailureCause();
+ assertNotNull(failureCause);
+ Throwable parentFailureCause = parent.getFailureCause();
+ assertNotNull(parentFailureCause);
+ assertEquals(parentFailureCause, failureCause);
+ assertInState(three, Service.STATE.NOTINITED);
+ }
+
+ @Test
+ public void testSequenceInSequence() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = buildService(one, two);
+ ServiceParent outer = startService(parent);
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ }
+
+ @Test
+ public void testVarargsConstructor() throws Throwable {
+ MockService one = new MockService("one", false, 100);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = new WorkflowSequenceService("test", one, two);
+ parent.init(new Configuration());
+ parent.start();
+ waitForParentToStop(parent);
+ assertStopped(one);
+ assertStopped(two);
+ }
+
+
+ @Test
+ public void testAddChild() throws Throwable {
+ MockService one = new MockService("one", false, 5000);
+ MockService two = new MockService("two", false, 100);
+ ServiceParent parent = startService(one, two);
+ CallableHandler handler = new CallableHandler("hello");
+ WorkflowCallbackService<String> ens =
+ new WorkflowCallbackService<String>("handler", handler, 100, true);
+ parent.addService(ens);
+ waitForParentToStop(parent, 10000);
+ assertStopped(one);
+ assertStopped(two);
+ assertStopped(ens);
+ assertStopped(two);
+ assertEquals("hello", ens.getScheduledFuture().get());
+ }
+
+ public WorkflowSequenceService buildService(Service... services) {
+ WorkflowSequenceService parent =
+ new WorkflowSequenceService("test", services);
+ parent.init(new Configuration());
+ return parent;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowServiceTerminatingRunnable.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowServiceTerminatingRunnable.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowServiceTerminatingRunnable.java
new file mode 100644
index 0000000..5b7a6f9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/TestWorkflowServiceTerminatingRunnable.java
@@ -0,0 +1,64 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.junit.Test;
+
+
+public class TestWorkflowServiceTerminatingRunnable extends WorkflowServiceTestBase {
+
+ @Test
+ public void testNoservice() throws Throwable {
+
+ try {
+ new ServiceTerminatingRunnable(null, new SimpleRunnable());
+ fail("unexpected ");
+ } catch (IllegalArgumentException e) {
+
+ // expected
+ }
+ }
+
+
+ @Test
+ public void testBasicRun() throws Throwable {
+
+ WorkflowCompositeService svc = run(new WorkflowCompositeService());
+ ServiceTerminatingRunnable runnable = new ServiceTerminatingRunnable(svc,
+ new SimpleRunnable());
+
+ // synchronous in-thread execution
+ runnable.run();
+ assertStopped(svc);
+ }
+
+ @Test
+ public void testFailureRun() throws Throwable {
+
+ WorkflowCompositeService svc = run(new WorkflowCompositeService());
+ ServiceTerminatingRunnable runnable =
+ new ServiceTerminatingRunnable(svc, new SimpleRunnable(true));
+
+ // synchronous in-thread execution
+ runnable.run();
+ assertStopped(svc);
+ assertNotNull(runnable.getException());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/4826d902/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
new file mode 100644
index 0000000..f38bd9d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
@@ -0,0 +1,139 @@
+/*
+ * 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 org.apache.slider.server.services.workflow;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.service.Service;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.junit.rules.Timeout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.Callable;
+
+/**
+ * Test base for workflow service tests.
+ */
+public abstract class WorkflowServiceTestBase extends Assert {
+ private static final Logger
+ log = LoggerFactory.getLogger(WorkflowServiceTestBase.class);
+
+ /**
+ * Set the timeout for every test
+ */
+ @Rule
+ public Timeout testTimeout = new Timeout(15000);
+
+ @Rule
+ public TestName name = new TestName();
+
+ @Before
+ public void nameThread() {
+ Thread.currentThread().setName("JUnit");
+ }
+
+
+ protected void assertInState(Service service, Service.STATE expected) {
+ Service.STATE actual = service.getServiceState();
+ if (actual != expected) {
+ fail("Service " + service.getName() + " in state " + actual
+ + " -expected " + expected);
+ }
+ }
+
+ protected void assertStopped(Service service) {
+ assertInState(service, Service.STATE.STOPPED);
+ }
+
+ protected void logState(ServiceParent p) {
+ logService(p);
+ for (Service s : p.getServices()) {
+ logService(s);
+ }
+ }
+
+ protected void logService(Service s) {
+ log.info(s.toString());
+ Throwable failureCause = s.getFailureCause();
+ if (failureCause != null) {
+ log.info("Failed in state {} with {}", s.getFailureState(),
+ failureCause);
+ }
+ }
+
+ /**
+ * Init and start a service
+ * @param svc the service
+ * @return the service
+ */
+ protected <S extends Service> S run(S svc) {
+ svc.init(new Configuration());
+ svc.start();
+ return svc;
+ }
+
+ /**
+ * Handler for callable events
+ */
+ public static class CallableHandler implements Callable<String> {
+ public volatile boolean notified = false;
+ public final String result;
+
+ public CallableHandler(String result) {
+ this.result = result;
+ }
+
+ @Override
+ public String call() throws Exception {
+ log.info("CallableHandler::call");
+ notified = true;
+ return result;
+ }
+ }
+
+ /**
+ * Assert that a string is in an output list. Fails fast if the output
+ * list is empty
+ * @param text text to scan for
+ * @param output list of output lines.
+ */
+ public void assertStringInOutput(String text, List<String> output) {
+ assertTrue("Empty output list", !output.isEmpty());
+ boolean found = false;
+ StringBuilder builder = new StringBuilder();
+ for (String s : output) {
+ builder.append(s.toLowerCase(Locale.ENGLISH)).append('\n');
+ if (s.contains(text)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ String message =
+ "Text \"" + text + "\" not found in " + output.size() + " lines\n";
+ fail(message + builder.toString());
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org