KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > smack > test > SmackTestCase


1 /**
2  * $RCSfile$
3  * $Revision: 2729 $
4  * $Date: 2005-08-26 23:21:24 -0300 (Fri, 26 Aug 2005) $
5  *
6  * Copyright (C) 2002-2003 Jive Software. All rights reserved.
7  * ====================================================================
8  * The Jive Software License (based on Apache Software License, Version 1.1)
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in
19  * the documentation and/or other materials provided with the
20  * distribution.
21  *
22  * 3. The end-user documentation included with the redistribution,
23  * if any, must include the following acknowledgment:
24  * "This product includes software developed by
25  * Jive Software (http://www.jivesoftware.com)."
26  * Alternately, this acknowledgment may appear in the software itself,
27  * if and wherever such third-party acknowledgments normally appear.
28  *
29  * 4. The names "Smack" and "Jive Software" must not be used to
30  * endorse or promote products derived from this software without
31  * prior written permission. For written permission, please
32  * contact webmaster@jivesoftware.com.
33  *
34  * 5. Products derived from this software may not be called "Smack",
35  * nor may "Smack" appear in their name, without prior written
36  * permission of Jive Software.
37  *
38  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
39  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41  * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
45  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
46  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
47  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
48  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49  * SUCH DAMAGE.
50  * ====================================================================
51  */

52 package org.jivesoftware.smack.test;
53
54 import java.io.InputStream JavaDoc;
55 import java.net.URL JavaDoc;
56 import java.util.Enumeration JavaDoc;
57
58 import javax.net.SocketFactory;
59
60 import org.jivesoftware.smack.XMPPConnection;
61 import org.jivesoftware.smack.XMPPException;
62 import org.xmlpull.v1.*;
63 import org.xmlpull.mxp1.MXParser;
64
65 import junit.framework.TestCase;
66
67 /**
68  * Base class for all the test cases which provides a pre-configured execution context. This
69  * means that any test case that subclassifies this base class will have access to a pool of
70  * connections and to the user of each connection. The maximum number of connections in the pool
71  * can be controlled by the message {@link #getMaxConnections()} which every subclass must
72  * implement.<p>
73  *
74  * This base class defines a default execution context (i.e. host, port, chat domain and muc
75  * domain) which can be found in the file "config/test-case.xml". However, each subclass could
76  * redefine the default configuration by providing its own configuration file (if desired). The
77  * name of the configuration file must be of the form <test class name>.xml (e.g. RosterTest.xml).
78  * The file must be placed in the folder "config". This folder is where the default configuration
79  * file is being held.
80  *
81  * @author Gaston Dombiak
82  */

