diff --git a/api/src/main/java/run/halo/app/infra/BackupRootGetter.java b/api/src/main/java/run/halo/app/infra/BackupRootGetter.java new file mode 100644 index 0000000000..ecf3c86ea7 --- /dev/null +++ b/api/src/main/java/run/halo/app/infra/BackupRootGetter.java @@ -0,0 +1,14 @@ +package run.halo.app.infra; + +import java.nio.file.Path; +import java.util.function.Supplier; + +/** + * Utility of getting backup root path. + * + * @author johnniang + * @since 2.9.0 + */ +public interface BackupRootGetter extends Supplier { + +} diff --git a/application/src/main/java/run/halo/app/infra/DefaultBackupRootGetter.java b/application/src/main/java/run/halo/app/infra/DefaultBackupRootGetter.java new file mode 100644 index 0000000000..976467aa31 --- /dev/null +++ b/application/src/main/java/run/halo/app/infra/DefaultBackupRootGetter.java @@ -0,0 +1,20 @@ +package run.halo.app.infra; + +import java.nio.file.Path; +import org.springframework.stereotype.Component; +import run.halo.app.infra.properties.HaloProperties; + +@Component +public class DefaultBackupRootGetter implements BackupRootGetter { + + private final HaloProperties haloProperties; + + public DefaultBackupRootGetter(HaloProperties haloProperties) { + this.haloProperties = haloProperties; + } + + @Override + public Path get() { + return haloProperties.getWorkDir().resolve("backups"); + } +} diff --git a/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java b/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java index 40d81fed69..27bb872143 100644 --- a/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java +++ b/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java @@ -34,6 +34,7 @@ import reactor.core.scheduler.Schedulers; import run.halo.app.extension.store.ExtensionStore; import run.halo.app.extension.store.ExtensionStoreRepository; +import run.halo.app.infra.BackupRootGetter; import run.halo.app.infra.exception.NotFoundException; import run.halo.app.infra.properties.HaloProperties; import run.halo.app.infra.utils.FileUtils; @@ -48,6 +49,8 @@ public class MigrationServiceImpl implements MigrationService { private final HaloProperties haloProperties; + private final BackupRootGetter backupRoot; + private final ObjectMapper objectMapper; private final Set excludes = Set.of( @@ -69,9 +72,10 @@ public class MigrationServiceImpl implements MigrationService { private final Scheduler scheduler = Schedulers.boundedElastic(); public MigrationServiceImpl(ExtensionStoreRepository repository, - HaloProperties haloProperties) { + HaloProperties haloProperties, BackupRootGetter backupRoot) { this.repository = repository; this.haloProperties = haloProperties; + this.backupRoot = backupRoot; this.objectMapper = JsonMapper.builder() .defaultPrettyPrinter(new MinimalPrettyPrinter()) .build(); @@ -90,7 +94,7 @@ ObjectMapper getObjectMapper() { } Path getBackupsRoot() { - return haloProperties.getWorkDir().resolve("backups"); + return backupRoot.get(); } @Override diff --git a/application/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java b/application/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java index 3559c4140d..96b3a2e4a0 100644 --- a/application/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java +++ b/application/src/main/java/run/halo/app/plugin/SharedApplicationContextHolder.java @@ -8,6 +8,7 @@ import run.halo.app.extension.DefaultSchemeManager; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.BackupRootGetter; import run.halo.app.infra.ExternalUrlSupplier; /** @@ -70,6 +71,8 @@ SharedApplicationContext createSharedApplicationContext() { rootApplicationContext.getBean(ServerSecurityContextRepository.class)); beanFactory.registerSingleton("attachmentService", rootApplicationContext.getBean(AttachmentService.class)); + beanFactory.registerSingleton("backupRootGetter", + rootApplicationContext.getBean(BackupRootGetter.class)); // TODO add more shared instance here return sharedApplicationContext; diff --git a/application/src/test/java/run/halo/app/infra/DefaultBackupRootGetterTest.java b/application/src/test/java/run/halo/app/infra/DefaultBackupRootGetterTest.java new file mode 100644 index 0000000000..bfba9f4386 --- /dev/null +++ b/application/src/test/java/run/halo/app/infra/DefaultBackupRootGetterTest.java @@ -0,0 +1,33 @@ +package run.halo.app.infra; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import run.halo.app.infra.properties.HaloProperties; + +@ExtendWith(MockitoExtension.class) +class DefaultBackupRootGetterTest { + + @Mock + HaloProperties haloProperties; + + @InjectMocks + DefaultBackupRootGetter backupRootGetter; + + @Test + void shouldGetBackupRootFromWorkDir() { + when(haloProperties.getWorkDir()).thenReturn(Path.of("workdir")); + var backupRoot = this.backupRootGetter.get(); + assertEquals(Path.of("workdir", "backups"), backupRoot); + verify(haloProperties).getWorkDir(); + } + + +} \ No newline at end of file diff --git a/application/src/test/java/run/halo/app/migration/impl/MigrationServiceImplTest.java b/application/src/test/java/run/halo/app/migration/impl/MigrationServiceImplTest.java index a4a1bc129a..1bbac7df3f 100644 --- a/application/src/test/java/run/halo/app/migration/impl/MigrationServiceImplTest.java +++ b/application/src/test/java/run/halo/app/migration/impl/MigrationServiceImplTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,6 +31,7 @@ import run.halo.app.extension.Metadata; import run.halo.app.extension.store.ExtensionStore; import run.halo.app.extension.store.ExtensionStoreRepository; +import run.halo.app.infra.BackupRootGetter; import run.halo.app.infra.exception.NotFoundException; import run.halo.app.infra.properties.HaloProperties; import run.halo.app.infra.utils.FileUtils; @@ -45,6 +46,9 @@ class MigrationServiceImplTest { @Mock HaloProperties haloProperties; + @Mock + BackupRootGetter backupRoot; + @InjectMocks MigrationServiceImpl migrationService; @@ -53,21 +57,23 @@ class MigrationServiceImplTest { @Test void backupTest() throws IOException { - var startTimestamp = Instant.now(); - var backup = createRunningBackup("fake-backup", startTimestamp); Files.writeString(tempDir.resolve("fake-file"), "halo", StandardOpenOption.CREATE_NEW); var extensionStores = List.of( createExtensionStore("fake-extension-store", "fake-data") ); when(repository.findAll()).thenReturn(Flux.fromIterable(extensionStores)); when(haloProperties.getWorkDir()).thenReturn(tempDir); + when(backupRoot.get()).thenReturn(tempDir.resolve("backups")); + var startTimestamp = Instant.now(); + var backup = createRunningBackup("fake-backup", startTimestamp); StepVerifier.create(migrationService.backup(backup)) .verifyComplete(); verify(repository).findAll(); // 1. backup workdir // 2. package backup - verify(haloProperties, times(2)).getWorkDir(); + verify(haloProperties).getWorkDir(); + verify(backupRoot).get(); var status = backup.getStatus(); var datetimePart = migrationService.getDateTimeFormatter().format(startTimestamp); @@ -134,26 +140,26 @@ void restoreTest() throws IOException, URISyntaxException { @Test void cleanupBackupTest() throws IOException { - var backup = createSucceededBackup("fake-backup", "backup.zip"); - var backupFile = tempDir.resolve("workdir").resolve("backups").resolve("backup.zip"); Files.createDirectories(backupFile.getParent()); Files.createFile(backupFile); - when(haloProperties.getWorkDir()).thenReturn(tempDir.resolve("workdir")); + when(backupRoot.get()).thenReturn(tempDir.resolve("workdir").resolve("backups")); + var backup = createSucceededBackup("fake-backup", "backup.zip"); StepVerifier.create(migrationService.cleanup(backup)) .verifyComplete(); - verify(haloProperties).getWorkDir(); + verify(haloProperties, never()).getWorkDir(); + verify(backupRoot).get(); assertTrue(Files.notExists(backupFile)); } @Test void downloadBackupTest() throws IOException { - var backup = createSucceededBackup("fake-backup", "backup.zip"); var backupFile = tempDir.resolve("workdir").resolve("backups").resolve("backup.zip"); Files.createDirectories(backupFile.getParent()); Files.writeString(backupFile, "this is a backup file.", StandardOpenOption.CREATE_NEW); - when(haloProperties.getWorkDir()).thenReturn(tempDir.resolve("workdir")); + when(backupRoot.get()).thenReturn(tempDir.resolve("workdir").resolve("backups")); + var backup = createSucceededBackup("fake-backup", "backup.zip"); StepVerifier.create(migrationService.download(backup)) .assertNext(resource -> { @@ -166,16 +172,21 @@ void downloadBackupTest() throws IOException { } }) .verifyComplete(); + + verify(haloProperties, never()).getWorkDir(); + verify(backupRoot).get(); } @Test void downloadBackupWhichDoesNotExist() { var backup = createSucceededBackup("fake-backup", "backup.zip"); - when(haloProperties.getWorkDir()).thenReturn(tempDir.resolve("workdir")); + when(backupRoot.get()).thenReturn(tempDir.resolve("workdir").resolve("backups")); StepVerifier.create(migrationService.download(backup)) .expectError(NotFoundException.class) .verify(); + verify(haloProperties, never()).getWorkDir(); + verify(backupRoot).get(); } Backup createSucceededBackup(String name, String filename) {