PageRenderTime 79ms CodeModel.GetById 49ms RepoModel.GetById 1ms app.codeStats 0ms

/org.eclipse.paho.client.mqttv3.test/src/test/java/org/eclipse/paho/client/mqttv3/test/LiveTakeOverTest.java

https://gitlab.com/jforge/paho.mqtt.java
Java | 292 lines | 215 code | 37 blank | 40 comment | 15 complexity | a0baedccb74ac1e3bc570540f9ca79fa MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2014 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. *******************************************************************************/
  14. package org.eclipse.paho.client.mqttv3.test;
  15. import java.net.URI;
  16. import java.util.logging.Level;
  17. import java.util.logging.Logger;
  18. import org.eclipse.paho.client.mqttv3.IMqttClient;
  19. import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
  20. import org.eclipse.paho.client.mqttv3.MqttException;
  21. import org.eclipse.paho.client.mqttv3.MqttTopic;
  22. import org.eclipse.paho.client.mqttv3.test.client.MqttClientFactoryPaho;
  23. import org.eclipse.paho.client.mqttv3.test.logging.LoggingUtilities;
  24. import org.eclipse.paho.client.mqttv3.test.properties.TestProperties;
  25. import org.eclipse.paho.client.mqttv3.test.utilities.MqttV3Receiver;
  26. import org.eclipse.paho.client.mqttv3.test.utilities.MqttV3Receiver.ReceivedMessage;
  27. import org.eclipse.paho.client.mqttv3.test.utilities.Utility;
  28. import org.junit.AfterClass;
  29. import org.junit.Assert;
  30. import org.junit.BeforeClass;
  31. import org.junit.Test;
  32. public class LiveTakeOverTest {
  33. private static final Class<?> cclass = LiveTakeOverTest.class;
  34. private static final String className = cclass.getName();
  35. private static final Logger log = Logger.getLogger(className);
  36. private static URI serverURI;
  37. private static MqttClientFactoryPaho clientFactory;
  38. static enum FirstClientState {
  39. INITIAL,
  40. READY,
  41. RUNNING,
  42. FINISHED,
  43. ERROR
  44. }
  45. private static String ClientId = "TakeOverClient";
  46. private static String FirstSubTopicString = "FirstClient/Topic";
  47. /**
  48. * @throws Exception
  49. */
  50. @BeforeClass
  51. public static void setUpBeforeClass() throws Exception {
  52. try {
  53. String methodName = Utility.getMethodName();
  54. LoggingUtilities.banner(log, cclass, methodName);
  55. serverURI = TestProperties.getServerURI();
  56. clientFactory = new MqttClientFactoryPaho();
  57. clientFactory.open();
  58. }
  59. catch (Exception exception) {
  60. log.log(Level.SEVERE, "caught exception:", exception);
  61. throw exception;
  62. }
  63. }
  64. /**
  65. * @throws Exception
  66. */
  67. @AfterClass
  68. public static void tearDownAfterClass() throws Exception {
  69. String methodName = Utility.getMethodName();
  70. LoggingUtilities.banner(log, cclass, methodName);
  71. try {
  72. if (clientFactory != null) {
  73. clientFactory.close();
  74. clientFactory.disconnect();
  75. }
  76. }
  77. catch (Exception exception) {
  78. log.log(Level.SEVERE, "caught exception:", exception);
  79. }
  80. }
  81. /**
  82. * Test that a client actively doing work can be taken over
  83. * @throws Exception
  84. */
  85. @Test
  86. public void testLiveTakeOver() throws Exception {
  87. String methodName = Utility.getMethodName();
  88. LoggingUtilities.banner(log, cclass, methodName);
  89. log.entering(className, methodName);
  90. IMqttClient mqttClient = null;
  91. try {
  92. FirstClient firstClient = new FirstClient();
  93. Thread firstClientThread = new Thread(firstClient);
  94. log.info("Starting the firstClient thread");
  95. firstClientThread.start();
  96. log.info("firstClientThread Started");
  97. firstClient.waitForState(FirstClientState.READY);
  98. log.fine("telling the 1st client to go and let it publish for 2 seconds");
  99. //Tell the first client to go and let it publish for a couple of seconds
  100. firstClient.setState(FirstClientState.RUNNING);
  101. Thread.sleep(2000);
  102. log.fine("Client has been run for 2 seconds, now taking over connection");
  103. //Now lets take over the connection
  104. // Create a second MQTT client connection with the same clientid. The
  105. // server should spot this and kick the first client connection off.
  106. // To do this from the same box the 2nd client needs to use either
  107. // a different form of persistent store or a different locaiton for
  108. // the store to the first client.
  109. // MqttClientPersistence persist = new MemoryPersistence();
  110. mqttClient = clientFactory.createMqttClient(serverURI, ClientId, null);
  111. MqttV3Receiver mqttV3Receiver = new MqttV3Receiver(mqttClient, LoggingUtilities.getPrintStream());
  112. mqttClient.setCallback(mqttV3Receiver);
  113. MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
  114. mqttConnectOptions.setCleanSession(false);
  115. mqttConnectOptions.setWill("WillTopic", "payload".getBytes(), 2, true);
  116. log.info("Connecting...(serverURI:" + serverURI + ", ClientId:" + ClientId);
  117. mqttClient.connect(mqttConnectOptions);
  118. //We should have taken over the first Client's subscription...we may have some
  119. //of his publishes arrive.
  120. // NOTE: as a different persistence is used for the second client any inflight
  121. // publications from the client will not be recovered / restarted. This will
  122. // leave debris on the server.
  123. log.fine("We should have taken over the first Client's subscription...we may have some of his publishes arrive.");
  124. //Ignore his publishes that arrive...
  125. ReceivedMessage oldMsg;
  126. do {
  127. oldMsg = mqttV3Receiver.receiveNext(1000);
  128. }
  129. while (oldMsg != null);
  130. log.fine("Now check we have grabbed his subscription by publishing..");
  131. //Now check we have grabbed his subscription by publishing..
  132. byte[] payload = ("Message payload from second client " + getClass().getName() + "." + methodName).getBytes();
  133. MqttTopic mqttTopic = mqttClient.getTopic(FirstSubTopicString);
  134. log.info("Publishing to..." + FirstSubTopicString);
  135. mqttTopic.publish(payload, 1, false);
  136. log.info("Publish sent, checking for receipt...");
  137. boolean ok = mqttV3Receiver.validateReceipt(FirstSubTopicString, 1, payload);
  138. if (!ok) {
  139. throw new Exception("Receive failed");
  140. }
  141. }
  142. catch (Exception exception) {
  143. log.throwing(className, methodName, exception);
  144. throw exception;
  145. }
  146. finally {
  147. try {
  148. if (mqttClient != null) {
  149. mqttClient.disconnect();
  150. log.info("Disconnecting...");
  151. mqttClient.close();
  152. log.info("Close...");
  153. }
  154. }
  155. catch (Exception exception) {
  156. log.throwing(className, methodName, exception);
  157. throw exception;
  158. }
  159. }
  160. log.exiting(className, methodName);
  161. }
  162. class FirstClient implements Runnable {
  163. private FirstClientState state = FirstClientState.INITIAL;
  164. public Object stateLock = new Object();
  165. IMqttClient mqttClient = null;
  166. MqttV3Receiver mqttV3Receiver = null;
  167. void waitForState(FirstClientState desiredState) throws InterruptedException {
  168. final String methodName = "waitForState";
  169. synchronized (stateLock) {
  170. while ((state != desiredState) && (state != FirstClientState.ERROR)) {
  171. try {
  172. stateLock.wait();
  173. }
  174. catch (InterruptedException exception) {
  175. log.throwing(className, methodName, exception);
  176. throw exception;
  177. }
  178. }
  179. if (state == FirstClientState.ERROR) {
  180. Assert.fail("Firstclient entered an ERROR state");
  181. }
  182. }
  183. log.exiting(className, methodName);
  184. }
  185. void setState(FirstClientState newState) {
  186. synchronized (stateLock) {
  187. state = newState;
  188. stateLock.notifyAll();
  189. }
  190. }
  191. void connectAndSub() {
  192. String methodName = Utility.getMethodName();
  193. try {
  194. mqttClient = clientFactory.createMqttClient(serverURI, ClientId);
  195. mqttV3Receiver = new MqttV3Receiver(mqttClient, LoggingUtilities.getPrintStream());
  196. mqttV3Receiver.setReportConnectionLoss(false);
  197. mqttClient.setCallback(mqttV3Receiver);
  198. MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
  199. mqttConnectOptions.setCleanSession(false);
  200. mqttConnectOptions.setWill("WillTopic", "payload".getBytes(), 2, true);
  201. log.info("Connecting...(serverURI:" + serverURI + ", ClientId:" + ClientId);
  202. mqttClient.connect(mqttConnectOptions);
  203. log.info("Subscribing to..." + FirstSubTopicString);
  204. mqttClient.subscribe(FirstSubTopicString, 2);
  205. }
  206. catch (Exception exception) {
  207. log.log(Level.SEVERE, "caugh exception:" + exception);
  208. setState(FirstClientState.ERROR);
  209. Assert.fail("Failed ConnectAndSub exception=" + exception);
  210. }
  211. }
  212. void repeatedlyPub() {
  213. String methodName = Utility.getMethodName();
  214. int i = 0;
  215. while (mqttClient.isConnected()) {
  216. try {
  217. if (i > 999999) {
  218. i = 0;
  219. }
  220. byte[] payload = ("Message payload " + getClass().getName() + ".publish" + (i++)).getBytes();
  221. MqttTopic mqttTopic = mqttClient.getTopic(FirstSubTopicString);
  222. log.info("Publishing to..." + FirstSubTopicString);
  223. mqttTopic.publish(payload, 1, false);
  224. }
  225. catch (Exception exception) {
  226. log.fine("Caught exception:" + exception);
  227. // Don't fail - we are going to get an exception as we disconnected during takeOver
  228. // Its likely the publish rate is too high i.e. inflight window is full
  229. }
  230. }
  231. }
  232. public void run() {
  233. String methodName = Utility.getMethodName();
  234. LoggingUtilities.banner(log, cclass, methodName);
  235. log.entering(className, methodName);
  236. connectAndSub();
  237. try {
  238. setState(FirstClientState.READY);
  239. waitForState(FirstClientState.RUNNING);
  240. repeatedlyPub();
  241. log.info("FirstClient exiting...");
  242. log.exiting(className, methodName);
  243. mqttClient.close();
  244. }
  245. catch (InterruptedException exception) {
  246. setState(FirstClientState.ERROR);
  247. log.log(Level.SEVERE, "caught exception:", exception);
  248. }
  249. catch (MqttException exception) {
  250. setState(FirstClientState.ERROR);
  251. log.log(Level.SEVERE, "caught exception:", exception);
  252. }
  253. }
  254. }
  255. }