83 public abstract class SmackTestCase extends TestCase {
84
85     private String JavaDoc host = "localhost";
86     private String JavaDoc serviceName = "localhost";
87     private int port = 5222;
88
89     private String JavaDoc chatDomain = "chat.localhost";
90     private String JavaDoc mucDomain = "conference.localhost";
91
92     private XMPPConnection[] connections = null;
93
94     /**
95      * Constructor for SmackTestCase.
96      * @param arg0
97      */

98     public SmackTestCase(String JavaDoc arg0) {
99         super(arg0);
100     }
101
102     /**
103      * Returns the maximum number of connections to initialize for this test case. All the
104      * initialized connections will be connected to the server using a new test account for
105      * each conection.
106      *
107      * @return the maximum number of connections to initialize for this test case.
108      */

109     protected abstract int getMaxConnections();
110
111     /**
112      * Returns a SocketFactory that will be used to create the socket to the XMPP server. By
113      * default no SocketFactory is used but subclasses my want to redefine this method.<p>
114      *
115      * A custom SocketFactory allows fine-grained control of the actual connection to the XMPP
116      * server. A typical use for a custom SocketFactory is when connecting through a SOCKS proxy.
117      *
118      * @return a SocketFactory that will be used to create the socket to the XMPP server.
119      */

120     protected SocketFactory getSocketFactory() {
121         return null;
122     }
123
124     /**
125      * Returns the XMPPConnection located at the requested position. Each test case holds a
126      * pool of connections which is initialized while setting up the test case. The maximum
127      * number of connections is controlled by the message {@link #getMaxConnections()} which
128      * every subclass must implement.<p>
129      *
130      * If the requested position is greater than the connections size then an
131      * IllegalArgumentException will be thrown.
132      *
133      * @param index the position in the pool of the connection to look for.
134      * @return the XMPPConnection located at the requested position.
135      */

136     protected XMPPConnection getConnection(int index) {
137         if (index > getMaxConnections()) {
138             throw new IllegalArgumentException JavaDoc("Index out of bounds");
139         }
140         return connections[index];
141     }
142
143     /**
144      * Returns the name of the user (e.g. johndoe) that is using the connection
145      * located at the requested position.
146      *
147      * @param index the position in the pool of the connection to look for.
148      * @return the user of the user (e.g. johndoe).
149      */

150     protected String JavaDoc getUsername(int index) {
151         if (index > getMaxConnections()) {
152             throw new IllegalArgumentException JavaDoc("Index out of bounds");
153         }
154         return "user" + index;
155     }
156
157     /**
158      * Returns the bare XMPP address of the user (e.g. johndoe@jabber.org) that is
159      * using the connection located at the requested position.
160      *
161      * @param index the position in the pool of the connection to look for.
162      * @return the bare XMPP address of the user (e.g. johndoe@jabber.org).
163      */

164     protected String JavaDoc getBareJID(int index) {
165         return getUsername(index) + "@" + getConnection(index).getServiceName();
166     }
167
168     /**
169      * Returns the full XMPP address of the user (e.g. johndoe@jabber.org/Smack) that is
170      * using the connection located at the requested position.
171      *
172      * @param index the position in the pool of the connection to look for.
173      * @return the full XMPP address of the user (e.g. johndoe@jabber.org/Smack).
174      */

175     protected String JavaDoc getFullJID(int index) {
176         return getBareJID(index) + "/Smack";
177     }
178
179     protected String JavaDoc getHost() {
180         return host;
181     }
182
183     protected int getPort() {
184         return port;
185     }
186
187     protected String JavaDoc getServiceName() {
188         return serviceName;
189     }
190
191     /**
192      * Returns the default groupchat service domain.
193      *
194      * @return the default groupchat service domain.
195      */

196     protected String JavaDoc getChatDomain() {
197         return chatDomain;
198     }
199
200     /**
201      * Returns the default MUC service domain.
202      *
203      * @return the default MUC service domain.
204      */

205     protected String JavaDoc getMUCDomain() {
206         return mucDomain;
207     }
208
209     protected void setUp() throws Exception JavaDoc {
210         super.setUp();
211         init();
212         if (getMaxConnections() < 1) {
213             return;
214         }
215         connections = new XMPPConnection[getMaxConnections()];
216         try {
217             // Connect to the server
218
for (int i = 0; i < getMaxConnections(); i++) {
219                 if (getSocketFactory() == null) {
220                     connections[i] = new XMPPConnection(host, port);
221                 }
222                 else {
223                     connections[i] = new XMPPConnection(host, port, host, getSocketFactory());
224                 }
225             }
226             // Use the host name that the server reports. This is a good idea in most
227
// cases, but could fail if the user set a hostname in their XMPP server
228
// that will not resolve as a network connection.
229
host = connections[0].getHost();
230             serviceName = connections[0].getServiceName();
231             // Create the test accounts
232
if (!getConnection(0).getAccountManager().supportsAccountCreation())
233                 fail("Server does not support account creation");
234
235             for (int i = 0; i < getMaxConnections(); i++) {
236                 // Create the test account
237
try {
238                     getConnection(i).getAccountManager().createAccount("user" + i, "user" + i);
239                 } catch (XMPPException e) {
240                     // Do nothing if the accout already exists
241
if (e.getXMPPError().getCode() != 409) {
242                         throw e;
243                     }
244                 }
245                 // Login with the new test account
246
getConnection(i).login("user" + i, "user" + i);
247             }
248             // Let the server process the available presences
249
Thread.sleep(150);
250         }
251         catch (Exception JavaDoc e) {
252             e.printStackTrace();
253             fail(e.getMessage());
254         }
255     }
256
257     protected void tearDown() throws Exception JavaDoc {
258         super.tearDown();
259
260         for (int i = 0; i < getMaxConnections(); i++) {
261             // Delete the created account for the test
262
getConnection(i).getAccountManager().deleteAccount();
263             // Close the connection
264
getConnection(i).close();
265
266         }
267     }
268
269     /**
270      * Initializes the context of the test case. We will first try to load the configuration from
271      * a file whose name is conformed by the test case class name plus an .xml extension
272      * (e.g RosterTest.xml). If no file was found under that name then we will try to load the
273      * default configuration for all the test cases from the file "config/test-case.xml".
274      *
275      */

276     private void init() {
277         try {
278             boolean found = false;
279             // Try to load the configutation from an XML file specific for this test case
280
Enumeration JavaDoc resources =
281                 ClassLoader.getSystemClassLoader().getResources(getConfigurationFilename());
282             while (resources.hasMoreElements()) {
283                 found = parseURL((URL JavaDoc) resources.nextElement());
284             }
285             // If none was found then try to load the configuration from the default configuration
286
// file (i.e. "config/test-case.xml")
287
if (!found) {
288                 resources = ClassLoader.getSystemClassLoader().getResources("config/test-case.xml");
289                 while (resources.hasMoreElements()) {
290                     found = parseURL((URL JavaDoc) resources.nextElement());
291                 }
292             }
293             if (!found) {
294                 System.err.println("File config/test-case.xml not found. Using default config.");
295             }
296         }
297         catch (Exception JavaDoc e) {
298         }
299     }
300
301     /**
302      * Returns true if the given URL was found and parsed without problems. The file provided
303      * by the URL must contain information useful for the test case configuration, such us,
304      * host and port of the server.
305      *
306      * @param url the url of the file to parse.
307      * @return true if the given URL was found and parsed without problems.
308      */

309     private boolean parseURL(URL JavaDoc url) {
310         boolean parsedOK = false;
311         InputStream JavaDoc systemStream = null;
312         try {
313             systemStream = url.openStream();
314             XmlPullParser parser = new MXParser();
315             parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
316             parser.setInput(systemStream, "UTF-8");
317             int eventType = parser.getEventType();
318             do {
319                 if (eventType == XmlPullParser.START_TAG) {
320                     if (parser.getName().equals("host")) {
321                         host = parser.nextText();
322                     }
323                     else if (parser.getName().equals("port")) {
324                         port = parseIntProperty(parser, port);
325                     }
326                     else if (parser.getName().equals("serviceName")) {
327                         serviceName = parser.nextText();
328                     }
329                     else if (parser.getName().equals("chat")) {
330                         chatDomain = parser.nextText();
331                     }
332                     else if (parser.getName().equals("muc")) {
333                         mucDomain = parser.nextText();
334                     }
335                 }
336                 eventType = parser.next();
337             }
338             while (eventType != XmlPullParser.END_DOCUMENT);
339             parsedOK = true;
340         }
341         catch (Exception JavaDoc e) {
342             e.printStackTrace();
343         }
344         finally {
345             try {
346                 systemStream.close();
347             }
348             catch (Exception JavaDoc e) {
349             }
350         }
351         return parsedOK;
352     }
353
354     private static int parseIntProperty(XmlPullParser parser, int defaultValue) throws Exception JavaDoc {
355         try {
356             return Integer.parseInt(parser.nextText());
357         }
358         catch (NumberFormatException JavaDoc nfe) {
359             nfe.printStackTrace();
360             return defaultValue;
361         }
362     }
363
364     /**
365      * Returns the name of the configuration file related to <b>this</b> test case. By default all
366      * the test cases will use the same configuration file. However, it's possible to override the
367      * default configuration by providing a file of the form <test case class name>.xml
368      * (e.g. RosterTest.xml).
369      *
370      * @return the name of the configuration file related to this test case.
371      */

372     private String JavaDoc getConfigurationFilename() {
373         String JavaDoc fullClassName = this.getClass().getName();
374         int firstChar = fullClassName.lastIndexOf('.') + 1;
375         return "config/" + fullClassName.substring(firstChar) + ".xml";
376     }
377
378 }
379
Popular Tags