GEODE-3383: Refactor deploy tests
Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/c5dd26b7 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/c5dd26b7 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/c5dd26b7 Branch: refs/heads/feature/GEODE-1279 Commit: c5dd26b7f7317c93666583b405006e1bb7c9255e Parents: e07b5c1 Author: Jared Stewart <[email protected]> Authored: Tue Aug 8 10:32:32 2017 -0700 Committer: Jared Stewart <[email protected]> Committed: Tue Aug 15 15:42:11 2017 -0700 ---------------------------------------------------------------------- .../ClassPathLoaderIntegrationTest.java | 171 ++++++++ .../geode/internal/DeployedJarJUnitTest.java | 400 ++----------------- .../geode/internal/JarDeployerDeadlockTest.java | 131 ++++++ .../geode/management/DeployJarTestSuite.java | 4 +- .../cli/commands/DeployCommandsDUnitTest.java | 303 -------------- .../cli/commands/DeployWithGroupsDUnitTest.java | 303 ++++++++++++++ .../cli/commands/CommandOverHttpDUnitTest.java | 2 +- 7 files changed, 636 insertions(+), 678 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java index 34d8a23..2fdc085 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/ClassPathLoaderIntegrationTest.java @@ -27,9 +27,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Method; import java.net.URL; import java.util.Enumeration; import java.util.List; +import java.util.Random; import java.util.Vector; import org.apache.bcel.Constants; @@ -44,10 +46,14 @@ import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; import org.apache.geode.cache.execute.Execution; +import org.apache.geode.cache.execute.Function; +import org.apache.geode.cache.execute.FunctionContext; import org.apache.geode.cache.execute.FunctionService; import org.apache.geode.cache.execute.ResultCollector; +import org.apache.geode.cache.execute.ResultSender; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.cache.execute.FunctionContextImpl; import org.apache.geode.test.dunit.rules.ServerStarterRule; import org.apache.geode.test.junit.categories.IntegrationTest; import org.apache.geode.test.junit.rules.RestoreTCCLRule; @@ -64,6 +70,7 @@ public class ClassPathLoaderIntegrationTest { private File tempFile; private File tempFile2; + private ClassBuilder classBuilder = new ClassBuilder(); @Rule public RestoreTCCLRule restoreTCCLRule = new RestoreTCCLRule(); @@ -452,6 +459,145 @@ public class ClassPathLoaderIntegrationTest { } } + @Test + public void testDeclarableFunctionsWithNoCacheXml() throws Exception { + final String jarName = "JarClassLoaderJUnitNoXml.jar"; + + // Add a Declarable Function without parameters for the class to the Classpath + String functionString = + "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;" + + "import org.apache.geode.cache.execute.Function;" + + "import org.apache.geode.cache.execute.FunctionContext;" + + "public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {" + + "public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}" + + "public void init(Properties props) {}" + + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}" + + "public boolean hasResult() {return true;}" + + "public boolean optimizeForWrite() {return false;}" + + "public boolean isHA() {return false;}}"; + + byte[] jarBytes = this.classBuilder + .createJarFromClassContent("JarClassLoaderJUnitFunctionNoXml", functionString); + + ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes); + + ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml"); + + // Check to see if the function without parameters executes correctly + Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionNoXml"); + assertThat(function).isNotNull(); + TestResultSender resultSender = new TestResultSender(); + function.execute(new FunctionContextImpl(null, function.getId(), null, resultSender)); + assertThat((String) resultSender.getResults()).isEqualTo("NOPARMSv1"); + } + + @Test + public void testDependencyBetweenJars() throws Exception { + final File parentJarFile = temporaryFolder.newFile("JarClassLoaderJUnitParent.jar"); + final File usesJarFile = temporaryFolder.newFile("JarClassLoaderJUnitUses.jar"); + + // Write out a JAR files. + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append("package jcljunit.parent;"); + stringBuffer.append("public class JarClassLoaderJUnitParent {"); + stringBuffer.append("public String getValueParent() {"); + stringBuffer.append("return \"PARENT\";}}"); + + byte[] jarBytes = this.classBuilder.createJarFromClassContent( + "jcljunit/parent/JarClassLoaderJUnitParent", stringBuffer.toString()); + writeJarBytesToFile(parentJarFile, jarBytes); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitParent.jar", jarBytes); + + stringBuffer = new StringBuffer(); + stringBuffer.append("package jcljunit.uses;"); + stringBuffer.append("public class JarClassLoaderJUnitUses {"); + stringBuffer.append("public String getValueUses() {"); + stringBuffer.append("return \"USES\";}}"); + + jarBytes = this.classBuilder.createJarFromClassContent("jcljunit/uses/JarClassLoaderJUnitUses", + stringBuffer.toString()); + writeJarBytesToFile(usesJarFile, jarBytes); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUses.jar", jarBytes); + + stringBuffer = new StringBuffer(); + stringBuffer.append("package jcljunit.function;"); + stringBuffer.append("import jcljunit.parent.JarClassLoaderJUnitParent;"); + stringBuffer.append("import jcljunit.uses.JarClassLoaderJUnitUses;"); + stringBuffer.append("import org.apache.geode.cache.execute.Function;"); + stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;"); + stringBuffer.append( + "public class JarClassLoaderJUnitFunction extends JarClassLoaderJUnitParent implements Function {"); + stringBuffer.append("private JarClassLoaderJUnitUses uses = new JarClassLoaderJUnitUses();"); + stringBuffer.append("public boolean hasResult() {return true;}"); + stringBuffer.append( + "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}"); + stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}"); + stringBuffer.append("public boolean optimizeForWrite() {return false;}"); + stringBuffer.append("public boolean isHA() {return false;}}"); + + ClassBuilder functionClassBuilder = new ClassBuilder(); + functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath()); + functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath()); + jarBytes = functionClassBuilder.createJarFromClassContent( + "jcljunit/function/JarClassLoaderJUnitFunction", stringBuffer.toString()); + + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar", + jarBytes); + + Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction"); + assertThat(function).isNotNull(); + TestResultSender resultSender = new TestResultSender(); + FunctionContext functionContext = + new FunctionContextImpl(null, function.getId(), null, resultSender); + function.execute(functionContext); + assertThat((String) resultSender.getResults()).isEqualTo("PARENT:USES"); + } + + @Test + public void testFindResource() throws IOException, ClassNotFoundException { + final String fileName = "file.txt"; + final String fileContent = "FILE CONTENT"; + + byte[] jarBytes = this.classBuilder.createJarFromFileContent(fileName, fileContent); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitResource.jar", + jarBytes); + + InputStream inputStream = ClassPathLoader.getLatest().getResourceAsStream(fileName); + assertThat(inputStream).isNotNull(); + + final byte[] fileBytes = new byte[fileContent.length()]; + inputStream.read(fileBytes); + inputStream.close(); + assertThat(fileContent).isEqualTo(new String(fileBytes)); + } + + + @Test + public void testUpdateClassInJar() throws Exception { + // First use of the JAR file + byte[] jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass", + "public class JarClassLoaderJUnitTestClass { public Integer getValue5() { return new Integer(5); } }"); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes); + + Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass"); + Object object = clazz.newInstance(); + Method getValue5Method = clazz.getMethod("getValue5"); + Integer value = (Integer) getValue5Method.invoke(object); + assertThat(value).isEqualTo(5); + + // Now create an updated JAR file and make sure that the method from the new + // class is available. + jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass", + "public class JarClassLoaderJUnitTestClass { public Integer getValue10() { return new Integer(10); } }"); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes); + + clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass"); + object = clazz.newInstance(); + Method getValue10Method = clazz.getMethod("getValue10"); + value = (Integer) getValue10Method.invoke(object); + assertThat(value).isEqualTo(10); + } + private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException { final OutputStream outStream = new FileOutputStream(jarFile); outStream.write(jarBytes); @@ -538,4 +684,29 @@ public class ClassPathLoaderIntegrationTest { return new ClassBuilder().createJarFromClassContent("integration/parent/" + className, stringBuilder); } + + private static class TestResultSender implements ResultSender<Object> { + private Object result; + + public TestResultSender() {} + + protected Object getResults() { + return this.result; + } + + @Override + public void lastResult(final Object lastResult) { + this.result = lastResult; + } + + @Override + public void sendResult(final Object oneResult) { + throw new UnsupportedOperationException(); + } + + @Override + public void sendException(final Throwable t) { + throw new UnsupportedOperationException(); + } + } } http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java index 178dbae..853696a 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/DeployedJarJUnitTest.java @@ -18,411 +18,67 @@ package org.apache.geode.internal; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import org.apache.geode.cache.execute.Function; -import org.apache.geode.cache.execute.FunctionContext; -import org.apache.geode.cache.execute.FunctionService; -import org.apache.geode.cache.execute.ResultSender; -import org.apache.geode.internal.cache.execute.FunctionContextImpl; +import org.apache.geode.test.compiler.JarBuilder; import org.apache.geode.test.junit.categories.IntegrationTest; -import org.awaitility.Awaitility; -import org.junit.After; + +import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.lang.reflect.Method; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; @Category(IntegrationTest.class) public class DeployedJarJUnitTest { + private static final String JAR_NAME = "test.jar"; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); - - private ClassBuilder classBuilder; + private JarBuilder jarBuilder; + private File jarFile; + private byte[] expectedJarBytes; @Before public void setup() throws Exception { - File workingDir = temporaryFolder.newFolder(); - ClassPathLoader.setLatestToDefault(workingDir); - classBuilder = new ClassBuilder(); - } - - @After - public void tearDown() throws Exception { - for (String functionName : FunctionService.getRegisteredFunctions().keySet()) { - FunctionService.unregisterFunction(functionName); - } - - ClassPathLoader.setLatestToDefault(); + jarBuilder = new JarBuilder(); + jarFile = new File(temporaryFolder.getRoot(), JAR_NAME); + jarBuilder.buildJarFromClassNames(jarFile, "ExpectedClass"); + expectedJarBytes = FileUtils.readFileToByteArray(jarFile); } @Test - public void testIsValidJarContent() throws IOException { - assertThat( - DeployedJar.hasValidJarContent(this.classBuilder.createJarFromName("JarClassLoaderJUnitA"))) - .isTrue(); + public void validJarContentDoesNotThrow() throws Exception { + new DeployedJar(jarFile, JAR_NAME, expectedJarBytes); } @Test - public void testIsInvalidJarContent() { - assertThat(DeployedJar.hasValidJarContent("INVALID JAR CONTENT".getBytes())).isFalse(); - } - - @Test - public void testClassOnClasspath() throws Exception { - // Deploy the first JAR file and make sure the class is on the Classpath - byte[] jarBytes = - this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitA", - "package com.jcljunit; public class JarClassLoaderJUnitA {}"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes); - - ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA"); + public void unexpectedContentThrowsException() throws Exception { + givenUnexpectedJarFileContents(); - // Update the JAR file and make sure the first class is no longer on the Classpath - // and the second one is. - jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB", - "package com.jcljunit; public class JarClassLoaderJUnitB {}"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes); - - ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitB"); - assertThatThrownBy( - () -> ClassPathLoader.getLatest().forName("com.jcljunit.JarClassLoaderJUnitA")) - .isInstanceOf(ClassNotFoundException.class); + assertThatThrownBy(() -> new DeployedJar(jarFile, JAR_NAME, expectedJarBytes)) + .isInstanceOf(IllegalStateException.class); } @Test - public void testFailingCompilation() throws Exception { - String functionString = "import org.apache.geode.cache.Declarable;" - + "import org.apache.geode.cache.execute.Function;" - + "import org.apache.geode.cache.execute.FunctionContext;" - + "public class JarClassLoaderJUnitFunction implements Function {}"; + public void invalidContentThrowsException() throws Exception { + byte[] invalidJarBytes = givenInvalidJarBytes(); - assertThatThrownBy(() -> this.classBuilder - .createJarFromClassContent("JarClassLoaderJUnitFunction", functionString)).isNotNull(); + assertThatThrownBy(() -> new DeployedJar(jarFile, JAR_NAME, invalidJarBytes)) + .isInstanceOf(IllegalArgumentException.class); } - @Test - public void testFunctions() throws Exception { - // Test creating a JAR file with a function - String functionString = - "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;" - + "import org.apache.geode.cache.execute.Function;" - + "import org.apache.geode.cache.execute.FunctionContext;" - + "public class JarClassLoaderJUnitFunction implements Function {" - + "public void init(Properties props) {}" + "public boolean hasResult() {return true;}" - + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"GOODv1\");}" - + "public String getId() {return \"JarClassLoaderJUnitFunction\";}" - + "public boolean optimizeForWrite() {return false;}" - + "public boolean isHA() {return false;}}"; - - byte[] jarBytes = - this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString); - - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes); - - Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction"); - assertThat(function).isNotNull(); - TestResultSender resultSender = new TestResultSender(); - FunctionContext functionContext = - new FunctionContextImpl(null, function.getId(), null, resultSender); - function.execute(functionContext); - assertThat(resultSender.getResults()).isEqualTo("GOODv1"); - - // Test updating the function with a new JAR file - functionString = functionString.replace("v1", "v2"); - jarBytes = - this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes); - - function = FunctionService.getFunction("JarClassLoaderJUnitFunction"); - assertThat(function).isNotNull(); - resultSender = new TestResultSender(); - functionContext = new FunctionContextImpl(null, function.getId(), null, resultSender); - function.execute(functionContext); - assertThat(resultSender.getResults()).isEqualTo("GOODv2"); - - // Test returning null for the Id - String functionNullIdString = - functionString.replace("return \"JarClassLoaderJUnitFunction\"", "return null"); - jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", - functionNullIdString); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnit.jar", jarBytes); - - assertThat(FunctionService.getFunction("JarClassLoaderJUnitFunction")).isNull(); - - // Test removing the JAR - ClassPathLoader.getLatest().getJarDeployer().undeploy("JarClassLoaderJUnit.jar"); - assertThat(FunctionService.getFunction("JarClassLoaderJUnitFunction")).isNull(); + private void givenUnexpectedJarFileContents() throws IOException { + FileUtils.deleteQuietly(jarFile); + jarBuilder.buildJarFromClassNames(jarFile, "UnexpectedClass"); } - /** - * Ensure that abstract functions aren't added to the Function Service. - */ - @Test - public void testAbstractFunction() throws Exception { - // Add an abstract Function to the Classpath - String functionString = "import org.apache.geode.cache.execute.Function;" - + "public abstract class JarClassLoaderJUnitFunction implements Function {" - + "public String getId() {return \"JarClassLoaderJUnitFunction\";}}"; - - byte[] jarBytes = - this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitFunction", functionString); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar", - jarBytes); - - ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunction"); - - Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction"); - assertThat(function).isNull(); - } - - @Test - public void testDeclarableFunctionsWithNoCacheXml() throws Exception { - final String jarName = "JarClassLoaderJUnitNoXml.jar"; - - // Add a Declarable Function without parameters for the class to the Classpath - String functionString = - "import java.util.Properties;" + "import org.apache.geode.cache.Declarable;" - + "import org.apache.geode.cache.execute.Function;" - + "import org.apache.geode.cache.execute.FunctionContext;" - + "public class JarClassLoaderJUnitFunctionNoXml implements Function, Declarable {" - + "public String getId() {return \"JarClassLoaderJUnitFunctionNoXml\";}" - + "public void init(Properties props) {}" - + "public void execute(FunctionContext context) {context.getResultSender().lastResult(\"NOPARMSv1\");}" - + "public boolean hasResult() {return true;}" - + "public boolean optimizeForWrite() {return false;}" - + "public boolean isHA() {return false;}}"; - - byte[] jarBytes = this.classBuilder - .createJarFromClassContent("JarClassLoaderJUnitFunctionNoXml", functionString); - - ClassPathLoader.getLatest().getJarDeployer().deploy(jarName, jarBytes); - - ClassPathLoader.getLatest().forName("JarClassLoaderJUnitFunctionNoXml"); - - // Check to see if the function without parameters executes correctly - Function function = FunctionService.getFunction("JarClassLoaderJUnitFunctionNoXml"); - assertThat(function).isNotNull(); - TestResultSender resultSender = new TestResultSender(); - function.execute(new FunctionContextImpl(null, function.getId(), null, resultSender)); - assertThat((String) resultSender.getResults()).isEqualTo("NOPARMSv1"); - } - - @Test - public void testDependencyBetweenJars() throws Exception { - final File parentJarFile = temporaryFolder.newFile("JarClassLoaderJUnitParent.jar"); - final File usesJarFile = temporaryFolder.newFile("JarClassLoaderJUnitUses.jar"); - - // Write out a JAR files. - StringBuffer stringBuffer = new StringBuffer(); - stringBuffer.append("package jcljunit.parent;"); - stringBuffer.append("public class JarClassLoaderJUnitParent {"); - stringBuffer.append("public String getValueParent() {"); - stringBuffer.append("return \"PARENT\";}}"); - - byte[] jarBytes = this.classBuilder.createJarFromClassContent( - "jcljunit/parent/JarClassLoaderJUnitParent", stringBuffer.toString()); - writeJarBytesToFile(parentJarFile, jarBytes); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitParent.jar", jarBytes); - - stringBuffer = new StringBuffer(); - stringBuffer.append("package jcljunit.uses;"); - stringBuffer.append("public class JarClassLoaderJUnitUses {"); - stringBuffer.append("public String getValueUses() {"); - stringBuffer.append("return \"USES\";}}"); - - jarBytes = this.classBuilder.createJarFromClassContent("jcljunit/uses/JarClassLoaderJUnitUses", - stringBuffer.toString()); - writeJarBytesToFile(usesJarFile, jarBytes); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUses.jar", jarBytes); - - stringBuffer = new StringBuffer(); - stringBuffer.append("package jcljunit.function;"); - stringBuffer.append("import jcljunit.parent.JarClassLoaderJUnitParent;"); - stringBuffer.append("import jcljunit.uses.JarClassLoaderJUnitUses;"); - stringBuffer.append("import org.apache.geode.cache.execute.Function;"); - stringBuffer.append("import org.apache.geode.cache.execute.FunctionContext;"); - stringBuffer.append( - "public class JarClassLoaderJUnitFunction extends JarClassLoaderJUnitParent implements Function {"); - stringBuffer.append("private JarClassLoaderJUnitUses uses = new JarClassLoaderJUnitUses();"); - stringBuffer.append("public boolean hasResult() {return true;}"); - stringBuffer.append( - "public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}"); - stringBuffer.append("public String getId() {return \"JarClassLoaderJUnitFunction\";}"); - stringBuffer.append("public boolean optimizeForWrite() {return false;}"); - stringBuffer.append("public boolean isHA() {return false;}}"); - - ClassBuilder functionClassBuilder = new ClassBuilder(); - functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath()); - functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath()); - jarBytes = functionClassBuilder.createJarFromClassContent( - "jcljunit/function/JarClassLoaderJUnitFunction", stringBuffer.toString()); - - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitFunction.jar", - jarBytes); - - Function function = FunctionService.getFunction("JarClassLoaderJUnitFunction"); - assertThat(function).isNotNull(); - TestResultSender resultSender = new TestResultSender(); - FunctionContext functionContext = - new FunctionContextImpl(null, function.getId(), null, resultSender); - function.execute(functionContext); - assertThat((String) resultSender.getResults()).isEqualTo("PARENT:USES"); - } - - @Test - public void testFindResource() throws IOException, ClassNotFoundException { - final String fileName = "file.txt"; - final String fileContent = "FILE CONTENT"; - - byte[] jarBytes = this.classBuilder.createJarFromFileContent(fileName, fileContent); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitResource.jar", - jarBytes); - - InputStream inputStream = ClassPathLoader.getLatest().getResourceAsStream(fileName); - assertThat(inputStream).isNotNull(); - - final byte[] fileBytes = new byte[fileContent.length()]; - inputStream.read(fileBytes); - inputStream.close(); - assertThat(fileContent).isEqualTo(new String(fileBytes)); - } - - @Test - public void testUpdateClassInJar() throws Exception { - // First use of the JAR file - byte[] jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass", - "public class JarClassLoaderJUnitTestClass { public Integer getValue5() { return new Integer(5); } }"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes); - - Class<?> clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass"); - Object object = clazz.newInstance(); - Method getValue5Method = clazz.getMethod("getValue5"); - Integer value = (Integer) getValue5Method.invoke(object); - assertThat(value).isEqualTo(5); - - // Now create an updated JAR file and make sure that the method from the new - // class is available. - jarBytes = this.classBuilder.createJarFromClassContent("JarClassLoaderJUnitTestClass", - "public class JarClassLoaderJUnitTestClass { public Integer getValue10() { return new Integer(10); } }"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitUpdate.jar", jarBytes); - - clazz = ClassPathLoader.getLatest().forName("JarClassLoaderJUnitTestClass"); - object = clazz.newInstance(); - Method getValue10Method = clazz.getMethod("getValue10"); - value = (Integer) getValue10Method.invoke(object); - assertThat(value).isEqualTo(10); - } - - @Test - public void testMultiThreadingDoesNotCauseDeadlock() throws Exception { - // Add two JARs to the classpath - byte[] jarBytes = this.classBuilder.createJarFromName("JarClassLoaderJUnitA"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitA.jar", jarBytes); - - jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB", - "package com.jcljunit; public class JarClassLoaderJUnitB {}"); - ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitB.jar", jarBytes); - - String[] classNames = new String[] {"JarClassLoaderJUnitA", "com.jcljunit.JarClassLoaderJUnitB", - "NON-EXISTENT CLASS"}; - - final int threadCount = 10; - ExecutorService executorService = Executors.newFixedThreadPool(threadCount); - for (int i = 0; i < threadCount; i++) { - executorService.submit(new ForNameExerciser(classNames)); - } - - executorService.shutdown(); - Awaitility.await().atMost(60, TimeUnit.SECONDS).until(executorService::isTerminated); - - ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); - long[] threadIds = threadMXBean.findDeadlockedThreads(); - - if (threadIds != null) { - StringBuilder deadLockTrace = new StringBuilder(); - for (long threadId : threadIds) { - ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100); - deadLockTrace.append(threadInfo.getThreadName()).append("\n"); - for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) { - deadLockTrace.append("\t").append(stackTraceElem).append("\n"); - } - } - System.out.println(deadLockTrace); - } - assertThat(threadIds).isNull(); - } - - private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException { - final OutputStream outStream = new FileOutputStream(jarFile); - outStream.write(jarBytes); - outStream.close(); - } - - private static class TestResultSender implements ResultSender<Object> { - private Object result; - - public TestResultSender() {} - - protected Object getResults() { - return this.result; - } - - @Override - public void lastResult(final Object lastResult) { - this.result = lastResult; - } - - @Override - public void sendResult(final Object oneResult) { - throw new UnsupportedOperationException(); - } - - @Override - public void sendException(final Throwable t) { - throw new UnsupportedOperationException(); - } - } - - static final Random random = new Random(); - - private class ForNameExerciser implements Runnable { - private final int numLoops = 1000; - private final String[] classNames; - - ForNameExerciser(final String[] classNames) { - this.classNames = classNames; - } + private byte[] givenInvalidJarBytes() throws IOException { + byte[] invalidJarBytes = "INVALID JAR CONTENT".getBytes(); + FileUtils.writeByteArrayToFile(jarFile, invalidJarBytes); - @Override - public void run() { - for (int i = 0; i < this.numLoops; i++) { - try { - // Random select a name from the list of class names and try to load it - String className = this.classNames[random.nextInt(this.classNames.length)]; - ClassPathLoader.getLatest().forName(className); - } catch (ClassNotFoundException expected) { // expected - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } + return invalidJarBytes; } } http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDeadlockTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDeadlockTest.java b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDeadlockTest.java new file mode 100644 index 0000000..7ff1774 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/JarDeployerDeadlockTest.java @@ -0,0 +1,131 @@ +/* + * 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.geode.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.awaitility.Awaitility; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.cache.execute.FunctionService; +import org.apache.geode.test.compiler.JarBuilder; +import org.apache.geode.test.junit.categories.IntegrationTest; + +@Category(IntegrationTest.class) +public class JarDeployerDeadlockTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + private ClassBuilder classBuilder; + + @Before + public void setup() throws Exception { + File workingDir = temporaryFolder.newFolder(); + ClassPathLoader.setLatestToDefault(workingDir); + classBuilder = new ClassBuilder(); + } + + @After + public void tearDown() throws Exception { + for (String functionName : FunctionService.getRegisteredFunctions().keySet()) { + FunctionService.unregisterFunction(functionName); + } + + ClassPathLoader.setLatestToDefault(); + } + + @Test + public void testMultiThreadingDoesNotCauseDeadlock() throws Exception { + // Add two JARs to the classpath + byte[] jarBytes = this.classBuilder.createJarFromName("JarClassLoaderJUnitA"); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitA.jar", jarBytes); + + jarBytes = this.classBuilder.createJarFromClassContent("com/jcljunit/JarClassLoaderJUnitB", + "package com.jcljunit; public class JarClassLoaderJUnitB {}"); + ClassPathLoader.getLatest().getJarDeployer().deploy("JarClassLoaderJUnitB.jar", jarBytes); + + String[] classNames = new String[] {"JarClassLoaderJUnitA", "com.jcljunit.JarClassLoaderJUnitB", + "NON-EXISTENT CLASS"}; + + final int threadCount = 10; + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + for (int i = 0; i < threadCount; i++) { + executorService.submit(new ForNameExerciser(classNames)); + } + + executorService.shutdown(); + Awaitility.await().atMost(60, TimeUnit.SECONDS).until(executorService::isTerminated); + + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + long[] threadIds = threadMXBean.findDeadlockedThreads(); + + if (threadIds != null) { + StringBuilder deadLockTrace = new StringBuilder(); + for (long threadId : threadIds) { + ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId, 100); + deadLockTrace.append(threadInfo.getThreadName()).append("\n"); + for (StackTraceElement stackTraceElem : threadInfo.getStackTrace()) { + deadLockTrace.append("\t").append(stackTraceElem).append("\n"); + } + } + System.out.println(deadLockTrace); + } + assertThat(threadIds).isNull(); + } + + private class ForNameExerciser implements Runnable { + private final Random random = new Random(); + + private final int numLoops = 1000; + private final String[] classNames; + + ForNameExerciser(final String[] classNames) { + this.classNames = classNames; + } + + @Override + public void run() { + for (int i = 0; i < this.numLoops; i++) { + try { + // Random select a name from the list of class names and try to load it + String className = this.classNames[random.nextInt(this.classNames.length)]; + ClassPathLoader.getLatest().forName(className); + } catch (ClassNotFoundException expected) { // expected + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java index 6dfab66..9a8348e 100644 --- a/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java +++ b/geode-core/src/test/java/org/apache/geode/management/DeployJarTestSuite.java @@ -19,7 +19,7 @@ import org.apache.geode.internal.ClassPathLoaderTest; import org.apache.geode.internal.DeployedJarJUnitTest; import org.apache.geode.internal.JarDeployerIntegrationTest; import org.apache.geode.management.internal.cli.commands.DeployCommandRedeployDUnitTest; -import org.apache.geode.management.internal.cli.commands.DeployCommandsDUnitTest; +import org.apache.geode.management.internal.cli.commands.DeployWithGroupsDUnitTest; import org.apache.geode.management.internal.configuration.ClusterConfigDeployJarDUnitTest; import org.junit.Ignore; import org.junit.runner.RunWith; @@ -28,7 +28,7 @@ import org.junit.runners.Suite; @Ignore @RunWith(Suite.class) [email protected]({DeployedJarJUnitTest.class, DeployCommandsDUnitTest.class, [email protected]({DeployedJarJUnitTest.class, DeployWithGroupsDUnitTest.class, JarDeployerIntegrationTest.class, ClassPathLoaderIntegrationTest.class, ClassPathLoaderTest.class, DeployCommandRedeployDUnitTest.class, ClusterConfigDeployJarDUnitTest.class}) http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java deleted file mode 100644 index 89148d7..0000000 --- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployCommandsDUnitTest.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * 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.geode.management.internal.cli.commands; - -import static org.apache.geode.distributed.ConfigurationProperties.GROUPS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.io.File; -import java.io.Serializable; -import java.util.Properties; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.internal.ClassBuilder; -import org.apache.geode.internal.ClassPathLoader; -import org.apache.geode.test.dunit.rules.GfshShellConnectionRule; -import org.apache.geode.test.dunit.rules.LocatorServerStartupRule; -import org.apache.geode.test.dunit.rules.MemberVM; -import org.apache.geode.test.junit.categories.DistributedTest; -import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder; - -/** - * Unit tests for the DeployCommands class - * - * @since GemFire 7.0 - */ -@SuppressWarnings("serial") -@Category(DistributedTest.class) -public class DeployCommandsDUnitTest implements Serializable { - private static final String GROUP1 = "Group1"; - private static final String GROUP2 = "Group2"; - - private final String class1 = "DeployCommandsDUnitA"; - private final String class2 = "DeployCommandsDUnitB"; - private final String class3 = "DeployCommandsDUnitC"; - private final String class4 = "DeployCommandsDUnitD"; - - private final String jarName1 = "DeployCommandsDUnit1.jar"; - private final String jarName2 = "DeployCommandsDUnit2.jar"; - private final String jarName3 = "DeployCommandsDUnit3.jar"; - private final String jarName4 = "DeployCommandsDUnit4.jar"; - - private File jar1; - private File jar2; - private File jar3; - private File jar4; - private File subdirWithJars3and4; - - private MemberVM locator; - private MemberVM server1; - private MemberVM server2; - - @Rule - public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder(); - - @Rule - public LocatorServerStartupRule lsRule = new LocatorServerStartupRule(); - - @Rule - public transient GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule(); - - @Before - public void setup() throws Exception { - ClassBuilder classBuilder = new ClassBuilder(); - File jarsDir = temporaryFolder.newFolder(); - jar1 = new File(jarsDir, jarName1); - jar2 = new File(jarsDir, jarName2); - - subdirWithJars3and4 = new File(jarsDir, "subdir"); - subdirWithJars3and4.mkdirs(); - jar3 = new File(subdirWithJars3and4, jarName3); - jar4 = new File(subdirWithJars3and4, jarName4); - - classBuilder.writeJarFromName(class1, jar1); - classBuilder.writeJarFromName(class2, jar2); - classBuilder.writeJarFromName(class3, jar3); - classBuilder.writeJarFromName(class4, jar4); - - locator = lsRule.startLocatorVM(0); - - Properties props = new Properties(); - props.setProperty(GROUPS, GROUP1); - server1 = lsRule.startServerVM(1, props, locator.getPort()); - - props.setProperty(GROUPS, GROUP2); - server2 = lsRule.startServerVM(2, props, locator.getPort()); - - gfshConnector.connectAndVerify(locator); - } - - @Test - public void deployJarToOneGroup() throws Exception { - // Deploy a jar to a single group - gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar2 + " --group=" + GROUP1); - String resultString = gfshConnector.getGfshOutput(); - - assertThat(resultString).contains(server1.getName()); - assertThat(resultString).doesNotContain(server2.getName()); - assertThat(resultString).contains(jarName2); - - server1.invoke(() -> assertThatCanLoad(jarName2, class2)); - server2.invoke(() -> assertThatCannotLoad(jarName2, class2)); - } - - @Test - public void deployJarsInDirToOneGroup() throws Exception { - // Deploy of multiple JARs to a single group - gfshConnector.executeAndVerifyCommand( - "deploy --group=" + GROUP1 + " --dir=" + subdirWithJars3and4.getCanonicalPath()); - String resultString = gfshConnector.getGfshOutput(); - - assertThat(resultString).describedAs(resultString).contains(server1.getName()); - assertThat(resultString).doesNotContain(server2.getName()); - assertThat(resultString).contains(jarName3); - assertThat(resultString).contains(jarName4); - - server1.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - - // Undeploy of multiple jars by specifying group - gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1); - server1.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - } - - @Test - public void deployMultipleJarsToOneGroup() throws Exception { - // Deploy of multiple JARs to a single group - gfshConnector.executeAndVerifyCommand("deploy --group=" + GROUP1 + " --jars=" - + jar3.getAbsolutePath() + "," + jar4.getAbsolutePath()); - String resultString = gfshConnector.getGfshOutput(); - - assertThat(resultString).describedAs(resultString).contains(server1.getName()); - assertThat(resultString).doesNotContain(server2.getName()); - assertThat(resultString).contains(jarName3); - assertThat(resultString).contains(jarName4); - - server1.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - - // Undeploy of multiple jars by specifying group - gfshConnector.executeAndVerifyCommand("undeploy --jars=" + jarName3 + "," + jarName4); - server1.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - } - - - @Test - public void deployJarToAllServers() throws Exception { - // Deploy a jar to all servers - gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar1); - String resultString = gfshConnector.getGfshOutput(); - - assertThat(resultString).contains(server1.getName()); - assertThat(resultString).contains(server2.getName()); - assertThat(resultString).contains(jarName1); - - server1.invoke(() -> assertThatCanLoad(jarName1, class1)); - server2.invoke(() -> assertThatCanLoad(jarName1, class1)); - - // Undeploy of jar by specifying group - gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1); - server1.invoke(() -> assertThatCannotLoad(jarName1, class1)); - server2.invoke(() -> assertThatCanLoad(jarName1, class1)); - } - - @Test - public void deployMultipleJarsToAllServers() throws Exception { - gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath()); - - server1.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - - gfshConnector.executeAndVerifyCommand("undeploy"); - - server1.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - } - - @Test - public void undeployOfMultipleJars() throws Exception { - gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath()); - - server1.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCanLoad(jarName3, class3); - assertThatCanLoad(jarName4, class4); - }); - - gfshConnector - .executeAndVerifyCommand("undeploy --jar=" + jar3.getName() + "," + jar4.getName()); - server1.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - server2.invoke(() -> { - assertThatCannotLoad(jarName3, class3); - assertThatCannotLoad(jarName4, class4); - }); - } - - private void assertThatCanLoad(String jarName, String className) throws ClassNotFoundException { - assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNotNull(); - assertThat(ClassPathLoader.getLatest().forName(className)).isNotNull(); - } - - private void assertThatCannotLoad(String jarName, String className) { - assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNull(); - assertThatThrownBy(() -> ClassPathLoader.getLatest().forName(className)) - .isExactlyInstanceOf(ClassNotFoundException.class); - } - - - @Test - public void testListDeployed() throws Exception { - // Deploy a couple of JAR files which can be listed - gfshConnector - .executeAndVerifyCommand("deploy --group=" + GROUP1 + " --jar=" + jar1.getCanonicalPath()); - gfshConnector - .executeAndVerifyCommand("deploy --group=" + GROUP2 + " --jar=" + jar2.getCanonicalPath()); - - // List for all members - gfshConnector.executeAndVerifyCommand("list deployed"); - String resultString = gfshConnector.getGfshOutput(); - assertThat(resultString).contains(server1.getName()); - assertThat(resultString).contains(server2.getName()); - assertThat(resultString).contains(jarName1); - assertThat(resultString).contains(jarName2); - - // List for members in Group1 - gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP1); - resultString = gfshConnector.getGfshOutput(); - assertThat(resultString).contains(server1.getName()); - assertThat(resultString).doesNotContain(server2.getName()); - - assertThat(resultString).contains(jarName1); - assertThat(resultString).doesNotContain(jarName2); - - // List for members in Group2 - gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP2); - resultString = gfshConnector.getGfshOutput(); - assertThat(resultString).doesNotContain(server1.getName()); - assertThat(resultString).contains(server2.getName()); - - assertThat(resultString).doesNotContain(jarName1); - assertThat(resultString).contains(jarName2); - } -} http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java new file mode 100644 index 0000000..8db7275 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java @@ -0,0 +1,303 @@ +/* + * 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.geode.management.internal.cli.commands; + +import static org.apache.geode.distributed.ConfigurationProperties.GROUPS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.File; +import java.io.Serializable; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.ClassBuilder; +import org.apache.geode.internal.ClassPathLoader; +import org.apache.geode.test.dunit.rules.GfshShellConnectionRule; +import org.apache.geode.test.dunit.rules.LocatorServerStartupRule; +import org.apache.geode.test.dunit.rules.MemberVM; +import org.apache.geode.test.junit.categories.DistributedTest; +import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder; + +/** + * Unit tests for the DeployCommands class + * + * @since GemFire 7.0 + */ +@SuppressWarnings("serial") +@Category(DistributedTest.class) +public class DeployWithGroupsDUnitTest implements Serializable { + private static final String GROUP1 = "Group1"; + private static final String GROUP2 = "Group2"; + + private final String class1 = "DeployCommandsDUnitA"; + private final String class2 = "DeployCommandsDUnitB"; + private final String class3 = "DeployCommandsDUnitC"; + private final String class4 = "DeployCommandsDUnitD"; + + private final String jarName1 = "DeployCommandsDUnit1.jar"; + private final String jarName2 = "DeployCommandsDUnit2.jar"; + private final String jarName3 = "DeployCommandsDUnit3.jar"; + private final String jarName4 = "DeployCommandsDUnit4.jar"; + + private File jar1; + private File jar2; + private File jar3; + private File jar4; + private File subdirWithJars3and4; + + private MemberVM locator; + private MemberVM server1; + private MemberVM server2; + + @Rule + public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder(); + + @Rule + public LocatorServerStartupRule lsRule = new LocatorServerStartupRule(); + + @Rule + public transient GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule(); + + @Before + public void setup() throws Exception { + ClassBuilder classBuilder = new ClassBuilder(); + File jarsDir = temporaryFolder.newFolder(); + jar1 = new File(jarsDir, jarName1); + jar2 = new File(jarsDir, jarName2); + + subdirWithJars3and4 = new File(jarsDir, "subdir"); + subdirWithJars3and4.mkdirs(); + jar3 = new File(subdirWithJars3and4, jarName3); + jar4 = new File(subdirWithJars3and4, jarName4); + + classBuilder.writeJarFromName(class1, jar1); + classBuilder.writeJarFromName(class2, jar2); + classBuilder.writeJarFromName(class3, jar3); + classBuilder.writeJarFromName(class4, jar4); + + locator = lsRule.startLocatorVM(0); + + Properties props = new Properties(); + props.setProperty(GROUPS, GROUP1); + server1 = lsRule.startServerVM(1, props, locator.getPort()); + + props.setProperty(GROUPS, GROUP2); + server2 = lsRule.startServerVM(2, props, locator.getPort()); + + gfshConnector.connectAndVerify(locator); + } + + @Test + public void deployJarToOneGroup() throws Exception { + // Deploy a jar to a single group + gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar2 + " --group=" + GROUP1); + String resultString = gfshConnector.getGfshOutput(); + + assertThat(resultString).contains(server1.getName()); + assertThat(resultString).doesNotContain(server2.getName()); + assertThat(resultString).contains(jarName2); + + server1.invoke(() -> assertThatCanLoad(jarName2, class2)); + server2.invoke(() -> assertThatCannotLoad(jarName2, class2)); + } + + @Test + public void deployJarsInDirToOneGroup() throws Exception { + // Deploy of multiple JARs to a single group + gfshConnector.executeAndVerifyCommand( + "deploy --group=" + GROUP1 + " --dir=" + subdirWithJars3and4.getCanonicalPath()); + String resultString = gfshConnector.getGfshOutput(); + + assertThat(resultString).describedAs(resultString).contains(server1.getName()); + assertThat(resultString).doesNotContain(server2.getName()); + assertThat(resultString).contains(jarName3); + assertThat(resultString).contains(jarName4); + + server1.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + + // Undeploy of multiple jars by specifying group + gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1); + server1.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + } + + @Test + public void deployMultipleJarsToOneGroup() throws Exception { + // Deploy of multiple JARs to a single group + gfshConnector.executeAndVerifyCommand("deploy --group=" + GROUP1 + " --jars=" + + jar3.getAbsolutePath() + "," + jar4.getAbsolutePath()); + String resultString = gfshConnector.getGfshOutput(); + + assertThat(resultString).describedAs(resultString).contains(server1.getName()); + assertThat(resultString).doesNotContain(server2.getName()); + assertThat(resultString).contains(jarName3); + assertThat(resultString).contains(jarName4); + + server1.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + + // Undeploy of multiple jars by specifying group + gfshConnector.executeAndVerifyCommand("undeploy --jars=" + jarName3 + "," + jarName4); + server1.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + } + + + @Test + public void deployJarToAllServers() throws Exception { + // Deploy a jar to all servers + gfshConnector.executeAndVerifyCommand("deploy --jar=" + jar1); + String resultString = gfshConnector.getGfshOutput(); + + assertThat(resultString).contains(server1.getName()); + assertThat(resultString).contains(server2.getName()); + assertThat(resultString).contains(jarName1); + + server1.invoke(() -> assertThatCanLoad(jarName1, class1)); + server2.invoke(() -> assertThatCanLoad(jarName1, class1)); + + // Undeploy of jar by specifying group + gfshConnector.executeAndVerifyCommand("undeploy --group=" + GROUP1); + server1.invoke(() -> assertThatCannotLoad(jarName1, class1)); + server2.invoke(() -> assertThatCanLoad(jarName1, class1)); + } + + @Test + public void deployMultipleJarsToAllServers() throws Exception { + gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath()); + + server1.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + + gfshConnector.executeAndVerifyCommand("undeploy"); + + server1.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + } + + @Test + public void undeployOfMultipleJars() throws Exception { + gfshConnector.executeAndVerifyCommand("deploy --dir=" + subdirWithJars3and4.getCanonicalPath()); + + server1.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCanLoad(jarName3, class3); + assertThatCanLoad(jarName4, class4); + }); + + gfshConnector + .executeAndVerifyCommand("undeploy --jar=" + jar3.getName() + "," + jar4.getName()); + server1.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + server2.invoke(() -> { + assertThatCannotLoad(jarName3, class3); + assertThatCannotLoad(jarName4, class4); + }); + } + + private void assertThatCanLoad(String jarName, String className) throws ClassNotFoundException { + assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNotNull(); + assertThat(ClassPathLoader.getLatest().forName(className)).isNotNull(); + } + + private void assertThatCannotLoad(String jarName, String className) { + assertThat(ClassPathLoader.getLatest().getJarDeployer().findDeployedJar(jarName)).isNull(); + assertThatThrownBy(() -> ClassPathLoader.getLatest().forName(className)) + .isExactlyInstanceOf(ClassNotFoundException.class); + } + + + @Test + public void testListDeployed() throws Exception { + // Deploy a couple of JAR files which can be listed + gfshConnector + .executeAndVerifyCommand("deploy --group=" + GROUP1 + " --jar=" + jar1.getCanonicalPath()); + gfshConnector + .executeAndVerifyCommand("deploy --group=" + GROUP2 + " --jar=" + jar2.getCanonicalPath()); + + // List for all members + gfshConnector.executeAndVerifyCommand("list deployed"); + String resultString = gfshConnector.getGfshOutput(); + assertThat(resultString).contains(server1.getName()); + assertThat(resultString).contains(server2.getName()); + assertThat(resultString).contains(jarName1); + assertThat(resultString).contains(jarName2); + + // List for members in Group1 + gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP1); + resultString = gfshConnector.getGfshOutput(); + assertThat(resultString).contains(server1.getName()); + assertThat(resultString).doesNotContain(server2.getName()); + + assertThat(resultString).contains(jarName1); + assertThat(resultString).doesNotContain(jarName2); + + // List for members in Group2 + gfshConnector.executeAndVerifyCommand("list deployed --group=" + GROUP2); + resultString = gfshConnector.getGfshOutput(); + assertThat(resultString).doesNotContain(server1.getName()); + assertThat(resultString).contains(server2.getName()); + + assertThat(resultString).doesNotContain(jarName1); + assertThat(resultString).contains(jarName2); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c5dd26b7/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java index 7753aaf..e74830c 100644 --- a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java +++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpDUnitTest.java @@ -26,7 +26,7 @@ import org.apache.geode.test.junit.runner.SuiteRunner; @Category({DistributedTest.class, SecurityTest.class}) @RunWith(SuiteRunner.class) [email protected]({ConfigCommandsDUnitTest.class, DeployCommandsDUnitTest.class, [email protected]({ConfigCommandsDUnitTest.class, DeployWithGroupsDUnitTest.class, DiskStoreCommandsDUnitTest.class, FunctionCommandsDUnitTest.class, GemfireDataCommandsDUnitTest.class, GetCommandOnRegionWithCacheLoaderDuringCacheMissDUnitTest.class,
