1   package org.sourceforge.vlibrary;
2   
3   import java.util.Iterator;
4   import java.util.PropertyResourceBundle;
5   import java.util.ResourceBundle;
6   import java.util.concurrent.locks.Lock;
7   
8   import junit.framework.Assert;
9   import junit.framework.AssertionFailedError;
10  
11  import org.apache.log4j.Logger;
12  import org.dbunit.database.DatabaseConnection;
13  import org.dbunit.database.IDatabaseConnection;
14  import org.sourceforge.vlibrary.user.workers.DelegatingSimpleSmtpServer;
15  import org.springframework.beans.factory.BeanFactory;
16  import org.springframework.context.support.ClassPathXmlApplicationContext;
17  import org.springframework.jdbc.core.JdbcTemplate;
18  
19  import com.dumbster.smtp.SimpleSmtpServer;
20  import com.dumbster.smtp.SmtpMessage;
21  
22  import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
23  
24  /**
25   * Utility class containing static methods useful in vlibrary testing.
26   *
27   * @version $Revision$ $Date$
28   *
29   */
30  public class TestUtils {
31  
32      /** Class should not be instantiated */
33      protected TestUtils() {
34      }
35      
36      private static ReentrantLock dumbsterLock = new ReentrantLock();
37      private static ReentrantLock databaseLock = new ReentrantLock();
38  
39      public static void getDatabaseLock() {
40          databaseLock.lock();
41      }
42      
43      public static void getDumbsterLock() {
44          dumbsterLock.lock();
45      }
46      
47      public static void releaseDatabaseLock() {
48          databaseLock.unlock();
49      }
50      
51      public static void releaseDumbsterLock() {
52          dumbsterLock.unlock();
53      }
54      
55      /**
56       * Creates a test database with the vlibrary table definitions
57       * (use this in setup() methods to create a test database)
58       *
59       */
60      public static void createTestDatabase() throws Exception {
61          BeanFactory context =
62           new ClassPathXmlApplicationContext("/lightweightcontainer.xml");
63  
64          JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean(
65           "JdbcTemplate", JdbcTemplate.class);
66  
67          // Create the schema including all tables
68          // TODO: Find a cleaner way to do this - pipe in ddl script
69          StringBuffer sqlBuffer = new StringBuffer();
70  
71          sqlBuffer.append(
72           "CREATE TABLE TRAN (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), TRANS_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, READER INTEGER NOT NULL, BOOK INTEGER NOT NULL, ACTION INTEGER NOT NULL, LOCATION INTEGER NOT NULL);"
73           );
74          sqlBuffer.append(
75           " CREATE TABLE ACTION (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), DESCRIPTION VARCHAR(255) NOT NULL);"
76           );
77          sqlBuffer.append(
78           " CREATE TABLE READER (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), LASTNAME VARCHAR(255) NOT NULL, FIRSTNAME VARCHAR(255) NOT NULL, EMAIL VARCHAR(255) NOT NULL, DESK_PHONE VARCHAR(255) NOT NULL, MOBILE_PHONE VARCHAR(255) NOT NULL, PAGER VARCHAR(255), SCREEN_NAME VARCHAR(255), UID VARCHAR(255) NOT NULL, PASSWD VARCHAR(255) NOT NULL, IM_SERVICE VARCHAR(255));"
79           );
80          sqlBuffer.append(
81           " CREATE TABLE BOOK (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), TITLE VARCHAR(255) NOT NULL, PUBLISHER VARCHAR(255), ISBN VARCHAR(255) NOT NULL, OWNER INTEGER, CREATED TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PUB_DATE VARCHAR(255), COPY INTEGER DEFAULT 0, FOREIGN KEY (OWNER) REFERENCES READER (ID));"
82           );
83          sqlBuffer.append(
84           " CREATE TABLE AUTHOR_X_BOOK (AUTHOR INTEGER NOT NULL, BOOK INTEGER NOT NULL);"
85           );
86          sqlBuffer.append(
87           " CREATE TABLE SUBJECT (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), DESCRIPTION VARCHAR(255) NOT NULL);"
88           );
89          sqlBuffer.append(
90           " CREATE TABLE LOCATION (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), DESCRIPTION VARCHAR(255) NOT NULL);"
91           );
92          sqlBuffer.append(
93           " CREATE TABLE USER_X_ROLE (UID VARCHAR(255) NOT NULL, ROLE VARCHAR(255) NOT NULL);"
94           );
95          sqlBuffer.append(
96           " CREATE TABLE AUTHOR (ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 101, INCREMENT BY 1), LASTNAME VARCHAR(255) NOT NULL, FIRSTNAME VARCHAR(255) NOT NULL);"
97           );
98          sqlBuffer.append(
99           " CREATE TABLE BOOK_X_SUBJECT (BOOK INTEGER NOT NULL, SUBJECT INTEGER NOT NULL);"
100          );
101         sqlBuffer.append(";");
102 
103         jdbcTemplate.execute(sqlBuffer.toString());
104 
105         // Now add uniquenss constraints
106         jdbcTemplate.execute(
107          "CREATE UNIQUE INDEX reader_id ON READER (ID);"
108          );
109         jdbcTemplate.execute(
110          "CREATE UNIQUE INDEX reader_uid ON READER(UID);"
111          );
112         jdbcTemplate.execute(
113          "CREATE UNIQUE INDEX reader_phone ON READER(DESK_PHONE);"
114          );
115         jdbcTemplate.execute(
116          "CREATE UNIQUE INDEX reader_name ON READER(LASTNAME, FIRSTNAME);"
117          );
118         jdbcTemplate.execute(
119          "CREATE UNIQUE INDEX user_role ON USER_X_ROLE(UID, ROLE);"
120          );
121         jdbcTemplate.execute(
122          "CREATE UNIQUE INDEX book_subject ON BOOK_X_SUBJECT(BOOK, SUBJECT);"
123          );
124         jdbcTemplate.execute(
125          "CREATE UNIQUE INDEX book_id ON BOOK(ID);"
126          );
127     }
128 
129     /**
130      * Destroys all objects defined in the test database
131      * (suitable for use in tearDown())
132      *
133      * @throws Exception
134      */
135     public static void destroyDatabase() throws Exception {
136 
137         BeanFactory context =
138          new ClassPathXmlApplicationContext("/lightweightcontainer.xml");
139 
140         JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean(
141          "JdbcTemplate", JdbcTemplate.class);
142 
143         jdbcTemplate.execute("DROP TABLE TRAN;");
144         jdbcTemplate.execute("DROP TABLE ACTION;");
145         jdbcTemplate.execute("DROP TABLE BOOK_X_SUBJECT;");
146         jdbcTemplate.execute("DROP TABLE AUTHOR_X_BOOK;");
147         jdbcTemplate.execute("DROP TABLE USER_X_ROLE;");
148         jdbcTemplate.execute("DROP TABLE BOOK;");
149         jdbcTemplate.execute("DROP TABLE SUBJECT;");
150         jdbcTemplate.execute("DROP TABLE LOCATION;");
151         jdbcTemplate.execute("DROP TABLE READER;");
152         jdbcTemplate.execute("DROP TABLE AUTHOR;");
153     }
154 
155     /**
156      * Shuts down test database
157      *
158      * (IDE test runners may require this in tearDown(), following
159      * destroyDatabase)
160      *
161      */
162     public static void shutDownDatabase() {
163 
164         BeanFactory context =
165          new ClassPathXmlApplicationContext("/lightweightcontainer.xml");
166 
167         JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean(
168          "JdbcTemplate", JdbcTemplate.class);
169         try {
170             jdbcTemplate.execute("SHUTDOWN COMPACT");
171         } catch (Exception ex) {
172             System.out.println(ex);
173         }
174 
175     }
176 
177     /**
178      * Creates and returns a new dbunit database connection
179      * using properties defined in database.properties
180      */
181     public static IDatabaseConnection getConnection() throws Exception {
182         ResourceBundle bundle = new PropertyResourceBundle(
183          TestUtils.class.getResourceAsStream("/database.properties"));
184         String driverName = bundle.getString("database.driverClassName");
185         String url = bundle.getString("database.url");
186         String userName = bundle.getString("database.username");
187         String userPassword = bundle.getString("database.password");
188         Class driverClass = Class.forName(driverName);
189         java.sql.Connection jdbcConnection =
190          java.sql.DriverManager.getConnection(url, userName, userPassword);
191         return new DatabaseConnection(jdbcConnection);
192     }
193 
194     /*********************************************************
195           DUMBSTER MOCK SMTP SERVER CHECKS
196      ********************************************************/
197 
198     /**
199      * Verifies that the dumbster server has "sent" exactly one
200      * message with the expected recipient, subject line and
201      * initial body text.
202      *
203      * @param server  mock smtp server
204      * @param expectedRecipient  expected recipient
205      * @param expectedSubject  expected subject
206      * @param expectedBodyStart expected initial body text
207      */
208     public static void checkMessage(SimpleSmtpServer server,
209             String expectedRecipient, String expectedSubject,
210             String expectedBodyStart) {
211         Assert.assertTrue(server.getReceivedEmailSize() == 1);
212         Iterator emailIter = server.getReceivedEmail();
213         SmtpMessage email = (SmtpMessage)emailIter.next();
214         checkMessage(
215                 email, expectedRecipient, expectedSubject, expectedBodyStart);
216     }
217 
218     /**
219      * Verifies that the dumbster server delegate has "sent" exactly one
220      * message with the expected recipient, subject line and
221      * initial body text.
222      *
223      * @param server  delegating mock smtp server
224      * @param expectedRecipient  expected recipient
225      * @param expectedSubject  expected subject
226      * @param expectedBodyStart expected initial body text
227      */
228     public static void checkMessage(DelegatingSimpleSmtpServer server,
229             String expectedRecipient, String expectedSubject,
230             String expectedBodyStart) {
231         checkMessage(server.getDelegate(),expectedRecipient,expectedSubject,
232                 expectedBodyStart);
233     }
234 
235     /**
236      * Verifies that the last message the dumbster sent has the expected
237      * recipient, subject line and initial body text.
238      *
239      * @param server  mock smtp server
240      * @param expectedRecipient  expected recipient
241      * @param expectedSubject  expected subject
242      * @param expectedBodyStart expected initial body text
243      */
244     public static void checkLastMessage(SimpleSmtpServer server,
245             String expectedRecipient, String expectedSubject,
246             String expectedBodyStart) {
247         Iterator iterator = server.getReceivedEmail();
248         SmtpMessage email = null;
249         while (iterator.hasNext()) {
250            email = (SmtpMessage)iterator.next();
251         }
252         checkMessage(
253                 email, expectedRecipient, expectedSubject, expectedBodyStart);
254     }
255 
256     /**
257      * Verifies that the last message the dumbster server delegate sent has the
258      * expected recipient, subject line and initial body text.
259      *
260      * @param server  delegating mock smtp server
261      * @param expectedRecipient  expected recipient
262      * @param expectedSubject  expected subject
263      * @param expectedBodyStart expected initial body text
264      */
265     public static void checkLastMessage(DelegatingSimpleSmtpServer server,
266             String expectedRecipient, String expectedSubject,
267             String expectedBodyStart) {
268         Iterator<SmtpMessage> iterator = server.getReceivedEmail();
269         SmtpMessage email = null;
270         while (iterator.hasNext()) {
271            email = (SmtpMessage)iterator.next();
272         }
273         checkMessage(
274                 email, expectedRecipient, expectedSubject, expectedBodyStart);
275     }
276 
277     /**
278      * Verifies that the dumbster server delegate has sent a message with
279      * expected recipient, subject line and initial body text.
280      *
281      * @param server  delegating mock smtp server
282      * @param expectedRecipient  expected recipient
283      * @param expectedSubject  expected subject
284      * @param expectedBodyStart expected initial body text
285      */
286     public static void checkMessageExists(DelegatingSimpleSmtpServer server,
287                                           String expectedRecipient, String expectedSubject,
288                                           String expectedBodyStart) {
289         Iterator<SmtpMessage> iterator = server.getReceivedEmail();
290         SmtpMessage email = null;
291         boolean found = false;
292         while (iterator.hasNext()) {
293             email = (SmtpMessage)iterator.next();
294             try {
295                 checkMessage(email, expectedRecipient, expectedSubject, expectedBodyStart);
296                 found = true;
297             } catch (AssertionFailedError ex) {
298                 // swallow assertion failure
299             }
300         }
301         Assert.assertTrue("Message not found", found);
302     }
303 
304     /**
305      * Verifies that a message has expected recipient, subject line and
306      * initial body text.
307      *
308      * @param message  smtp message
309      * @param expectedRecipient  expected recipient
310      * @param expectedSubject  expected subject
311      * @param expectedBodyStart expected initial body text
312      */
313     public static void checkMessage(SmtpMessage message, String expectedRecipient,
314             String expectedSubject,String expectedBodyStart) {
315 
316         Assert.assertTrue("To should be " + expectedRecipient + " but was " + message.getHeaderValue("To"),
317                 message.getHeaderValue("To").equals(expectedRecipient));
318         Assert.assertTrue("Subject should be " + expectedSubject + " but was " + message.getHeaderValue("Subject"),
319                 message.getHeaderValue("Subject").equals(expectedSubject));
320         Assert.assertTrue("Body should start with " + expectedBodyStart + " but was " + message.getBody(),
321                 message.getBody().startsWith(expectedBodyStart));
322     }
323 
324     public static void stopDumbster(Logger logger, DelegatingSimpleSmtpServer server) {
325         logger.debug("Contents of dumbster at shutdown: ");
326         logger.debug(getMessagesAsString(server.getDelegate()));
327         server.stop();
328     }
329 
330     public static DelegatingSimpleSmtpServer startDumbster(Logger logger, int port) {
331         logger.info("creating DelegatingSimpleSmtpServer listening on port " + port);
332         DelegatingSimpleSmtpServer ret = null;
333         ret =  new DelegatingSimpleSmtpServer(2500);
334         logger.info("Starting DelegatingSimpleSmtpServer... ");
335         ret.start();
336         logger.info("returning DelegatingSimpleSmtpServer listening on port " + port);
337         return ret;
338     }
339 
340     /**
341      * Dumps out the contents of the dumbster mock smtp server.
342      * Useful for debugging.
343      *
344      * @param server dumbster server whose contents are dumped
345      */
346     public static void dumpMessages(SimpleSmtpServer server) {
347         System.out.println(getMessagesAsString(server));
348     }
349 
350     public static void logMessages(SimpleSmtpServer server, Logger logger) {
351         logger.info(getMessagesAsString(server));
352     }
353 
354     public static String getMessagesAsString(SimpleSmtpServer server) {
355         StringBuffer buffer = new StringBuffer();
356         @SuppressWarnings("unchecked")
357         Iterator<SmtpMessage> emailIter = server.getReceivedEmail();
358         while (emailIter.hasNext()) {
359             SmtpMessage email = emailIter.next();
360             buffer.append("************************************");
361             buffer.append("To: " + email.getHeaderValue("To"));
362             buffer.append("Subject: " + email.getHeaderValue("Subject"));
363             buffer.append("Message text: " + email.getBody());
364         }
365         return buffer.toString();
366     }
367 
368     /**
369      * Dumps out the contents of the delegating dumbster mock smtp server
370      * Useful for debugging.
371      *
372      * @param server delegating dumbster server whose contents are dumped
373      */
374     public static void dumpMessages(DelegatingSimpleSmtpServer server) {
375         dumpMessages(server.getDelegate());
376     }
377 
378 }