001: /*
002: * HA-JDBC: High-Availability JDBC
003: * Copyright (c) 2004-2007 Paul Ferraro
004: *
005: * This library is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU Lesser General Public License as published by the
007: * Free Software Foundation; either version 2.1 of the License, or (at your
008: * option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
013: * for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public License
016: * along with this library; if not, write to the Free Software Foundation,
017: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * Contact: ferraro@users.sourceforge.net
020: */
021: package net.sf.hajdbc.sync;
022:
023: import java.sql.Connection;
024: import java.sql.PreparedStatement;
025: import java.sql.ResultSet;
026: import java.sql.SQLException;
027: import java.sql.Statement;
028: import java.sql.Types;
029: import java.util.Arrays;
030: import java.util.Collections;
031: import java.util.concurrent.ExecutorService;
032: import java.util.concurrent.Executors;
033:
034: import net.sf.hajdbc.ColumnProperties;
035: import net.sf.hajdbc.Database;
036: import net.sf.hajdbc.DatabaseMetaDataCache;
037: import net.sf.hajdbc.DatabaseProperties;
038: import net.sf.hajdbc.Dialect;
039: import net.sf.hajdbc.ForeignKeyConstraint;
040: import net.sf.hajdbc.SequenceProperties;
041: import net.sf.hajdbc.SynchronizationContext;
042: import net.sf.hajdbc.SynchronizationStrategy;
043: import net.sf.hajdbc.TableProperties;
044:
045: import org.easymock.EasyMock;
046: import org.testng.annotations.DataProvider;
047: import org.testng.annotations.Test;
048:
049: /**
050: * @author Paul Ferraro
051: */
052: @SuppressWarnings("nls")
053: public class TestFullSynchronizationStrategy implements
054: SynchronizationStrategy {
055: private SynchronizationStrategy strategy = new FullSynchronizationStrategy();
056:
057: @DataProvider(name="context")
058: Object[][] contextProvider() {
059: return new Object[][] { new Object[] { EasyMock
060: .createStrictMock(SynchronizationContext.class) } };
061: }
062:
063: @Override
064: @SuppressWarnings("unchecked")
065: @Test(dataProvider="context")
066: public <D> void synchronize(SynchronizationContext<D> context)
067: throws SQLException {
068: Database<D> sourceDatabase = EasyMock
069: .createStrictMock(Database.class);
070: Database<D> targetDatabase = EasyMock
071: .createStrictMock(Database.class);
072: Connection sourceConnection = EasyMock
073: .createStrictMock(Connection.class);
074: Connection targetConnection = EasyMock
075: .createStrictMock(Connection.class);
076: Statement statement = EasyMock
077: .createStrictMock(Statement.class);
078: DatabaseMetaDataCache metaData = EasyMock
079: .createStrictMock(DatabaseMetaDataCache.class);
080: DatabaseProperties database = EasyMock
081: .createStrictMock(DatabaseProperties.class);
082: TableProperties table = EasyMock
083: .createStrictMock(TableProperties.class);
084: Dialect dialect = EasyMock.createStrictMock(Dialect.class);
085: Statement targetStatement = EasyMock
086: .createStrictMock(Statement.class);
087: Statement sourceStatement = EasyMock
088: .createStrictMock(Statement.class);
089: ResultSet sourceResultSet = EasyMock
090: .createStrictMock(ResultSet.class);
091: ForeignKeyConstraint foreignKey = EasyMock
092: .createStrictMock(ForeignKeyConstraint.class);
093: Statement selectStatement = EasyMock
094: .createStrictMock(Statement.class);
095: ResultSet resultSet = EasyMock
096: .createStrictMock(ResultSet.class);
097: Statement deleteStatement = EasyMock
098: .createStrictMock(Statement.class);
099: PreparedStatement insertStatement = EasyMock
100: .createStrictMock(PreparedStatement.class);
101: ColumnProperties column1 = EasyMock
102: .createStrictMock(ColumnProperties.class);
103: ColumnProperties column2 = EasyMock
104: .createStrictMock(ColumnProperties.class);
105: ExecutorService executor = Executors.newSingleThreadExecutor();
106: SequenceProperties sequence = EasyMock
107: .createStrictMock(SequenceProperties.class);
108:
109: EasyMock.expect(context.getSourceDatabase()).andReturn(
110: sourceDatabase);
111: EasyMock.expect(context.getConnection(sourceDatabase))
112: .andReturn(sourceConnection);
113:
114: EasyMock.expect(context.getTargetDatabase()).andReturn(
115: targetDatabase);
116: EasyMock.expect(context.getConnection(targetDatabase))
117: .andReturn(targetConnection);
118:
119: EasyMock.expect(context.getDialect()).andReturn(dialect);
120: EasyMock.expect(context.getExecutor()).andReturn(executor);
121:
122: targetConnection.setAutoCommit(true);
123:
124: EasyMock.expect(context.getDatabaseProperties()).andReturn(
125: database);
126: EasyMock.expect(database.getTables()).andReturn(
127: Collections.singleton(table));
128: EasyMock.expect(context.getDialect()).andReturn(dialect);
129:
130: EasyMock.expect(context.getTargetDatabase()).andReturn(
131: targetDatabase);
132: EasyMock.expect(context.getConnection(targetDatabase))
133: .andReturn(targetConnection);
134:
135: EasyMock.expect(targetConnection.createStatement()).andReturn(
136: targetStatement);
137:
138: EasyMock.expect(table.getForeignKeyConstraints()).andReturn(
139: Collections.singleton(foreignKey));
140: EasyMock.expect(
141: dialect.getDropForeignKeyConstraintSQL(foreignKey))
142: .andReturn("drop fk");
143:
144: targetStatement.addBatch("drop fk");
145:
146: EasyMock.expect(targetStatement.executeBatch()).andReturn(null);
147:
148: targetStatement.close();
149:
150: targetConnection.setAutoCommit(false);
151:
152: EasyMock.expect(context.getDatabaseProperties()).andReturn(
153: database);
154: EasyMock.expect(database.getTables()).andReturn(
155: Collections.singleton(table));
156:
157: EasyMock.expect(table.getName()).andReturn("table");
158: EasyMock.expect(table.getColumns()).andReturn(
159: Arrays.asList(new String[] { "column1", "column2" }));
160:
161: EasyMock.expect(sourceConnection.createStatement()).andReturn(
162: selectStatement);
163: selectStatement.setFetchSize(0);
164:
165: EasyMock.checkOrder(dialect, false);
166: EasyMock.checkOrder(targetConnection, false);
167: EasyMock.checkOrder(deleteStatement, false);
168: EasyMock.checkOrder(selectStatement, false);
169:
170: EasyMock.expect(dialect.getTruncateTableSQL(table)).andReturn(
171: "DELETE FROM table");
172: EasyMock.expect(targetConnection.createStatement()).andReturn(
173: deleteStatement);
174: EasyMock.expect(
175: deleteStatement.executeUpdate("DELETE FROM table"))
176: .andReturn(0);
177:
178: deleteStatement.close();
179:
180: EasyMock
181: .expect(
182: selectStatement
183: .executeQuery("SELECT column1, column2 FROM table"))
184: .andReturn(resultSet);
185:
186: EasyMock.checkOrder(dialect, true);
187: EasyMock.checkOrder(targetConnection, true);
188: EasyMock.checkOrder(deleteStatement, true);
189: EasyMock.checkOrder(selectStatement, true);
190:
191: EasyMock
192: .expect(
193: targetConnection
194: .prepareStatement("INSERT INTO table (column1, column2) VALUES (?, ?)"))
195: .andReturn(insertStatement);
196:
197: EasyMock.expect(resultSet.next()).andReturn(true);
198:
199: EasyMock.expect(table.getColumnProperties("column1"))
200: .andReturn(column1);
201: EasyMock.expect(dialect.getColumnType(column1)).andReturn(
202: Types.INTEGER);
203: EasyMock.expect(resultSet.getObject(1)).andReturn(1);
204: EasyMock.expect(resultSet.wasNull()).andReturn(false);
205: insertStatement.setObject(1, 1, Types.INTEGER);
206:
207: EasyMock.expect(table.getColumnProperties("column2"))
208: .andReturn(column2);
209: EasyMock.expect(dialect.getColumnType(column2)).andReturn(
210: Types.VARCHAR);
211: EasyMock.expect(resultSet.getObject(2)).andReturn("");
212: EasyMock.expect(resultSet.wasNull()).andReturn(false);
213: insertStatement.setObject(2, "", Types.VARCHAR);
214:
215: insertStatement.addBatch();
216: insertStatement.clearParameters();
217:
218: EasyMock.expect(resultSet.next()).andReturn(true);
219:
220: EasyMock.expect(table.getColumnProperties("column1"))
221: .andReturn(column1);
222: EasyMock.expect(dialect.getColumnType(column1)).andReturn(
223: Types.BLOB);
224: EasyMock.expect(resultSet.getBlob(1)).andReturn(null);
225: EasyMock.expect(resultSet.wasNull()).andReturn(true);
226: insertStatement.setNull(1, Types.BLOB);
227:
228: EasyMock.expect(table.getColumnProperties("column2"))
229: .andReturn(column2);
230: EasyMock.expect(dialect.getColumnType(column2)).andReturn(
231: Types.CLOB);
232: EasyMock.expect(resultSet.getClob(2)).andReturn(null);
233: EasyMock.expect(resultSet.wasNull()).andReturn(true);
234: insertStatement.setNull(2, Types.CLOB);
235:
236: insertStatement.addBatch();
237: insertStatement.clearParameters();
238:
239: EasyMock.expect(resultSet.next()).andReturn(false);
240:
241: EasyMock.expect(insertStatement.executeBatch()).andReturn(null);
242:
243: insertStatement.close();
244: selectStatement.close();
245:
246: targetConnection.commit();
247:
248: targetConnection.setAutoCommit(true);
249:
250: EasyMock.expect(context.getDatabaseProperties()).andReturn(
251: database);
252: EasyMock.expect(database.getTables()).andReturn(
253: Collections.singleton(table));
254: EasyMock.expect(context.getDialect()).andReturn(dialect);
255:
256: EasyMock.expect(context.getTargetDatabase()).andReturn(
257: targetDatabase);
258: EasyMock.expect(context.getConnection(targetDatabase))
259: .andReturn(targetConnection);
260:
261: EasyMock.expect(targetConnection.createStatement()).andReturn(
262: targetStatement);
263:
264: EasyMock.expect(table.getForeignKeyConstraints()).andReturn(
265: Collections.singleton(foreignKey));
266: EasyMock.expect(
267: dialect.getCreateForeignKeyConstraintSQL(foreignKey))
268: .andReturn("create fk");
269:
270: targetStatement.addBatch("create fk");
271:
272: EasyMock.expect(targetStatement.executeBatch()).andReturn(null);
273:
274: targetStatement.close();
275:
276: {
277: EasyMock.expect(context.getSourceDatabase()).andReturn(
278: sourceDatabase);
279: EasyMock.expect(context.getConnection(sourceDatabase))
280: .andReturn(sourceConnection);
281: EasyMock.expect(sourceConnection.createStatement())
282: .andReturn(sourceStatement);
283:
284: EasyMock.expect(context.getTargetDatabase()).andReturn(
285: targetDatabase);
286: EasyMock.expect(context.getConnection(targetDatabase))
287: .andReturn(targetConnection);
288: EasyMock.expect(targetConnection.createStatement())
289: .andReturn(targetStatement);
290:
291: EasyMock.expect(context.getDialect()).andReturn(dialect);
292:
293: EasyMock.expect(context.getDatabaseProperties()).andReturn(
294: database);
295: EasyMock.expect(database.getTables()).andReturn(
296: Collections.singleton(table));
297:
298: EasyMock.expect(table.getIdentityColumns()).andReturn(
299: Collections.singleton("column"));
300: EasyMock.expect(table.getName()).andReturn("table");
301: EasyMock
302: .expect(
303: sourceStatement
304: .executeQuery("SELECT max(column) FROM table"))
305: .andReturn(sourceResultSet);
306: EasyMock.expect(sourceResultSet.next()).andReturn(true);
307: EasyMock.expect(sourceResultSet.getLong(1)).andReturn(1L);
308:
309: sourceResultSet.close();
310:
311: EasyMock.expect(table.getColumnProperties("column"))
312: .andReturn(column1);
313: EasyMock.expect(
314: dialect.getAlterIdentityColumnSQL(table, column1,
315: 2L)).andReturn("column = 1");
316:
317: targetStatement.addBatch("column = 1");
318: EasyMock.expect(targetStatement.executeBatch()).andReturn(
319: null);
320:
321: sourceStatement.close();
322: targetStatement.close();
323: }
324: {
325: EasyMock.expect(context.getDatabaseProperties()).andReturn(
326: database);
327: EasyMock.expect(database.getSequences()).andReturn(
328: Collections.singleton(sequence));
329:
330: EasyMock.expect(context.getSourceDatabase()).andReturn(
331: sourceDatabase);
332: EasyMock.expect(context.getActiveDatabaseSet()).andReturn(
333: Collections.singleton(sourceDatabase));
334: EasyMock.expect(context.getExecutor()).andReturn(executor);
335: EasyMock.expect(context.getDialect()).andReturn(dialect);
336:
337: EasyMock.expect(dialect.getNextSequenceValueSQL(sequence))
338: .andReturn("sequence next value");
339:
340: EasyMock.expect(context.getConnection(sourceDatabase))
341: .andReturn(sourceConnection);
342: EasyMock.expect(sourceConnection.createStatement())
343: .andReturn(sourceStatement);
344: EasyMock
345: .expect(
346: sourceStatement
347: .executeQuery("sequence next value"))
348: .andReturn(sourceResultSet);
349:
350: EasyMock.expect(sourceResultSet.next()).andReturn(true);
351:
352: EasyMock.expect(sourceResultSet.getLong(1)).andReturn(1L);
353:
354: sourceStatement.close();
355:
356: EasyMock.expect(context.getTargetDatabase()).andReturn(
357: targetDatabase);
358: EasyMock.expect(context.getConnection(targetDatabase))
359: .andReturn(targetConnection);
360: EasyMock.expect(targetConnection.createStatement())
361: .andReturn(targetStatement);
362:
363: EasyMock.expect(dialect.getAlterSequenceSQL(sequence, 2L))
364: .andReturn("alter sequence");
365:
366: targetStatement.addBatch("alter sequence");
367:
368: EasyMock.expect(targetStatement.executeBatch()).andReturn(
369: null);
370:
371: targetStatement.close();
372: }
373:
374: EasyMock.replay(context, sourceDatabase, targetDatabase,
375: sourceConnection, targetConnection, statement,
376: metaData, database, table, dialect, targetStatement,
377: sourceStatement, sourceResultSet, foreignKey,
378: selectStatement, resultSet, deleteStatement,
379: insertStatement, column1, column2);
380:
381: this.strategy.synchronize(context);
382:
383: EasyMock.verify(context, sourceDatabase, targetDatabase,
384: sourceConnection, targetConnection, statement,
385: metaData, database, table, dialect, targetStatement,
386: sourceStatement, sourceResultSet, foreignKey,
387: selectStatement, resultSet, deleteStatement,
388: insertStatement, column1, column2);
389: }
390: }
|