1 /*------------------------------------------------------------------------------
  2 Name:      TestSession.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 package org.xmlBlaster.test.authentication;
  7 
  8 import java.util.logging.Logger;
  9 import org.xmlBlaster.util.Global;
 10 import org.xmlBlaster.util.XmlBlasterException;
 11 import org.xmlBlaster.client.qos.ConnectQos;
 12 import org.xmlBlaster.client.qos.DisconnectQos;
 13 import org.xmlBlaster.client.I_XmlBlasterAccess;
 14 import org.xmlBlaster.client.I_Callback;
 15 import org.xmlBlaster.client.key.UpdateKey;
 16 import org.xmlBlaster.client.qos.UpdateQos;
 17 import org.xmlBlaster.util.MsgUnit;
 18 
 19 import org.xmlBlaster.test.Util;
 20 
 21 import junit.framework.*;
 22 
 23 
 24 /**
 25  * This client does test login sessions.<br />
 26  * login/logout combinations are checked with subscribe()/publish() calls
 27  * <p />
 28  * This client may be invoked multiple time on the same xmlBlaster server,
 29  * as it cleans up everything after his tests are done.
 30  * <p>
 31  * Invoke examples:<br />
 32  * <pre>
 33  *    java junit.textui.TestRunner org.xmlBlaster.test.authentication.TestSession
 34  *    java junit.swingui.TestRunner org.xmlBlaster.test.authentication.TestSession
 35  * </pre>
 36  */
 37 public class TestSession extends TestCase implements I_Callback
 38 {
 39    private final Global glob;
 40    private static Logger log = Logger.getLogger(TestSession.class.getName());
 41    private String name;
 42    private String passwd = "secret";
 43    private int numReceived = 0;         // error checking
 44 
 45    /**
 46     * Constructs the TestSession object.
 47     * <p />
 48     * @param testName   The name used in the test suite
 49     * @param name       The name to login to the xmlBlaster
 50     */
 51    public TestSession(Global glob, String testName, String name)
 52    {
 53        super(testName);
 54        this.glob = glob;
 55 
 56        this.name = name;
 57    }
 58 
 59    /**
 60     * Sets up the fixture.
 61     * <p />
 62     * Connect to xmlBlaster and login
 63     */
 64    protected void setUp()
 65    {
 66    }
 67 
 68    /**
 69     * Tears down the fixture.
 70     * <p />
 71     * cleaning up .... erase() the previous message OID and logout
 72     */
 73    protected void tearDown()
 74    {
 75    }
 76 
 77    /**
 78     */
 79    public void testZeroSessions()
 80    {
 81       log.info("testZeroSessions() ...");
 82       try {
 83          log.info("Connecting ...");
 84          Global glob = this.glob.getClone(null);
 85          I_XmlBlasterAccess con = glob.getXmlBlasterAccess();
 86          ConnectQos qos = new ConnectQos(glob, name, passwd);
 87          qos.setMaxSessions(-16);
 88          con.connect(qos, this); // Login to xmlBlaster
 89          assertTrue("Connecting with zero sessions should not be possible", false);
 90       }
 91       catch (Exception e) {
 92          log.info("Success, can't connect with zero sessions");
 93       }
 94       log.info("Success in testZeroSessions()");
 95    }
 96 
 97 
 98    /**
 99     */
100    public void testSessionOverflow()
101    {
102       log.info("testSessionOverflow() ...");
103       int numLogin = 5;
104       int maxSessions = numLogin - 2;
105       I_XmlBlasterAccess[] con = new I_XmlBlasterAccess[5];
106       try {
107          for (int ii=0; ii<numLogin; ii++) {
108             try {
109                log.info("Connecting number " + ii + " of " + numLogin + " max=" + maxSessions);
110                con[ii] = glob.getClone(null).getXmlBlasterAccess();
111                ConnectQos qos = new ConnectQos(con[ii].getGlobal(), name, passwd);
112                qos.setMaxSessions(maxSessions);
113                con[ii].connect(qos, this); // Login to xmlBlaster
114                if (ii >= maxSessions)
115                   assertTrue("Connecting number " + ii + " of max=" + maxSessions + " is not allowed", false);
116             }
117             catch (Exception e) {
118                if (ii >= maxSessions) {
119                   log.info("Success, connecting number " + ii + " of max=" + maxSessions + " was denied: " + e.toString());
120                }
121                else {
122                   log.severe(e.toString());
123                   assertTrue("Connecting number " + ii + " of max=" + maxSessions + " should be possible", false);
124                }
125             }
126          }
127       }
128       finally { // clean up
129          try {
130             for (int ii=0; ii<maxSessions; ii++) {
131                DisconnectQos disQos = null;
132                if (con[ii] != null) {
133                   con[ii].disconnect(disQos);
134                }
135             }
136          }
137          catch (Throwable e) {
138             assertTrue(e.toString(), false);
139          }
140       }
141       log.info("Success in testSessionOverflow()");
142    }
143 
144 
145    /**
146     * We login with session timeout 1 sec and sleep for 2 sec.
147     * A get() invocation should fail since the session is expired.
148     */
149    public void testSessionTimeout()
150    {
151       log.info("testSessionTimeout() ...");
152       long timeout = 1000L;
153       I_XmlBlasterAccess con = null;
154       Global glob = this.glob.getClone(null);
155       try {
156          try {
157             con = glob.getXmlBlasterAccess();
158             ConnectQos qos = new ConnectQos(glob, name, passwd);
159             qos.setSessionTimeout(timeout);
160             con.connect(qos, this);
161          }
162          catch (Exception e) {
163             log.severe(e.toString());
164             assertTrue("Login failed" + e.toString(), false);
165          }
166 
167          try { Thread.sleep(timeout*2); } catch (Exception e) { } // wait until session expires
168 
169          try {
170             log.info("Check that session has dissapeared ...");
171             MsgUnit[] msgs = Util.adminGet(glob, "__cmd:?clientList");
172             assertEquals("Can't access __cmd:?clientList", 1, msgs.length);
173             log.info("Got userList=" + msgs[0].getContentStr());
174             assertEquals("Session of " + name + " was not destroyed by failing callback",
175                       -1, msgs[0].getContentStr().indexOf(name));
176          }
177          catch (XmlBlasterException e) {
178             fail("Session was not destroyed: " + e.toString());
179          }
180       }
181       finally { // clean up
182          try {
183             con.disconnect(null);
184          }
185          catch (Throwable e) {
186             assertTrue(e.toString(), false);
187          }
188       }
189       log.info("Success in testSessionTimeout()");
190    }
191 
192 
193    /**
194     * We login with session timeout 2 sec and let it automatically refresh. 
195     * A get() invocation should fail since the session is expired.
196     */
197    public void testSessionRefresh()
198    {
199       log.info("testSessionRefresh() ...");
200       long timeout = 2000L;
201       I_XmlBlasterAccess con = null;
202       Global glob = this.glob.getClone(null);
203       try {
204          try {
205             con = glob.getXmlBlasterAccess();
206             ConnectQos qos = new ConnectQos(glob, name, passwd);
207             qos.setRefreshSession(true);
208             qos.setSessionTimeout(timeout);
209             con.connect(qos, this);
210          }
211          catch (Exception e) {
212             log.severe(e.toString());
213             assertTrue("Login failed" + e.toString(), false);
214          }
215 
216          log.info("Wait " + timeout*2 + " sec if session expires (because of inactivity)");
217          try { Thread.sleep(timeout*2); } catch (Exception e) { }
218 
219          try {
220             for (int ii=0; ii<1; ii++) {
221                try { Thread.sleep(timeout/2); } catch (Exception e) { }
222                log.info("Check access #" + ii + " ...");
223                con.get("<key oid='__cmd:?freeMem'/>", null);
224                log.info("Check access #" + ii + " OK");
225             }
226          }
227          catch (Exception e) {
228             log.severe("No access: " + e.toString());
229             assertTrue("Session is expired", false);
230          }
231       }
232       finally { // clean up
233          try {
234             con.disconnect(null);
235          }
236          catch (Throwable e) {
237             assertTrue(e.toString(), false);
238          }
239       }
240       log.info("Success in testSessionRefresh()");
241    }
242 
243 
244    /**
245     * We login with session timeout 2 sec, call every 1000 millis get()
246     * which should respan the session timeout. 
247     * If this goes well for 8 sec, the refresh seems to work
248     */
249    public void testSessionTimeoutRespan()
250    {
251       log.info("testSessionTimeoutRespan() ...");
252       long timeout = 2000L;
253       I_XmlBlasterAccess con = null;
254       Global glob = this.glob.getClone(null);
255       try {
256          try {
257             con = glob.getXmlBlasterAccess();
258             ConnectQos qos = new ConnectQos(glob, name, passwd);
259             qos.setSessionTimeout(timeout);
260             con.connect(qos, this);
261          }
262          catch (Exception e) {
263             log.severe(e.toString());
264             assertTrue("Login failed" + e.toString(), false);
265          }
266 
267          try {
268             for (int ii=0; ii<4; ii++) {
269                try { Thread.sleep(timeout/2); } catch (Exception e) { }
270                log.info("Check access #" + ii + " ...");
271                con.get("<key oid='__cmd:?freeMem'/>", null);
272                log.info("Check access #" + ii + " OK");
273             }
274          }
275          catch (Exception e) {
276             log.severe("No access: " + e.toString());
277             assertTrue("Session is expired", false);
278          }
279       }
280       finally { // clean up
281          try {
282             con.disconnect(null);
283          }
284          catch (Throwable e) {
285             assertTrue(e.toString(), false);
286          }
287       }
288       log.info("Success in testSessionTimeoutRespan()");
289    }
290 
291 
292    /**
293     */
294    public void testClearSession()
295    {
296       log.info("***testClearSession() ...");
297       int numLogin = 5;
298       int maxSessions = numLogin - 2;
299       I_XmlBlasterAccess[] con = new I_XmlBlasterAccess[5];
300       for (int ii=0; ii<numLogin; ii++) {
301          try {
302             log.info("Connecting number " + ii + " of " + numLogin + " max=" + maxSessions);
303             con[ii] = glob.getClone(null).getXmlBlasterAccess();
304             ConnectQos qos = new ConnectQos(con[ii].getGlobal(), name, passwd);
305             qos.setMaxSessions(maxSessions);
306             con[ii].connect(qos, this); // Login to xmlBlaster
307          }
308          catch (XmlBlasterException e) {
309             if (ii >= maxSessions) {
310                log.info("Success, connecting number " + ii + " of max=" + maxSessions + " was denied: " + e.toString());
311                log.info("We try to clear the old sessions now");
312                try {
313                   ConnectQos qos = new ConnectQos(null, name, passwd);
314                   qos.setMaxSessions(maxSessions);
315                   qos.clearSessions(true);
316                   con[ii].connect(qos, this);
317                   log.info("Success, login is possible again");
318                   con[ii].get("<key oid='__cmd:?freeMem'/>", null);
319                   log.info("Success, get works");
320                }
321                catch (Exception e2) {
322                   log.severe("Clear session failed: " + e2.toString());
323                   e2.printStackTrace();
324                   fail("Login failed" + e2.toString());
325                }
326             }
327             else {
328                log.severe(e.toString());
329                assertTrue("Connecting number " + ii + " of max=" + maxSessions + " should be possible", false);
330             }
331          }
332       }
333          
334       // clean up
335       for (int ii=maxSessions; ii<numLogin; ii++) {
336          DisconnectQos disQos = null;
337          if (con[ii] != null) {
338             con[ii].disconnect(disQos);
339          }
340       }
341       log.info("***Success in testClearSession()");
342    }
343 
344    /**
345     * This is the callback method invoked from xmlBlaster
346     * delivering us a new asynchronous message. 
347     * @see org.xmlBlaster.client.I_Callback#update(String, UpdateKey, byte[], UpdateQos)
348     */
349    public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos)
350    {
351       log.info("Receiving update of a message " + updateKey.getOid());
352       numReceived++;
353       return "";
354    }
355 
356 
357    /**
358     * Little helper, waits until the wanted number of messages are arrived
359     * or returns when the given timeout occurs.
360     * <p />
361     * @param timeout in milliseconds
362     * @param numWait how many messages to wait
363     */
364    private void waitOnUpdate(final long timeout, final int numWait)
365    {
366       long pollingInterval = 50L;  // check every 0.05 seconds
367       if (timeout < 50)  pollingInterval = timeout / 10L;
368       long sum = 0L;
369       // check if too few are arriving
370       while (numReceived < numWait) {
371          try { Thread.sleep(pollingInterval); } catch( InterruptedException i) {}
372          sum += pollingInterval;
373          assertTrue("Timeout of " + timeout + " occurred without update", sum <= timeout);
374       }
375 
376       // check if too many are arriving
377       try { Thread.sleep(timeout); } catch( InterruptedException i) {}
378       assertEquals("Wrong number of messages arrived", numWait, numReceived);
379 
380       numReceived = 0;
381    }
382 
383    /**
384     * Method is used by TestRunner to load these tests
385     */
386    public static Test suite()
387    {
388        TestSuite suite= new TestSuite();
389        String loginName = "Tim";
390        Global glob = new Global();
391        suite.addTest(new TestSession(glob, "testZeroSessions", loginName));
392        suite.addTest(new TestSession(glob, "testSessionOverflow", loginName));
393        suite.addTest(new TestSession(glob, "testSessionTimeout", loginName));
394        suite.addTest(new TestSession(glob, "testSessionRefresh", loginName));
395        suite.addTest(new TestSession(glob, "testSessionTimeoutRespan", loginName));
396        suite.addTest(new TestSession(glob, "testClearSession", loginName));
397        return suite;
398    }
399 
400    /**
401     * Invoke: 
402     * <pre>
403     *   java org.xmlBlaster.test.authentication.TestSession
404     *   java -Djava.compiler= junit.textui.TestRunner org.xmlBlaster.test.authentication.TestSession
405     * <pre>
406     */
407    public static void main(String args[])
408    {
409       TestSession testSub = new TestSession(new Global(args), "TestSession", "Tim");
410       testSub.setUp();
411       testSub.testZeroSessions();
412       testSub.testSessionOverflow();
413       testSub.testSessionTimeout();
414       testSub.testSessionRefresh();
415       testSub.testSessionTimeoutRespan();
416       testSub.testClearSession();
417       testSub.tearDown();
418    }
419 }


syntax highlighted by Code2HTML, v. 0.9.1