From ac851d4e8ac8df63e8ea966b287ee2ea811b46ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 22 May 2019 16:05:35 +0200 Subject: [PATCH] Implement copy strategy --- .../AbstractSimpleRepositoryHandler.java | 2 +- .../update/CopyMigrationStrategy.java | 66 +++++++++++++- .../update/CopyMigrationStrategyTest.java | 89 +++++++++++++++++++ .../update/V1RepositoryFileSystem.java | 67 ++++++++++++++ .../update/XmlRepositoryV1UpdateStepTest.java | 57 +----------- 5 files changed, 222 insertions(+), 59 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/repository/update/CopyMigrationStrategyTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/repository/update/V1RepositoryFileSystem.java diff --git a/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java index 875fb55617..1335001cdc 100644 --- a/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java +++ b/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java @@ -60,7 +60,7 @@ public abstract class AbstractSimpleRepositoryHandler path.resolve(namePart), (p1, p2) -> p1); + } + + private Path getTypeDependentPath(String type) { + return contextProvider.getBaseDirectory().toPath().resolve("repositories").resolve(type); + } + + private void copyData(Path sourceDirectory, Path targetDirectory) { + createDataDirectory(targetDirectory); + Stream list = listSourceDirectory(sourceDirectory); + list.forEach( + sourceFile -> { + Path targetFile = targetDirectory.resolve(sourceFile.getFileName()); + if (Files.isDirectory(sourceFile)) { + copyData(sourceFile, targetFile); + } else { + copyFile(sourceFile, targetFile); + } + } + ); + } + + private Stream listSourceDirectory(Path sourceDirectory) { + try { + return Files.list(sourceDirectory); + } catch (IOException e) { + throw new UpdateException("could not read original directory", e); + } + } + + private void copyFile(Path sourceFile, Path targetFile) { + try { + Files.copy(sourceFile, targetFile); + } catch (IOException e) { + throw new UpdateException("could not copy original file from " + sourceFile + " to " + targetFile, e); + } + } + + private void createDataDirectory(Path target) { + try { + Files.createDirectories(target); + } catch (IOException e) { + throw new UpdateException("could not create data directory " + target, e); + } } } diff --git a/scm-webapp/src/test/java/sonia/scm/repository/update/CopyMigrationStrategyTest.java b/scm-webapp/src/test/java/sonia/scm/repository/update/CopyMigrationStrategyTest.java new file mode 100644 index 0000000000..d7217bec48 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/repository/update/CopyMigrationStrategyTest.java @@ -0,0 +1,89 @@ +package sonia.scm.repository.update; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junitpioneer.jupiter.TempDirectory; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.SCMContextProvider; +import sonia.scm.repository.RepositoryLocationResolver; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +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.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(TempDirectory.class) +@ExtendWith(MockitoExtension.class) +class CopyMigrationStrategyTest { + + @Mock + SCMContextProvider contextProvider; + @Mock + RepositoryLocationResolver locationResolver; + + @BeforeEach + void mockContextProvider(@TempDirectory.TempDir Path tempDir) { + when(contextProvider.getBaseDirectory()).thenReturn(tempDir.toFile()); + } + + @BeforeEach + void createV1Home(@TempDirectory.TempDir Path tempDir) throws IOException { + V1RepositoryFileSystem.createV1Home(tempDir); + } + + @BeforeEach + void mockLocationResolver(@TempDirectory.TempDir Path tempDir) { + RepositoryLocationResolver.RepositoryLocationResolverInstance instanceMock = mock(RepositoryLocationResolver.RepositoryLocationResolverInstance.class); + when(locationResolver.forClass(Path.class)).thenReturn(instanceMock); + when(instanceMock.getLocation(anyString())).thenAnswer(invocation -> tempDir.resolve((String) invocation.getArgument(0))); + } + + @Test + void shouldUseStandardDirectory(@TempDirectory.TempDir Path tempDir) { + Path target = new CopyMigrationStrategy(contextProvider, locationResolver).migrate("b4f-a9f0-49f7-ad1f-37d3aae1c55f", "some/more/directories/than/one", "git"); + assertThat(target).isEqualTo(tempDir.resolve("b4f-a9f0-49f7-ad1f-37d3aae1c55f")); + } + + @Test + void shouldCopyDataDirectory(@TempDirectory.TempDir Path tempDir) { + Path target = new CopyMigrationStrategy(contextProvider, locationResolver).migrate("b4f-a9f0-49f7-ad1f-37d3aae1c55f", "some/more/directories/than/one", "git"); + assertThat(target.resolve("data")).exists(); + Path originalDataDir = tempDir + .resolve("repositories") + .resolve("git") + .resolve("some") + .resolve("more") + .resolve("directories") + .resolve("than") + .resolve("one"); + assertDirectoriesEqual(target.resolve("data"), originalDataDir); + } + + private void assertDirectoriesEqual(Path targetDataDir, Path originalDataDir) { + Stream list = null; + try { + list = Files.list(originalDataDir); + } catch (IOException e) { + fail("could not read original directory", e); + } + list.forEach( + original -> { + Path expectedTarget = targetDataDir.resolve(original.getFileName()); + assertThat(expectedTarget).exists(); + if (Files.isDirectory(original)) { + assertDirectoriesEqual(expectedTarget, original); + } else { + assertThat(expectedTarget).hasSameContentAs(original); + } + } + ); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/repository/update/V1RepositoryFileSystem.java b/scm-webapp/src/test/java/sonia/scm/repository/update/V1RepositoryFileSystem.java new file mode 100644 index 0000000000..146953d790 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/repository/update/V1RepositoryFileSystem.java @@ -0,0 +1,67 @@ +package sonia.scm.repository.update; + +import sonia.scm.repository.spi.ZippedRepositoryTestBase; + +import java.io.IOException; +import java.nio.file.Path; + +class V1RepositoryFileSystem { + /** + * Creates the following v1 repositories in the temp dir: + *
+   * 
+   *     
+   *     arthur@dent.uk
+   *     1558423492071
+   *     A repository with two folders.
+   *     3b91caa5-59c3-448f-920b-769aaa56b761
+   *     one/directory
+   *     false
+   *     false
+   *     git
+   * 
+   * 
+   *     
+   *     arthur@dent.uk
+   *     1558423543716
+   *     A repository in deeply nested folders.
+   *     c1597b4f-a9f0-49f7-ad1f-37d3aae1c55f
+   *     some/more/directories/than/one
+   *     false
+   *     false
+   *     git
+   * 
+   * 
+   *     
+   *     arthur@dent.uk
+   *     1558423440258
+   *     A simple repository without directories.
+   *     454972da-faf9-4437-b682-dc4a4e0aa8eb
+   *     1558425918578
+   *     simple
+   *     
+   *         true
+   *         mice
+   *         WRITE
+   *     
+   *     
+   *         false
+   *         dent
+   *         OWNER
+   *     
+   *     
+   *         false
+   *         trillian
+   *         READ
+   *     
+   *     false
+   *     false
+   *     git
+   *     http://localhost:8081/scm/git/simple
+   * 
+   * 
+ */ + static void createV1Home(Path tempDir) throws IOException { + ZippedRepositoryTestBase.extract(tempDir.toFile(), "sonia/scm/repository/update/scm-home.v1.zip"); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java b/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java index c9a64a10e4..9b455b9590 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java @@ -63,64 +63,9 @@ class XmlRepositoryV1UpdateStepTest { @Nested class WithExistingDatabase { - /** - * Creates the following v1 repositories in the temp dir: - *
-     * 
-     *     
-     *     arthur@dent.uk
-     *     1558423492071
-     *     A repository with two folders.
-     *     3b91caa5-59c3-448f-920b-769aaa56b761
-     *     one/directory
-     *     false
-     *     false
-     *     git
-     * 
-     * 
-     *     
-     *     arthur@dent.uk
-     *     1558423543716
-     *     A repository in deeply nested folders.
-     *     c1597b4f-a9f0-49f7-ad1f-37d3aae1c55f
-     *     some/more/directories/than/one
-     *     false
-     *     false
-     *     git
-     * 
-     * 
-     *     
-     *     arthur@dent.uk
-     *     1558423440258
-     *     A simple repository without directories.
-     *     454972da-faf9-4437-b682-dc4a4e0aa8eb
-     *     1558425918578
-     *     simple
-     *     
-     *         true
-     *         mice
-     *         WRITE
-     *     
-     *     
-     *         false
-     *         dent
-     *         OWNER
-     *     
-     *     
-     *         false
-     *         trillian
-     *         READ
-     *     
-     *     false
-     *     false
-     *     git
-     *     http://localhost:8081/scm/git/simple
-     * 
-     * 
- */ @BeforeEach void createV1Home(@TempDirectory.TempDir Path tempDir) throws IOException { - ZippedRepositoryTestBase.extract(tempDir.toFile(), "sonia/scm/repository/update/scm-home.v1.zip"); + V1RepositoryFileSystem.createV1Home(tempDir); } @BeforeEach