PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/findbugsCommunalCloud/src/junit/edu/umd/cs/findbugs/cloud/appEngine/MockWebCloudClient.java

http://findbugs.googlecode.com/
Java | 374 lines | 301 code | 61 blank | 12 comment | 24 complexity | 8c9402418807bb5eff88b1fa905d7be7 MD5 | raw file
Possible License(s): Unlicense, GPL-2.0, LGPL-2.0, LGPL-2.1, BSD-3-Clause, Apache-2.0
  1. package edu.umd.cs.findbugs.cloud.appEngine;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.net.HttpURLConnection;
  7. import java.util.ArrayList;
  8. import java.util.Arrays;
  9. import java.util.List;
  10. import java.util.Properties;
  11. import java.util.concurrent.CopyOnWriteArrayList;
  12. import java.util.concurrent.CountDownLatch;
  13. import java.util.concurrent.ExecutorService;
  14. import java.util.concurrent.TimeUnit;
  15. import java.util.regex.Pattern;
  16. import javax.annotation.CheckForNull;
  17. import junit.framework.Assert;
  18. import org.mockito.Matchers;
  19. import org.mockito.Mockito;
  20. import org.mockito.invocation.InvocationOnMock;
  21. import org.mockito.stubbing.Answer;
  22. import com.google.protobuf.GeneratedMessage;
  23. import edu.umd.cs.findbugs.BugCollection;
  24. import edu.umd.cs.findbugs.BugInstance;
  25. import edu.umd.cs.findbugs.IGuiCallback;
  26. import edu.umd.cs.findbugs.SortedBugCollection;
  27. import edu.umd.cs.findbugs.cloud.CloudPlugin;
  28. import edu.umd.cs.findbugs.cloud.username.WebCloudNameLookup;
  29. class MockWebCloudClient extends WebCloudClient {
  30. private List<ExpectedConnection> expectedConnections = new ArrayList<ExpectedConnection>();
  31. private int nextConnection = 0;
  32. private WebCloudNameLookup mockNameLookup;
  33. private Long mockSessionId = null;
  34. public List<String> urlsRequested;
  35. public IGuiCallback mockGuiCallback;
  36. public List<String> statusMsgHistory = new CopyOnWriteArrayList<String>();
  37. private final Object statusMsgLock = new Object();
  38. public MockWebCloudClient(CloudPlugin plugin, SortedBugCollection bugs, List<HttpURLConnection> mockConnections)
  39. throws IOException {
  40. super(plugin, bugs, new Properties());
  41. setNetworkClient(new MockWebCloudNetworkClient());
  42. urlsRequested = new ArrayList<String>();
  43. for (HttpURLConnection mockConnection : mockConnections) {
  44. expectedConnections.add(new ExpectedConnection().withLegacyMock(mockConnection));
  45. }
  46. mockNameLookup = createMockNameLookup();
  47. mockGuiCallback = Mockito.mock(IGuiCallback.class);
  48. Mockito.doAnswer(new Answer<Void>() {
  49. public Void answer(InvocationOnMock invocation) {
  50. Object[] args = invocation.getArguments();
  51. Runnable r = (Runnable) args[0];
  52. r.run();
  53. return null;
  54. }
  55. }).when(mockGuiCallback).invokeInGUIThread(Matchers.isA(Runnable.class));
  56. initStatusBarHistory();
  57. initialized = true;
  58. }
  59. @Override
  60. public String getCloudName() {
  61. return "FindBugs Cloud";
  62. }
  63. @Override
  64. protected ExecutorService getBugUpdateExecutor() {
  65. return backgroundExecutorService;
  66. }
  67. @Override
  68. public IGuiCallback getGuiCallback() {
  69. return mockGuiCallback;
  70. }
  71. @SuppressWarnings({ "ThrowableInstanceNeverThrown" })
  72. public WebCloudNetworkClient createSpyNetworkClient() throws IOException {
  73. WebCloudNetworkClient spyNetworkClient = Mockito.spy(getNetworkClient());
  74. Mockito.doThrow(new IOException()).when(spyNetworkClient).signIn(true);
  75. setNetworkClient(spyNetworkClient);
  76. return spyNetworkClient;
  77. }
  78. @Override
  79. public void setSigninState(SigninState state) {
  80. super.setSigninState(state);
  81. }
  82. public ExpectedConnection expectConnection(String url) {
  83. ExpectedConnection connection = new ExpectedConnection();
  84. expectedConnections.add(connection.withUrl(url));
  85. return connection;
  86. }
  87. /**
  88. * Returns POST data submitted for the given URL. If the URL was expected &
  89. * requested more than once, this will return only the data from the LATEST
  90. * one.
  91. */
  92. public byte[] postedData(String url) {
  93. return getLatestExpectedConnection(url).getPostData();
  94. }
  95. public void verifyConnections() {
  96. if (expectedConnections.size() != nextConnection) {
  97. Assert.fail("some connections were not opened\n" + "opened: " + expectedConnections.subList(0, nextConnection) + "\n"
  98. + "missed: " + expectedConnections.subList(nextConnection, expectedConnections.size()));
  99. }
  100. }
  101. public void waitUntilIssuesUploaded(long timeout, TimeUnit unit) throws InterruptedException {
  102. if (!newIssuesUploaded.await(timeout, unit)) {
  103. Assert.fail("issues uploaded event never fired after " + timeout + " " + unit.toString());
  104. }
  105. }
  106. /**
  107. * Returns a {@link CountDownLatch} that waits for a IGuiCallback
  108. * showMessageDialog call with a message matching the given regex.
  109. */
  110. public CountDownLatch getDialogLatch(final String dialogRegex) {
  111. final CountDownLatch latch = new CountDownLatch(1);
  112. Mockito.doAnswer(new Answer<Void>() {
  113. public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
  114. String message = (String) invocationOnMock.getArguments()[0];
  115. boolean match = Pattern.compile(dialogRegex).matcher(message).find();
  116. System.out.println("QQQ match: " + " " + match + "\nexpecting \"" + dialogRegex + "\"\nsaw \"" + message + "\"");
  117. if (match)
  118. latch.countDown();
  119. return null;
  120. }
  121. }).when(mockGuiCallback).showMessageDialog(Matchers.anyString());
  122. return latch;
  123. }
  124. public void clickYes(String regex) {
  125. Mockito.when(mockGuiCallback.showConfirmDialog(Matchers.matches(regex), Matchers.anyString(), Matchers.anyString(), Matchers.anyString())).thenReturn(
  126. IGuiCallback.YES_OPTION);
  127. }
  128. // ========================== end of public methods
  129. // =========================
  130. private void initStatusBarHistory() {
  131. addListener(new CloudListener() {
  132. public void issueUpdated(BugInstance bug) {
  133. }
  134. public void statusUpdated() {
  135. String statusMsg = getStatusMsg();
  136. if (!statusMsgHistory.isEmpty()) {
  137. String last = statusMsgHistory.get(statusMsgHistory.size() - 1);
  138. if (statusMsg.equals(last))
  139. return;
  140. }
  141. statusMsgHistory.add(statusMsg);
  142. synchronized (statusMsgLock) {
  143. statusMsgLock.notifyAll();
  144. }
  145. }
  146. public void taskStarted(CloudTask task) {
  147. }
  148. });
  149. }
  150. private WebCloudNameLookup createMockNameLookup() throws IOException {
  151. WebCloudNameLookup mockNameLookup = Mockito.mock(WebCloudNameLookup.class);
  152. Mockito.when(mockNameLookup.getHost()).thenReturn("host");
  153. Mockito.when(mockNameLookup.getUsername()).thenReturn("test@example.com");
  154. Mockito.when(mockNameLookup.getSessionId()).thenAnswer(new Answer<Long>() {
  155. public Long answer(InvocationOnMock invocationOnMock) throws Throwable {
  156. return mockSessionId;
  157. }
  158. });
  159. Mockito.when(mockNameLookup.signIn(Matchers.<CloudPlugin> any(), Matchers.<BugCollection> any())).thenAnswer(new Answer<Boolean>() {
  160. public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
  161. mockSessionId = 555L;
  162. return true;
  163. }
  164. });
  165. return mockNameLookup;
  166. }
  167. private ExpectedConnection getLatestExpectedConnection(String url) {
  168. for (int i = expectedConnections.size() - 1; i >= 0; i--) {
  169. ExpectedConnection expectedConnection = expectedConnections.get(i);
  170. if (url.equals(expectedConnection.url()))
  171. return expectedConnection;
  172. }
  173. return null;
  174. }
  175. public void checkStatusBarHistory(String... expectedStatusLines) {
  176. Assert.assertEquals(Arrays.asList(expectedStatusLines), statusMsgHistory);
  177. }
  178. public void waitForStatusMsg(String regex) throws InterruptedException {
  179. Pattern pattern = Pattern.compile(regex);
  180. long start = System.currentTimeMillis();
  181. while (System.currentTimeMillis() - start < 15 * 1000) {
  182. synchronized (statusMsgLock) {
  183. statusMsgLock.wait(1000);
  184. for (String status : statusMsgHistory) {
  185. if (pattern.matcher(status).matches())
  186. return;
  187. }
  188. }
  189. }
  190. if (statusMsgHistory.isEmpty())
  191. Assert.fail("Expected " + regex + ", didn't see any status messages");
  192. Assert.fail("Did not see status message " + regex + " in:\n" + statusMsgHistory);
  193. }
  194. private class MockWebCloudNetworkClient extends WebCloudNetworkClient {
  195. @Override
  196. HttpURLConnection openConnection(String url) {
  197. System.out.println("request " + url);
  198. ExpectedConnection connection = null;
  199. if (nextConnection >= expectedConnections.size()) {
  200. ExpectedConnection lastConnection = expectedConnections.get(expectedConnections.size() - 1);
  201. if (lastConnection.isRepeatIndefinitely())
  202. connection = lastConnection;
  203. else
  204. Assert.fail("Cannot open " + url + " - already requested all " + expectedConnections.size() + " url's: "
  205. + expectedConnections);
  206. }
  207. urlsRequested.add(url);
  208. if (connection == null)
  209. connection = expectedConnections.get(nextConnection);
  210. nextConnection++;
  211. String expectedUrl = connection.url();
  212. if (expectedUrl != null) {
  213. expectedUrl = "/" + expectedUrl;
  214. if (!expectedUrl.equals(url)) {
  215. Assert.fail("Expected '" + expectedUrl + "' but '" + url + "' was requested");
  216. }
  217. }
  218. System.err.println("opening " + url + " at " + Thread.currentThread().getStackTrace()[2]);
  219. return connection.mockConnection;
  220. }
  221. @Override
  222. protected WebCloudNameLookup createNameLookup() {
  223. return mockNameLookup;
  224. }
  225. }
  226. public class ExpectedConnection {
  227. private HttpURLConnection mockConnection;
  228. private String url = null;
  229. private int responseCode = 200;
  230. private InputStream responseStream;
  231. private IOException networkError = null;
  232. private ByteArrayOutputStream postDataStream;
  233. private CountDownLatch latch = new CountDownLatch(1);
  234. private boolean repeatIndefinitely = false;
  235. public ExpectedConnection() {
  236. mockConnection = Mockito.mock(HttpURLConnection.class);
  237. postDataStream = new ByteArrayOutputStream();
  238. try {
  239. Mockito.when(mockConnection.getOutputStream()).thenAnswer(new Answer<Object>() {
  240. public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
  241. latch.countDown();
  242. if (networkError != null)
  243. throw networkError;
  244. return postDataStream;
  245. }
  246. });
  247. Mockito.when(mockConnection.getInputStream()).thenAnswer(new Answer<InputStream>() {
  248. public InputStream answer(InvocationOnMock invocationOnMock) throws Throwable {
  249. latch.countDown();
  250. return responseStream;
  251. }
  252. });
  253. Mockito.when(mockConnection.getResponseCode()).thenAnswer(new Answer<Integer>() {
  254. public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
  255. latch.countDown();
  256. return responseCode;
  257. }
  258. });
  259. } catch (IOException e) {
  260. }
  261. }
  262. public ExpectedConnection withLegacyMock(HttpURLConnection mockConnection) {
  263. this.mockConnection = mockConnection;
  264. return this;
  265. }
  266. public @CheckForNull
  267. String url() {
  268. return url;
  269. }
  270. public ExpectedConnection withUrl(String url) {
  271. this.url = url;
  272. return this;
  273. }
  274. public ExpectedConnection withResponse(GeneratedMessage response) {
  275. if (responseStream != null)
  276. throw new IllegalStateException("Already have response stream");
  277. responseStream = new ByteArrayInputStream(response.toByteArray());
  278. return this;
  279. }
  280. public byte[] getPostData() {
  281. return getOutputStream().toByteArray();
  282. }
  283. public ExpectedConnection withErrorCode(int code) {
  284. this.responseCode = code;
  285. return this;
  286. }
  287. public void throwsNetworkError(IOException e) {
  288. networkError = e;
  289. }
  290. public CountDownLatch getLatch() {
  291. return latch;
  292. }
  293. public void repeatIndefinitely() {
  294. this.repeatIndefinitely = true;
  295. }
  296. public boolean isRepeatIndefinitely() {
  297. return repeatIndefinitely;
  298. }
  299. @Override
  300. public String toString() {
  301. ByteArrayOutputStream postStream = getOutputStream();
  302. return "/" + url() + (postStream.size() > 0 ? " <" + postStream.size() + ">" : "");
  303. }
  304. // ====================== end of public methods =======================
  305. private ByteArrayOutputStream getOutputStream() {
  306. try {
  307. return (ByteArrayOutputStream) mockConnection.getOutputStream();
  308. } catch (IOException e) {
  309. throw new IllegalStateException(e);
  310. }
  311. }
  312. }
  313. }