1 /*------------------------------------------------------------------------------
  2 Name:      TestTimestamp.java
  3 Project:   org.xmlBlasterProject:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 package org.xmlBlaster.test.contrib.dbwatcher;
  7 
  8 import java.text.SimpleDateFormat;
  9 import java.util.prefs.Preferences;
 10 
 11 
 12 import junit.framework.TestCase;
 13 import org.custommonkey.xmlunit.XMLTestCase;
 14 import org.xmlBlaster.contrib.I_Info;
 15 import org.xmlBlaster.contrib.db.I_DbPool;
 16 import org.xmlBlaster.contrib.dbwatcher.DbWatcher;
 17 import org.xmlBlaster.contrib.dbwatcher.Info;
 18 import org.xmlBlaster.contrib.dbwatcher.detector.I_ChangeDetector;
 19 import org.xmlBlaster.contrib.dbwatcher.detector.TimestampChangeDetector;
 20 
 21 import java.util.logging.Logger;
 22 
 23 import java.util.Map;
 24 import java.util.HashMap;
 25 
 26 
 27 /**
 28  * Test basic functionality. 
 29  * <p> 
 30  * To run most of the tests you need to have a databse (for example Oracle)
 31  * and XmlBlaster up and running.
 32  * </p>
 33  * <p>
 34  * The connection configuration (url, password etc.) is configured
 35  * as JVM property or in
 36  * {@link org.xmlBlaster.test.contrib.dbwatcher.TestResultSetToXmlConverter#createTest(I_Info, Map)}
 37  * and 
 38  * {@link org.xmlBlaster.test.contrib.dbwatcher.TestResultSetToXmlConverter#setUpDbPool(I_Info)}
 39  * </p> 
 40  *
 41  * @see DbWatcher
 42  * @author Marcel Ruff
 43  */
 44 public class TestTimestamp extends XMLTestCase {
 45     private static Logger log = Logger.getLogger(TestTimestamp.class.getName());
 46     private Preferences prefs;
 47     private I_Info info;
 48     private I_DbPool dbPool;
 49     private Map updateMap = new HashMap(); // collects received update messages
 50     private DbWatcher processor;
 51 
 52     /**
 53      * Start the test. 
 54      * <pre>
 55      * java -Ddb.password=secret junit.swingui.TestRunner -noloading org.xmlBlaster.test.contrib.dbwatcher.TestTimestamp
 56      * </pre>
 57      * @param args Command line settings
 58      */
 59     public static void main(String[] args) {
 60         // junit.swingui.TestRunner.run(TestResultSetToXmlConverter.class);
 61         
 62        TestTimestamp test = new TestTimestamp();
 63        try {
 64           // test.setUp();
 65           test.testReplaceDate();
 66           // test.tearDown();
 67           
 68        }
 69        catch (Exception ex) {
 70           ex.printStackTrace();
 71           fail("An exception occured: '" + ex.getMessage() + "-");
 72        }
 73     }
 74 
 75     /**
 76      * Default ctor. 
 77      */
 78     public TestTimestamp() {
 79     }
 80 
 81    /**
 82     * Constructor for TestResultSetToXmlConverter.
 83     * @param arg0
 84     */
 85     public TestTimestamp(String arg0) {
 86        super(arg0);
 87     }
 88 
 89     /**
 90      * Configure database access. 
 91      * @see TestCase#setUp()
 92      */
 93    protected void setUp() throws Exception {
 94       super.setUp();
 95       this.prefs = Preferences.userRoot();
 96       this.prefs.clear();
 97       this.info = new Info(this.prefs);
 98       this.dbPool = org.xmlBlaster.test.contrib.dbwatcher.TestResultSetToXmlConverter.setUpDbPool(info);
 99       this.processor = null;
100       try {
101          this.dbPool.update("DROP TABLE TEST_TS");
102       } catch(Exception e) {
103          log.warning(e.toString()); 
104       }
105    }
106 
107    /**
108     * Creates a DbWatcher instance and listens on MoM messages. 
109     * @see org.xmlBlaster.test.contrib.dbwatcher.TestResultSetToXmlConverter#createTest(I_Info, Map) 
110     */
111    private DbWatcher createTest(I_Info info, final Map updateMap) throws Exception {
112       return org.xmlBlaster.test.contrib.dbwatcher.TestResultSetToXmlConverter.createTest(info, updateMap);
113    }
114 
115    /*
116     * @see TestCase#tearDown()
117     */
118    protected void tearDown() throws Exception {
119       super.tearDown();
120        
121       if (this.processor != null) {
122          this.processor.shutdown();
123          this.processor = null;
124       }
125        
126       if (this.dbPool != null) {
127          try {
128             this.dbPool.update("DROP TABLE TEST_TS");
129          } catch(Exception e) {
130             log.warning(e.toString()); 
131          }
132          this.dbPool.shutdown();
133       }
134    }
135 
136    private void sleep(long millis) {
137       try { Thread.sleep(millis); } catch(Exception e) { /* Ignore */ }
138    }
139    
140    /**
141     * Check detection of changes on a table and deliver the change as
142     * pure event without XML dump.  
143     * @throws Exception Any type is possible
144     */
145    public final void testEmptyTableStates() throws Exception {
146 
147       this.prefs.put("changeDetector.class", "org.xmlBlaster.contrib.dbwatcher.detector.TimestampChangeDetector");
148       this.prefs.put("converter.class", "");
149       this.prefs.put("changeDetector.detectStatement", "SELECT MAX(TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SSXFF')) FROM TEST_TS");
150       this.prefs.put("changeDetector.timestampColName", "ts");
151       this.prefs.put("alertScheduler.pollInterval", "0"); // switch off
152       this.prefs.put("changeDetector.groupColName", "ICAO_ID");
153       this.prefs.put("converter.rootName", "myRootTag");
154       this.prefs.put("converter.addMeta", ""+true);
155       this.prefs.put("db.queryMeatStatement", "SELECT * FROM TEST_TS WHERE TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SSXFF') > '${oldTimestamp}' ORDER BY ICAO_ID");
156       this.prefs.put("mom.topicName", "db.change.event.${groupColValue}");
157       
158       this.processor = createTest(new Info(prefs), this.updateMap);
159       I_ChangeDetector changeDetector = processor.getChangeDetector();
160       
161       for (int i=0; i<2; i++) {
162          log.info("Testing no table ...");
163          changeDetector.checkAgain(null);
164          sleep(500);
165          assertEquals("Number of message is wrong", 0, this.updateMap.size());
166       }
167 
168       {
169       log.info("Now testing an empty table ...");
170       this.dbPool.update("CREATE TABLE TEST_TS (ts TIMESTAMP(9), colKey NUMBER(10,3), col1 VARCHAR(20), col2 NUMBER(12), ICAO_ID VARCHAR(10))");
171       changeDetector.checkAgain(null);
172       sleep(500);
173       assertEquals("Number of message is wrong", 1, this.updateMap.size());
174       String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
175       assertNotNull("No db.change.event.${groupColValue} message has arrived", xml);
176       assertEquals("", xml);
177       this.updateMap.clear();
178 
179       changeDetector.checkAgain(null);
180       sleep(500);
181       assertEquals("Number of message is wrong", 0, this.updateMap.size());
182       }
183 
184       {
185       log.info("Insert one row");
186       this.dbPool.update("INSERT INTO TEST_TS VALUES (CURRENT_TIMESTAMP, '1.1', '<Bla', '9000', 'EDDI')");
187       changeDetector.checkAgain(null);
188       sleep(500);
189       assertEquals("Number of message is wrong", 1, this.updateMap.size());
190       String xml = (String)this.updateMap.get("db.change.event.EDDI");
191       assertEquals("", xml);
192       this.updateMap.clear();
193 
194       changeDetector.checkAgain(null);
195       sleep(500);
196       assertEquals("Number of message is wrong", 0, this.updateMap.size());
197       }
198 
199       {
200          log.info("Update one row");
201          this.dbPool.update("UPDATE TEST_TS SET ts=CURRENT_TIMESTAMP, colKey='4.44' WHERE ICAO_ID='EDDI'");
202          changeDetector.checkAgain(null);
203          Thread.sleep(500);
204          assertEquals("Number of message is wrong", 1, this.updateMap.size());
205          String xml = (String)this.updateMap.get("db.change.event.EDDI");
206          assertNotNull("xml returned is null", xml);
207          assertEquals("", xml);
208          this.updateMap.clear();
209 
210          changeDetector.checkAgain(null);
211          sleep(500);
212          assertEquals("Number of message is wrong", 0, this.updateMap.size());
213       }
214 
215       // Is not detected by Timestamp poller!
216       {
217          log.info("Delete one row");
218          this.dbPool.update("DELETE FROM TEST_TS WHERE ICAO_ID='EDDI'");
219          changeDetector.checkAgain(null);
220          sleep(500);
221          assertEquals("Number of message is wrong", 0, this.updateMap.size());
222          // TODO: We don't know that EDDI was deleted
223          //String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
224          //assertNotNull("xml returned is null", xml);
225          //assertEquals("", xml);
226          this.updateMap.clear();
227 
228          changeDetector.checkAgain(null);
229          sleep(500);
230          assertEquals("Number of message is wrong", 0, this.updateMap.size());
231       }
232 
233       {
234          log.info("Drop a table");
235          this.dbPool.update("DROP TABLE TEST_TS");
236          changeDetector.checkAgain(null);
237          sleep(500);
238          assertEquals("Number of message is wrong", 1, this.updateMap.size());
239          String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
240          assertNotNull("xml returned is null", xml);
241          assertEquals("", xml);
242          this.updateMap.clear();
243 
244          changeDetector.checkAgain(null);
245          sleep(500);
246          assertEquals("Number of message is wrong", 0, this.updateMap.size());
247       }
248 
249       log.info("SUCCESS");
250    }
251 
252 
253    /**
254     * Checks if the conversion of the special token ${currentDate} is correct
255     */
256    public final void testReplaceDate() throws Exception {
257       // time='1157049798000' gives '2006-08-31 20:43:18.0'
258       // String       // '2005-11-25 12:48:00.0' "yyyy-MM-dd HH:mm:ss.0"
259 
260       long refTime = 1157049798000L;
261       String format = "yyyy-MM-dd HH:mm:ss.0";
262       
263       String txt = "${currentDate}=" + format;
264       SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
265       txt = "${currentDate}=yyyy-MM-dd HH:mm:ss.0";
266       String res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
267       assertEquals("date conversion is wrong", "2006-08-31 20:43:18.0", res);
268 
269       txt = "${currentDate}= " + format;
270       res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
271       assertEquals("date conversion is wrong", " 2006-08-31 20:43:18.0", res);
272       
273       txt = "${currentDate}";
274       res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
275       assertEquals("date conversion is wrong", "1157049798000", res);
276       
277       txt = "${currentDate}=";
278       res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
279       assertEquals("date conversion is wrong", "", res);
280       
281       txt = "currentDate";
282       res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
283       assertEquals("date conversion is wrong", "currentDate", res);
284       
285       txt = null;
286       res = TimestampChangeDetector.modifyMinStrIfDate(txt, refTime);
287       assertNull("must be null", res);
288 
289       txt = "${currentDate}=" + format;
290       res = TimestampChangeDetector.modifyMinStrIfDate(txt, 0L);
291       long currentTime = dateFormatter.parse(res).getTime();
292       String res2 = TimestampChangeDetector.modifyMinStrIfDate(txt, currentTime);
293       assertEquals("Wrong data conversion", res, res2);
294       log.info("SUCCESS");
295    }
296    
297    /**
298     * Check detection of changes on a table and deliver the change as XML. 
299     * @throws Exception Any type is possible
300     */
301    public final void testQueryMeatTableStates() throws Exception {
302       log.info("Start testQueryMeatTableStates()");
303 
304       this.prefs.put("changeDetector.class", "org.xmlBlaster.contrib.dbwatcher.detector.TimestampChangeDetector");
305       this.prefs.put("changeDetector.detectStatement", "SELECT MAX(TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SSXFF')) FROM TEST_TS");
306       this.prefs.put("changeDetector.timestampColName", "ts");
307       this.prefs.put("alertScheduler.pollInterval", "0"); // switch off
308       this.prefs.put("changeDetector.groupColName", "ICAO_ID");
309       this.prefs.put("converter.rootName", "myRootTag");
310       this.prefs.put("converter.addMeta", ""+true);
311       this.prefs.put("db.queryMeatStatement", "SELECT * FROM TEST_TS WHERE TO_CHAR(ts, 'YYYY-MM-DD HH24:MI:SSXFF') > '${oldTimestamp}' ORDER BY ICAO_ID");
312       this.prefs.put("mom.topicName", "db.change.event.${groupColValue}");
313       
314       this.processor = createTest(new Info(prefs), this.updateMap);
315       I_ChangeDetector changeDetector = processor.getChangeDetector();
316       
317       for (int i=0; i<2; i++) {
318          log.info("Testing no table ...");
319          changeDetector.checkAgain(null);
320          sleep(500);
321          assertEquals("Number of message is wrong", 0, this.updateMap.size());
322       }
323 
324       {
325       log.info("Now testing an empty table ...");
326       this.dbPool.update("CREATE TABLE TEST_TS (ts TIMESTAMP(9), colKey NUMBER(10,3), col1 VARCHAR(20), col2 NUMBER(12), ICAO_ID VARCHAR(10))");
327       changeDetector.checkAgain(null);
328       sleep(500);
329       assertEquals("Number of message is wrong", 1, this.updateMap.size());
330       String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
331       assertNotNull("No db.change.event.${groupColValue} message has arrived", xml);
332       assertXpathNotExists("/myRootTag/row[@num='0']", xml);
333       assertXpathEvaluatesTo("CREATE", "/myRootTag/desc/command/text()", xml);
334       this.updateMap.clear();
335 
336       changeDetector.checkAgain(null);
337       sleep(500);
338       assertEquals("Number of message is wrong", 0, this.updateMap.size());
339       }
340 
341       {
342       log.info("Insert one row");
343       this.dbPool.update("INSERT INTO TEST_TS VALUES (CURRENT_TIMESTAMP, '1.1', '<Bla', '9000', 'EDDI')");
344       changeDetector.checkAgain(null);
345       sleep(500);
346       assertEquals("Number of message is wrong", 1, this.updateMap.size());
347       String xml = (String)this.updateMap.get("db.change.event.EDDI");
348       assertNotNull("xml returned is null", xml);
349       assertXpathEvaluatesTo("UPDATE", "/myRootTag/desc/command/text()", xml);
350       assertXpathEvaluatesTo("<Bla", "/myRootTag/row[@num='0']/col[@name='COL1']/text()", xml);
351       //assertTrue(xml.indexOf("Bla-1.1") != -1);
352       this.updateMap.clear();
353 
354       writeToFile("db.change.event.INSERT", xml);
355 
356       changeDetector.checkAgain(null);
357       sleep(500);
358       assertEquals("Number of message is wrong", 0, this.updateMap.size());
359       }
360 
361       {
362          log.info("Update one row");
363          this.dbPool.update("UPDATE TEST_TS SET ts=CURRENT_TIMESTAMP, colKey='4.44' WHERE ICAO_ID='EDDI'");
364          changeDetector.checkAgain(null);
365          Thread.sleep(500);
366          assertEquals("Number of message is wrong", 1, this.updateMap.size());
367          String xml = (String)this.updateMap.get("db.change.event.EDDI");
368          assertNotNull("xml returned is null", xml);
369          assertXpathEvaluatesTo("UPDATE", "/myRootTag/desc/command/text()", xml);
370          assertXpathEvaluatesTo("4.44", "/myRootTag/row[@num='0']/col[@name='COLKEY']/text()", xml);
371          this.updateMap.clear();
372 
373          writeToFile("db.change.event.UPDATE", xml);
374 
375          changeDetector.checkAgain(null);
376          sleep(500);
377          assertEquals("Number of message is wrong", 0, this.updateMap.size());
378       }
379 
380       // Is not detected by Timestamp poller!
381       {
382          log.info("Delete one row");
383          this.dbPool.update("DELETE FROM TEST_TS WHERE ICAO_ID='EDDI'");
384          changeDetector.checkAgain(null);
385          sleep(500);
386          assertEquals("Number of message is wrong", 0, this.updateMap.size());
387          // TODO: We don't know that EDDI was deleted
388          //String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
389          //assertNotNull("xml returned is null", xml);
390          this.updateMap.clear();
391 
392          changeDetector.checkAgain(null);
393          sleep(500);
394          assertEquals("Number of message is wrong", 0, this.updateMap.size());
395       }
396 
397       {
398          log.info("Drop a table");
399          this.dbPool.update("DROP TABLE TEST_TS");
400          changeDetector.checkAgain(null);
401          sleep(500);
402          assertEquals("Number of message is wrong", 1, this.updateMap.size());
403          String xml = (String)this.updateMap.get("db.change.event.${groupColValue}");
404          assertNotNull("xml returned is null", xml);
405          assertXpathEvaluatesTo("DROP", "/myRootTag/desc/command/text()", xml);
406          assertXpathNotExists("/myRootTag/row[@num='0']", xml);
407          this.updateMap.clear();
408 
409          writeToFile("db.change.event.DROP", xml);
410 
411          changeDetector.checkAgain(null);
412          sleep(500);
413          assertEquals("Number of message is wrong", 0, this.updateMap.size());
414       }
415 
416       log.info("SUCCESS");
417    }
418 
419    /**
420     * Dump to file. 
421     * @param topic The file name body
422     * @param xml The file content
423     * @throws Exception IOException
424     */
425    public static void writeToFile(String topic, String xml) throws Exception {
426       java.io.File f = new java.io.File(System.getProperty("java.io.tmpdir")+System.getProperty("file.separator")+topic+".xml");
427       java.io.FileOutputStream to = new java.io.FileOutputStream(f);
428       to.write(xml.getBytes());
429       to.close();
430    }
431 }


syntax highlighted by Code2HTML, v. 0.9.1