1 /*------------------------------------------------------------------------------
2 Name: TestCallback.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Login/logout test for xmlBlaster
6 Version: $Id: TestCallback.java 17762 2009-09-09 20:20:13Z laghi $
7 ------------------------------------------------------------------------------*/
8 package org.xmlBlaster.test.qos;
9
10 import java.util.logging.Logger;
11
12 import junit.framework.Test;
13 import junit.framework.TestCase;
14 import junit.framework.TestSuite;
15
16 import org.xmlBlaster.client.I_Callback;
17 import org.xmlBlaster.client.I_XmlBlasterAccess;
18 import org.xmlBlaster.client.key.UpdateKey;
19 import org.xmlBlaster.client.qos.ConnectQos;
20 import org.xmlBlaster.client.qos.EraseReturnQos;
21 import org.xmlBlaster.client.qos.UpdateQos;
22 import org.xmlBlaster.test.Util;
23 import org.xmlBlaster.test.util.Client;
24 import org.xmlBlaster.util.Global;
25 import org.xmlBlaster.util.MsgUnit;
26 import org.xmlBlaster.util.XmlBlasterException;
27
28
29 /**
30 * This client test dead letter generation on callback problems.
31 * <p />
32 * Works only if callback server is a separate instance (Corba is OK, but not SOCKET).
33 * <p />
34 * This client may be invoked multiple time on the same xmlBlaster server,
35 * as it cleans up everything after his tests are done.
36 */
37 public class TestCallback extends TestCase implements I_Callback
38 {
39 private static String ME = "TestCallback";
40 private final Global glob;
41 private static Logger log = Logger.getLogger(TestCallback.class.getName());
42 private String name;
43 private String passwd = "secret";
44 private int numReceived = 0; // error checking
45
46 private boolean isDeadMessage = false;
47 private String subscribeDeadMessageOid = null;
48 private I_XmlBlasterAccess conAdmin = null;
49 private String publishOid = null;
50
51 private boolean isSocket = false;
52
53 /**
54 * Constructs the TestCallback object.
55 * <p />
56 * @param testName The name used in the test suite
57 * @param name The name to login to the xmlBlaster
58 */
59 public TestCallback(Global glob, String testName, String name)
60 {
61 super(testName);
62 this.glob = glob;
63
64 this.name = name;
65 }
66
67 /**
68 * Sets up the fixture.
69 * <p />
70 * Connect to xmlBlaster and login as admin, subscribe to dead letters
71 */
72 protected void setUp()
73 {
74 /*
75 String driverType = glob.getProperty().get("client.protocol", "dummy");
76 if (driverType.equalsIgnoreCase("SOCKET"))
77 isSocket = true;
78 else {
79 driverType = glob.getProperty().get("protocol", "dummy");
80 if (driverType.equalsIgnoreCase("SOCKET"))
81 isSocket = true;
82 }
83
84 if (isSocket) {
85 log.warning("callback test ignored for driverType=" + driverType + " as callback server uses same socket as invoke channel");
86 return;
87 }
88 */
89
90 try {
91 Global globAdmin = this.glob.getClone(null);
92 conAdmin = globAdmin.getXmlBlasterAccess();
93 ConnectQos qos = new ConnectQos(globAdmin, "admin", passwd);
94 conAdmin.connect(qos, this);
95 isSocket = !Client.shutdownCb(conAdmin, Client.Shutdown.KEEP_LOGGED_IN);
96 if (isSocket)
97 return;
98
99 subscribeDeadMessageOid = conAdmin.subscribe("<key oid='__sys__deadMessage'/>", null).getSubscriptionId();
100 log.info("Success: Subscribe on " + subscribeDeadMessageOid + " done");
101 }
102 catch (Exception e) {
103 log.severe(e.toString());
104 assertTrue(e.toString(), false);
105 }
106 }
107
108 /**
109 * Tears down the fixture.
110 * <p />
111 * cleaning up .... erase() the previous message OID and logout
112 */
113 protected void tearDown()
114 {
115 if (isSocket) return;
116 try {
117 if (conAdmin != null) {
118 EraseReturnQos[] strArr = conAdmin.erase("<key oid='" + publishOid + "'/>", null);
119 if (strArr.length != 1) log.severe("ERROR: Erased " + strArr.length + " messages");
120 conAdmin.disconnect(null);
121 }
122 }
123 catch (Exception e) {
124 log.severe(e.toString());
125 e.printStackTrace();
126 assertTrue(e.toString(), false);
127 }
128 }
129
130 /**
131 * We expect dead letters after destroying our callback server.
132 */
133 public void testCallbackFailure()
134 {
135 if (isSocket) return;
136 log.info("testCallbackFailure() ...");
137 try {
138 log.info("Connecting ...");
139 Global globSub = this.glob.getClone(null);
140 I_XmlBlasterAccess con = globSub.getXmlBlasterAccess();
141 ConnectQos qos = new ConnectQos(globSub, name, passwd);
142 con.connect(qos, this); // Login to xmlBlaster
143
144 try {
145 Client.shutdownCb(con, Client.Shutdown.KEEP_LOGGED_IN);
146 }
147 catch (Throwable e) {
148 log.severe("testCallbackFailure: " + e.toString());
149 fail(e.toString());
150 }
151
152 String subscribeOid = con.subscribe("<key oid='testCallbackMsg'/>", null).getSubscriptionId();
153 log.info("Success: Subscribe on " + subscribeOid + " done");
154
155 MsgUnit msgUnit = new MsgUnit("<key oid='testCallbackMsg'/>", "Bla".getBytes(), null);
156 publishOid = con.publish(msgUnit).getKeyOid();
157 log.info("Success: Publishing done, returned oid=" + publishOid);
158
159 waitOnUpdate(2000L, 1);
160 assertTrue("Expected a dead letter", isDeadMessage);
161 isDeadMessage = false;
162
163 //Global.waitOnKeyboardHit("Session destroyed? Hit a key to continue");
164
165 // Check with user "admin" if session of "Tim" has disappeared
166 try {
167 MsgUnit[] msgs = Util.adminGet(glob, "__cmd:?clientList");
168 assertEquals("Can't access __cmd:?clientList", 1, msgs.length);
169 log.info("Got clientList=" + msgs[0].getContentStr());
170 assertEquals("Session of " + name + " was not destroyed by failing callback",
171 -1, msgs[0].getContentStr().indexOf(name));
172 }
173 catch (XmlBlasterException e) {
174 fail("Session was not destroyed: " + e.toString());
175 }
176 }
177 catch (Exception e) {
178 log.severe(e.toString());
179 assertTrue(e.toString(), false);
180 }
181 log.info("Success in testCallbackFailure()");
182 }
183
184 /**
185 * This is the callback method invoked from xmlBlaster
186 * delivering us a new asynchronous message.
187 * @see org.xmlBlaster.client.I_Callback#update(String, UpdateKey, byte[], UpdateQos)
188 */
189 public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos)
190 {
191 log.info("Receiving update of a message " + updateKey.getOid());
192 numReceived++;
193 isDeadMessage = updateKey.isDeadMessage();
194 return "";
195 }
196
197 /**
198 * Little helper, waits until the wanted number of messages are arrived
199 * or returns when the given timeout occurs.
200 * <p />
201 * @param timeout in milliseconds
202 * @param numWait how many messages to wait
203 */
204 private void waitOnUpdate(final long timeout, final int numWait)
205 {
206 long pollingInterval = 50L; // check every 0.05 seconds
207 if (timeout < 50) pollingInterval = timeout / 10L;
208 long sum = 0L;
209 // check if too few are arriving
210 while (numReceived < numWait) {
211 try { Thread.sleep(pollingInterval); } catch( InterruptedException i) {}
212 sum += pollingInterval;
213 assertTrue("Timeout of " + timeout + " occurred without update", sum <= timeout);
214 }
215
216 // check if too many are arriving
217 try { Thread.sleep(timeout); } catch( InterruptedException i) {}
218 assertEquals("Wrong number of messages arrived", numWait, numReceived);
219
220 numReceived = 0;
221 }
222
223 /**
224 * Method is used by TestRunner to load these tests
225 */
226 public static Test suite()
227 {
228 TestSuite suite= new TestSuite();
229 String loginName = "Tim";
230 suite.addTest(new TestCallback(new Global(), "testCallbackFailure", "Tim"));
231 return suite;
232 }
233
234 /**
235 * Invoke:
236 * <pre>
237 * java -Djava.compiler= junit.textui.TestRunner org.xmlBlaster.test.qos.TestCallback
238 *
239 * java org.xmlBlaster.test.qos.TestCallback -dispatch/callback/retries 0 -dispatch/callback/delay 3000
240 * </pre>
241 */
242 public static void main(String args[])
243 {
244 TestCallback testSub = new TestCallback(new Global(args), "TestCallback", "Tim");
245 testSub.setUp();
246 testSub.testCallbackFailure();
247 testSub.tearDown();
248 }
249 }
syntax highlighted by Code2HTML, v. 0.9.1