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


syntax highlighted by Code2HTML, v. 0.9.1