/**
* Licensed to JumpMind Inc under one or more contributor
* license agreements. See the NOTICE file distributed
* with this work for additional information regarding
* copyright ownership. JumpMind Inc licenses this file
* to you under the GNU General Public License, version 3.0 (GPLv3)
* (the "License"); you may not use this file except in compliance
* with the License.
*
* You should have received a copy of the GNU General Public License,
* version 3.0 (GPLv3) along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jumpmind.symmetric.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.sql.Types;
import java.util.List;
import org.jumpmind.db.model.Column;
import org.jumpmind.db.model.Table;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.model.IncomingBatch;
import org.jumpmind.symmetric.model.IncomingError;
public class ConflictResolutionTest extends AbstractTest {
Table testTableA;
@Override
protected Table[] getTables(String name) {
testTableA = new Table("conflict_table_a");
testTableA.addColumn(new Column("id", true, Types.VARCHAR, 255, 0));
testTableA.addColumn(new Column("string_a", false, Types.VARCHAR, 255, 0));
testTableA.addColumn(new Column("tm", false, Types.TIMESTAMP, -1, -1));
return new Table[] { testTableA };
}
@Override
protected String[] getGroupNames() {
return new String[] { "server", "client" };
}
@Override
protected void test(ISymmetricEngine rootServer, ISymmetricEngine clientServer) throws Exception {
loadConfigAndRegisterNode("client", "server");
push("client");
testBasicSync(rootServer, clientServer);
testExistingRowInServerInsertOnClient(rootServer, clientServer);
testUpdateRowOnServerThenUpdateRowOnClient(rootServer, clientServer);
/*
* assertFalse(pullFiles());
*
* testInitialLoadFromServerToClient(rootServer, clientServer);
*
* testPullAllFromServerToClient(rootServer, clientServer);
*
* testPingback();
*
* testChooseTargetDirectory(rootServer, clientServer);
*
* testChangeFileNameAndCreateTargetDir(rootServer, clientServer);
*/
}
protected void testBasicSync(ISymmetricEngine rootServer, ISymmetricEngine clientServer) throws Exception {
clientServer.getSqlTemplate().update(
clientServer.getDatabasePlatform().scrubSql(String.format("insert into %s values (?,?,current_timestamp)", testTableA.getName())), "1", "c1");
push("client");
assertEquals(1, rootServer.getSqlTemplate().queryForInt("select count(*) from conflict_table_a"));
assertEquals("c1", rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a"));
}
protected void testExistingRowInServerInsertOnClient(ISymmetricEngine rootServer, ISymmetricEngine clientServer)
throws Exception {
rootServer.getSqlTemplate().update(
rootServer.getDatabasePlatform().scrubSql(String.format("insert into %s values (?,?,current_timestamp)", testTableA.getName())), "2", "s1");
assertEquals(2, rootServer.getSqlTemplate().queryForInt("select count(*) from conflict_table_a"));
assertEquals("s1",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
clientServer.getSqlTemplate().update(
clientServer.getDatabasePlatform().scrubSql(String.format("insert into %s values (?,?,current_timestamp)", testTableA.getName())), "2", "c1");
assertTrue(push("client"));
assertEquals("s1",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
IncomingError error = getOnlyIncomingError(rootServer, "client");
String rowData = error.getRowData();
assertTrue(rowData.contains("\"c1\""));
String resolveData = rowData.replace("\"c1\"", "\"s2\"");
rootServer.getSqlTemplate().update("update sym_incoming_error set resolve_data=? where batch_id=?",
resolveData, error.getBatchId());
assertTrue(push("client"));
assertEquals("s2",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
}
public IncomingError getOnlyIncomingError(ISymmetricEngine server, String nodeId) {
// assertEquals(1,
// server.getIncomingBatchService().countIncomingBatchesInError());
List<IncomingBatch> errorBatches = server.getIncomingBatchService().findIncomingBatchErrors(12);
if (errorBatches == null || errorBatches.size() == 0) {
return null;
}
long errorBatch = errorBatches.get(0).getBatchId();
List<IncomingError> errors = server.getDataLoaderService().getIncomingErrors(errorBatch, nodeId);
assertEquals(1, errors.size());
return errors.get(0);
}
// Tests simultaneous updates to an existing row with resolution based on resolve data and then same scenario again
// with resolution based on resolve_ignore.
protected void testUpdateRowOnServerThenUpdateRowOnClient(ISymmetricEngine rootServer, ISymmetricEngine clientServer)
throws Exception {
int count = rootServer.getSqlTemplate().update(
String.format("update %s set string_a=? where id=?", testTableA.getName()), "notS3", "2");
assertEquals(1, count);
count = clientServer.getSqlTemplate().update(
String.format("update %s set string_a=? where id=?", testTableA.getName()), "S3", "2");
assertEquals(1, count);
assertTrue(push("client"));
assertEquals("notS3",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
IncomingError error = getOnlyIncomingError(rootServer, "client");
String rowData = error.getRowData();
assertTrue(rowData.contains("\"S3\""));
String resolveData = rowData.replace("\"S3\"", "\"S4\"");
rootServer.getSqlTemplate().update("update sym_incoming_error set resolve_data=? where batch_id=?",
resolveData, error.getBatchId());
assertTrue(push("client"));
error = getOnlyIncomingError(rootServer, "client");
assertEquals(null, error);
assertEquals("S4",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
// Same test, but we're ignore row this time
count = rootServer.getSqlTemplate().update(
String.format("update %s set string_a=? where id=?", testTableA.getName()), "notS5", "2");
assertEquals(1, count);
count = clientServer.getSqlTemplate().update(
String.format("update %s set string_a=? where id=?", testTableA.getName()), "S5", "2");
assertEquals(1, count);
assertTrue(push("client"));
assertEquals("notS5",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
error = getOnlyIncomingError(rootServer, "client");
rowData = error.getRowData();
rootServer.getSqlTemplate().update("update sym_incoming_error set resolve_ignore=? where batch_id=?",
1, error.getBatchId());
assertTrue(push("client"));
error = getOnlyIncomingError(rootServer, "client");
assertEquals(null,error);
assertEquals("notS5",
rootServer.getSqlTemplate().queryForString("select string_a from conflict_table_a where id='2'"));
}
}