PageRenderTime 852ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/core/src/test/java/org/jclouds/concurrent/config/ExecutorServiceModuleTest.java

https://github.com/andreisavu/jclouds
Java | 259 lines | 143 code | 43 blank | 73 comment | 2 complexity | 1466ee77ccec762e2ac63395916c193e MD5 | raw file
  1. /**
  2. * Licensed to jclouds, Inc. (jclouds) under one or more
  3. * contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. jclouds licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.jclouds.concurrent.config;
  20. import static org.easymock.EasyMock.createMock;
  21. import static org.easymock.EasyMock.expect;
  22. import static org.easymock.EasyMock.replay;
  23. import static org.easymock.EasyMock.verify;
  24. import static org.testng.Assert.assertEquals;
  25. import static org.testng.Assert.fail;
  26. import java.io.IOException;
  27. import java.util.concurrent.Callable;
  28. import java.util.concurrent.ExecutionException;
  29. import java.util.concurrent.ExecutorService;
  30. import java.util.concurrent.Future;
  31. import org.jclouds.Constants;
  32. import org.jclouds.lifecycle.Closer;
  33. import org.testng.annotations.Test;
  34. import com.google.common.base.Throwables;
  35. import com.google.common.collect.ImmutableList;
  36. import com.google.inject.Guice;
  37. import com.google.inject.Injector;
  38. import com.google.inject.Key;
  39. import com.google.inject.name.Names;
  40. /**
  41. *
  42. * @author Adrian Cole
  43. */
  44. @Test
  45. public class ExecutorServiceModuleTest {
  46. @Test
  47. public void testShutdownOnClose() throws IOException {
  48. Injector i = Guice.createInjector();
  49. Closer closer = i.getInstance(Closer.class);
  50. ExecutorService executor = createMock(ExecutorService.class);
  51. ExecutorServiceModule.shutdownOnClose(executor, closer);
  52. expect(executor.shutdownNow()).andReturn(ImmutableList.<Runnable> of()).atLeastOnce();
  53. replay(executor);
  54. closer.close();
  55. verify(executor);
  56. }
  57. @Test
  58. public void testShutdownOnCloseThroughModule() throws IOException {
  59. ExecutorServiceModule module = new ExecutorServiceModule() {
  60. @Override
  61. protected void configure() {
  62. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
  63. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
  64. super.configure();
  65. }
  66. };
  67. Injector i = Guice.createInjector(module);
  68. assertEquals(module.userExecutorFromConstructor, null);
  69. assertEquals(module.ioExecutorFromConstructor, null);
  70. Closer closer = i.getInstance(Closer.class);
  71. ExecutorService user = i
  72. .getInstance(Key.get(ExecutorService.class, Names.named(Constants.PROPERTY_USER_THREADS)));
  73. ExecutorService io = i.getInstance(Key.get(ExecutorService.class, Names
  74. .named(Constants.PROPERTY_IO_WORKER_THREADS)));
  75. assert !user.isShutdown();
  76. assert !io.isShutdown();
  77. closer.close();
  78. assert user.isShutdown();
  79. assert io.isShutdown();
  80. }
  81. @Test
  82. public void testDescribedFutureToString() throws Exception {
  83. ExecutorServiceModule module = new ExecutorServiceModule() {
  84. @Override
  85. protected void configure() {
  86. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
  87. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
  88. super.configure();
  89. }
  90. };
  91. Injector i = Guice.createInjector(module);
  92. Closer closer = i.getInstance(Closer.class);
  93. ExecutorService user = i
  94. .getInstance(Key.get(ExecutorService.class, Names.named(Constants.PROPERTY_USER_THREADS)));
  95. ExecutorService io = i.getInstance(Key.get(ExecutorService.class, Names
  96. .named(Constants.PROPERTY_IO_WORKER_THREADS)));
  97. ConfigurableRunner t1 = new ConfigurableRunner();
  98. t1.result = "okay";
  99. Future<Object> euc = performSubmissionInSeparateMethod1(user, t1);
  100. assert euc.toString().indexOf("ConfigurableRunner") >= 0;
  101. assert euc.get().equals("okay");
  102. Future<Object> eic = performSubmissionInSeparateMethod1(io, t1);
  103. assert eic.toString().indexOf("ConfigurableRunner") >= 0;
  104. assert eic.get().equals("okay");
  105. closer.close();
  106. }
  107. /*
  108. * The decoration makes sure that the stack trace looks like the following.
  109. * Note the last three included trace elements: this details where the task was submitted _from_
  110. * (technically it is a different stack frame, since it is across threads; but logically it is the same)
  111. *
  112. java.util.concurrent.ExecutionException: java.lang.IllegalStateException: foo
  113. at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
  114. at java.util.concurrent.FutureTask.get(FutureTask.java:83)
  115. at org.jclouds.concurrent.config.ExecutorServiceModule$DescribedFuture.get(ExecutorServiceModule.java:232)
  116. at org.jclouds.concurrent.config.ExecutorServiceModuleTest.checkFutureGetFailsWith(ExecutorServiceModuleTest.java:186)
  117. at org.jclouds.concurrent.config.ExecutorServiceModuleTest.testDescribedFutureExceptionIncludesSubmissionTrace(ExecutorServiceModuleTest.java:171)
  118. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  119. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  120. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  121. at java.lang.reflect.Method.invoke(Method.java:597)
  122. at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
  123. at org.testng.internal.Invoker.invokeMethod(Invoker.java:691)
  124. at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:883)
  125. at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1208)
  126. at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
  127. at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
  128. at org.testng.TestRunner.privateRun(TestRunner.java:753)
  129. at org.testng.TestRunner.run(TestRunner.java:613)
  130. at org.testng.SuiteRunner.runTest(SuiteRunner.java:335)
  131. at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:330)
  132. at org.testng.SuiteRunner.privateRun(SuiteRunner.java:292)
  133. at org.testng.SuiteRunner.run(SuiteRunner.java:241)
  134. at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
  135. at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
  136. at org.testng.TestNG.runSuitesSequentially(TestNG.java:1169)
  137. at org.testng.TestNG.runSuitesLocally(TestNG.java:1094)
  138. at org.testng.TestNG.run(TestNG.java:1006)
  139. at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:107)
  140. at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:199)
  141. at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:170)
  142. Caused by: java.lang.IllegalStateException: foo
  143. at org.jclouds.concurrent.config.ExecutorServiceModuleTest$ConfigurableRunner.call(ExecutorServiceModuleTest.java:206)
  144. at org.jclouds.concurrent.config.ExecutorServiceModuleTest$ConfigurableRunner.run(ExecutorServiceModuleTest.java:203)
  145. at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
  146. at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
  147. at java.util.concurrent.FutureTask.run(FutureTask.java:138)
  148. at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
  149. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
  150. at java.lang.Thread.run(Thread.java:637)
  151. at org.jclouds.concurrent.config.ExecutorServiceModule$DescribingExecutorService.submit(ExecutorServiceModule.java:188)
  152. at org.jclouds.concurrent.config.ExecutorServiceModuleTest.performSubmissionInSeparateMethod2(ExecutorServiceModuleTest.java:181)
  153. at org.jclouds.concurrent.config.ExecutorServiceModuleTest.testDescribedFutureExceptionIncludesSubmissionTrace(ExecutorServiceModuleTest.java:170)
  154. ... 24 more
  155. *
  156. */
  157. @Test
  158. public void testDescribedFutureExceptionIncludesSubmissionTrace() throws Exception {
  159. ExecutorServiceModule module = new ExecutorServiceModule() {
  160. @Override
  161. protected void configure() {
  162. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
  163. bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
  164. super.configure();
  165. }
  166. };
  167. Injector i = Guice.createInjector(module);
  168. Closer closer = i.getInstance(Closer.class);
  169. ExecutorService user = i
  170. .getInstance(Key.get(ExecutorService.class, Names.named(Constants.PROPERTY_USER_THREADS)));
  171. ExecutorService io = i.getInstance(Key.get(ExecutorService.class, Names
  172. .named(Constants.PROPERTY_IO_WORKER_THREADS)));
  173. ConfigurableRunner t1 = new ConfigurableRunner();
  174. t1.failMessage = "foo";
  175. t1.result = "shouldn't happen";
  176. Future<Object> euc = performSubmissionInSeparateMethod1(user, t1);
  177. checkFutureGetFailsWith(euc, "foo", "testDescribedFutureExceptionIncludesSubmissionTrace", "performSubmissionInSeparateMethod1");
  178. Future<Object> eur = performSubmissionInSeparateMethod2(user, t1);
  179. checkFutureGetFailsWith(eur, "foo", "testDescribedFutureExceptionIncludesSubmissionTrace", "performSubmissionInSeparateMethod2");
  180. Future<Object> eic = performSubmissionInSeparateMethod1(io, t1);
  181. checkFutureGetFailsWith(eic, "foo", "testDescribedFutureExceptionIncludesSubmissionTrace", "performSubmissionInSeparateMethod1");
  182. Future<Object> eir = performSubmissionInSeparateMethod2(io, t1);
  183. checkFutureGetFailsWith(eir, "foo", "testDescribedFutureExceptionIncludesSubmissionTrace", "performSubmissionInSeparateMethod2");
  184. closer.close();
  185. }
  186. static Future<Object> performSubmissionInSeparateMethod1(ExecutorService user, ConfigurableRunner t1) {
  187. return user.submit((Callable<Object>)t1);
  188. }
  189. static Future<Object> performSubmissionInSeparateMethod2(ExecutorService io, ConfigurableRunner t1) {
  190. return io.submit((Runnable)t1, (Object)"shouldn't happen");
  191. }
  192. static void checkFutureGetFailsWith(Future<?> task, String ...requiredPhrases) throws Exception {
  193. try {
  194. task.get();
  195. fail("task should have failed");
  196. } catch (ExecutionException e) {
  197. String trace = Throwables.getStackTraceAsString(e);
  198. for (String requiredPhrase : requiredPhrases) {
  199. assert trace.indexOf(requiredPhrase) >= 0 : "stack trace should have contained '"+requiredPhrase+"'";
  200. }
  201. }
  202. }
  203. static class ConfigurableRunner implements Runnable, Callable<Object> {
  204. Object result;
  205. String failMessage;
  206. @Override
  207. public void run() {
  208. call();
  209. }
  210. public Object call() {
  211. if (failMessage!=null) throw new IllegalStateException(failMessage);
  212. return result;
  213. }
  214. }
  215. }