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