diff --git a/scm-core/src/main/java/sonia/scm/repository/InitialRepositoryLocationResolver.java b/scm-core/src/main/java/sonia/scm/repository/InitialRepositoryLocationResolver.java index 5d79124518..d5b80cb130 100644 --- a/scm-core/src/main/java/sonia/scm/repository/InitialRepositoryLocationResolver.java +++ b/scm-core/src/main/java/sonia/scm/repository/InitialRepositoryLocationResolver.java @@ -19,7 +19,7 @@ import java.io.IOException; * @author Mohamed Karray * @since 2.0.0 */ -public final class InitialRepositoryLocationResolver { +public class InitialRepositoryLocationResolver { private static final String DEFAULT_REPOSITORY_PATH = "repositories"; public static final String REPOSITORIES_NATIVE_DIRECTORY = "data"; @@ -38,24 +38,21 @@ public final class InitialRepositoryLocationResolver { } public File createDirectory(Repository repository) { - File initialRepoFolder = getDirectory(getDefaultRepositoryPath(), repository); + String initialRepoFolder = getRelativeRepositoryPath(repository); try { - fileSystem.create(initialRepoFolder); + File directory = new File(context.getBaseDirectory(), initialRepoFolder); + fileSystem.create(directory); + return directory; } catch (IOException e) { - throw new InternalRepositoryException(repository, "Cannot create repository directory for "+repository.getNamespaceAndName(), e); + throw new InternalRepositoryException(repository, "Cannot create repository directory for " + repository.getNamespaceAndName(), e); } - return initialRepoFolder; } - public File getDirectory(String defaultRepositoryRelativePath, Repository repository) { - return new File(context.getBaseDirectory(), defaultRepositoryRelativePath + File.separator + repository.getId()); + public String getRelativeRepositoryPath(Repository repository) { + return getDefaultRepositoryPath() + File.separator + repository.getId(); } public String getDefaultRepositoryPath() { - return DEFAULT_REPOSITORY_PATH ; - } - - public String getRelativePath(String absolutePath) { - return absolutePath.replaceFirst(context.getBaseDirectory().getAbsolutePath()+"/", ""); + return DEFAULT_REPOSITORY_PATH; } } diff --git a/scm-core/src/test/java/sonia/scm/repository/InitialRepositoryLocationResolverTest.java b/scm-core/src/test/java/sonia/scm/repository/InitialRepositoryLocationResolverTest.java new file mode 100644 index 0000000000..fda0445359 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/InitialRepositoryLocationResolverTest.java @@ -0,0 +1,43 @@ +package sonia.scm.repository; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.SCMContextProvider; +import sonia.scm.io.DefaultFileSystem; + +import java.io.File; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class InitialRepositoryLocationResolverTest { + + @Mock + private SCMContextProvider context; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void init() throws IOException { + when(context.getBaseDirectory()).thenReturn(temporaryFolder.newFolder()); + } + + @Test + public void x() { + InitialRepositoryLocationResolver resolver = new InitialRepositoryLocationResolver(context, new DefaultFileSystem()); + Repository repository = new Repository(); + repository.setId("ABC"); + File directory = resolver.createDirectory(repository); + + assertThat(directory).isEqualTo(new File(context.getBaseDirectory(), "repositories/ABC")); + assertThat(context.getBaseDirectory().exists()).isTrue(); + } +} diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java index 189eaa854d..db57b228f9 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java @@ -21,9 +21,6 @@ public class RepositoryPath implements ModelObject { @XmlTransient private Repository repository; - @XmlTransient - private String absolutePath; - @XmlTransient private boolean toBeSynchronized; @@ -33,9 +30,8 @@ public class RepositoryPath implements ModelObject { public RepositoryPath() { } - public RepositoryPath(String path, String absolutePath, String id, Repository repository) { + public RepositoryPath(String path, String id, Repository repository) { this.path = path; - this.absolutePath = absolutePath; this.id = id; this.repository = repository; } @@ -102,12 +98,4 @@ public class RepositoryPath implements ModelObject { public void setToBeSynchronized(boolean toBeSynchronized) { this.toBeSynchronized = toBeSynchronized; } - - public String getAbsolutePath() { - return absolutePath; - } - - public void setAbsolutePath(String absolutePath) { - this.absolutePath = absolutePath; - } } 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 9e16060d45..58cd35a895 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 @@ -35,19 +35,18 @@ package sonia.scm.repository.xml; import com.google.inject.Inject; import com.google.inject.Singleton; -import sonia.scm.SCMContext; +import sonia.scm.SCMContextProvider; import sonia.scm.repository.InitialRepositoryLocationResolver; +import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.PathBasedRepositoryDAO; import sonia.scm.repository.Repository; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.xml.AbstractXmlDAO; -import java.io.File; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Collection; -import java.util.function.Supplier; +import java.util.Optional; /** * @author Sebastian Sdorra @@ -59,6 +58,7 @@ public class XmlRepositoryDAO public static final String STORE_NAME = "repositories"; private InitialRepositoryLocationResolver initialRepositoryLocationResolver; + private final SCMContextProvider context; //~--- constructors --------------------------------------------------------- @@ -66,11 +66,13 @@ public class XmlRepositoryDAO * Constructs ... * * @param storeFactory + * @param context */ @Inject - public XmlRepositoryDAO(ConfigurationStoreFactory storeFactory, InitialRepositoryLocationResolver initialRepositoryLocationResolver) { + public XmlRepositoryDAO(ConfigurationStoreFactory storeFactory, InitialRepositoryLocationResolver initialRepositoryLocationResolver, SCMContextProvider context) { super(storeFactory.getStore(XmlRepositoryDatabase.class, STORE_NAME)); this.initialRepositoryLocationResolver = initialRepositoryLocationResolver; + this.context = context; } //~--- methods -------------------------------------------------------------- @@ -92,22 +94,17 @@ public class XmlRepositoryDAO @Override public void modify(Repository repository) { - String path = getPath(repository).toAbsolutePath().toString(); - db.remove(repository.getId()); - RepositoryPath repositoryPath = new RepositoryPath(initialRepositoryLocationResolver.getRelativePath(path), path, repository.getId(), repository.clone()); + RepositoryPath repositoryPath = findExistingRepositoryPath(repository).orElseThrow(() -> new InternalRepositoryException(repository, "path object for repository not found")); + repositoryPath.setRepository(repository); repositoryPath.setToBeSynchronized(true); - add(repositoryPath); + storeDB(); } @Override public void add(Repository repository) { - String path = getPath(repository).toAbsolutePath().toString(); - RepositoryPath repositoryPath = new RepositoryPath(initialRepositoryLocationResolver.getRelativePath(path),path, repository.getId(), repository.clone()); + String relativeRepositoryPath = initialRepositoryLocationResolver.getRelativeRepositoryPath(repository); + RepositoryPath repositoryPath = new RepositoryPath(relativeRepositoryPath, repository.getId(), repository.clone()); repositoryPath.setToBeSynchronized(true); - add(repositoryPath); - } - - public void add(RepositoryPath repositoryPath) { synchronized (store) { db.add(repositoryPath); storeDB(); @@ -151,20 +148,15 @@ public class XmlRepositoryDAO @Override public Path getPath(Repository repository) { - return db.getPaths().stream() - .filter(repoPath -> repoPath.getId().equals(repository.getId())) - .findFirst() - .map(RepositoryPath::getPath) - .map(relativePath -> new File(SCMContext.getContext().getBaseDirectory(), relativePath).toPath()) - .orElseGet(createRepositoryPath(repository)); + return context + .getBaseDirectory() + .toPath() + .resolve(findExistingRepositoryPath(repository).map(RepositoryPath::getPath).orElse(initialRepositoryLocationResolver.getRelativeRepositoryPath(repository))); } - private Supplier createRepositoryPath(Repository repository) { - return () -> { - if (db.getDefaultDirectory() == null) { - db.setDefaultDirectory(initialRepositoryLocationResolver.getDefaultRepositoryPath()); - } - return Paths.get(initialRepositoryLocationResolver.getDirectory(db.getDefaultDirectory(), repository).toURI()); - }; + private Optional findExistingRepositoryPath(Repository repository) { + return db.getPaths().stream() + .filter(repoPath -> repoPath.getId().equals(repository.getId())) + .findFirst(); } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java index 447d4311eb..bf08909378 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java @@ -60,8 +60,6 @@ public class XmlRepositoryDatabase implements XmlDatabase { private Long lastModified; - private String defaultDirectory; - @XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class) @XmlElement(name = "repositories") private Map repositoryPathMap = new LinkedHashMap<>(); @@ -202,12 +200,4 @@ public class XmlRepositoryDatabase implements XmlDatabase { { this.lastModified = lastModified; } - - public String getDefaultDirectory() { - return defaultDirectory; - } - - public void setDefaultDirectory(String defaultDirectory) { - this.defaultDirectory = defaultDirectory; - } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java index 9a9249163e..7931f1dfb8 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java @@ -33,10 +33,10 @@ package sonia.scm.repository.xml; import sonia.scm.SCMContext; import sonia.scm.SCMContextProvider; +import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import sonia.scm.store.StoreConstants; import sonia.scm.store.StoreException; -import sonia.scm.util.IOUtil; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -44,6 +44,8 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.adapters.XmlAdapter; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.LinkedHashMap; import java.util.Map; @@ -66,11 +68,13 @@ public class XmlRepositoryMapAdapter extends XmlAdapter store; + @Mock + private XmlRepositoryDatabase db; + @Mock + private SCMContextProvider context; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void init() throws IOException { + when(storeFactory.getStore(XmlRepositoryDatabase.class, STORE_NAME)).thenReturn(store); + when(store.get()).thenReturn(db); + when(context.getBaseDirectory()).thenReturn(temporaryFolder.newFolder()); + } + + @Test + public void addShouldCreateNewRepositoryPathWithRelativePath() { + InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver(context, null); + XmlRepositoryDAO dao = new XmlRepositoryDAO(storeFactory, initialRepositoryLocationResolver, context); + + dao.add(new Repository("id", null, null, null)); + + verify(db).add(argThat(repositoryPath -> { + assertThat(repositoryPath.getId()).isEqualTo("id"); + assertThat(repositoryPath.getPath()).isEqualTo(initialRepositoryLocationResolver.getDefaultRepositoryPath() + "/id"); + return true; + })); + verify(store).set(db); + } + + @Test + public void modifyShould() { + Repository oldRepository = new Repository("id", "old", null, null); + RepositoryPath repositoryPath = new RepositoryPath("/path", "id", oldRepository); + when(db.getPaths()).thenReturn(asList(repositoryPath)); + + XmlRepositoryDAO dao = new XmlRepositoryDAO(storeFactory, new InitialRepositoryLocationResolver(context, null), context); + + Repository newRepository = new Repository("id", "new", null, null); + dao.modify(newRepository); + + assertThat(repositoryPath.getRepository()).isSameAs(newRepository); + verify(store).set(db); + } + + @Test + public void shouldGetPathInBaseDirectoryForRelativePath() { + Repository existingRepository = new Repository("id", "old", null, null); + RepositoryPath repositoryPath = new RepositoryPath("path", "id", existingRepository); + when(db.getPaths()).thenReturn(asList(repositoryPath)); + + XmlRepositoryDAO dao = new XmlRepositoryDAO(storeFactory, new InitialRepositoryLocationResolver(context, null), context); + + Path path = dao.getPath(existingRepository); + + assertThat(path.toString()).isEqualTo(context.getBaseDirectory().getPath() + "/path"); + } + + @Test + public void shouldGetPathInBaseDirectoryForAbsolutePath() { + Repository existingRepository = new Repository("id", "old", null, null); + RepositoryPath repositoryPath = new RepositoryPath("/tmp/path", "id", existingRepository); + when(db.getPaths()).thenReturn(asList(repositoryPath)); + + XmlRepositoryDAO dao = new XmlRepositoryDAO(storeFactory, new InitialRepositoryLocationResolver(context, null), context); + + Path path = dao.getPath(existingRepository); + + assertThat(path.toString()).isEqualTo("/tmp/path"); + } + + @Test + public void shouldGetPathForNewRepository() { + when(db.getPaths()).thenReturn(emptyList()); + + InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver(context, null); + XmlRepositoryDAO dao = new XmlRepositoryDAO(storeFactory, initialRepositoryLocationResolver, context); + + Repository newRepository = new Repository("id", "new", null, null); + Path path = dao.getPath(newRepository); + + assertThat(path.toString()).isEqualTo(context.getBaseDirectory().getPath() + "/" + initialRepositoryLocationResolver.getDefaultRepositoryPath() + "/id"); + } +} diff --git a/scm-test/src/main/java/sonia/scm/ManagerTestBase.java b/scm-test/src/main/java/sonia/scm/ManagerTestBase.java index eda3182638..a12fb39726 100644 --- a/scm-test/src/main/java/sonia/scm/ManagerTestBase.java +++ b/scm-test/src/main/java/sonia/scm/ManagerTestBase.java @@ -39,6 +39,7 @@ import org.junit.Rule; import org.junit.rules.TemporaryFolder; import sonia.scm.util.MockUtil; +import java.io.File; import java.io.IOException; /** @@ -56,10 +57,12 @@ public abstract class ManagerTestBase protected SCMContextProvider contextProvider; protected Manager manager; - + protected File temp; + @Before public void setUp() throws IOException { - contextProvider = MockUtil.getSCMContextProvider(tempFolder.newFolder()); + temp = tempFolder.newFolder(); + contextProvider = MockUtil.getSCMContextProvider(temp); manager = createManager(); manager.init(contextProvider); } diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java index c5ac187237..31758e5430 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java @@ -39,10 +39,11 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.util.ThreadContext; -import org.junit.Ignore; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import sonia.scm.AlreadyExistsException; @@ -50,6 +51,7 @@ import sonia.scm.HandlerEventType; import sonia.scm.Manager; import sonia.scm.ManagerTestBase; import sonia.scm.NotFoundException; +import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; import sonia.scm.io.DefaultFileSystem; @@ -107,10 +109,18 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { @Rule public ExpectedException thrown = ExpectedException.none(); + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + private ScmConfiguration configuration; private String mockedNamespace = "default_namespace"; + @Before + public void initContext() { + ((TempSCMContextProvider)SCMContext.getContext()).setBaseDirectory(temp); + } + @Test public void testCreate() { Repository heartOfGold = createTestRepository(); @@ -159,7 +169,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { } @Test - @Ignore public void testDeleteWithEnabledArchive() { Repository repository = createTestRepository(); @@ -426,7 +435,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { Set handlerSet = new HashSet<>(); ConfigurationStoreFactory factory = new JAXBConfigurationStoreFactory(contextProvider); InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver(contextProvider, fileSystem); - XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory, initialRepositoryLocationResolver); + XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory, initialRepositoryLocationResolver, contextProvider); RepositoryLocationResolver repositoryLocationResolver = new RepositoryLocationResolver(repositoryDAO, initialRepositoryLocationResolver); handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver)); handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver) {