1   package org.melati.poem.test;
2   
3   import java.io.FileNotFoundException;
4   import java.io.IOException;
5   import java.io.InputStream;
6   import java.util.Enumeration;
7   import java.util.Properties;
8   
9   import org.melati.poem.AccessToken;
10  import org.melati.poem.Database;
11  import org.melati.poem.DatabaseInitialisationPoemException;
12  import org.melati.poem.Group;
13  import org.melati.poem.Persistent;
14  import org.melati.poem.PoemDatabase;
15  import org.melati.poem.PoemDatabaseFactory;
16  import org.melati.poem.PoemTask;
17  import org.melati.poem.Table;
18  import org.melati.poem.User;
19  import org.melati.poem.transaction.WriteCommittedException;
20  
21  import junit.framework.Test;
22  import junit.framework.TestCase;
23  
24  /**
25   * FIXME Postgresql seems to think that the committed transaction is in a funny state. 
26   * 
27   * @author timp
28   * @since 19-January-2007
29   */
30  public class DatabasePerformInCommittedTransactionTest 
31     extends TestCase implements Test {
32  
33    /**
34     * The name of the test case
35     */
36  
37    private PoemDatabase db = null;
38  
39    private String dbName = "melatijunit";
40    
41    private AccessToken userToRunAs;
42    
43    boolean skipTest = false;
44  
45    /**
46     * Constructor.
47     */
48    public DatabasePerformInCommittedTransactionTest() {
49      super();
50    }
51  
52    /**
53     * Constructor.
54     * 
55     * @param name
56     */
57    public DatabasePerformInCommittedTransactionTest(String name) {
58      super(name);
59    }
60  
61    String dbUrl = null;
62    /**
63     * @see TestCase#setUp()
64     */
65    protected void setUp() throws Exception {
66      super.setUp();
67      setDbName(getDbName());
68      setDb(getDbName());
69    }
70  
71    /**
72     * @see TestCase#tearDown()
73     */
74    protected void tearDown() throws Exception {
75      checkDbUnchanged();
76    }
77  
78    protected void checkDbUnchanged() {
79      getDb().inSession(AccessToken.root,
80          new PoemTask() {
81            public void run() {
82              if (dbName.equals("poemtest")) {
83                poemtestUnchanged();
84              } 
85              if (dbName.equals("melatijunit")) {
86                melatijunitUnchanged();
87              }
88            }
89          });
90  
91    }
92    protected void melatijunitUnchanged() { 
93      if (!getDb().getDbms().canDropColumns()) {
94        return;
95      }
96      assertEquals(0, getDb().getSettingTable().count());
97      assertEquals(1, getDb().getGroupTable().count());
98      assertEquals(1, getDb().getGroupMembershipTable().count());
99      assertEquals(5, getDb().getCapabilityTable().count());
100     assertEquals(1, getDb().getGroupCapabilityTable().count());
101     assertEquals(3, getDb().getTableCategoryTable().count());
102     assertEquals(2, getDb().getUserTable().count());
103     assertEquals(69, getDb().getColumnInfoTable().count());
104     assertEquals(9, getDb().getTableInfoTable().count());
105   }
106   protected void poemtestUnchanged() { 
107     assertEquals(0, getDb().getSettingTable().count());
108     assertEquals(1, getDb().getGroupTable().count());
109     assertEquals(1, getDb().getGroupMembershipTable().count());
110     assertEquals(5, getDb().getCapabilityTable().count());
111     assertEquals(1, getDb().getGroupCapabilityTable().count());
112     assertEquals(4, getDb().getTableCategoryTable().count());
113     assertEquals(2, getDb().getUserTable().count());
114     //dumpTable(getDb().getColumnInfoTable());
115     // Until table.dropColumnAndCommit() arrives...
116     assertEquals(147, getDb().getColumnInfoTable().count());
117     assertEquals(23, getDb().getTableInfoTable().count());
118 
119   }
120   protected void dumpTable(Table t) {
121     Enumeration them = t.selection();
122     while (them.hasMoreElements()) {
123       Persistent it = (Persistent)them.nextElement();
124       System.err.println(it.getTroid() + " " + it.getCooked("name") + " " +
125           it.getTable().getName());
126     }
127     
128   }
129   /**
130    * @return Returns the dbName.
131    */
132   protected String getDbName() {
133     return this.dbName;
134   }
135 
136   /**
137    * @param dbName
138    *          The dbName to set.
139    */
140   protected void setDbName(String dbName) {
141     this.dbName = dbName;
142   }
143 
144   /**
145    * @return Returns the db.
146    */
147   public PoemDatabase getDb() {
148     return db;
149   }
150 
151   /**
152    * @param dbName the name of the db to set
153    */
154   public void setDb(String dbName) {
155     if (dbName == null)
156       throw new NullPointerException();
157     try {
158       db = (PoemDatabase)getDatabase(dbName);
159     } catch (DatabaseInitialisationPoemException e) {
160       e.printStackTrace();
161       fail(e.getMessage());
162     }
163   }
164 
165   /**
166    * @param name the name of the logical database
167    * @return a database with that name 
168    */
169   public Database getDatabase(String name){ 
170     Properties defs = databaseDefs();
171     String pref = "org.melati.poem.test.PoemTestCase." + name + ".";
172     if (PoemTestCase.getOrDie(defs, pref + "dbmsclass").indexOf("Postgres") > 0) skipTest = true;
173 
174     return PoemDatabaseFactory.getDatabase(name,
175             PoemTestCase.getOrDie(defs, pref + "url"), 
176             PoemTestCase.getOrDie(defs, pref + "user"),
177             PoemTestCase.getOrDie(defs, pref + "password"),
178             PoemTestCase.getOrDie(defs, pref + "class"),
179             PoemTestCase.getOrDie(defs, pref + "dbmsclass"),
180             new Boolean(PoemTestCase.getOrDie(defs, pref + "addconstraints")).booleanValue(),
181             new Boolean(PoemTestCase.getOrDie(defs, pref + "logsql")).booleanValue(),
182             new Boolean(PoemTestCase.getOrDie(defs, pref + "logcommits")).booleanValue(),
183             new Integer(PoemTestCase.getOrDie(defs, pref + "maxtransactions")).intValue());
184   }
185 
186   /** Properties, named for this class. */
187   public static Properties databaseDefs = null;
188   /**
189    * @returnthe databse defs
190    */
191   public  Properties databaseDefs() {
192     if (databaseDefs == null)
193       databaseDefs = getProperties();
194     return databaseDefs;
195   }
196   /**
197    * @return a properties object
198    */
199   public Properties getProperties() {
200     String className = "org.melati.poem.test.PoemTestCase";
201     String name = className + ".properties";
202     InputStream is = this.getClass().getResourceAsStream(name);
203 
204     if (is == null)
205       throw new RuntimeException(new FileNotFoundException(name + ": is it in CLASSPATH?"));
206 
207     Properties them = new Properties();
208     try {
209       them.load(is);
210     } catch (IOException e) {
211       throw new RuntimeException(new IOException("Corrupt properties file `" + name + "': " +
212       e.getMessage()));
213     }
214     return them;
215   }
216 
217   
218   /**
219    * @return the user
220    */
221   public AccessToken getUserToRunAs() {
222     if (userToRunAs == null) return AccessToken.root;
223     return userToRunAs;
224   }
225 
226   /**
227    * @param userToRunAs the user to set
228    */
229   public void setUserToRunAs(AccessToken userToRunAs) {
230     if (userToRunAs == null) 
231       this.userToRunAs = AccessToken.root;
232     else
233       this.userToRunAs = userToRunAs;
234   }
235 
236   /**
237    * @see org.melati.poem.Database#inCommittedTransaction(AccessToken, PoemTask)
238    */
239   public void testInCommittedTransaction() {
240     PoemTask doNothing = new PoemTask() {
241       public void run() {
242       }
243     };
244     getDb().inCommittedTransaction(AccessToken.root, doNothing);
245     
246   }
247 
248   /**
249    * @see org.melati.poem.Database#inCommittedTransaction(AccessToken, PoemTask)
250    */
251   public void testReadInCommittedTransaction() {
252     if (skipTest) return;
253     PoemTask read = new PoemTask() {
254       public void run() {
255         assertEquals("Melati guest user",
256                 ((User)getDb().getUserTable().getObject(new Integer(0))).getName());
257       }
258     };
259 
260     getDb().inCommittedTransaction(AccessToken.root, read);
261     getDb().uncache();
262     getDb().inCommittedTransaction(AccessToken.root, read);
263     
264   }
265   
266   /**
267    * @see org.melati.poem.Database#inCommittedTransaction(AccessToken, PoemTask)
268    */
269   public void testUpdateInCommittedTransaction() {
270     if (skipTest) return;
271     PoemTask modify = new PoemTask() {
272       public void run() {
273         try { 
274           getDb().guestUser().setName(getDb().guestUser().getName());
275           fail("Should have blown up");
276         } catch (WriteCommittedException e ) { 
277           e = null;
278         }
279       }
280     };
281     getDb().inCommittedTransaction(AccessToken.root, modify);
282     
283   }
284   
285   /**
286    * @see org.melati.poem.Database#inCommittedTransaction(AccessToken, PoemTask)
287    */
288   public void testDeleteInCommittedTransaction() {
289     if (skipTest) return;
290     PoemTask modify = new PoemTask() {
291       public void run() {
292         try { 
293           getDb().guestUser().delete_unsafe();
294           fail("Should have blown up");
295         } catch (WriteCommittedException e ) { 
296           e = null;
297         }
298       }
299     };
300     getDb().inCommittedTransaction(AccessToken.root, modify);
301     
302   }
303   
304   /**
305    * It might be a good idea to handle this more elegantly than by throwing NPE. 
306    * @see org.melati.poem.Database#inCommittedTransaction(AccessToken, PoemTask)
307    */
308   public void testCreateInCommittedTransaction() {
309     if (skipTest) return;
310     PoemTask create = new PoemTask() {
311       public void run() {
312         try { 
313           Group g = (Group)getDb().getGroupTable().newPersistent();
314           g.setName("failure");
315           g.makePersistent();
316           fail("Should have blown up");
317         } catch (NullPointerException e ) { 
318           e = null;
319         }
320       }
321     };
322     getDb().inCommittedTransaction(AccessToken.root, create);
323     create = new PoemTask() {
324       public void run() {
325         try { 
326           getDb().getGroupTable().ensure("failure");
327           fail("Should have blown up");
328         } catch (NullPointerException e ) { 
329           e = null;
330         }
331       }
332     };
333   }
334   
335   /**
336    * @see org.melati.poem.Database#toString()
337    */
338   public void testToString() {
339     PoemDatabase d = new PoemDatabase();
340     assertEquals("unconnected database", d.toString());
341   }
342   
343   /**
344    * Test troidSelection uses committed transaction.
345    * FIXME Relies upon session
346    */
347   public void testTableTroidSelection() {
348     //Enumeration en = getDb().getUserTable().troidSelection(
349     //        getDb().getUserTable().troidColumn().fullQuotedName() + "=0",null, false);
350     //assertEquals(2, EnumUtils.vectorOf(en).size());
351   }
352   
353   /**
354    * Test that committed transaction is used.
355    */
356   public void testTableCount() {
357     if (skipTest) return;
358     getDb().setLogSQL(true);
359     assertEquals(1, getDb().getGroupTable().count());
360     getDb().setLogSQL(false);
361     assertEquals(1, getDb().getGroupTable().count(null, true));
362     
363   }
364 }