@Test
public void testDirtyCleanupDirty() throws Exception {
// Setup
TransferSettings testConnection = TestConfigUtil.createTestLocalConnection();
TestClient clientA = new TestClient("A", testConnection);
TestClient clientB = new TestClient("B", testConnection);
TestClient clientC = new TestClient("C", testConnection);
TestClient clientD = new TestClient("D", testConnection);
StatusOperationOptions statusOptions = new StatusOperationOptions();
statusOptions.setForceChecksum(true);
UpOperationOptions upOptionsForceEnabled = new UpOperationOptions();
upOptionsForceEnabled.setStatusOptions(statusOptions);
upOptionsForceEnabled.setForceUploadEnabled(true);
CleanupOperationOptions cleanupOptions = new CleanupOperationOptions();
cleanupOptions.setMinSecondsBetweenCleanups(0);
// Run
//// 1. CREATE FIRST DIRTY VERSION
clientA.createNewFile("A-file1.jpg", 50*1024);
clientA.up(upOptionsForceEnabled); // (A1)
clientB.down();
clientB.changeFile("A-file1.jpg");;
clientB.up(upOptionsForceEnabled); // (A1,B1)
clientA.down();
clientA.changeFile("A-file1.jpg"); // conflict (winner)
clientA.up(upOptionsForceEnabled); // (A2,B1)
clientB.changeFile("A-file1.jpg"); // conflict (loser)
clientB.up(upOptionsForceEnabled);
clientA.createNewFolder("new folder at A"); // don't care about the conflict, just continue
clientA.up(upOptionsForceEnabled); // (A3,B1)
clientB.createNewFolder("new folder at B"); // don't care about the conflict, just continue
clientB.up(upOptionsForceEnabled);
clientA.down(); // resolve conflict (wins, no DIRTY)
java.sql.Connection databaseConnectionA = DatabaseConnectionFactory.createConnection(clientA.getDatabaseFile());
assertEquals("0", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status='DIRTY'", databaseConnectionA));
clientB.down(); // resolve conflict (loses, creates DIRTY version)
java.sql.Connection databaseConnectionB = DatabaseConnectionFactory.createConnection(clientB.getDatabaseFile());
assertEquals("2", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status='DIRTY'", databaseConnectionB));
assertEquals("(A1,B2)\n(A1,B3)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion where status='DIRTY' order by id", databaseConnectionB));
assertEquals("(A1)\n(A1,B1)\n(A2,B1)\n(A3,B1)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion where status<>'DIRTY' order by id", databaseConnectionB));
StatusOperationResult statusResultBAfterDirty = clientB.status();
assertNotNull(statusResultBAfterDirty);
ChangeSet changeSetBAfterDirty = statusResultBAfterDirty.getChangeSet();
assertEquals(2, changeSetBAfterDirty.getNewFiles().size());
TestAssertUtil.assertConflictingFileExists("A-file1.jpg", clientB.getLocalFiles());
clientB.up(upOptionsForceEnabled); // (A3,B2)
assertEquals("0", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status='DIRTY'", databaseConnectionB));
assertEquals("4", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionA)); // (A1), (A1,B1), (A2,B1), (A3,B1)
assertEquals("(A1)\n(A1,B1)\n(A2,B1)\n(A3,B1)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion order by id", databaseConnectionA));
assertEquals("5", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionB));
assertEquals("(A1)\n(A1,B1)\n(A2,B1)\n(A3,B1)\n(A3,B4)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion order by id", databaseConnectionB));
//// 2. NOW THAT CLIENT B RESOLVED IT, A GETS DIRTY
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty1");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty2");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty3");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty4");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty5");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty6");
clientA.up(upOptionsForceEnabled);
clientA.changeFile("A-file1.jpg"); // No 'down'! This version will become DIRTY
clientA.createNewFile("dirty7");
clientA.up(upOptionsForceEnabled);
assertEquals("11", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionA));
clientA.down();
assertEquals("12", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionA));
assertEquals("7", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status='DIRTY'", databaseConnectionA));
assertEquals("5", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status<>'DIRTY'", databaseConnectionA));
assertEquals("(A1)\n(A1,B1)\n(A2,B1)\n(A3,B1)\n(A3,B4)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion where status<>'DIRTY' order by id", databaseConnectionA));
clientB.down(); // Does nothing; A versions lose against (A3,B2) // same as above!
assertEquals("5", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionB));
assertEquals("(A1)\n(A1,B1)\n(A2,B1)\n(A3,B1)\n(A3,B4)", TestSqlUtil.runSqlSelect("select vectorclock_serialized from databaseversion order by id", databaseConnectionB));
//// 3. NEW CLIENT JOINS
clientC.down();
TestAssertUtil.assertSqlDatabaseEquals(clientB.getDatabaseFile(), clientC.getDatabaseFile());
//// 4. FORCE MERGE DATABASES ON CLIENT A
clientA.deleteFile("dirty1");
clientA.deleteFile("dirty2");
clientA.up(upOptionsForceEnabled); // upload DIRTY version
assertEquals("6", TestSqlUtil.runSqlSelect("select count(*) from databaseversion", databaseConnectionA));
assertEquals("0", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status='DIRTY'", databaseConnectionA));
assertEquals("6", TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status<>'DIRTY'", databaseConnectionA));
clientA.createNewFile("A-file2.jpg");
int numberOfDatabaseVersions = 6;
int cleanupEveryXUps = 7; // For every X up's call 'cleanup' ("X" is larger than the max. length of file versions in a history)
for (int i=1; i<=21; i++) {
clientA.changeFile("A-file2.jpg");
clientA.up(upOptionsForceEnabled);
numberOfDatabaseVersions++;
if (i % cleanupEveryXUps == 0) {
clientA.cleanup(cleanupOptions);
numberOfDatabaseVersions++;
assertEquals(""+numberOfDatabaseVersions, TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status<>'DIRTY'", databaseConnectionA));
}
else {
assertEquals(""+numberOfDatabaseVersions, TestSqlUtil.runSqlSelect("select count(*) from databaseversion where status<>'DIRTY'", databaseConnectionA));
}
}
clientA.cleanup(cleanupOptions);
clientB.down();
clientC.down();
clientD.down();
TestAssertUtil.assertSqlDatabaseEquals(clientA.getDatabaseFile(), clientB.getDatabaseFile());
TestAssertUtil.assertSqlDatabaseEquals(clientA.getDatabaseFile(), clientC.getDatabaseFile());
TestAssertUtil.assertSqlDatabaseEquals(clientA.getDatabaseFile(), clientD.getDatabaseFile());
// Tear down
clientA.deleteTestData();
clientB.deleteTestData();
clientC.deleteTestData();
clientD.deleteTestData();
}