package co.codewizards.cloudstore.local;
import static co.codewizards.cloudstore.core.oio.OioFileFactory.*;
import static org.assertj.core.api.Assertions.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import co.codewizards.cloudstore.core.oio.File;
import co.codewizards.cloudstore.core.progress.LoggerProgressMonitor;
import co.codewizards.cloudstore.core.repo.local.LocalRepoManager;
import co.codewizards.cloudstore.core.repo.local.LocalRepoTransaction;
import co.codewizards.cloudstore.local.persistence.DeleteModification;
import co.codewizards.cloudstore.local.persistence.LocalRepositoryDao;
import co.codewizards.cloudstore.local.persistence.Modification;
import co.codewizards.cloudstore.local.persistence.ModificationDao;
import co.codewizards.cloudstore.local.persistence.RepoFile;
import co.codewizards.cloudstore.local.persistence.RepoFileDao;
public class LocalRepoManagerTest extends AbstractTest {
private static final Logger logger = LoggerFactory.getLogger(LocalRepoManagerTest.class);
private File localRoot;
@Test
public void syncExistingDirectoryGraph() throws Exception {
localRoot = newTestRepositoryLocalRoot();
assertThat(localRoot.exists()).isFalse();
localRoot.mkdirs();
assertThat(localRoot.isDirectory()).isTrue();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForNewRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createDirectory(localRoot, "1");
createFileWithRandomContent(child_1, "a");
createFileWithRandomContent(child_1, "b");
createFileWithRandomContent(child_1, "c");
final File child_2 = createDirectory(localRoot, "2");
createFileWithRandomContent(child_2, "a");
final File child_2_1 = createDirectory(child_2, "1");
createFileWithRandomContent(child_2_1, "a");
final File child_3 = createDirectory(localRoot, "3");
createFileWithRandomContent(child_3, "a");
createFileWithRandomContent(child_3, "b");
createFileWithRandomContent(child_3, "c");
createFileWithRandomContent(child_3, "d");
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
localRepoManager.close();
}
@Test
public void syncAddedFiles() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createFile(localRoot, "1");
final File child_1_1 = createDirectory(child_1, "1");
final File child_1_2 = createDirectory(child_1, "2");
final File child_2 = createFile(localRoot, "2");
createFileWithRandomContent(child_1, "d");
createFileWithRandomContent(child_1_1, "aa");
createFileWithRandomContent(child_1_1, "bb");
createFileWithRandomContent(child_1_2, "aaa");
createFileWithRandomContent(child_1_2, "bbb");
createFileWithRandomContent(child_1_2, "ccc");
createFileWithRandomContent(child_1_2, "ddd");
createFileWithRandomContent(child_2, "b");
createFileWithRandomContent(child_2, "c");
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
localRepoManager.close();
}
@Test
public void syncDeletedFiles() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createFile(localRoot, "1");
assertThat(child_1.isDirectory()).isTrue();
final File child_1_b = createFile(child_1, "b");
assertThat(child_1_b.isFile()).isTrue();
final File child_1_c = createFile(child_1, "c");
assertThat(child_1_c.isFile()).isTrue();
final File child_2 = createFile(localRoot, "2");
assertThat(child_2.isDirectory()).isTrue();
final File child_2_1 = createFile(child_2, "1");
assertThat(child_2_1.isDirectory()).isTrue();
final File child_2_1_a = createFile(child_2_1, "a");
assertThat(child_2_1_a.isFile()).isTrue();
final File child_2_a = createFile(child_2, "a");
assertThat(child_2_a.isFile()).isTrue();
deleteFile(child_1_b);
deleteFile(child_1_c);
deleteFile(child_2_a);
deleteFile(child_2_1_a);
deleteFile(child_2_1);
deleteFile(child_2);
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
localRepoManager.close();
}
@Test
public void syncSwitchingFromFilesToDirectoriesAndViceVersa() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createFile(localRoot, "1");
assertThat(child_1.isDirectory()).isTrue();
final File child_1_b = createFile(child_1, "b");
assertThat(child_1_b.isFile()).isTrue();
final File child_1_c = createFile(child_1, "c");
assertThat(child_1_c.isFile()).isTrue();
final File child_2 = createFile(localRoot, "2");
assertThat(child_2.isDirectory()).isTrue();
final File child_2_1 = createFile(child_2, "1");
assertThat(child_2_1.isDirectory()).isTrue();
final File child_2_1_a = createFile(child_2_1, "a");
assertThat(child_2_1_a.isFile()).isTrue();
final File child_2_a = createFile(child_2, "a");
assertThat(child_2_a.isFile()).isTrue();
deleteFile(child_1_b);
deleteFile(child_1_c);
deleteFile(child_2_a);
deleteFile(child_2_1_a);
deleteFile(child_2_1);
deleteFile(child_2);
// child_2 was a directory => switching it to a file now.
createFileWithRandomContent(child_2);
assertThat(child_2.isFile()).isTrue();
// child_1_b was a file => switching it to a directory now.
createDirectory(child_1_b);
assertThat(child_1_b.isDirectory()).isTrue();
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
localRepoManager.close();
}
@Test
public void checkParentLocalRevisionAfterChildDeletion() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createFile(localRoot, "1");
assertThat(child_1.isDirectory()).isTrue();
final File child_1_b = createFile(child_1, "b");
assertThat(child_1_b.isFile()).isTrue();
long localRepositoryRevisionBeforeSync;
long child_1_localRevisionBeforeSync;
LocalRepoTransaction transaction = localRepoManager.beginWriteTransaction();
try {
localRepositoryRevisionBeforeSync = transaction.getDao(LocalRepositoryDao.class).getLocalRepositoryOrFail().getRevision();
final RepoFile childRepoFile_1 = transaction.getDao(RepoFileDao.class).getRepoFile(localRoot, child_1);
child_1_localRevisionBeforeSync = childRepoFile_1.getLocalRevision();
} finally {
transaction.rollbackIfActive();
}
final long child_1LastModifiedBeforeModification = child_1.lastModified();
deleteFile(child_1_b);
// In GNU/Linux, the parent-directory's last-modified timestamp is changed, if a child is added or removed.
// To make sure, this has no influence on our test, we reset this timestamp after our change.
child_1.setLastModified(child_1LastModifiedBeforeModification);
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
long localRepositoryRevisionAfterSync;
long child_1_localRevisionAfterSync;
transaction = localRepoManager.beginWriteTransaction();
try {
localRepositoryRevisionAfterSync = transaction.getDao(LocalRepositoryDao.class).getLocalRepositoryOrFail().getRevision();
final RepoFile childRepoFile_1 = transaction.getDao(RepoFileDao.class).getRepoFile(localRoot, child_1);
child_1_localRevisionAfterSync = childRepoFile_1.getLocalRevision();
} finally {
transaction.rollbackIfActive();
}
assertThat(localRepositoryRevisionAfterSync).isGreaterThan(localRepositoryRevisionBeforeSync);
assertThat(child_1_localRevisionAfterSync).isEqualTo(child_1_localRevisionBeforeSync);
localRepoManager.close();
}
@Test
public void checkDeleteModificationAfterFileDeletion() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
// We must connect another repository, because there is otherwise no DeleteModification created.
// Only if at least one DeleteModification is created, we'll have a change.
final File localRoot2 = newTestRepositoryLocalRoot();
localRoot2.mkdir();
final LocalRepoManager localRepoManager2 = localRepoManagerFactory.createLocalRepoManagerForNewRepository(localRoot2);
localRepoManager.putRemoteRepository(localRepoManager2.getRepositoryId(), null, localRepoManager2.getPublicKey(), "");
final File child_1 = createFile(localRoot, "1");
assertThat(child_1.isDirectory()).isTrue();
final File child_1_b = createFile(child_1, "b");
assertThat(child_1_b.isFile()).isTrue();
LocalRepoTransaction transaction = localRepoManager.beginWriteTransaction();
try {
final Collection<Modification> modifications = transaction.getDao(ModificationDao.class).getObjects();
assertThat(getDeleteModifications(modifications)).isEmpty();
} finally {
transaction.rollbackIfActive();
}
final long child_1LastModifiedBeforeModification = child_1.lastModified();
deleteFile(child_1_b);
// In GNU/Linux, the parent-directory's last-modified timestamp is changed, if a child is added or removed.
// To make sure, this has no influence on our test, we reset this timestamp after our change.
child_1.setLastModified(child_1LastModifiedBeforeModification);
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
transaction = localRepoManager.beginWriteTransaction();
try {
final Collection<Modification> modifications = transaction.getDao(ModificationDao.class).getObjects();
final List<DeleteModification> deleteModifications = getDeleteModifications(modifications);
assertThat(deleteModifications).hasSize(1);
final DeleteModification deleteModification = deleteModifications.get(0);
assertThat(deleteModification).isNotNull();
assertThat(deleteModification.getPath()).isEqualTo("/1/b");
assertThat(deleteModification.getRemoteRepository()).isNotNull();
assertThat(deleteModification.getRemoteRepository().getRepositoryId()).isEqualTo(localRepoManager2.getRepositoryId());
} finally {
transaction.rollbackIfActive();
}
localRepoManager2.close();
localRepoManager.close();
}
private List<DeleteModification> getDeleteModifications(final Collection<Modification> modifications) {
final List<DeleteModification> result = new ArrayList<DeleteModification>();
for (final Modification modification : modifications) {
if (modification instanceof DeleteModification)
result.add((DeleteModification) modification);
}
return result;
}
@Test
public void checkParentLocalRevisionAfterChildAddition() throws Exception {
syncExistingDirectoryGraph();
final LocalRepoManager localRepoManager = localRepoManagerFactory.createLocalRepoManagerForExistingRepository(localRoot);
assertThat(localRepoManager).isNotNull();
final File child_1 = createFile(localRoot, "1");
assertThat(child_1.isDirectory()).isTrue();
long localRepositoryRevisionBeforeSync;
long child_1_localRevisionBeforeSync;
LocalRepoTransaction transaction = localRepoManager.beginWriteTransaction();
try {
localRepositoryRevisionBeforeSync = transaction.getDao(LocalRepositoryDao.class).getLocalRepositoryOrFail().getRevision();
final RepoFile childRepoFile_1 = transaction.getDao(RepoFileDao.class).getRepoFile(localRoot, child_1);
child_1_localRevisionBeforeSync = childRepoFile_1.getLocalRevision();
} finally {
transaction.rollbackIfActive();
}
final long child_1LastModifiedBeforeModification = child_1.lastModified();
createFileWithRandomContent(child_1, "d");
// In GNU/Linux, the parent-directory's last-modified timestamp is changed, if a child is added or removed.
// To make sure, this has no influence on our test, we reset this timestamp after our change.
child_1.setLastModified(child_1LastModifiedBeforeModification);
localRepoManager.localSync(new LoggerProgressMonitor(logger));
assertThatFilesInRepoAreCorrect(localRoot);
long localRepositoryRevisionAfterSync;
long child_1_localRevisionAfterSync;
transaction = localRepoManager.beginWriteTransaction();
try {
localRepositoryRevisionAfterSync = transaction.getDao(LocalRepositoryDao.class).getLocalRepositoryOrFail().getRevision();
final RepoFile childRepoFile_1 = transaction.getDao(RepoFileDao.class).getRepoFile(localRoot, child_1);
child_1_localRevisionAfterSync = childRepoFile_1.getLocalRevision();
} finally {
transaction.rollbackIfActive();
}
assertThat(localRepositoryRevisionAfterSync).isGreaterThan(localRepositoryRevisionBeforeSync);
assertThat(child_1_localRevisionAfterSync).isEqualTo(child_1_localRevisionBeforeSync);
localRepoManager.close();
}
private File newTestRepositoryLocalRoot() throws IOException {
return newTestRepositoryLocalRoot("");
}
}