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