From e0ad5c76a787ad1a3b31c495c58486ea8a936cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 14 May 2019 10:08:45 +0200 Subject: [PATCH] Cleanup tests for repository dao --- .../RepositoryLocationResolver.java | 1 + .../scm/repository/xml/XmlRepositoryDAO.java | 8 +- .../repository/xml/XmlRepositoryDAOTest.java | 579 +++++++----------- 3 files changed, 241 insertions(+), 347 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java index 28b0f34308..bc8df673d0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java @@ -13,6 +13,7 @@ public abstract class RepositoryLocationResolver { return create(type); } + @FunctionalInterface public interface RepositoryLocationResolverInstance { T getLocation(String repositoryId); } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java index 6c7030e2b0..c19b81d574 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java @@ -62,7 +62,6 @@ public class XmlRepositoryDAO implements RepositoryDAO { private final MetadataStore metadataStore = new MetadataStore(); - private final SCMContextProvider context; private final PathBasedRepositoryLocationResolver repositoryLocationResolver; private final FileSystem fileSystem; @@ -70,8 +69,7 @@ public class XmlRepositoryDAO implements RepositoryDAO { private final Map byNamespaceAndName; @Inject - public XmlRepositoryDAO(SCMContextProvider context, PathBasedRepositoryLocationResolver repositoryLocationResolver, FileSystem fileSystem) { - this.context = context; + public XmlRepositoryDAO(PathBasedRepositoryLocationResolver repositoryLocationResolver, FileSystem fileSystem) { this.repositoryLocationResolver = repositoryLocationResolver; this.fileSystem = fileSystem; @@ -165,7 +163,9 @@ public class XmlRepositoryDAO implements RepositoryDAO { 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); metadataStore.write(metadataPath, clone); } diff --git a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java index a5dda838c9..fd23091beb 100644 --- a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java +++ b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java @@ -2,391 +2,284 @@ package sonia.scm.repository.xml; import com.google.common.base.Charsets; +import com.google.common.io.Resources; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junitpioneer.jupiter.TempDirectory; -import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import sonia.scm.SCMContextProvider; import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.FileSystem; +import sonia.scm.repository.NamespaceAndName; 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.net.URL; import java.nio.file.Files; 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.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; +import static sonia.scm.repository.RepositoryTestData.createHeartOfGold; @ExtendWith({MockitoExtension.class, TempDirectory.class}) @MockitoSettings(strictness = Strictness.LENIENT) class XmlRepositoryDAOTest { - private static final Repository REPOSITORY = createRepository("42"); + private final Repository REPOSITORY = createRepository("42"); @Mock - private SCMContextProvider context; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PathBasedRepositoryLocationResolver locationResolver; + @Captor + private ArgumentCaptor> forAllCaptor; + private FileSystem fileSystem = new DefaultFileSystem(); private XmlRepositoryDAO dao; - private Path basePath; - @BeforeEach void createDAO(@TempDirectory.TempDir Path basePath) { - this.basePath = basePath; - - when(locationResolver.create(anyString())).thenAnswer(invocation -> { - Path resolvedPath = basePath.resolve(invocation.getArgument(0).toString()); - Files.createDirectories(resolvedPath); - return resolvedPath; - }); + when(locationResolver.create(Path.class)).thenReturn(locationResolver::create); + when(locationResolver.create(anyString())).thenAnswer(invocation -> createMockedRepoPath(basePath, invocation)); when(locationResolver.remove(anyString())).thenAnswer(invocation -> basePath.resolve(invocation.getArgument(0).toString())); - - when(context.getBaseDirectory()).thenReturn(basePath.toFile()); - - dao = createDAO(); } - private XmlRepositoryDAO createDAO() { - return new XmlRepositoryDAO(context, locationResolver, fileSystem); + private Path createMockedRepoPath(@TempDirectory.TempDir Path basePath, InvocationOnMock invocation) { + 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("42"); + } + + @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 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("hog"); + } + + @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", "read", "write"); + assertThat(content).containsSubsequence("vogons", "delete"); + } } @Test - void shouldReturnXmlType() { - assertThat(dao.getType()).isEqualTo("xml"); + void shouldReadExistingRepositoriesFromPathDatabase(@TempDirectory.TempDir Path basePath) throws IOException { + 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("42"); - } - - @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 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", "read", "write"); -// assertThat(content).containsSubsequence("vogons", "delete"); -// } -// -// @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) { Path storePath = metadataFile(id); @@ -407,6 +300,6 @@ class XmlRepositoryDAOTest { } private static Repository createRepository(String id) { - return new Repository(id, "xml", "space", "id"); + return new Repository(id, "xml", "space", id); } }