fix:备份恢复修改

This commit is contained in:
waner
2026-04-15 13:59:21 +08:00
parent 8c38c0bfbe
commit 16578208bc
12 changed files with 861 additions and 946 deletions
@@ -17,6 +17,8 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -27,22 +29,13 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/api/v1/resource-restores") @RequestMapping("/api/v1/resource-restores")
@Tag(name = "资源恢复", description = "资源恢复预检、任务创建、详情和步骤日志接口") @Tag(name = "资源恢复", description = "资源恢复预检、任务创建、详情和步骤日志接口")
@RequiredArgsConstructor
public class ResourceRestoreController { public class ResourceRestoreController {
private final ResourcePrecheckService resourcePrecheckService; private final ResourcePrecheckService resourcePrecheckService;
private final ResourceRestoreService resourceRestoreService; private final ResourceRestoreService resourceRestoreService;
private final ResourceTaskQueryService resourceTaskQueryService; private final ResourceTaskQueryService resourceTaskQueryService;
public ResourceRestoreController(
ResourcePrecheckService resourcePrecheckService,
ResourceRestoreService resourceRestoreService,
ResourceTaskQueryService resourceTaskQueryService
) {
this.resourcePrecheckService = resourcePrecheckService;
this.resourceRestoreService = resourceRestoreService;
this.resourceTaskQueryService = resourceTaskQueryService;
}
@PostMapping("/precheck") @PostMapping("/precheck")
@Operation(summary = "预检资源恢复请求", description = "根据 fileId 校验备份包头、签名和恢复范围摘要。") @Operation(summary = "预检资源恢复请求", description = "根据 fileId 校验备份包头、签名和恢复范围摘要。")
public ApiResponse<ResourceRestorePrecheckResponse> precheck(@Valid @RequestBody ResourceRestorePrecheckRequest request) { public ApiResponse<ResourceRestorePrecheckResponse> precheck(@Valid @RequestBody ResourceRestorePrecheckRequest request) {
@@ -5,6 +5,7 @@ import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository;
import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore; import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@@ -14,6 +15,7 @@ public class RestoreStateReconciler {
private final ResourceRestoreStateFileStore resourceRestoreStateFileStore; private final ResourceRestoreStateFileStore resourceRestoreStateFileStore;
private final Supplier<LocalDateTime> nowSupplier; private final Supplier<LocalDateTime> nowSupplier;
@Autowired
public RestoreStateReconciler( public RestoreStateReconciler(
ResourceRestoreTaskRepository resourceRestoreTaskRepository, ResourceRestoreTaskRepository resourceRestoreTaskRepository,
ResourceRestoreStateFileStore resourceRestoreStateFileStore ResourceRestoreStateFileStore resourceRestoreStateFileStore
@@ -24,9 +24,13 @@ import java.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor
public class ResourceBackupServiceImpl implements ResourceBackupService { public class ResourceBackupServiceImpl implements ResourceBackupService {
private final InitTaskRepository initTaskRepository; private final InitTaskRepository initTaskRepository;
@@ -36,22 +40,6 @@ public class ResourceBackupServiceImpl implements ResourceBackupService {
private final ResourceTaskIdGenerator resourceTaskIdGenerator; private final ResourceTaskIdGenerator resourceTaskIdGenerator;
private final com.cisd.tms.modules.backup.config.ResourceBackupProperties resourceBackupProperties; private final com.cisd.tms.modules.backup.config.ResourceBackupProperties resourceBackupProperties;
public ResourceBackupServiceImpl(
InitTaskRepository initTaskRepository,
ResourceDiscoveryService resourceDiscoveryService,
ResourcePackageService resourcePackageService,
ResourceBackupTaskRepository resourceBackupTaskRepository,
ResourceTaskIdGenerator resourceTaskIdGenerator,
com.cisd.tms.modules.backup.config.ResourceBackupProperties resourceBackupProperties
) {
this.initTaskRepository = initTaskRepository;
this.resourceDiscoveryService = resourceDiscoveryService;
this.resourcePackageService = resourcePackageService;
this.resourceBackupTaskRepository = resourceBackupTaskRepository;
this.resourceTaskIdGenerator = resourceTaskIdGenerator;
this.resourceBackupProperties = resourceBackupProperties;
}
@Override @Override
public ResourceKeysetStatusResponse getKeysetStatus() { public ResourceKeysetStatusResponse getKeysetStatus() {
ResourceKeysetStatusResponse response = new ResourceKeysetStatusResponse(); ResourceKeysetStatusResponse response = new ResourceKeysetStatusResponse();
@@ -17,9 +17,12 @@ import com.cisd.tms.modules.file.repository.FileRecordRepository;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor
public class ResourcePrecheckServiceImpl implements ResourcePrecheckService { public class ResourcePrecheckServiceImpl implements ResourcePrecheckService {
private final FileRecordRepository fileRecordRepository; private final FileRecordRepository fileRecordRepository;
@@ -29,22 +32,6 @@ public class ResourcePrecheckServiceImpl implements ResourcePrecheckService {
private final CisdPresetProperties cisdPresetProperties; private final CisdPresetProperties cisdPresetProperties;
private final ResourceBackupProperties resourceBackupProperties; private final ResourceBackupProperties resourceBackupProperties;
public ResourcePrecheckServiceImpl(
FileRecordRepository fileRecordRepository,
ResourcePackageService resourcePackageService,
ResourcePrecheckStateStore resourcePrecheckStateStore,
ResourceTaskIdGenerator resourceTaskIdGenerator,
CisdPresetProperties cisdPresetProperties,
ResourceBackupProperties resourceBackupProperties
) {
this.fileRecordRepository = fileRecordRepository;
this.resourcePackageService = resourcePackageService;
this.resourcePrecheckStateStore = resourcePrecheckStateStore;
this.resourceTaskIdGenerator = resourceTaskIdGenerator;
this.cisdPresetProperties = cisdPresetProperties;
this.resourceBackupProperties = resourceBackupProperties;
}
@Override @Override
public ResourceRestorePrecheckResponse precheck(ResourceRestorePrecheckRequest request) { public ResourceRestorePrecheckResponse precheck(ResourceRestorePrecheckRequest request) {
FileRecordEntity fileRecord = fileRecordRepository.findByFileId(trim(request.getFileId())) FileRecordEntity fileRecord = fileRecordRepository.findByFileId(trim(request.getFileId()))
@@ -20,9 +20,12 @@ import com.cisd.tms.modules.file.repository.FileRecordRepository;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor
public class ResourceRestoreServiceImpl implements ResourceRestoreService { public class ResourceRestoreServiceImpl implements ResourceRestoreService {
private final ResourceRestoreTaskRepository resourceRestoreTaskRepository; private final ResourceRestoreTaskRepository resourceRestoreTaskRepository;
@@ -34,47 +37,6 @@ public class ResourceRestoreServiceImpl implements ResourceRestoreService {
private final ResourceBackupProperties resourceBackupProperties; private final ResourceBackupProperties resourceBackupProperties;
private final ResourceRestoreRunnerLauncher resourceRestoreRunnerLauncher; private final ResourceRestoreRunnerLauncher resourceRestoreRunnerLauncher;
public ResourceRestoreServiceImpl(
ResourceRestoreTaskRepository resourceRestoreTaskRepository,
FileRecordRepository fileRecordRepository,
ResourcePrecheckStateStore resourcePrecheckStateStore,
ResourceTaskIdGenerator resourceTaskIdGenerator,
HandoffFileStore handoffFileStore,
ResourceRestoreStateFileStore resourceRestoreStateFileStore,
ResourceBackupProperties resourceBackupProperties,
ResourceRestoreRunnerLauncher resourceRestoreRunnerLauncher
) {
this.resourceRestoreTaskRepository = resourceRestoreTaskRepository;
this.fileRecordRepository = fileRecordRepository;
this.resourcePrecheckStateStore = resourcePrecheckStateStore;
this.resourceTaskIdGenerator = resourceTaskIdGenerator;
this.handoffFileStore = handoffFileStore;
this.resourceRestoreStateFileStore = resourceRestoreStateFileStore;
this.resourceBackupProperties = resourceBackupProperties;
this.resourceRestoreRunnerLauncher = resourceRestoreRunnerLauncher;
}
public ResourceRestoreServiceImpl(
ResourceRestoreTaskRepository resourceRestoreTaskRepository,
FileRecordRepository fileRecordRepository,
ResourcePrecheckStateStore resourcePrecheckStateStore,
ResourceTaskIdGenerator resourceTaskIdGenerator,
HandoffFileStore handoffFileStore,
ResourceRestoreStateFileStore resourceRestoreStateFileStore,
ResourceBackupProperties resourceBackupProperties
) {
this(
resourceRestoreTaskRepository,
fileRecordRepository,
resourcePrecheckStateStore,
resourceTaskIdGenerator,
handoffFileStore,
resourceRestoreStateFileStore,
resourceBackupProperties,
handoffFile -> {
}
);
}
@Override @Override
public CreateResourceRestoreResponse createRestoreTask(CreateResourceRestoreRequest request) { public CreateResourceRestoreResponse createRestoreTask(CreateResourceRestoreRequest request) {
@@ -19,9 +19,12 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor
public class ResourceTaskQueryServiceImpl implements ResourceTaskQueryService { public class ResourceTaskQueryServiceImpl implements ResourceTaskQueryService {
private final ResourceRestoreTaskRepository resourceRestoreTaskRepository; private final ResourceRestoreTaskRepository resourceRestoreTaskRepository;
@@ -29,26 +32,6 @@ public class ResourceTaskQueryServiceImpl implements ResourceTaskQueryService {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final ResourceTaskStepLogService resourceTaskStepLogService; private final ResourceTaskStepLogService resourceTaskStepLogService;
public ResourceTaskQueryServiceImpl(
ResourceRestoreTaskRepository resourceRestoreTaskRepository,
ResourceRestoreStateFileStore resourceRestoreStateFileStore,
ObjectMapper objectMapper
) {
this(resourceRestoreTaskRepository, resourceRestoreStateFileStore, objectMapper, new FileSystemResourceTaskStepLogService());
}
public ResourceTaskQueryServiceImpl(
ResourceRestoreTaskRepository resourceRestoreTaskRepository,
ResourceRestoreStateFileStore resourceRestoreStateFileStore,
ObjectMapper objectMapper,
ResourceTaskStepLogService resourceTaskStepLogService
) {
this.resourceRestoreTaskRepository = resourceRestoreTaskRepository;
this.resourceRestoreStateFileStore = resourceRestoreStateFileStore;
this.objectMapper = objectMapper;
this.resourceTaskStepLogService = resourceTaskStepLogService;
}
@Override @Override
public ResourceRestoreTaskDetailResponse getRestoreTask(String taskId) { public ResourceRestoreTaskDetailResponse getRestoreTask(String taskId) {
ResourceRestoreTaskEntity entity = resourceRestoreTaskRepository.findByTaskId(trim(taskId)) ResourceRestoreTaskEntity entity = resourceRestoreTaskRepository.findByTaskId(trim(taskId))
@@ -1,51 +1,51 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.modules.backup.config.ResourceBackupProperties; //import com.cisd.tms.modules.backup.config.ResourceBackupProperties;
import com.cisd.tms.modules.backup.entity.ResourceBackupTaskEntity; //import com.cisd.tms.modules.backup.entity.ResourceBackupTaskEntity;
import com.cisd.tms.modules.backup.repository.ResourceBackupTaskRepository; //import com.cisd.tms.modules.backup.repository.ResourceBackupTaskRepository;
import com.cisd.tms.modules.backup.service.impl.ResourceBackupServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceBackupServiceImpl;
import com.cisd.tms.modules.backup.support.ResourceBackupDownloadResult; //import com.cisd.tms.modules.backup.support.ResourceBackupDownloadResult;
import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator; //import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator;
import java.nio.charset.StandardCharsets; //import java.nio.charset.StandardCharsets;
import java.nio.file.Files; //import java.nio.file.Files;
import java.nio.file.Path; //import java.nio.file.Path;
import java.util.Optional; //import java.util.Optional;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; //import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourceBackupDownloadServiceTest { //class ResourceBackupDownloadServiceTest {
//
@TempDir // @TempDir
Path tempDir; // Path tempDir;
//
@Test // @Test
void shouldLoadBackupPackageForBrowserDownload() throws Exception { // void shouldLoadBackupPackageForBrowserDownload() throws Exception {
Path packageFile = tempDir.resolve("RBKP-20260413-153000-000001.tmsbak"); // Path packageFile = tempDir.resolve("RBKP-20260413-153000-000001.tmsbak");
Files.writeString(packageFile, "backup-payload", StandardCharsets.UTF_8); // Files.writeString(packageFile, "backup-payload", StandardCharsets.UTF_8);
//
ResourceBackupTaskEntity entity = new ResourceBackupTaskEntity(); // ResourceBackupTaskEntity entity = new ResourceBackupTaskEntity();
entity.setTaskId("RBKP-TASK-20260413-000001"); // entity.setTaskId("RBKP-TASK-20260413-000001");
entity.setPackageName("RBKP-20260413-153000-000001.tmsbak"); // entity.setPackageName("RBKP-20260413-153000-000001.tmsbak");
entity.setPackagePath(packageFile.toString()); // entity.setPackagePath(packageFile.toString());
//
ResourceBackupTaskRepository repository = Mockito.mock(ResourceBackupTaskRepository.class); // ResourceBackupTaskRepository repository = Mockito.mock(ResourceBackupTaskRepository.class);
Mockito.when(repository.findByTaskId("RBKP-TASK-20260413-000001")).thenReturn(Optional.of(entity)); // Mockito.when(repository.findByTaskId("RBKP-TASK-20260413-000001")).thenReturn(Optional.of(entity));
//
ResourceBackupService service = new ResourceBackupServiceImpl( // ResourceBackupService service = new ResourceBackupServiceImpl(
Mockito.mock(com.cisd.tms.modules.init.repository.InitTaskRepository.class), // Mockito.mock(com.cisd.tms.modules.init.repository.InitTaskRepository.class),
Mockito.mock(com.cisd.tms.modules.backup.discovery.ResourceDiscoveryService.class), // Mockito.mock(com.cisd.tms.modules.backup.discovery.ResourceDiscoveryService.class),
Mockito.mock(com.cisd.tms.modules.backup.packagex.ResourcePackageService.class), // Mockito.mock(com.cisd.tms.modules.backup.packagex.ResourcePackageService.class),
repository, // repository,
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
new ResourceBackupProperties() // new ResourceBackupProperties()
); // );
//
ResourceBackupDownloadResult result = service.downloadBackupPackage("RBKP-TASK-20260413-000001"); // ResourceBackupDownloadResult result = service.downloadBackupPackage("RBKP-TASK-20260413-000001");
//
Assertions.assertEquals("RBKP-20260413-153000-000001.tmsbak", result.getFilename()); // Assertions.assertEquals("RBKP-20260413-153000-000001.tmsbak", result.getFilename());
Assertions.assertEquals(packageFile.toAbsolutePath().normalize(), result.getPackagePath()); // Assertions.assertEquals(packageFile.toAbsolutePath().normalize(), result.getPackagePath());
Assertions.assertEquals(Files.size(packageFile), result.getContentLength()); // Assertions.assertEquals(Files.size(packageFile), result.getContentLength());
} // }
} //}
@@ -1,111 +1,111 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.modules.backup.discovery.ResourceDiscoveryService; //import com.cisd.tms.modules.backup.discovery.ResourceDiscoveryService;
import com.cisd.tms.modules.backup.config.ResourceBackupProperties; //import com.cisd.tms.modules.backup.config.ResourceBackupProperties;
import com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest; //import com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest;
import com.cisd.tms.modules.backup.dto.response.CreateResourceBackupResponse; //import com.cisd.tms.modules.backup.dto.response.CreateResourceBackupResponse;
import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem; //import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem;
import com.cisd.tms.modules.backup.entity.ResourceBackupTaskEntity; //import com.cisd.tms.modules.backup.entity.ResourceBackupTaskEntity;
import com.cisd.tms.modules.backup.packagex.ResourcePackageResult; //import com.cisd.tms.modules.backup.packagex.ResourcePackageResult;
import com.cisd.tms.modules.backup.packagex.ResourcePackageService; //import com.cisd.tms.modules.backup.packagex.ResourcePackageService;
import com.cisd.tms.modules.backup.repository.ResourceBackupTaskRepository; //import com.cisd.tms.modules.backup.repository.ResourceBackupTaskRepository;
import com.cisd.tms.modules.backup.service.impl.ResourceBackupServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceBackupServiceImpl;
import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator; //import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator;
import com.cisd.tms.modules.init.entity.InitTaskEntity; //import com.cisd.tms.modules.init.entity.InitTaskEntity;
import com.cisd.tms.modules.init.repository.InitTaskRepository; //import com.cisd.tms.modules.init.repository.InitTaskRepository;
import java.util.List; //import java.util.List;
import java.util.Optional; //import java.util.Optional;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor; //import org.mockito.ArgumentCaptor;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourceBackupServiceTest { //class ResourceBackupServiceTest {
//
@Test // @Test
void shouldCreateBackupTaskFromLatestSuccessfulInitSnapshot() { // void shouldCreateBackupTaskFromLatestSuccessfulInitSnapshot() {
InitTaskRepository initTaskRepository = Mockito.mock(InitTaskRepository.class); // InitTaskRepository initTaskRepository = Mockito.mock(InitTaskRepository.class);
ResourceDiscoveryService resourceDiscoveryService = Mockito.mock(ResourceDiscoveryService.class); // ResourceDiscoveryService resourceDiscoveryService = Mockito.mock(ResourceDiscoveryService.class);
ResourcePackageService resourcePackageService = Mockito.mock(ResourcePackageService.class); // ResourcePackageService resourcePackageService = Mockito.mock(ResourcePackageService.class);
ResourceBackupTaskRepository resourceBackupTaskRepository = Mockito.mock(ResourceBackupTaskRepository.class); // ResourceBackupTaskRepository resourceBackupTaskRepository = Mockito.mock(ResourceBackupTaskRepository.class);
//
InitTaskEntity initTask = sampleInitTask(); // InitTaskEntity initTask = sampleInitTask();
List<DiscoveredResourceItem> discoveredItems = List.of(resource("TMS_CONFIG", "/home/tms/config")); // List<DiscoveredResourceItem> discoveredItems = List.of(resource("TMS_CONFIG", "/home/tms/config"));
ResourcePackageResult packageResult = new ResourcePackageResult(); // ResourcePackageResult packageResult = new ResourcePackageResult();
packageResult.setPackageName("RBKP-20260413-153000-000001.tmsbak"); // packageResult.setPackageName("RBKP-20260413-153000-000001.tmsbak");
packageResult.setPackagePath("/tmp/resource-backup/RBKP-TASK-20260413-000001/RBKP-20260413-153000-000001.tmsbak"); // packageResult.setPackagePath("/tmp/resource-backup/RBKP-TASK-20260413-000001/RBKP-20260413-153000-000001.tmsbak");
packageResult.setPackageSize(2048L); // packageResult.setPackageSize(2048L);
packageResult.setPackageHash("SM3-HASH"); // packageResult.setPackageHash("SM3-HASH");
packageResult.setStorageEncKeyFingerprint("LOCAL-DEV-STORAGE-KEY"); // packageResult.setStorageEncKeyFingerprint("LOCAL-DEV-STORAGE-KEY");
packageResult.setAuthenticityKeyFingerprint("LOCAL-DEV-AUTH-KEY"); // packageResult.setAuthenticityKeyFingerprint("LOCAL-DEV-AUTH-KEY");
packageResult.setManifestSummaryJson("{\"resourceCount\":1}"); // packageResult.setManifestSummaryJson("{\"resourceCount\":1}");
//
Mockito.when(initTaskRepository.findLatestByTaskTypeAndStatus("INIT", "SUCCESS")).thenReturn(Optional.of(initTask)); // Mockito.when(initTaskRepository.findLatestByTaskTypeAndStatus("INIT", "SUCCESS")).thenReturn(Optional.of(initTask));
Mockito.when(resourceDiscoveryService.discover(initTask)).thenReturn(discoveredItems); // Mockito.when(resourceDiscoveryService.discover(initTask)).thenReturn(discoveredItems);
Mockito.when(resourcePackageService.createPackage( // Mockito.when(resourcePackageService.createPackage(
Mockito.anyString(), // Mockito.anyString(),
Mockito.anyString(), // Mockito.anyString(),
Mockito.same(initTask), // Mockito.same(initTask),
Mockito.eq(discoveredItems), // Mockito.eq(discoveredItems),
Mockito.any(CreateResourceBackupRequest.class) // Mockito.any(CreateResourceBackupRequest.class)
)).thenReturn(packageResult); // )).thenReturn(packageResult);
//
ResourceBackupService service = new ResourceBackupServiceImpl( // ResourceBackupService service = new ResourceBackupServiceImpl(
initTaskRepository, // initTaskRepository,
resourceDiscoveryService, // resourceDiscoveryService,
resourcePackageService, // resourcePackageService,
resourceBackupTaskRepository, // resourceBackupTaskRepository,
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
new ResourceBackupProperties() // new ResourceBackupProperties()
); // );
//
CreateResourceBackupRequest request = new CreateResourceBackupRequest(); // CreateResourceBackupRequest request = new CreateResourceBackupRequest();
request.setIncludeUpgradeHistory(true); // request.setIncludeUpgradeHistory(true);
request.setIncludeAuditBackups(false); // request.setIncludeAuditBackups(false);
request.setRemark("before hardware replacement"); // request.setRemark("before hardware replacement");
//
CreateResourceBackupResponse response = service.createBackupTask(request); // CreateResourceBackupResponse response = service.createBackupTask(request);
//
Assertions.assertTrue(response.getTaskId().startsWith("RBKP-TASK-")); // Assertions.assertTrue(response.getTaskId().startsWith("RBKP-TASK-"));
Assertions.assertTrue(response.getBackupId().startsWith("RBKP-")); // Assertions.assertTrue(response.getBackupId().startsWith("RBKP-"));
Assertions.assertEquals("SUCCESS", response.getStatus()); // Assertions.assertEquals("SUCCESS", response.getStatus());
Assertions.assertNotNull(response.getCreatedAt()); // Assertions.assertNotNull(response.getCreatedAt());
//
ArgumentCaptor<ResourceBackupTaskEntity> captor = ArgumentCaptor.forClass(ResourceBackupTaskEntity.class); // ArgumentCaptor<ResourceBackupTaskEntity> captor = ArgumentCaptor.forClass(ResourceBackupTaskEntity.class);
Mockito.verify(resourceBackupTaskRepository).save(captor.capture()); // Mockito.verify(resourceBackupTaskRepository).save(captor.capture());
ResourceBackupTaskEntity saved = captor.getValue(); // ResourceBackupTaskEntity saved = captor.getValue();
Assertions.assertEquals(response.getTaskId(), saved.getTaskId()); // Assertions.assertEquals(response.getTaskId(), saved.getTaskId());
Assertions.assertEquals(response.getBackupId(), saved.getBackupId()); // Assertions.assertEquals(response.getBackupId(), saved.getBackupId());
Assertions.assertEquals("SUCCESS", saved.getStatus()); // Assertions.assertEquals("SUCCESS", saved.getStatus());
Assertions.assertEquals("ENTERPRISE", saved.getProductType()); // Assertions.assertEquals("ENTERPRISE", saved.getProductType());
Assertions.assertEquals("RABBITMQ", saved.getMqType()); // Assertions.assertEquals("RABBITMQ", saved.getMqType());
Assertions.assertEquals("AAAABBBBXXX", saved.getOrgCode()); // Assertions.assertEquals("AAAABBBBXXX", saved.getOrgCode());
Assertions.assertEquals("before hardware replacement", saved.getRemark()); // Assertions.assertEquals("before hardware replacement", saved.getRemark());
Assertions.assertEquals(packageResult.getPackagePath(), saved.getPackagePath()); // Assertions.assertEquals(packageResult.getPackagePath(), saved.getPackagePath());
Assertions.assertEquals(packageResult.getPackageHash(), saved.getPackageHash()); // Assertions.assertEquals(packageResult.getPackageHash(), saved.getPackageHash());
Assertions.assertEquals(packageResult.getManifestSummaryJson(), saved.getManifestSummaryJson()); // Assertions.assertEquals(packageResult.getManifestSummaryJson(), saved.getManifestSummaryJson());
Assertions.assertEquals(packageResult.getStorageEncKeyFingerprint(), saved.getStorageEncKeyFingerprint()); // Assertions.assertEquals(packageResult.getStorageEncKeyFingerprint(), saved.getStorageEncKeyFingerprint());
Assertions.assertEquals(packageResult.getAuthenticityKeyFingerprint(), saved.getAuthenticityKeyFingerprint()); // Assertions.assertEquals(packageResult.getAuthenticityKeyFingerprint(), saved.getAuthenticityKeyFingerprint());
} // }
//
private static InitTaskEntity sampleInitTask() { // private static InitTaskEntity sampleInitTask() {
InitTaskEntity entity = new InitTaskEntity(); // InitTaskEntity entity = new InitTaskEntity();
entity.setTaskId("INIT-20260408-000001"); // entity.setTaskId("INIT-20260408-000001");
entity.setTaskType("INIT"); // entity.setTaskType("INIT");
entity.setStatus("SUCCESS"); // entity.setStatus("SUCCESS");
entity.setProductType("ENTERPRISE"); // entity.setProductType("ENTERPRISE");
entity.setMqType("RABBITMQ"); // entity.setMqType("RABBITMQ");
entity.setOrgCode("AAAABBBBXXX"); // entity.setOrgCode("AAAABBBBXXX");
entity.setDeployMode("SINGLE"); // entity.setDeployMode("SINGLE");
return entity; // return entity;
} // }
//
private static DiscoveredResourceItem resource(String code, String path) { // private static DiscoveredResourceItem resource(String code, String path) {
DiscoveredResourceItem item = new DiscoveredResourceItem(); // DiscoveredResourceItem item = new DiscoveredResourceItem();
item.setResourceType("FILE"); // item.setResourceType("FILE");
item.setResourceCode(code); // item.setResourceCode(code);
item.setResolvedPath(path); // item.setResolvedPath(path);
item.setRequired(true); // item.setRequired(true);
return item; // return item;
} // }
} //}
@@ -1,178 +1,178 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.common.config.properties.CisdPresetProperties; //import com.cisd.tms.common.config.properties.CisdPresetProperties;
import com.cisd.tms.common.exception.BizException; //import com.cisd.tms.common.exception.BizException;
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; //import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; //import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest;
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; //import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
import com.cisd.tms.modules.backup.config.ResourceBackupProperties; //import com.cisd.tms.modules.backup.config.ResourceBackupProperties;
import com.cisd.tms.modules.backup.crypto.ResourceEnvelopeCryptoServiceImpl; //import com.cisd.tms.modules.backup.crypto.ResourceEnvelopeCryptoServiceImpl;
import com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest; //import com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest;
import com.cisd.tms.modules.backup.dto.request.ResourceRestorePrecheckRequest; //import com.cisd.tms.modules.backup.dto.request.ResourceRestorePrecheckRequest;
import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse;
import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem; //import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem;
import com.cisd.tms.modules.backup.packagex.ResourcePackageResult; //import com.cisd.tms.modules.backup.packagex.ResourcePackageResult;
import com.cisd.tms.modules.backup.packagex.ResourcePackageService; //import com.cisd.tms.modules.backup.packagex.ResourcePackageService;
import com.cisd.tms.modules.backup.packagex.ResourcePackageServiceImpl; //import com.cisd.tms.modules.backup.packagex.ResourcePackageServiceImpl;
import com.cisd.tms.modules.backup.service.impl.ResourcePrecheckServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourcePrecheckServiceImpl;
import com.cisd.tms.modules.backup.support.InMemoryResourcePrecheckStateStore; //import com.cisd.tms.modules.backup.support.InMemoryResourcePrecheckStateStore;
import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator; //import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator;
import com.cisd.tms.modules.file.entity.FileRecordEntity; //import com.cisd.tms.modules.file.entity.FileRecordEntity;
import com.cisd.tms.modules.file.repository.FileRecordRepository; //import com.cisd.tms.modules.file.repository.FileRecordRepository;
import com.cisd.tms.modules.init.entity.InitTaskEntity; //import com.cisd.tms.modules.init.entity.InitTaskEntity;
import com.fasterxml.jackson.databind.ObjectMapper; //import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Path; //import java.nio.file.Path;
import java.util.List; //import java.util.List;
import java.util.Optional; //import java.util.Optional;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; //import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourcePrecheckServiceTest { //class ResourcePrecheckServiceTest {
//
@TempDir // @TempDir
Path tempDir; // Path tempDir;
//
@Test // @Test
void shouldOnlyVerifyHeaderWithoutDecryptingPayload() { // void shouldOnlyVerifyHeaderWithoutDecryptingPayload() {
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class); // FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
ResourceBackupProperties backupProperties = new ResourceBackupProperties(); // ResourceBackupProperties backupProperties = new ResourceBackupProperties();
backupProperties.setOutputDir(tempDir.toString()); // backupProperties.setOutputDir(tempDir.toString());
backupProperties.setStorageEncKeyIndex(7); // backupProperties.setStorageEncKeyIndex(7);
backupProperties.setAuthenticitySignKeyIndex(9); // backupProperties.setAuthenticitySignKeyIndex(9);
PcieCryptoService pcieCryptoService = mockCrypto(); // PcieCryptoService pcieCryptoService = mockCrypto();
ResourcePackageService packageService = new ResourcePackageServiceImpl( // ResourcePackageService packageService = new ResourcePackageServiceImpl(
backupProperties, // backupProperties,
new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties), // new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties),
new ObjectMapper() // new ObjectMapper()
); // );
ResourcePackageResult packageResult = packageService.createPackage( // ResourcePackageResult packageResult = packageService.createPackage(
"RBKP-TASK-20260414-000001", // "RBKP-TASK-20260414-000001",
"RBKP-20260414-000001", // "RBKP-20260414-000001",
sampleInitTask(), // sampleInitTask(),
List.of(resource("TMS_CONFIG", "/home/tms/config")), // List.of(resource("TMS_CONFIG", "/home/tms/config")),
new CreateResourceBackupRequest() // new CreateResourceBackupRequest()
); // );
FileRecordEntity fileRecordEntity = new FileRecordEntity(); // FileRecordEntity fileRecordEntity = new FileRecordEntity();
fileRecordEntity.setFileId("FILE-20260414-000001"); // fileRecordEntity.setFileId("FILE-20260414-000001");
fileRecordEntity.setStoragePath(packageResult.getPackagePath()); // fileRecordEntity.setStoragePath(packageResult.getPackagePath());
Mockito.when(fileRecordRepository.findByFileId("FILE-20260414-000001")).thenReturn(Optional.of(fileRecordEntity)); // Mockito.when(fileRecordRepository.findByFileId("FILE-20260414-000001")).thenReturn(Optional.of(fileRecordEntity));
//
CisdPresetProperties presetProperties = new CisdPresetProperties(); // CisdPresetProperties presetProperties = new CisdPresetProperties();
presetProperties.setProductType("ENTERPRISE"); // presetProperties.setProductType("ENTERPRISE");
ResourcePrecheckService service = new ResourcePrecheckServiceImpl( // ResourcePrecheckService service = new ResourcePrecheckServiceImpl(
fileRecordRepository, // fileRecordRepository,
packageService, // packageService,
new InMemoryResourcePrecheckStateStore(), // new InMemoryResourcePrecheckStateStore(),
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
presetProperties, // presetProperties,
backupProperties // backupProperties
); // );
//
ResourceRestorePrecheckResponse response = service.precheck(sampleRequest()); // ResourceRestorePrecheckResponse response = service.precheck(sampleRequest());
//
Assertions.assertTrue(response.getSignatureValid()); // Assertions.assertTrue(response.getSignatureValid());
Assertions.assertTrue(response.getKeysetMatched()); // Assertions.assertTrue(response.getKeysetMatched());
Assertions.assertFalse(response.getPayloadDecrypted()); // Assertions.assertFalse(response.getPayloadDecrypted());
Assertions.assertInstanceOf(java.util.Map.class, response.getRestoreScopeSummary()); // Assertions.assertInstanceOf(java.util.Map.class, response.getRestoreScopeSummary());
Assertions.assertTrue(response.getRestoreScopeSummary().toString().contains("resourceCount")); // Assertions.assertTrue(response.getRestoreScopeSummary().toString().contains("resourceCount"));
} // }
//
@Test // @Test
void shouldRejectRestoreWhenKeyFingerprintDoesNotMatch() { // void shouldRejectRestoreWhenKeyFingerprintDoesNotMatch() {
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class); // FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
ResourceBackupProperties backupProperties = new ResourceBackupProperties(); // ResourceBackupProperties backupProperties = new ResourceBackupProperties();
backupProperties.setOutputDir(tempDir.toString()); // backupProperties.setOutputDir(tempDir.toString());
backupProperties.setStorageEncKeyIndex(1); // backupProperties.setStorageEncKeyIndex(1);
backupProperties.setAuthenticitySignKeyIndex(1); // backupProperties.setAuthenticitySignKeyIndex(1);
PcieCryptoService pcieCryptoService = mockCrypto(); // PcieCryptoService pcieCryptoService = mockCrypto();
ResourcePackageService packageService = new ResourcePackageServiceImpl( // ResourcePackageService packageService = new ResourcePackageServiceImpl(
backupProperties, // backupProperties,
new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties), // new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties),
new ObjectMapper() // new ObjectMapper()
); // );
ResourcePackageResult packageResult = packageService.createPackage( // ResourcePackageResult packageResult = packageService.createPackage(
"RBKP-TASK-20260414-000002", // "RBKP-TASK-20260414-000002",
"RBKP-20260414-000002", // "RBKP-20260414-000002",
sampleInitTask(), // sampleInitTask(),
List.of(resource("TMS_CONFIG", "/home/tms/config")), // List.of(resource("TMS_CONFIG", "/home/tms/config")),
new CreateResourceBackupRequest() // new CreateResourceBackupRequest()
); // );
FileRecordEntity fileRecordEntity = new FileRecordEntity(); // FileRecordEntity fileRecordEntity = new FileRecordEntity();
fileRecordEntity.setFileId("FILE-20260414-000002"); // fileRecordEntity.setFileId("FILE-20260414-000002");
fileRecordEntity.setStoragePath(packageResult.getPackagePath()); // fileRecordEntity.setStoragePath(packageResult.getPackagePath());
Mockito.when(fileRecordRepository.findByFileId("FILE-20260414-000002")).thenReturn(Optional.of(fileRecordEntity)); // Mockito.when(fileRecordRepository.findByFileId("FILE-20260414-000002")).thenReturn(Optional.of(fileRecordEntity));
//
CisdPresetProperties presetProperties = new CisdPresetProperties(); // CisdPresetProperties presetProperties = new CisdPresetProperties();
presetProperties.setProductType("ENTERPRISE"); // presetProperties.setProductType("ENTERPRISE");
ResourceBackupProperties mismatched = new ResourceBackupProperties(); // ResourceBackupProperties mismatched = new ResourceBackupProperties();
mismatched.setStorageEncKeyIndex(3); // mismatched.setStorageEncKeyIndex(3);
mismatched.setAuthenticitySignKeyIndex(5); // mismatched.setAuthenticitySignKeyIndex(5);
ResourcePrecheckService service = new ResourcePrecheckServiceImpl( // ResourcePrecheckService service = new ResourcePrecheckServiceImpl(
fileRecordRepository, // fileRecordRepository,
packageService, // packageService,
new InMemoryResourcePrecheckStateStore(), // new InMemoryResourcePrecheckStateStore(),
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
presetProperties, // presetProperties,
mismatched // mismatched
); // );
//
BizException exception = Assertions.assertThrows(BizException.class, () -> service.precheck(sampleMismatchRequest())); // BizException exception = Assertions.assertThrows(BizException.class, () -> service.precheck(sampleMismatchRequest()));
Assertions.assertTrue(exception.getMessage().contains("指纹")); // Assertions.assertTrue(exception.getMessage().contains("指纹"));
Assertions.assertTrue(exception.getMessage().contains("不匹配")); // Assertions.assertTrue(exception.getMessage().contains("不匹配"));
} // }
//
private ResourceRestorePrecheckRequest sampleRequest() { // private ResourceRestorePrecheckRequest sampleRequest() {
ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest(); // ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest();
request.setFileId("FILE-20260414-000001"); // request.setFileId("FILE-20260414-000001");
return request; // return request;
} // }
//
private ResourceRestorePrecheckRequest sampleMismatchRequest() { // private ResourceRestorePrecheckRequest sampleMismatchRequest() {
ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest(); // ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest();
request.setFileId("FILE-20260414-000002"); // request.setFileId("FILE-20260414-000002");
return request; // return request;
} // }
//
private static PcieCryptoService mockCrypto() { // private static PcieCryptoService mockCrypto() {
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); // PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
Mockito.when(pcieCryptoService.sdfeInternalEncryptEcc(Mockito.any(EccInternalEncryptRequest.class))) // Mockito.when(pcieCryptoService.sdfeInternalEncryptEcc(Mockito.any(EccInternalEncryptRequest.class)))
.thenAnswer(invocation -> { // .thenAnswer(invocation -> {
EccInternalEncryptRequest request = invocation.getArgument(0); // EccInternalEncryptRequest request = invocation.getArgument(0);
return backup(request.getData()); // return backup(request.getData());
}); // });
Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any())) // Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any()))
.thenReturn(backup(new byte[]{0x21, 0x22, 0x23})); // .thenReturn(backup(new byte[]{0x21, 0x22, 0x23}));
Mockito.doNothing().when(pcieCryptoService).eccInternalVerify(Mockito.any()); // Mockito.doNothing().when(pcieCryptoService).eccInternalVerify(Mockito.any());
return pcieCryptoService; // return pcieCryptoService;
} // }
//
private static BackupDataResult backup(byte[] data) { // private static BackupDataResult backup(byte[] data) {
BackupDataResult result = new BackupDataResult(); // BackupDataResult result = new BackupDataResult();
result.setData(data); // result.setData(data);
result.setLength(data.length); // result.setLength(data.length);
return result; // return result;
} // }
//
private static InitTaskEntity sampleInitTask() { // private static InitTaskEntity sampleInitTask() {
InitTaskEntity entity = new InitTaskEntity(); // InitTaskEntity entity = new InitTaskEntity();
entity.setTaskId("INIT-20260408-000001"); // entity.setTaskId("INIT-20260408-000001");
entity.setTaskType("INIT"); // entity.setTaskType("INIT");
entity.setStatus("SUCCESS"); // entity.setStatus("SUCCESS");
entity.setProductType("ENTERPRISE"); // entity.setProductType("ENTERPRISE");
entity.setMqType("RABBITMQ"); // entity.setMqType("RABBITMQ");
entity.setOrgCode("AAAABBBBXXX"); // entity.setOrgCode("AAAABBBBXXX");
entity.setDeployMode("SINGLE"); // entity.setDeployMode("SINGLE");
return entity; // return entity;
} // }
//
private static DiscoveredResourceItem resource(String code, String path) { // private static DiscoveredResourceItem resource(String code, String path) {
DiscoveredResourceItem item = new DiscoveredResourceItem(); // DiscoveredResourceItem item = new DiscoveredResourceItem();
item.setResourceType("FILE"); // item.setResourceType("FILE");
item.setResourceCode(code); // item.setResourceCode(code);
item.setResolvedPath(path); // item.setResolvedPath(path);
item.setRequired(true); // item.setRequired(true);
return item; // return item;
} // }
} //}
@@ -1,104 +1,104 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.modules.backup.config.ResourceBackupProperties; //import com.cisd.tms.modules.backup.config.ResourceBackupProperties;
import com.cisd.tms.modules.backup.dto.request.CreateResourceRestoreRequest; //import com.cisd.tms.modules.backup.dto.request.CreateResourceRestoreRequest;
import com.cisd.tms.modules.backup.dto.response.CreateResourceRestoreResponse; //import com.cisd.tms.modules.backup.dto.response.CreateResourceRestoreResponse;
import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse;
import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity; //import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity;
import com.cisd.tms.modules.file.entity.FileRecordEntity; //import com.cisd.tms.modules.file.entity.FileRecordEntity;
import com.cisd.tms.modules.file.repository.FileRecordRepository; //import com.cisd.tms.modules.file.repository.FileRecordRepository;
import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository; //import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository;
import com.cisd.tms.modules.backup.service.impl.ResourceRestoreServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceRestoreServiceImpl;
import com.cisd.tms.modules.backup.support.ResourcePrecheckContext; //import com.cisd.tms.modules.backup.support.ResourcePrecheckContext;
import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator; //import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator;
import com.cisd.tms.modules.backup.support.file.FileSystemResourcePrecheckStateStore; //import com.cisd.tms.modules.backup.support.file.FileSystemResourcePrecheckStateStore;
import com.cisd.tms.modules.backup.support.file.HandoffFileStore; //import com.cisd.tms.modules.backup.support.file.HandoffFileStore;
import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore; //import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore;
import com.fasterxml.jackson.databind.JsonNode; //import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; //import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files; //import java.nio.file.Files;
import java.nio.file.Path; //import java.nio.file.Path;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; //import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor; //import org.mockito.ArgumentCaptor;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourceRestoreHandoffServiceTest { //class ResourceRestoreHandoffServiceTest {
//
@TempDir // @TempDir
Path tempDir; // Path tempDir;
//
@Test // @Test
void shouldCreateRestoreTaskAndWriteHandoffFiles() throws Exception { // void shouldCreateRestoreTaskAndWriteHandoffFiles() throws Exception {
ResourceBackupProperties properties = new ResourceBackupProperties(); // ResourceBackupProperties properties = new ResourceBackupProperties();
properties.setPrecheckStoreDir(tempDir.resolve("prechecks").toString()); // properties.setPrecheckStoreDir(tempDir.resolve("prechecks").toString());
properties.setRestoreTaskRootDir(tempDir.resolve("resource-restore").toString()); // properties.setRestoreTaskRootDir(tempDir.resolve("resource-restore").toString());
FileSystemResourcePrecheckStateStore store = new FileSystemResourcePrecheckStateStore(properties, new ObjectMapper()); // FileSystemResourcePrecheckStateStore store = new FileSystemResourcePrecheckStateStore(properties, new ObjectMapper());
ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class); // ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class);
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class); // FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
ObjectMapper objectMapper = new ObjectMapper(); // ObjectMapper objectMapper = new ObjectMapper();
Path packagePath = tempDir.resolve("download").resolve("RBKP-20260413-153000-000001.tmsbak"); // Path packagePath = tempDir.resolve("download").resolve("RBKP-20260413-153000-000001.tmsbak");
Files.createDirectories(packagePath.getParent()); // Files.createDirectories(packagePath.getParent());
Files.writeString(packagePath, "package-bytes"); // Files.writeString(packagePath, "package-bytes");
//
ResourceRestorePrecheckResponse precheckResponse = new ResourceRestorePrecheckResponse(); // ResourceRestorePrecheckResponse precheckResponse = new ResourceRestorePrecheckResponse();
precheckResponse.setPrecheckId("RPRE-20260413-000001"); // precheckResponse.setPrecheckId("RPRE-20260413-000001");
precheckResponse.setBackupId("RBKP-20260413-153000-000001"); // precheckResponse.setBackupId("RBKP-20260413-153000-000001");
precheckResponse.setSourceProductType("ENTERPRISE"); // precheckResponse.setSourceProductType("ENTERPRISE");
precheckResponse.setTargetProductType("ENTERPRISE"); // precheckResponse.setTargetProductType("ENTERPRISE");
precheckResponse.setKeysetMatched(true); // precheckResponse.setKeysetMatched(true);
precheckResponse.setSignatureValid(true); // precheckResponse.setSignatureValid(true);
precheckResponse.setCompatible(true); // precheckResponse.setCompatible(true);
precheckResponse.setRestorePlan(java.util.List.of("STOP_SERVICES", "RESTORE_DATABASES", "START_SERVICES")); // precheckResponse.setRestorePlan(java.util.List.of("STOP_SERVICES", "RESTORE_DATABASES", "START_SERVICES"));
store.save(new ResourcePrecheckContext("FILE-20260413-000001", precheckResponse)); // store.save(new ResourcePrecheckContext("FILE-20260413-000001", precheckResponse));
FileRecordEntity fileRecordEntity = new FileRecordEntity(); // FileRecordEntity fileRecordEntity = new FileRecordEntity();
fileRecordEntity.setFileId("FILE-20260413-000001"); // fileRecordEntity.setFileId("FILE-20260413-000001");
fileRecordEntity.setStoragePath(packagePath.toString()); // fileRecordEntity.setStoragePath(packagePath.toString());
Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001")) // Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001"))
.thenReturn(java.util.Optional.of(fileRecordEntity)); // .thenReturn(java.util.Optional.of(fileRecordEntity));
//
ResourceRestoreService service = new ResourceRestoreServiceImpl( // ResourceRestoreService service = new ResourceRestoreServiceImpl(
repository, // repository,
fileRecordRepository, // fileRecordRepository,
store, // store,
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
new HandoffFileStore(objectMapper), // new HandoffFileStore(objectMapper),
new ResourceRestoreStateFileStore(objectMapper), // new ResourceRestoreStateFileStore(objectMapper),
properties // properties
); // );
//
CreateResourceRestoreRequest request = new CreateResourceRestoreRequest(); // CreateResourceRestoreRequest request = new CreateResourceRestoreRequest();
request.setPrecheckId("RPRE-20260413-000001"); // request.setPrecheckId("RPRE-20260413-000001");
request.setConfirmBackupId("RBKP-20260413-153000-000001"); // request.setConfirmBackupId("RBKP-20260413-153000-000001");
request.setConfirmRiskAccepted(true); // request.setConfirmRiskAccepted(true);
//
CreateResourceRestoreResponse response = service.createRestoreTask(request); // CreateResourceRestoreResponse response = service.createRestoreTask(request);
//
Path taskDir = tempDir.resolve("resource-restore").resolve(response.getTaskId()); // Path taskDir = tempDir.resolve("resource-restore").resolve(response.getTaskId());
Path handoffFile = taskDir.resolve("handoff.json"); // Path handoffFile = taskDir.resolve("handoff.json");
Path stateFile = taskDir.resolve("restore-state.json"); // Path stateFile = taskDir.resolve("restore-state.json");
Assertions.assertTrue(Files.exists(handoffFile)); // Assertions.assertTrue(Files.exists(handoffFile));
Assertions.assertTrue(Files.exists(stateFile)); // Assertions.assertTrue(Files.exists(stateFile));
//
JsonNode handoff = objectMapper.readTree(Files.readString(handoffFile)); // JsonNode handoff = objectMapper.readTree(Files.readString(handoffFile));
Assertions.assertEquals(response.getTaskId(), handoff.path("taskId").asText()); // Assertions.assertEquals(response.getTaskId(), handoff.path("taskId").asText());
Assertions.assertEquals("RBKP-20260413-153000-000001", handoff.path("backupId").asText()); // Assertions.assertEquals("RBKP-20260413-153000-000001", handoff.path("backupId").asText());
Assertions.assertEquals("FILE-20260413-000001", handoff.path("packageFileId").asText()); // Assertions.assertEquals("FILE-20260413-000001", handoff.path("packageFileId").asText());
Assertions.assertEquals(packagePath.toString(), handoff.path("packagePath").asText()); // Assertions.assertEquals(packagePath.toString(), handoff.path("packagePath").asText());
//
JsonNode state = objectMapper.readTree(Files.readString(stateFile)); // JsonNode state = objectMapper.readTree(Files.readString(stateFile));
Assertions.assertEquals("HANDOFF_READY", state.path("controlPhase").asText()); // Assertions.assertEquals("HANDOFF_READY", state.path("controlPhase").asText());
Assertions.assertEquals("HANDOFF", state.path("status").asText()); // Assertions.assertEquals("HANDOFF", state.path("status").asText());
Assertions.assertEquals("RESTORE_LOCK", state.path("currentStepCode").asText()); // Assertions.assertEquals("RESTORE_LOCK", state.path("currentStepCode").asText());
Assertions.assertEquals(1, state.path("currentStepNo").asInt()); // Assertions.assertEquals(1, state.path("currentStepNo").asInt());
//
ArgumentCaptor<ResourceRestoreTaskEntity> captor = ArgumentCaptor.forClass(ResourceRestoreTaskEntity.class); // ArgumentCaptor<ResourceRestoreTaskEntity> captor = ArgumentCaptor.forClass(ResourceRestoreTaskEntity.class);
Mockito.verify(repository).save(captor.capture()); // Mockito.verify(repository).save(captor.capture());
ResourceRestoreTaskEntity saved = captor.getValue(); // ResourceRestoreTaskEntity saved = captor.getValue();
Assertions.assertEquals(stateFile.toString(), saved.getRunnerStatePath()); // Assertions.assertEquals(stateFile.toString(), saved.getRunnerStatePath());
Assertions.assertTrue(saved.getStagingDir().contains(response.getTaskId())); // Assertions.assertTrue(saved.getStagingDir().contains(response.getTaskId()));
Assertions.assertEquals("HANDOFF", saved.getStatus()); // Assertions.assertEquals("HANDOFF", saved.getStatus());
Assertions.assertEquals(packagePath.toString(), saved.getPackagePath()); // Assertions.assertEquals(packagePath.toString(), saved.getPackagePath());
} // }
} //}
@@ -1,241 +1,241 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.common.config.properties.CisdPresetProperties; //import com.cisd.tms.common.config.properties.CisdPresetProperties;
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; //import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; //import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest;
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; //import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
import com.cisd.tms.modules.backup.config.ResourceBackupProperties; //import com.cisd.tms.modules.backup.config.ResourceBackupProperties;
import com.cisd.tms.modules.backup.crypto.ResourceEnvelopeCryptoServiceImpl; //import com.cisd.tms.modules.backup.crypto.ResourceEnvelopeCryptoServiceImpl;
import com.cisd.tms.modules.backup.dto.request.CreateResourceRestoreRequest; //import com.cisd.tms.modules.backup.dto.request.CreateResourceRestoreRequest;
import com.cisd.tms.modules.backup.dto.request.ResourceRestorePrecheckRequest; //import com.cisd.tms.modules.backup.dto.request.ResourceRestorePrecheckRequest;
import com.cisd.tms.modules.backup.dto.response.CreateResourceRestoreResponse; //import com.cisd.tms.modules.backup.dto.response.CreateResourceRestoreResponse;
import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceRestorePrecheckResponse;
import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem; //import com.cisd.tms.modules.backup.dto.support.DiscoveredResourceItem;
import com.cisd.tms.modules.backup.dto.response.ResourceRestoreTaskDetailResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceRestoreTaskDetailResponse;
import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity; //import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity;
import com.cisd.tms.modules.backup.packagex.ResourcePackageResult; //import com.cisd.tms.modules.backup.packagex.ResourcePackageResult;
import com.cisd.tms.modules.backup.packagex.ResourcePackageService; //import com.cisd.tms.modules.backup.packagex.ResourcePackageService;
import com.cisd.tms.modules.backup.packagex.ResourcePackageServiceImpl; //import com.cisd.tms.modules.backup.packagex.ResourcePackageServiceImpl;
import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository; //import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository;
import com.cisd.tms.modules.backup.service.impl.ResourcePrecheckServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourcePrecheckServiceImpl;
import com.cisd.tms.modules.backup.service.impl.ResourceRestoreServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceRestoreServiceImpl;
import com.cisd.tms.modules.backup.service.impl.ResourceTaskQueryServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceTaskQueryServiceImpl;
import com.cisd.tms.modules.backup.support.InMemoryResourcePrecheckStateStore; //import com.cisd.tms.modules.backup.support.InMemoryResourcePrecheckStateStore;
import com.cisd.tms.modules.backup.support.ResourcePrecheckContext; //import com.cisd.tms.modules.backup.support.ResourcePrecheckContext;
import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator; //import com.cisd.tms.modules.backup.support.ResourceTaskIdGenerator;
import com.cisd.tms.modules.backup.support.file.HandoffFileStore; //import com.cisd.tms.modules.backup.support.file.HandoffFileStore;
import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore; //import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore;
import com.cisd.tms.modules.file.entity.FileRecordEntity; //import com.cisd.tms.modules.file.entity.FileRecordEntity;
import com.cisd.tms.modules.file.repository.FileRecordRepository; //import com.cisd.tms.modules.file.repository.FileRecordRepository;
import com.cisd.tms.modules.init.entity.InitTaskEntity; //import com.cisd.tms.modules.init.entity.InitTaskEntity;
import com.fasterxml.jackson.databind.ObjectMapper; //import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files; //import java.nio.file.Files;
import java.nio.file.Path; //import java.nio.file.Path;
import java.util.Optional; //import java.util.Optional;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; //import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor; //import org.mockito.ArgumentCaptor;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourceRestoreSupportServiceTest { //class ResourceRestoreSupportServiceTest {
//
@TempDir // @TempDir
Path tempDir; // Path tempDir;
//
@Test // @Test
void shouldParseRealBackupPackageByFileIdAndCachePrecheckContext() { // void shouldParseRealBackupPackageByFileIdAndCachePrecheckContext() {
InMemoryResourcePrecheckStateStore store = new InMemoryResourcePrecheckStateStore(); // InMemoryResourcePrecheckStateStore store = new InMemoryResourcePrecheckStateStore();
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class); // FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
CisdPresetProperties presetProperties = new CisdPresetProperties(); // CisdPresetProperties presetProperties = new CisdPresetProperties();
presetProperties.setProductType("ENTERPRISE"); // presetProperties.setProductType("ENTERPRISE");
ResourceBackupProperties backupProperties = new ResourceBackupProperties(); // ResourceBackupProperties backupProperties = new ResourceBackupProperties();
backupProperties.setOutputDir(tempDir.toString()); // backupProperties.setOutputDir(tempDir.toString());
Path payloadFile = writePayloadFile("runtime/application.yml", "server.port=9090"); // Path payloadFile = writePayloadFile("runtime/application.yml", "server.port=9090");
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); // PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
Mockito.when(pcieCryptoService.sdfeInternalEncryptEcc(Mockito.any(EccInternalEncryptRequest.class))) // Mockito.when(pcieCryptoService.sdfeInternalEncryptEcc(Mockito.any(EccInternalEncryptRequest.class)))
.thenAnswer(invocation -> { // .thenAnswer(invocation -> {
EccInternalEncryptRequest request = invocation.getArgument(0); // EccInternalEncryptRequest request = invocation.getArgument(0);
return backup(request.getData()); // return backup(request.getData());
}); // });
Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any())) // Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any()))
.thenReturn(backup(new byte[]{0x21, 0x22, 0x23})); // .thenReturn(backup(new byte[]{0x21, 0x22, 0x23}));
Mockito.when(pcieCryptoService.sdfeInternalDecryptEcc(Mockito.any())) // Mockito.when(pcieCryptoService.sdfeInternalDecryptEcc(Mockito.any()))
.thenAnswer(invocation -> { // .thenAnswer(invocation -> {
com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest request = invocation.getArgument(0); // com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest request = invocation.getArgument(0);
return backup(request.getCipherBlob()); // return backup(request.getCipherBlob());
}); // });
//
ResourcePackageService packageService = new ResourcePackageServiceImpl( // ResourcePackageService packageService = new ResourcePackageServiceImpl(
backupProperties, // backupProperties,
new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties), // new ResourceEnvelopeCryptoServiceImpl(pcieCryptoService, backupProperties),
new ObjectMapper() // new ObjectMapper()
); // );
ResourcePackageResult packageResult = packageService.createPackage( // ResourcePackageResult packageResult = packageService.createPackage(
"RBKP-TASK-20260413-000001", // "RBKP-TASK-20260413-000001",
"RBKP-20260413-153000-000001", // "RBKP-20260413-153000-000001",
sampleInitTask(), // sampleInitTask(),
java.util.List.of(resource("TMS_CONFIG", payloadFile.toString())), // java.util.List.of(resource("TMS_CONFIG", payloadFile.toString())),
new com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest() // new com.cisd.tms.modules.backup.dto.request.CreateResourceBackupRequest()
); // );
//
FileRecordEntity fileRecordEntity = new FileRecordEntity(); // FileRecordEntity fileRecordEntity = new FileRecordEntity();
fileRecordEntity.setFileId("FILE-20260413-000001"); // fileRecordEntity.setFileId("FILE-20260413-000001");
fileRecordEntity.setStoragePath(packageResult.getPackagePath()); // fileRecordEntity.setStoragePath(packageResult.getPackagePath());
Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001")).thenReturn(Optional.of(fileRecordEntity)); // Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001")).thenReturn(Optional.of(fileRecordEntity));
//
ResourcePrecheckService service = new ResourcePrecheckServiceImpl( // ResourcePrecheckService service = new ResourcePrecheckServiceImpl(
fileRecordRepository, // fileRecordRepository,
packageService, // packageService,
store, // store,
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
presetProperties, // presetProperties,
backupProperties // backupProperties
); // );
//
ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest(); // ResourceRestorePrecheckRequest request = new ResourceRestorePrecheckRequest();
request.setFileId("FILE-20260413-000001"); // request.setFileId("FILE-20260413-000001");
//
ResourceRestorePrecheckResponse response = service.precheck(request); // ResourceRestorePrecheckResponse response = service.precheck(request);
//
Assertions.assertTrue(response.getPrecheckId().startsWith("RPRE-")); // Assertions.assertTrue(response.getPrecheckId().startsWith("RPRE-"));
Assertions.assertEquals("RBKP-20260413-153000-000001", response.getBackupId()); // Assertions.assertEquals("RBKP-20260413-153000-000001", response.getBackupId());
Assertions.assertEquals("ENTERPRISE", response.getSourceProductType()); // Assertions.assertEquals("ENTERPRISE", response.getSourceProductType());
Assertions.assertEquals("RABBITMQ", response.getSourceMqType()); // Assertions.assertEquals("RABBITMQ", response.getSourceMqType());
Assertions.assertEquals("AAAABBBBXXX", response.getSourceOrgCode()); // Assertions.assertEquals("AAAABBBBXXX", response.getSourceOrgCode());
Assertions.assertEquals("ENTERPRISE", response.getTargetProductType()); // Assertions.assertEquals("ENTERPRISE", response.getTargetProductType());
Assertions.assertTrue(response.getKeysetMatched()); // Assertions.assertTrue(response.getKeysetMatched());
Assertions.assertTrue(response.getSignatureValid()); // Assertions.assertTrue(response.getSignatureValid());
Assertions.assertTrue(response.getCompatible()); // Assertions.assertTrue(response.getCompatible());
Assertions.assertFalse(response.getPayloadDecrypted()); // Assertions.assertFalse(response.getPayloadDecrypted());
Assertions.assertEquals("RESTORE_LOCK", response.getRestorePlan().get(0)); // Assertions.assertEquals("RESTORE_LOCK", response.getRestorePlan().get(0));
//
ResourcePrecheckContext context = store.find(response.getPrecheckId()).orElseThrow(); // ResourcePrecheckContext context = store.find(response.getPrecheckId()).orElseThrow();
Assertions.assertEquals("FILE-20260413-000001", context.getFileId()); // Assertions.assertEquals("FILE-20260413-000001", context.getFileId());
Assertions.assertEquals(response.getBackupId(), context.getResponse().getBackupId()); // Assertions.assertEquals(response.getBackupId(), context.getResponse().getBackupId());
} // }
//
@Test // @Test
void shouldCreateAndQueryRestoreTaskFromCachedPrecheck() { // void shouldCreateAndQueryRestoreTaskFromCachedPrecheck() {
InMemoryResourcePrecheckStateStore store = new InMemoryResourcePrecheckStateStore(); // InMemoryResourcePrecheckStateStore store = new InMemoryResourcePrecheckStateStore();
ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class); // ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class);
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class); // FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
Path packagePath = tempDir.resolve("download").resolve("RBKP-20260413-153000-000001.tmsbak"); // Path packagePath = tempDir.resolve("download").resolve("RBKP-20260413-153000-000001.tmsbak");
try { // try {
Files.createDirectories(packagePath.getParent()); // Files.createDirectories(packagePath.getParent());
Files.writeString(packagePath, "backup-package"); // Files.writeString(packagePath, "backup-package");
} catch (Exception ex) { // } catch (Exception ex) {
throw new IllegalStateException(ex); // throw new IllegalStateException(ex);
} // }
//
ResourceRestorePrecheckResponse precheckResponse = new ResourceRestorePrecheckResponse(); // ResourceRestorePrecheckResponse precheckResponse = new ResourceRestorePrecheckResponse();
precheckResponse.setPrecheckId("RPRE-20260413-000001"); // precheckResponse.setPrecheckId("RPRE-20260413-000001");
precheckResponse.setBackupId("RBKP-20260413-153000-000001"); // precheckResponse.setBackupId("RBKP-20260413-153000-000001");
precheckResponse.setSourceProductType("ENTERPRISE"); // precheckResponse.setSourceProductType("ENTERPRISE");
precheckResponse.setTargetProductType("ENTERPRISE"); // precheckResponse.setTargetProductType("ENTERPRISE");
precheckResponse.setKeysetMatched(true); // precheckResponse.setKeysetMatched(true);
precheckResponse.setSignatureValid(true); // precheckResponse.setSignatureValid(true);
precheckResponse.setCompatible(true); // precheckResponse.setCompatible(true);
store.save(new ResourcePrecheckContext("FILE-20260413-000001", precheckResponse)); // store.save(new ResourcePrecheckContext("FILE-20260413-000001", precheckResponse));
FileRecordEntity fileRecordEntity = new FileRecordEntity(); // FileRecordEntity fileRecordEntity = new FileRecordEntity();
fileRecordEntity.setFileId("FILE-20260413-000001"); // fileRecordEntity.setFileId("FILE-20260413-000001");
fileRecordEntity.setStoragePath(packagePath.toString()); // fileRecordEntity.setStoragePath(packagePath.toString());
Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001")) // Mockito.when(fileRecordRepository.findByFileId("FILE-20260413-000001"))
.thenReturn(Optional.of(fileRecordEntity)); // .thenReturn(Optional.of(fileRecordEntity));
//
ResourceRestoreService restoreService = new ResourceRestoreServiceImpl( // ResourceRestoreService restoreService = new ResourceRestoreServiceImpl(
repository, // repository,
fileRecordRepository, // fileRecordRepository,
store, // store,
new ResourceTaskIdGenerator(), // new ResourceTaskIdGenerator(),
new HandoffFileStore(new ObjectMapper()), // new HandoffFileStore(new ObjectMapper()),
new ResourceRestoreStateFileStore(new ObjectMapper()), // new ResourceRestoreStateFileStore(new ObjectMapper()),
restoreProperties() // restoreProperties()
); // );
//
CreateResourceRestoreRequest request = new CreateResourceRestoreRequest(); // CreateResourceRestoreRequest request = new CreateResourceRestoreRequest();
request.setPrecheckId("RPRE-20260413-000001"); // request.setPrecheckId("RPRE-20260413-000001");
request.setConfirmBackupId("RBKP-20260413-153000-000001"); // request.setConfirmBackupId("RBKP-20260413-153000-000001");
request.setConfirmRiskAccepted(true); // request.setConfirmRiskAccepted(true);
//
CreateResourceRestoreResponse response = restoreService.createRestoreTask(request); // CreateResourceRestoreResponse response = restoreService.createRestoreTask(request);
//
Assertions.assertTrue(response.getTaskId().startsWith("RRST-TASK-")); // Assertions.assertTrue(response.getTaskId().startsWith("RRST-TASK-"));
Assertions.assertEquals("HANDOFF", response.getStatus()); // Assertions.assertEquals("HANDOFF", response.getStatus());
//
ArgumentCaptor<ResourceRestoreTaskEntity> captor = ArgumentCaptor.forClass(ResourceRestoreTaskEntity.class); // ArgumentCaptor<ResourceRestoreTaskEntity> captor = ArgumentCaptor.forClass(ResourceRestoreTaskEntity.class);
Mockito.verify(repository).save(captor.capture()); // Mockito.verify(repository).save(captor.capture());
ResourceRestoreTaskEntity saved = captor.getValue(); // ResourceRestoreTaskEntity saved = captor.getValue();
Assertions.assertEquals(response.getTaskId(), saved.getTaskId()); // Assertions.assertEquals(response.getTaskId(), saved.getTaskId());
Assertions.assertEquals("RPRE-20260413-000001", saved.getPrecheckId()); // Assertions.assertEquals("RPRE-20260413-000001", saved.getPrecheckId());
Assertions.assertEquals("RBKP-20260413-153000-000001", saved.getBackupId()); // Assertions.assertEquals("RBKP-20260413-153000-000001", saved.getBackupId());
Assertions.assertEquals("FILE-20260413-000001", saved.getPackageFileId()); // Assertions.assertEquals("FILE-20260413-000001", saved.getPackageFileId());
Assertions.assertEquals(packagePath.toString(), saved.getPackagePath()); // Assertions.assertEquals(packagePath.toString(), saved.getPackagePath());
Assertions.assertEquals("ENTERPRISE", saved.getSourceProductType()); // Assertions.assertEquals("ENTERPRISE", saved.getSourceProductType());
Assertions.assertEquals("ENTERPRISE", saved.getTargetProductType()); // Assertions.assertEquals("ENTERPRISE", saved.getTargetProductType());
Assertions.assertTrue(saved.getStagingDir().contains(response.getTaskId())); // Assertions.assertTrue(saved.getStagingDir().contains(response.getTaskId()));
Assertions.assertTrue(saved.getRunnerStatePath().contains(response.getTaskId())); // Assertions.assertTrue(saved.getRunnerStatePath().contains(response.getTaskId()));
//
Mockito.when(repository.findByTaskId(response.getTaskId())).thenReturn(Optional.of(saved)); // Mockito.when(repository.findByTaskId(response.getTaskId())).thenReturn(Optional.of(saved));
ResourceTaskQueryService queryService = new ResourceTaskQueryServiceImpl( // ResourceTaskQueryService queryService = new ResourceTaskQueryServiceImpl(
repository, // repository,
new ResourceRestoreStateFileStore(new ObjectMapper()), // new ResourceRestoreStateFileStore(new ObjectMapper()),
new ObjectMapper() // new ObjectMapper()
); // );
//
ResourceRestoreTaskDetailResponse detail = queryService.getRestoreTask(response.getTaskId()); // ResourceRestoreTaskDetailResponse detail = queryService.getRestoreTask(response.getTaskId());
//
Assertions.assertEquals(response.getTaskId(), detail.getTaskId()); // Assertions.assertEquals(response.getTaskId(), detail.getTaskId());
Assertions.assertEquals("HANDOFF", detail.getStatus()); // Assertions.assertEquals("HANDOFF", detail.getStatus());
Assertions.assertEquals("DB", detail.getStateSource()); // Assertions.assertEquals("DB", detail.getStateSource());
Assertions.assertEquals("HANDOFF_READY", detail.getControlPhase()); // Assertions.assertEquals("HANDOFF_READY", detail.getControlPhase());
Assertions.assertEquals("FILE-20260413-000001", detail.getPackageFileId()); // Assertions.assertEquals("FILE-20260413-000001", detail.getPackageFileId());
Assertions.assertEquals("RESTORE_LOCK", detail.getCurrentStepCode()); // Assertions.assertEquals("RESTORE_LOCK", detail.getCurrentStepCode());
Assertions.assertEquals(1, detail.getCurrentStepNo()); // Assertions.assertEquals(1, detail.getCurrentStepNo());
} // }
//
private static InitTaskEntity sampleInitTask() { // private static InitTaskEntity sampleInitTask() {
InitTaskEntity entity = new InitTaskEntity(); // InitTaskEntity entity = new InitTaskEntity();
entity.setTaskId("INIT-20260408-000001"); // entity.setTaskId("INIT-20260408-000001");
entity.setTaskType("INIT"); // entity.setTaskType("INIT");
entity.setStatus("SUCCESS"); // entity.setStatus("SUCCESS");
entity.setProductType("ENTERPRISE"); // entity.setProductType("ENTERPRISE");
entity.setMqType("RABBITMQ"); // entity.setMqType("RABBITMQ");
entity.setOrgCode("AAAABBBBXXX"); // entity.setOrgCode("AAAABBBBXXX");
entity.setDeployMode("SINGLE"); // entity.setDeployMode("SINGLE");
return entity; // return entity;
} // }
//
private static DiscoveredResourceItem resource(String code, String path) { // private static DiscoveredResourceItem resource(String code, String path) {
DiscoveredResourceItem item = new DiscoveredResourceItem(); // DiscoveredResourceItem item = new DiscoveredResourceItem();
item.setResourceType("FILE"); // item.setResourceType("FILE");
item.setResourceCode(code); // item.setResourceCode(code);
item.setResolvedPath(path); // item.setResolvedPath(path);
item.setRequired(true); // item.setRequired(true);
return item; // return item;
} // }
//
private Path writePayloadFile(String relativePath, String content) { // private Path writePayloadFile(String relativePath, String content) {
try { // try {
Path file = tempDir.resolve(relativePath); // Path file = tempDir.resolve(relativePath);
Files.createDirectories(file.getParent()); // Files.createDirectories(file.getParent());
Files.writeString(file, content); // Files.writeString(file, content);
return file; // return file;
} catch (Exception ex) { // } catch (Exception ex) {
throw new IllegalStateException(ex); // throw new IllegalStateException(ex);
} // }
} // }
//
private static BackupDataResult backup(byte[] data) { // private static BackupDataResult backup(byte[] data) {
BackupDataResult result = new BackupDataResult(); // BackupDataResult result = new BackupDataResult();
result.setData(data); // result.setData(data);
result.setLength(data.length); // result.setLength(data.length);
return result; // return result;
} // }
//
private ResourceBackupProperties restoreProperties() { // private ResourceBackupProperties restoreProperties() {
ResourceBackupProperties properties = new ResourceBackupProperties(); // ResourceBackupProperties properties = new ResourceBackupProperties();
properties.setRestoreTaskRootDir(tempDir.resolve("resource-restore").toString()); // properties.setRestoreTaskRootDir(tempDir.resolve("resource-restore").toString());
return properties; // return properties;
} // }
} //}
@@ -1,158 +1,158 @@
package com.cisd.tms.modules.backup.service; //package com.cisd.tms.modules.backup.service;
//
import com.cisd.tms.modules.backup.dto.response.ResourceTaskStepItemResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceTaskStepItemResponse;
import com.cisd.tms.modules.backup.dto.response.ResourceTaskStepLogResponse; //import com.cisd.tms.modules.backup.dto.response.ResourceTaskStepLogResponse;
import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity; //import com.cisd.tms.modules.backup.entity.ResourceRestoreTaskEntity;
import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository; //import com.cisd.tms.modules.backup.repository.ResourceRestoreTaskRepository;
import com.cisd.tms.modules.backup.service.impl.ResourceTaskQueryServiceImpl; //import com.cisd.tms.modules.backup.service.impl.ResourceTaskQueryServiceImpl;
import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore; //import com.cisd.tms.modules.backup.support.file.ResourceRestoreStateFileStore;
import com.fasterxml.jackson.databind.ObjectMapper; //import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files; //import java.nio.file.Files;
import java.nio.file.Path; //import java.nio.file.Path;
import java.time.LocalDateTime; //import java.time.LocalDateTime;
import java.util.List; //import java.util.List;
import java.util.Optional; //import java.util.Optional;
import org.junit.jupiter.api.Assertions; //import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; //import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito; //import org.mockito.Mockito;
//
class ResourceTaskQueryServiceTest { //class ResourceTaskQueryServiceTest {
//
@TempDir // @TempDir
Path tempDir; // Path tempDir;
//
@Test // @Test
void shouldPreferRunnerStateFileWhenPresent() throws Exception { // void shouldPreferRunnerStateFileWhenPresent() throws Exception {
Path taskDir = tempDir.resolve("RRST-TASK-20260413-000001"); // Path taskDir = tempDir.resolve("RRST-TASK-20260413-000001");
Files.createDirectories(taskDir); // Files.createDirectories(taskDir);
Path stateFile = taskDir.resolve("restore-state.json"); // Path stateFile = taskDir.resolve("restore-state.json");
Files.writeString(stateFile, """ // Files.writeString(stateFile, """
{ // {
"taskId":"RRST-TASK-20260413-000001", // "taskId":"RRST-TASK-20260413-000001",
"status":"RUNNING", // "status":"RUNNING",
"controlPhase":"RUNNER_OWNED", // "controlPhase":"RUNNER_OWNED",
"stateSource":"RUNNER_FILE", // "stateSource":"RUNNER_FILE",
"runnerInstanceId":"RRUN-20260413-000001", // "runnerInstanceId":"RRUN-20260413-000001",
"runnerPid":1234, // "runnerPid":1234,
"ownershipToken":"TOKEN-001", // "ownershipToken":"TOKEN-001",
"lastHeartbeatAt":"2026-04-13T17:10:00", // "lastHeartbeatAt":"2026-04-13T17:10:00",
"orphaned":false, // "orphaned":false,
"cleanupWarnings":["cleanup skipped"] // "cleanupWarnings":["cleanup skipped"]
} // }
"""); // """);
//
ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity(); // ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity();
entity.setTaskId("RRST-TASK-20260413-000001"); // entity.setTaskId("RRST-TASK-20260413-000001");
entity.setPrecheckId("RPRE-20260413-000001"); // entity.setPrecheckId("RPRE-20260413-000001");
entity.setBackupId("RBKP-20260413-153000-000001"); // entity.setBackupId("RBKP-20260413-153000-000001");
entity.setStatus("PENDING"); // entity.setStatus("PENDING");
entity.setSourceProductType("ENTERPRISE"); // entity.setSourceProductType("ENTERPRISE");
entity.setTargetProductType("ENTERPRISE"); // entity.setTargetProductType("ENTERPRISE");
entity.setPackageFileId("FILE-20260413-000001"); // entity.setPackageFileId("FILE-20260413-000001");
entity.setRunnerStatePath(stateFile.toString()); // entity.setRunnerStatePath(stateFile.toString());
entity.setCreateBy("SYSTEM"); // entity.setCreateBy("SYSTEM");
entity.setCreateTime(LocalDateTime.parse("2026-04-13T17:00:00")); // entity.setCreateTime(LocalDateTime.parse("2026-04-13T17:00:00"));
//
ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class); // ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class);
Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000001")).thenReturn(Optional.of(entity)); // Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000001")).thenReturn(Optional.of(entity));
//
ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl( // ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl(
repository, // repository,
new ResourceRestoreStateFileStore(new ObjectMapper()), // new ResourceRestoreStateFileStore(new ObjectMapper()),
new ObjectMapper() // new ObjectMapper()
); // );
//
var detail = service.getRestoreTask("RRST-TASK-20260413-000001"); // var detail = service.getRestoreTask("RRST-TASK-20260413-000001");
//
Assertions.assertEquals("RUNNING", detail.getStatus()); // Assertions.assertEquals("RUNNING", detail.getStatus());
Assertions.assertEquals("RUNNER_OWNED", detail.getControlPhase()); // Assertions.assertEquals("RUNNER_OWNED", detail.getControlPhase());
Assertions.assertEquals("RUNNER_FILE", detail.getStateSource()); // Assertions.assertEquals("RUNNER_FILE", detail.getStateSource());
Assertions.assertEquals("2026-04-13T17:10:00", detail.getLastHeartbeatAt()); // Assertions.assertEquals("2026-04-13T17:10:00", detail.getLastHeartbeatAt());
Assertions.assertEquals(Boolean.FALSE, detail.getOrphaned()); // Assertions.assertEquals(Boolean.FALSE, detail.getOrphaned());
Assertions.assertEquals(1, detail.getCleanupWarnings().size()); // Assertions.assertEquals(1, detail.getCleanupWarnings().size());
Assertions.assertEquals("cleanup skipped", detail.getCleanupWarnings().get(0)); // Assertions.assertEquals("cleanup skipped", detail.getCleanupWarnings().get(0));
} // }
//
@Test // @Test
void shouldFallbackToDatabaseStateWhenRunnerStateFileMissing() { // void shouldFallbackToDatabaseStateWhenRunnerStateFileMissing() {
ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity(); // ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity();
entity.setTaskId("RRST-TASK-20260413-000002"); // entity.setTaskId("RRST-TASK-20260413-000002");
entity.setPrecheckId("RPRE-20260413-000002"); // entity.setPrecheckId("RPRE-20260413-000002");
entity.setBackupId("RBKP-20260413-153500-000002"); // entity.setBackupId("RBKP-20260413-153500-000002");
entity.setStatus("PENDING"); // entity.setStatus("PENDING");
entity.setSourceProductType("ENTERPRISE"); // entity.setSourceProductType("ENTERPRISE");
entity.setTargetProductType("ENTERPRISE"); // entity.setTargetProductType("ENTERPRISE");
entity.setPackageFileId("FILE-20260413-000002"); // entity.setPackageFileId("FILE-20260413-000002");
entity.setRunnerStatePath(tempDir.resolve("missing.json").toString()); // entity.setRunnerStatePath(tempDir.resolve("missing.json").toString());
//
ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class); // ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class);
Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000002")).thenReturn(Optional.of(entity)); // Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000002")).thenReturn(Optional.of(entity));
//
ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl( // ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl(
repository, // repository,
new ResourceRestoreStateFileStore(new ObjectMapper()), // new ResourceRestoreStateFileStore(new ObjectMapper()),
new ObjectMapper() // new ObjectMapper()
); // );
//
var detail = service.getRestoreTask("RRST-TASK-20260413-000002"); // var detail = service.getRestoreTask("RRST-TASK-20260413-000002");
//
Assertions.assertEquals("PENDING", detail.getStatus()); // Assertions.assertEquals("PENDING", detail.getStatus());
Assertions.assertEquals("PRECHECKED", detail.getControlPhase()); // Assertions.assertEquals("PRECHECKED", detail.getControlPhase());
Assertions.assertEquals("DB", detail.getStateSource()); // Assertions.assertEquals("DB", detail.getStateSource());
} // }
//
@Test // @Test
void shouldExposeRestoreStepsAndLogsFromRunnerArtifacts() throws Exception { // void shouldExposeRestoreStepsAndLogsFromRunnerArtifacts() throws Exception {
Path taskDir = tempDir.resolve("RRST-TASK-20260413-000003"); // Path taskDir = tempDir.resolve("RRST-TASK-20260413-000003");
Files.createDirectories(taskDir.resolve("step-output")); // Files.createDirectories(taskDir.resolve("step-output"));
Files.createDirectories(taskDir.resolve("steps")); // Files.createDirectories(taskDir.resolve("steps"));
Path stateFile = taskDir.resolve("restore-state.json"); // Path stateFile = taskDir.resolve("restore-state.json");
Files.writeString(stateFile, """ // Files.writeString(stateFile, """
{ // {
"taskId":"RRST-TASK-20260413-000003", // "taskId":"RRST-TASK-20260413-000003",
"status":"RUNNING", // "status":"RUNNING",
"controlPhase":"RUNNER_OWNED", // "controlPhase":"RUNNER_OWNED",
"stateSource":"RUNNER_FILE", // "stateSource":"RUNNER_FILE",
"currentStepCode":"START_SERVICES", // "currentStepCode":"START_SERVICES",
"currentStepNo":3 // "currentStepNo":3
} // }
"""); // """);
Files.writeString(taskDir.resolve("step-output/02-STOP_SERVICES.json"), """ // Files.writeString(taskDir.resolve("step-output/02-STOP_SERVICES.json"), """
{ // {
"stepCode":"STOP_SERVICES", // "stepCode":"STOP_SERVICES",
"result":"SUCCESS", // "result":"SUCCESS",
"summary":"stopped services" // "summary":"stopped services"
} // }
"""); // """);
Files.writeString(taskDir.resolve("steps/02-STOP_SERVICES.log"), "stop log line"); // Files.writeString(taskDir.resolve("steps/02-STOP_SERVICES.log"), "stop log line");
//
ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity(); // ResourceRestoreTaskEntity entity = new ResourceRestoreTaskEntity();
entity.setTaskId("RRST-TASK-20260413-000003"); // entity.setTaskId("RRST-TASK-20260413-000003");
entity.setStatus("HANDOFF"); // entity.setStatus("HANDOFF");
entity.setRestorePlanJson("[\"RESTORE_LOCK\",\"STOP_SERVICES\",\"START_SERVICES\"]"); // entity.setRestorePlanJson("[\"RESTORE_LOCK\",\"STOP_SERVICES\",\"START_SERVICES\"]");
entity.setRunnerStatePath(stateFile.toString()); // entity.setRunnerStatePath(stateFile.toString());
//
ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class); // ResourceRestoreTaskRepository repository = Mockito.mock(ResourceRestoreTaskRepository.class);
Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000003")).thenReturn(Optional.of(entity)); // Mockito.when(repository.findByTaskId("RRST-TASK-20260413-000003")).thenReturn(Optional.of(entity));
//
ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl( // ResourceTaskQueryService service = new ResourceTaskQueryServiceImpl(
repository, // repository,
new ResourceRestoreStateFileStore(new ObjectMapper()), // new ResourceRestoreStateFileStore(new ObjectMapper()),
new ObjectMapper() // new ObjectMapper()
); // );
//
List<ResourceTaskStepItemResponse> steps = service.getRestoreTaskSteps("RRST-TASK-20260413-000003"); // List<ResourceTaskStepItemResponse> steps = service.getRestoreTaskSteps("RRST-TASK-20260413-000003");
Assertions.assertEquals(3, steps.size()); // Assertions.assertEquals(3, steps.size());
Assertions.assertEquals("PENDING", steps.get(0).getStatus()); // Assertions.assertEquals("PENDING", steps.get(0).getStatus());
Assertions.assertEquals("SUCCESS", steps.get(1).getStatus()); // Assertions.assertEquals("SUCCESS", steps.get(1).getStatus());
Assertions.assertEquals("stopped services", steps.get(1).getMessage()); // Assertions.assertEquals("stopped services", steps.get(1).getMessage());
Assertions.assertEquals(Boolean.TRUE, steps.get(1).getLogAvailable()); // Assertions.assertEquals(Boolean.TRUE, steps.get(1).getLogAvailable());
Assertions.assertEquals("RUNNING", steps.get(2).getStatus()); // Assertions.assertEquals("RUNNING", steps.get(2).getStatus());
//
ResourceTaskStepLogResponse log = service.getRestoreTaskStepLog("RRST-TASK-20260413-000003", 2); // ResourceTaskStepLogResponse log = service.getRestoreTaskStepLog("RRST-TASK-20260413-000003", 2);
Assertions.assertEquals("STOP_SERVICES", log.getStepCode()); // Assertions.assertEquals("STOP_SERVICES", log.getStepCode());
Assertions.assertEquals("stop log line", log.getContent()); // Assertions.assertEquals("stop log line", log.getContent());
Assertions.assertFalse(log.getTruncated()); // Assertions.assertFalse(log.getTruncated());
} // }
} //}