View Javadoc
1   package com.atlassian.activeobjects.backup;
2   
3   import com.atlassian.activeobjects.test.model.Model;
4   import com.google.common.collect.ImmutableList;
5   import com.google.common.collect.ImmutableMap;
6   import net.java.ao.DatabaseProvider;
7   import net.java.ao.db.H2DatabaseProvider;
8   import net.java.ao.db.HSQLDatabaseProvider;
9   import net.java.ao.db.MsJdbcSQLServerDatabaseProvider;
10  import net.java.ao.db.MySQLDatabaseProvider;
11  import net.java.ao.db.OracleDatabaseProvider;
12  import net.java.ao.db.PostgreSQLDatabaseProvider;
13  import net.java.ao.db.SQLServerDatabaseProvider;
14  import org.custommonkey.xmlunit.SimpleNamespaceContext;
15  import org.custommonkey.xmlunit.XMLUnit;
16  import org.custommonkey.xmlunit.XpathEngine;
17  import org.custommonkey.xmlunit.exceptions.XpathException;
18  import org.junit.After;
19  import org.junit.Before;
20  import org.w3c.dom.Document;
21  import org.w3c.dom.Node;
22  import org.w3c.dom.NodeList;
23  
24  import java.sql.Types;
25  
26  import static net.java.ao.Common.fuzzyTypeCompare;
27  import static org.custommonkey.xmlunit.XMLAssert.assertEquals;
28  import static org.hamcrest.MatcherAssert.assertThat;
29  import static org.hamcrest.Matchers.is;
30  
31  public abstract class ActiveObjectsBackupDataSetup extends AbstractTestActiveObjectsBackup {
32      protected static final String H2 = "/com/atlassian/activeobjects/backup/h2.xml";
33      protected static final String HSQL = "/com/atlassian/activeobjects/backup/hsql.xml";
34      protected static final String HSQL_EMPTY = "/com/atlassian/activeobjects/backup/hsql_empty.xml";
35      protected static final String MYSQL = "/com/atlassian/activeobjects/backup/mysql.xml";
36      protected static final String ORACLE = "/com/atlassian/activeobjects/backup/oracle.xml";
37      protected static final String LEGACY_ORACLE = "/com/atlassian/activeobjects/backup/legacy_oracle.xml";
38      protected static final String POSTGRES = "/com/atlassian/activeobjects/backup/postgres.xml";
39      protected static final String SQLSERVER_JTDS = "/com/atlassian/activeobjects/backup/sqlserver_jtds.xml";
40      protected static final String SQLSERVER_MSJDBC = "/com/atlassian/activeobjects/backup/sqlserver_msjdbc.xml";
41  
42      private Model model;
43  
44      protected final void testBackup(String xml, Iterable<BackupData> data) throws Exception {
45          final String xmlBackup = read(xml);
46  
47          checkXmlBackup(xmlBackup, data);
48  
49          restore(xmlBackup);
50          restore(xmlBackup); // if we don't clean up correctly doing an second restore in a row will fail
51  
52          assertDataPresent();
53  
54          final String secondXmlBackup = save();
55  
56          checkXmlBackup(secondXmlBackup, getCurrentDatabaseData());
57      }
58  
59      private Iterable<BackupData> getCurrentDatabaseData() {
60          final DatabaseProvider provider = entityManager.getProvider();
61          if (provider.getClass() == H2DatabaseProvider.class) {
62              return H2_DATA;
63          } else if (provider.getClass() == HSQLDatabaseProvider.class) {
64              return HSQL_DATA;
65          } else if (provider.getClass() == MySQLDatabaseProvider.class) {
66              return MYSQL_DATA;
67          } else if (provider.getClass() == PostgreSQLDatabaseProvider.class) {
68              return POSTGRES_DATA;
69          } else if (provider.getClass() == OracleDatabaseProvider.class) {
70              return ORACLE_DATA;
71          } else if (provider.getClass() == SQLServerDatabaseProvider.class) {
72              return SQL_SERVER_DATA_JTDS;
73          } else if (provider.getClass() == MsJdbcSQLServerDatabaseProvider.class) {
74              return SQL_SERVER_DATA_MSJDBC;
75          } else {
76              throw new IllegalStateException("Can't figure out which DB we're testing against!");
77          }
78      }
79  
80      protected void checkXmlBackup(String xmlBackup, Iterable<BackupData> data) throws Exception {
81          final XpathEngine engine = newXpathEngine();
82          final Document doc = XMLUnit.buildControlDocument(xmlBackup);
83  
84          for (BackupData bd : data) {
85              assertHasBackupData(engine, doc, bd);
86          }
87      }
88  
89      private void assertHasBackupData(XpathEngine xpathEngine, Document xmlBackupDoc, BackupData bd) throws Exception {
90          assertHasColumn(xpathEngine, xmlBackupDoc, bd.table, bd.column, bd.primaryKey, bd.autoIncrement, bd.sqlType);
91      }
92  
93      private void assertHasColumn(XpathEngine xpathEngine, Document xmlBackupDoc, String tableName, String columnName, boolean pK, boolean autoIncrement, SqlType sqlType) throws XpathException {
94          NodeList tableNodes = xpathEngine.getMatchingNodes("/ao:backup/ao:table[@name='" + tableName + "']/ao:column[@name='" + columnName + "']", xmlBackupDoc);
95          assertEquals(1, tableNodes.getLength());
96          Node table = tableNodes.item(0);
97          assertAttributeEquals("Expected " + tableName + "." + columnName + " to " + (pK ? "" : "NOT ") + "be a primary key.", table, "primaryKey", pK);
98          assertAttributeEquals("Expected " + tableName + "." + columnName + " to " + (autoIncrement ? "" : "NOT ") + "be auto increment.", table, "autoIncrement", autoIncrement);
99  
100         assertThat("Expected " + tableName + "." + columnName + " to be of SQL Type: " + sqlType.type,
101                 fuzzyTypeCompare(sqlType.type, Integer.valueOf(attributeValue(table, "sqlType"))), is(true));
102 
103         if (sqlType.precision != null) {
104             assertAttributeEquals("Expected " + tableName + "." + columnName + " to have precision: " + sqlType.precision, table, "precision", sqlType.precision);
105         }
106         if (sqlType.scale != null) {
107             assertAttributeEquals("Expected " + tableName + "." + columnName + " to have scale: " + sqlType.scale, table, "scale", sqlType.scale);
108         }
109 
110         assertEquals(1, xpathEngine.getMatchingNodes("/ao:backup/ao:data[@tableName='" + tableName + "']/ao:column[@name='" + columnName + "']", xmlBackupDoc).getLength());
111     }
112 
113     private void assertAttributeEquals(String message, Node table, String attribute, Object expected) {
114         assertEquals(message, String.valueOf(expected), attributeValue(table, attribute));
115     }
116 
117     private XpathEngine newXpathEngine() {
118         XpathEngine engine = XMLUnit.newXpathEngine();
119         engine.setNamespaceContext(new SimpleNamespaceContext(ImmutableMap.of("ao", "http://www.atlassian.com/ao")));
120         return engine;
121     }
122 
123     private String attributeValue(Node node, String name) {
124         return node.getAttributes().getNamedItem(name).getNodeValue();
125     }
126 
127     private void assertDataPresent() {
128         model.checkAuthors();
129         model.checkBooks();
130     }
131 
132     @Before
133     public void setUpModel() {
134         model = new Model(entityManager);
135         model.emptyDatabase();
136     }
137 
138     @After
139     public void tearDownModel() {
140         model = null;
141     }
142 
143     private static final class BackupData {
144         public final String table, column;
145         public final boolean primaryKey;
146         public final boolean autoIncrement;
147         public final SqlType sqlType;
148 
149         public BackupData(String table, String column, boolean primaryKey, boolean autoIncrement, SqlType sqlType) {
150             this.table = table;
151             this.column = column;
152             this.sqlType = sqlType;
153             this.primaryKey = primaryKey;
154             this.autoIncrement = autoIncrement;
155         }
156 
157         static BackupData of(String table, String column, SqlType sqlType) {
158             return of(table, column, sqlType, false, false);
159         }
160 
161         static BackupData of(String table, String column, SqlType sqlType, boolean primaryKey, boolean autoIncrement) {
162             return new BackupData(table, column, primaryKey, autoIncrement, sqlType);
163         }
164 
165         static BackupData of(BackupData data, SqlType sqlType) {
166             return of(data.table, data.column, sqlType, data.primaryKey, data.autoIncrement);
167         }
168     }
169 
170     private static final class SqlType {
171         public final int type;
172         public final Integer precision;
173         public final Integer scale;
174 
175         public SqlType(int type, Integer precision, Integer scale) {
176             this.type = type;
177             this.precision = precision;
178             this.scale = scale;
179         }
180 
181         static SqlType of(int type) {
182             return of(type, null);
183         }
184 
185         private static SqlType of(int type, Integer precision) {
186             return of(type, precision, null);
187         }
188 
189         private static SqlType of(int type, Integer precision, Integer scale) {
190             return new SqlType(type, precision, scale);
191         }
192     }
193 
194     protected static final BackupData AUTHORSHIP_AUTHOR_ID = BackupData.of("AO_000000_AUTHORSHIP", "AUTHOR_ID", SqlType.of(Types.INTEGER));
195     protected static final BackupData AUTHORSHIP_BOOK_ID = BackupData.of("AO_000000_AUTHORSHIP", "BOOK_ID", SqlType.of(Types.BIGINT));
196     protected static final BackupData AUTHORSHIP_ID = BackupData.of("AO_000000_AUTHORSHIP", "ID", SqlType.of(Types.INTEGER), true, true);
197 
198     protected static final BackupData BOOK_ABSTRACT = BackupData.of("AO_000000_BOOK", "ABSTRACT", SqlType.of(Types.LONGVARCHAR));
199     protected static final BackupData BOOK_ISBN = BackupData.of("AO_000000_BOOK", "ISBN", SqlType.of(Types.BIGINT), true, false);
200     protected static final BackupData BOOK_READ = BackupData.of("AO_000000_BOOK", "IS_READ", SqlType.of(Types.BOOLEAN));
201     protected static final BackupData BOOK_PAGES = BackupData.of("AO_000000_BOOK", "NUMBER_OF_PAGES", SqlType.of(Types.INTEGER));
202     protected static final BackupData BOOK_PRICE = BackupData.of("AO_000000_BOOK", "PRICE", SqlType.of(Types.DOUBLE));
203     protected static final BackupData BOOK_PUBLISHED = BackupData.of("AO_000000_BOOK", "PUBLISHED", SqlType.of(Types.TIMESTAMP));
204     protected static final BackupData BOOK_TITLE = BackupData.of("AO_000000_BOOK", "TITLE", SqlType.of(Types.VARCHAR, 255));
205 
206     protected static final BackupData AUTHOR_NAME = BackupData.of("AO_000000_LONG_NAME_TO_AUTHOR", "NAME", SqlType.of(Types.VARCHAR, 60));
207     protected static final BackupData AUTHOR_ID = BackupData.of("AO_000000_LONG_NAME_TO_AUTHOR", "ID", SqlType.of(Types.INTEGER), true, true);
208 
209     protected static Iterable<BackupData> H2_DATA = ImmutableList.of(
210             AUTHORSHIP_AUTHOR_ID,
211             AUTHORSHIP_BOOK_ID,
212             AUTHORSHIP_ID,
213 
214             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.CLOB)),
215             BOOK_ISBN,
216             BOOK_READ,
217             BOOK_PAGES,
218             BOOK_PRICE,
219             BOOK_PUBLISHED,
220             BOOK_TITLE,
221 
222             AUTHOR_NAME,
223             AUTHOR_ID
224     );
225 
226     protected static Iterable<BackupData> HSQL_DATA = ImmutableList.of(
227             AUTHORSHIP_AUTHOR_ID,
228             AUTHORSHIP_BOOK_ID,
229             AUTHORSHIP_ID,
230 
231             BOOK_ABSTRACT,
232             BOOK_ISBN,
233             BOOK_READ,
234             BOOK_PAGES,
235             BOOK_PRICE,
236             BOOK_PUBLISHED,
237             BOOK_TITLE,
238 
239             AUTHOR_NAME,
240             AUTHOR_ID
241     );
242 
243     protected static Iterable<BackupData> MYSQL_DATA = ImmutableList.of(
244             AUTHORSHIP_AUTHOR_ID,
245             AUTHORSHIP_BOOK_ID,
246             AUTHORSHIP_ID,
247 
248             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.LONGVARCHAR)),
249             BOOK_ISBN,
250             BackupData.of(BOOK_READ, SqlType.of(Types.BIT)),
251             BOOK_PAGES,
252             BOOK_PRICE,
253             BOOK_PUBLISHED,
254             BOOK_TITLE,
255 
256             AUTHOR_NAME,
257             AUTHOR_ID
258     );
259 
260     protected static Iterable<BackupData> POSTGRES_DATA = ImmutableList.of(
261             AUTHORSHIP_AUTHOR_ID,
262             AUTHORSHIP_BOOK_ID,
263             AUTHORSHIP_ID,
264 
265             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.VARCHAR)),
266             BOOK_ISBN,
267             BackupData.of(BOOK_READ, SqlType.of(Types.BIT)),
268             BOOK_PAGES,
269             BOOK_PRICE,
270             BOOK_PUBLISHED,
271             BOOK_TITLE,
272 
273             AUTHOR_NAME,
274             AUTHOR_ID
275     );
276 
277     protected static Iterable<BackupData> ORACLE_DATA = ImmutableList.of(
278             BackupData.of(AUTHORSHIP_AUTHOR_ID, SqlType.of(Types.NUMERIC, 11)),
279             BackupData.of(AUTHORSHIP_BOOK_ID, SqlType.of(Types.NUMERIC, 20)),
280             BackupData.of(AUTHORSHIP_ID, SqlType.of(Types.NUMERIC, 11)),
281 
282             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.CLOB)),
283             BackupData.of(BOOK_ISBN, SqlType.of(Types.NUMERIC, 20)),
284             BackupData.of(BOOK_READ, SqlType.of(Types.NUMERIC, 1)),
285             BackupData.of(BOOK_PAGES, SqlType.of(Types.NUMERIC, 11)),
286             BackupData.of(BOOK_PRICE, SqlType.of(Types.NUMERIC, 126)),
287             BOOK_PUBLISHED,
288             BOOK_TITLE,
289 
290             AUTHOR_NAME,
291             BackupData.of(AUTHOR_ID, SqlType.of(Types.NUMERIC, 11))
292     );
293 
294     protected static Iterable<BackupData> LEGACY_ORACLE_DATA = ImmutableList.of(
295             BackupData.of(AUTHORSHIP_AUTHOR_ID, SqlType.of(Types.NUMERIC, 11)),
296             BackupData.of(AUTHORSHIP_BOOK_ID, SqlType.of(Types.NUMERIC, 20)),
297             BackupData.of(AUTHORSHIP_ID, SqlType.of(Types.NUMERIC, 11)),
298 
299             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.CLOB)),
300             BackupData.of(BOOK_ISBN, SqlType.of(Types.NUMERIC, 20)),
301             BackupData.of(BOOK_READ, SqlType.of(Types.NUMERIC, 1)),
302             BackupData.of(BOOK_PAGES, SqlType.of(Types.NUMERIC, 11)),
303             BackupData.of(BOOK_PRICE, SqlType.of(Types.NUMERIC, 32, 16)),
304             BOOK_PUBLISHED,
305             BOOK_TITLE,
306 
307             AUTHOR_NAME,
308             BackupData.of(AUTHOR_ID, SqlType.of(Types.NUMERIC, 11))
309     );
310 
311     protected static Iterable<BackupData> SQL_SERVER_DATA_JTDS = ImmutableList.of(
312             AUTHORSHIP_AUTHOR_ID,
313             AUTHORSHIP_BOOK_ID,
314             AUTHORSHIP_ID,
315 
316             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.CLOB)),
317             BOOK_ISBN,
318             BackupData.of(BOOK_READ, SqlType.of(Types.BIT)),
319             BOOK_PAGES,
320             BOOK_PRICE,
321             BOOK_PUBLISHED,
322             BOOK_TITLE,
323 
324             AUTHOR_NAME,
325             AUTHOR_ID
326     );
327 
328     protected static Iterable<BackupData> SQL_SERVER_DATA_MSJDBC = ImmutableList.of(
329             AUTHORSHIP_AUTHOR_ID,
330             AUTHORSHIP_BOOK_ID,
331             AUTHORSHIP_ID,
332 
333             BackupData.of(BOOK_ABSTRACT, SqlType.of(Types.NVARCHAR)),
334             BOOK_ISBN,
335             BackupData.of(BOOK_READ, SqlType.of(Types.BIT)),
336             BOOK_PAGES,
337             BOOK_PRICE,
338             BOOK_PUBLISHED,
339             BOOK_TITLE,
340 
341             AUTHOR_NAME,
342             AUTHOR_ID
343     );
344 }