Cleanup tests for repository dao

This commit is contained in:
René Pfeuffer
2019-05-14 10:08:45 +02:00
parent c63510536a
commit e0ad5c76a7
3 changed files with 241 additions and 347 deletions

View File

@@ -13,6 +13,7 @@ public abstract class RepositoryLocationResolver {
return create(type); return create(type);
} }
@FunctionalInterface
public interface RepositoryLocationResolverInstance<T> { public interface RepositoryLocationResolverInstance<T> {
T getLocation(String repositoryId); T getLocation(String repositoryId);
} }

View File

@@ -62,7 +62,6 @@ public class XmlRepositoryDAO implements RepositoryDAO {
private final MetadataStore metadataStore = new MetadataStore(); private final MetadataStore metadataStore = new MetadataStore();
private final SCMContextProvider context;
private final PathBasedRepositoryLocationResolver repositoryLocationResolver; private final PathBasedRepositoryLocationResolver repositoryLocationResolver;
private final FileSystem fileSystem; private final FileSystem fileSystem;
@@ -70,8 +69,7 @@ public class XmlRepositoryDAO implements RepositoryDAO {
private final Map<NamespaceAndName, Repository> byNamespaceAndName; private final Map<NamespaceAndName, Repository> byNamespaceAndName;
@Inject @Inject
public XmlRepositoryDAO(SCMContextProvider context, PathBasedRepositoryLocationResolver repositoryLocationResolver, FileSystem fileSystem) { public XmlRepositoryDAO(PathBasedRepositoryLocationResolver repositoryLocationResolver, FileSystem fileSystem) {
this.context = context;
this.repositoryLocationResolver = repositoryLocationResolver; this.repositoryLocationResolver = repositoryLocationResolver;
this.fileSystem = fileSystem; this.fileSystem = fileSystem;
@@ -165,7 +163,9 @@ public class XmlRepositoryDAO implements RepositoryDAO {
byNamespaceAndName.put(clone.getNamespaceAndName(), clone); byNamespaceAndName.put(clone.getNamespaceAndName(), clone);
} }
Path repositoryPath = repositoryLocationResolver.create(Path.class).getLocation(repository.getId()); Path repositoryPath = repositoryLocationResolver
.create(Path.class)
.getLocation(repository.getId());
Path metadataPath = resolveDataPath(repositoryPath); Path metadataPath = resolveDataPath(repositoryPath);
metadataStore.write(metadataPath, clone); metadataStore.write(metadataPath, clone);
} }

View File

@@ -2,391 +2,284 @@ package sonia.scm.repository.xml;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.TempDirectory; import org.junitpioneer.jupiter.TempDirectory;
import org.mockito.Answers; import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import sonia.scm.SCMContextProvider; import sonia.scm.SCMContextProvider;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.io.FileSystem; import sonia.scm.io.FileSystem;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryPermission;
import sonia.scm.util.IOUtil;
import sun.misc.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.function.BiConsumer;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static sonia.scm.repository.RepositoryTestData.createHeartOfGold;
@ExtendWith({MockitoExtension.class, TempDirectory.class}) @ExtendWith({MockitoExtension.class, TempDirectory.class})
@MockitoSettings(strictness = Strictness.LENIENT) @MockitoSettings(strictness = Strictness.LENIENT)
class XmlRepositoryDAOTest { class XmlRepositoryDAOTest {
private static final Repository REPOSITORY = createRepository("42"); private final Repository REPOSITORY = createRepository("42");
@Mock @Mock
private SCMContextProvider context;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PathBasedRepositoryLocationResolver locationResolver; private PathBasedRepositoryLocationResolver locationResolver;
@Captor
private ArgumentCaptor<BiConsumer<String, Path>> forAllCaptor;
private FileSystem fileSystem = new DefaultFileSystem(); private FileSystem fileSystem = new DefaultFileSystem();
private XmlRepositoryDAO dao; private XmlRepositoryDAO dao;
private Path basePath;
@BeforeEach @BeforeEach
void createDAO(@TempDirectory.TempDir Path basePath) { void createDAO(@TempDirectory.TempDir Path basePath) {
this.basePath = basePath; when(locationResolver.create(Path.class)).thenReturn(locationResolver::create);
when(locationResolver.create(anyString())).thenAnswer(invocation -> createMockedRepoPath(basePath, invocation));
when(locationResolver.create(anyString())).thenAnswer(invocation -> {
Path resolvedPath = basePath.resolve(invocation.getArgument(0).toString());
Files.createDirectories(resolvedPath);
return resolvedPath;
});
when(locationResolver.remove(anyString())).thenAnswer(invocation -> basePath.resolve(invocation.getArgument(0).toString())); when(locationResolver.remove(anyString())).thenAnswer(invocation -> basePath.resolve(invocation.getArgument(0).toString()));
when(context.getBaseDirectory()).thenReturn(basePath.toFile());
dao = createDAO();
} }
private XmlRepositoryDAO createDAO() { private Path createMockedRepoPath(@TempDirectory.TempDir Path basePath, InvocationOnMock invocation) {
return new XmlRepositoryDAO(context, locationResolver, fileSystem); Path resolvedPath = basePath.resolve(invocation.getArgument(0).toString());
try {
Files.createDirectories(resolvedPath);
} catch (IOException e) {
fail(e);
}
return resolvedPath;
}
@Nested
class WithEmptyDatabase {
@BeforeEach
void createDAO() {
dao = new XmlRepositoryDAO(locationResolver, fileSystem);
}
@Test
void shouldReturnXmlType() {
assertThat(dao.getType()).isEqualTo("xml");
}
@Test
void shouldReturnCreationTimeOfLocationResolver() {
long now = 42L;
when(locationResolver.getCreationTime()).thenReturn(now);
assertThat(dao.getCreationTime()).isEqualTo(now);
}
@Test
void shouldReturnLasModifiedOfLocationResolver() {
long now = 42L;
when(locationResolver.getLastModified()).thenReturn(now);
assertThat(dao.getLastModified()).isEqualTo(now);
}
@Test
void shouldReturnTrueForEachContainsMethod() {
dao.add(REPOSITORY);
assertThat(dao.contains(REPOSITORY)).isTrue();
assertThat(dao.contains(REPOSITORY.getId())).isTrue();
assertThat(dao.contains(REPOSITORY.getNamespaceAndName())).isTrue();
}
@Test
void shouldPersistRepository() {
dao.add(REPOSITORY);
String content = getXmlFileContent(REPOSITORY.getId());
assertThat(content).contains("<id>42</id>");
}
@Test
void shouldDeleteDataFile() {
dao.add(REPOSITORY);
dao.delete(REPOSITORY);
assertThat(metadataFile(REPOSITORY.getId())).doesNotExist();
}
@Test
void shouldModifyRepository() {
dao.add(REPOSITORY);
Repository changedRepository = REPOSITORY.clone();
changedRepository.setContact("change");
dao.modify(changedRepository);
String content = getXmlFileContent(REPOSITORY.getId());
assertThat(content).contains("change");
}
@Test
void shouldReturnFalseForEachContainsMethod() {
assertThat(dao.contains(REPOSITORY)).isFalse();
assertThat(dao.contains(REPOSITORY.getId())).isFalse();
assertThat(dao.contains(REPOSITORY.getNamespaceAndName())).isFalse();
}
@Test
void shouldReturnNullForEachGetMethod() {
assertThat(dao.get("42")).isNull();
assertThat(dao.get(new NamespaceAndName("hitchhiker", "HeartOfGold"))).isNull();
}
@Test
void shouldReturnRepository() {
dao.add(REPOSITORY);
assertThat(dao.get("42")).isEqualTo(REPOSITORY);
assertThat(dao.get(new NamespaceAndName("space", "42"))).isEqualTo(REPOSITORY);
}
@Test
void shouldNotReturnTheSameInstance() {
dao.add(REPOSITORY);
Repository repository = dao.get("42");
assertThat(repository).isNotSameAs(REPOSITORY);
}
@Test
void shouldReturnAllRepositories() {
dao.add(REPOSITORY);
Repository secondRepository = createRepository("23");
dao.add(secondRepository);
Collection<Repository> repositories = dao.getAll();
assertThat(repositories)
.containsExactlyInAnyOrder(REPOSITORY, secondRepository);
}
@Test
void shouldModifyRepositoryTwice() {
REPOSITORY.setDescription("HeartOfGold");
dao.add(REPOSITORY);
assertThat(dao.get("42").getDescription()).isEqualTo("HeartOfGold");
Repository heartOfGold = createRepository("42");
heartOfGold.setDescription("Heart of Gold");
dao.modify(heartOfGold);
assertThat(dao.get("42").getDescription()).isEqualTo("Heart of Gold");
}
@Test
void shouldRemoveRepository() {
dao.add(REPOSITORY);
assertThat(dao.contains("42")).isTrue();
dao.delete(REPOSITORY);
assertThat(dao.contains("42")).isFalse();
assertThat(dao.contains(REPOSITORY.getNamespaceAndName())).isFalse();
Path storePath = metadataFile(REPOSITORY.getId());
assertThat(storePath).doesNotExist();
}
@Test
void shouldRenameTheRepository() {
dao.add(REPOSITORY);
REPOSITORY.setNamespace("hg2tg");
REPOSITORY.setName("hog");
dao.modify(REPOSITORY);
Repository repository = dao.get("42");
assertThat(repository.getNamespace()).isEqualTo("hg2tg");
assertThat(repository.getName()).isEqualTo("hog");
assertThat(dao.contains(new NamespaceAndName("hg2tg", "hog"))).isTrue();
assertThat(dao.contains(new NamespaceAndName("hitchhiker", "HeartOfGold"))).isFalse();
String content = getXmlFileContent(REPOSITORY.getId());
assertThat(content).contains("<name>hog</name>");
}
@Test
void shouldDeleteRepositoryEvenWithChangedNamespace() {
dao.add(REPOSITORY);
REPOSITORY.setNamespace("hg2tg");
REPOSITORY.setName("hog");
dao.delete(REPOSITORY);
assertThat(dao.contains(new NamespaceAndName("space", "42"))).isFalse();
}
@Test
void shouldRemoveRepositoryDirectoryAfterDeletion() {
dao.add(REPOSITORY);
Path path = locationResolver.create(REPOSITORY.getId());
assertThat(path).isDirectory();
dao.delete(REPOSITORY);
assertThat(path).doesNotExist();
}
@Test
void shouldPersistPermissions() {
REPOSITORY.setPermissions(asList(new RepositoryPermission("trillian", asList("read", "write"), false), new RepositoryPermission("vogons", singletonList("delete"), true)));
dao.add(REPOSITORY);
String content = getXmlFileContent(REPOSITORY.getId());
System.out.println(content);
assertThat(content).containsSubsequence("trillian", "<verb>read</verb>", "<verb>write</verb>");
assertThat(content).containsSubsequence("vogons", "<verb>delete</verb>");
}
} }
@Test @Test
void shouldReturnXmlType() { void shouldReadExistingRepositoriesFromPathDatabase(@TempDirectory.TempDir Path basePath) throws IOException {
assertThat(dao.getType()).isEqualTo("xml"); doNothing().when(locationResolver).forAllPaths(forAllCaptor.capture());
XmlRepositoryDAO dao = new XmlRepositoryDAO(locationResolver, fileSystem);
Path repositoryPath = basePath.resolve("existing");
Files.createDirectories(repositoryPath);
URL metadataUrl = Resources.getResource("sonia/scm/store/repositoryDaoMetadata.xml");
Files.copy(metadataUrl.openStream(), repositoryPath.resolve("metadata.xml"));
forAllCaptor.getValue().accept("existing", repositoryPath);
assertThat(dao.contains(new NamespaceAndName("space", "existing"))).isTrue();
} }
@Test
void shouldReturnCreationTimeOfLocationResolver() {
long now = 42L;
when(locationResolver.getCreationTime()).thenReturn(now);
assertThat(dao.getCreationTime()).isEqualTo(now);
}
@Test
void shouldReturnLasModifiedOfLocationResolver() {
long now = 42L;
when(locationResolver.getLastModified()).thenReturn(now);
assertThat(dao.getLastModified()).isEqualTo(now);
}
@Test
void shouldReturnTrueForEachContainsMethod() {
dao.add(REPOSITORY);
assertThat(dao.contains(REPOSITORY)).isTrue();
assertThat(dao.contains(REPOSITORY.getId())).isTrue();
assertThat(dao.contains(REPOSITORY.getNamespaceAndName())).isTrue();
}
@Test
void shouldPersistRepository() {
dao.add(REPOSITORY);
String content = getXmlFileContent(REPOSITORY.getId());
assertThat(content).contains("<id>42</id>");
}
@Test
void shouldDeleteDataFile() {
dao.add(REPOSITORY);
dao.delete(REPOSITORY);
assertThat(metadataFile(REPOSITORY.getId())).doesNotExist();
}
@Test
void shouldModifyRepository() {
dao.add(REPOSITORY);
Repository changedRepository = REPOSITORY.clone();
changedRepository.setContact("change");
dao.modify(changedRepository);
String content = getXmlFileContent(REPOSITORY.getId());
assertThat(content).contains("change");
}
// @Test
// void shouldReturnFalseForEachContainsMethod() {
// Repository heartOfGold = createHeartOfGold();
//
// assertThat(dao.contains(heartOfGold)).isFalse();
// assertThat(dao.contains(heartOfGold.getId())).isFalse();
// assertThat(dao.contains(heartOfGold.getNamespaceAndName())).isFalse();
// }
//
// @Test
// void shouldReturnNullForEachGetMethod() {
// assertThat(dao.get("42")).isNull();
// assertThat(dao.get(new NamespaceAndName("hitchhiker","HeartOfGold"))).isNull();
// }
//
// @Test
// void shouldReturnRepository() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// assertThat(dao.get("42")).isEqualTo(heartOfGold);
// assertThat(dao.get(new NamespaceAndName("hitchhiker","HeartOfGold"))).isEqualTo(heartOfGold);
// }
//
// @Test
// void shouldNotReturnTheSameInstance() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Repository repository = dao.get("42");
// assertThat(repository).isNotSameAs(heartOfGold);
// }
//
// @Test
// void shouldReturnAllRepositories() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Repository puzzle = createPuzzle();
// dao.add(puzzle);
//
// Collection<Repository> repositories = dao.getAll();
// assertThat(repositories).containsExactlyInAnyOrder(heartOfGold, puzzle);
// }
//
// private Repository createPuzzle() {
// Repository puzzle = RepositoryTestData.create42Puzzle();
// puzzle.setId("42+1");
// return puzzle;
// }
//
// @Test
// void shouldModifyRepository() {
// Repository heartOfGold = createHeartOfGold();
// heartOfGold.setDescription("HeartOfGold");
// dao.add(heartOfGold);
// assertThat(dao.get("42").getDescription()).isEqualTo("HeartOfGold");
//
// heartOfGold = createHeartOfGold();
// heartOfGold.setDescription("Heart of Gold");
// dao.modify(heartOfGold);
//
// assertThat(dao.get("42").getDescription()).isEqualTo("Heart of Gold");
// }
//
// @Test
// void shouldRemoveRepository() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
// assertThat(dao.contains("42")).isTrue();
//
// dao.delete(heartOfGold);
// assertThat(dao.contains("42")).isFalse();
// assertThat(dao.contains(new NamespaceAndName("hitchhiker", "HeartOfGold"))).isFalse();
// }
//
// @Test
// void shouldUpdateLastModifiedAfterEachWriteOperation() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Long firstLastModified = dao.getLastModified();
// assertThat(firstLastModified).isNotNull();
//
// Repository puzzle = createPuzzle();
// dao.add(puzzle);
//
// Long lastModifiedAdded = dao.getLastModified();
// assertThat(lastModifiedAdded).isGreaterThan(firstLastModified);
//
// heartOfGold.setDescription("Heart of Gold");
// dao.modify(heartOfGold);
//
// Long lastModifiedModified = dao.getLastModified();
// assertThat(lastModifiedModified).isGreaterThan(lastModifiedAdded);
//
// dao.delete(puzzle);
//
// Long lastModifiedRemoved = dao.getLastModified();
// assertThat(lastModifiedRemoved).isGreaterThan(lastModifiedModified);
// }
//
// @Test
// void shouldRenameTheRepository() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// heartOfGold.setNamespace("hg2tg");
// heartOfGold.setName("hog");
//
// dao.modify(heartOfGold);
//
// Repository repository = dao.get("42");
// assertThat(repository.getNamespace()).isEqualTo("hg2tg");
// assertThat(repository.getName()).isEqualTo("hog");
//
// assertThat(dao.contains(new NamespaceAndName("hg2tg", "hog"))).isTrue();
// assertThat(dao.contains(new NamespaceAndName("hitchhiker", "HeartOfGold"))).isFalse();
// }
//
// @Test
// void shouldDeleteRepositoryEvenWithChangedNamespace() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// heartOfGold.setNamespace("hg2tg");
// heartOfGold.setName("hog");
//
// dao.delete(heartOfGold);
//
// assertThat(dao.contains(new NamespaceAndName("hitchhiker", "HeartOfGold"))).isFalse();
// }
//
// @Test
// void shouldReturnThePathForTheRepository() {
// Path repositoryPath = Paths.get("r", "42");
// when(initialLocationResolver.getPath("42")).thenReturn(repositoryPath);
//
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Path path = dao.getPath("42");
// assertThat(path).isEqualTo(repositoryPath);
// }
//
// @Test
// void shouldCreateTheDirectoryForTheRepository() {
// Path repositoryPath = Paths.get("r", "42");
// when(initialLocationResolver.getPath("42")).thenReturn(repositoryPath);
//
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Path path = getAbsolutePathFromDao("42");
// assertThat(path).isDirectory();
// }
//
// @Test
// void shouldRemoveRepositoryDirectoryAfterDeletion() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Path path = getAbsolutePathFromDao(heartOfGold.getId());
// assertThat(path).isDirectory();
//
// dao.delete(heartOfGold);
// assertThat(path).doesNotExist();
// }
//
// private Path getAbsolutePathFromDao(String id) {
// return context.resolve(dao.getPath(id));
// }
//
// @Test
// void shouldCreateRepositoryPathDatabase() throws IOException {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Path storePath = dao.resolveStorePath();
// assertThat(storePath).isRegularFile();
//
// String content = content(storePath);
//
// assertThat(content).contains(heartOfGold.getId());
// assertThat(content).contains(dao.getPath(heartOfGold.getId()).toString());
// }
//
// private String content(Path storePath) throws IOException {
// return new String(Files.readAllBytes(storePath), Charsets.UTF_8);
// }
//
// @Test
// void shouldStoreRepositoryMetadataAfterAdd() throws IOException {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Path repositoryDirectory = getAbsolutePathFromDao(heartOfGold.getId());
// Path metadataPath = dao.resolveDataPath(repositoryDirectory);
//
// assertThat(metadataPath).isRegularFile();
//
// String content = content(metadataPath);
// assertThat(content).contains(heartOfGold.getName());
// assertThat(content).contains(heartOfGold.getNamespace());
// assertThat(content).contains(heartOfGold.getDescription());
// }
//
// @Test
// void shouldUpdateRepositoryMetadataAfterModify() throws IOException {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// heartOfGold.setDescription("Awesome Spaceship");
// dao.modify(heartOfGold);
//
// Path repositoryDirectory = getAbsolutePathFromDao(heartOfGold.getId());
// Path metadataPath = dao.resolveDataPath(repositoryDirectory);
//
// String content = content(metadataPath);
// assertThat(content).contains("Awesome Spaceship");
// }
//
// @Test
// void shouldPersistPermissions() throws IOException {
// Repository heartOfGold = createHeartOfGold();
// heartOfGold.setPermissions(asList(new RepositoryPermission("trillian", asList("read", "write"), false), new RepositoryPermission("vogons", Collections.singletonList("delete"), true)));
// dao.add(heartOfGold);
//
// Path repositoryDirectory = getAbsolutePathFromDao(heartOfGold.getId());
// Path metadataPath = dao.resolveDataPath(repositoryDirectory);
//
// String content = content(metadataPath);
// System.out.println(content);
// assertThat(content).containsSubsequence("trillian", "<verb>read</verb>", "<verb>write</verb>");
// assertThat(content).containsSubsequence("vogons", "<verb>delete</verb>");
// }
//
// @Test
// void shouldReadPathDatabaseAndMetadataOfRepositories() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// // reload data
// dao = createDAO();
//
// heartOfGold = dao.get("42");
// assertThat(heartOfGold.getName()).isEqualTo("HeartOfGold");
//
// Path path = getAbsolutePathFromDao(heartOfGold.getId());
// assertThat(path).isDirectory();
// }
//
// @Test
// void shouldReadCreationTimeAndLastModifedDateFromDatabase() {
// Repository heartOfGold = createHeartOfGold();
// dao.add(heartOfGold);
//
// Long creationTime = dao.getCreationTime();
// Long lastModified = dao.getLastModified();
//
// // reload data
// dao = createDAO();
//
// assertThat(dao.getCreationTime()).isEqualTo(creationTime);
// assertThat(dao.getLastModified()).isEqualTo(lastModified);
// }
private String getXmlFileContent(String id) { private String getXmlFileContent(String id) {
Path storePath = metadataFile(id); Path storePath = metadataFile(id);
@@ -407,6 +300,6 @@ class XmlRepositoryDAOTest {
} }
private static Repository createRepository(String id) { private static Repository createRepository(String id) {
return new Repository(id, "xml", "space", "id"); return new Repository(id, "xml", "space", id);
} }
} }