feat(接口测试): 添加用例批量同步以及忽略变更相关日志

--task=1015860 --user=陈建星 【接口测试】接口用例支持同步更新接口变更-后端-批量同步更新接口 https://www.tapd.cn/55049933/s/1559954
This commit is contained in:
AgAngle 2024-08-08 20:38:11 +08:00 committed by Craftsman
parent d7d10f5f05
commit d7927a663a
13 changed files with 126 additions and 23 deletions

View File

@ -445,3 +445,6 @@ api_definition.status.completed=已完成
api_definition.status.abandoned=已废弃
api_definition.status.continuous=连调中
api_test_case.clear.api_change=忽略本次变更差异
api_test_case.ignore.api_change=忽略全部变更差异

View File

@ -449,4 +449,7 @@ report.status.fake_error=Fake error
api_definition.status.ongoing=Underway
api_definition.status.completed=Completed
api_definition.status.abandoned=Abandoned
api_definition.status.continuous=Continuous
api_definition.status.continuous=Continuous
api_test_case.clear.api_change=Ignore the differences in this change
api_test_case.ignore.api_change=Ignore all change differences

View File

@ -417,4 +417,7 @@ report.status.fake_error=误报
api_definition.status.ongoing=进行中
api_definition.status.completed=已完成
api_definition.status.abandoned=已废弃
api_definition.status.continuous=连调中
api_definition.status.continuous=连调中
api_test_case.clear.api_change=忽略本次变更差异
api_test_case.ignore.api_change=忽略全部变更差异

View File

@ -417,4 +417,7 @@ report.status.fake_error=誤報
api_definition.status.ongoing=進行中
api_definition.status.completed=已完成
api_definition.status.abandoned=已作廢
api_definition.status.continuous=持續中
api_definition.status.continuous=持續中
api_test_case.clear.api_change=忽略本次變更差異
api_test_case.ignore.api_change=忽略全部變更差異

View File

@ -315,6 +315,7 @@ public class ApiTestCaseController {
@Operation(summary = "清除接口参数变更标识")
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE})
@CheckOwner(resourceId = "#id", resourceType = "api_test_case")
@Log(type = OperationLogType.UPDATE, expression = "#msClass.clearApiChangeLog(#id)", msClass = ApiTestCaseLogService.class)
public void clearApiChange(@PathVariable String id) {
apiTestCaseService.clearApiChange(id);
}
@ -323,6 +324,7 @@ public class ApiTestCaseController {
@Operation(summary = "忽略接口变更提示")
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE})
@CheckOwner(resourceId = "#id", resourceType = "api_test_case")
@Log(type = OperationLogType.UPDATE, expression = "#msClass.ignoreApiChange(#id)", msClass = ApiTestCaseLogService.class)
public void ignoreApiChange(@PathVariable String id, @RequestParam(name = "ignore") boolean ignore) {
apiTestCaseService.ignoreApiChange(id, ignore);
}

View File

@ -111,6 +111,4 @@ public interface ExtApiTestCaseMapper {
List<ApiTestCase> getCaseListBySelectIds(@Param("isRepeat") boolean isRepeat, @Param("projectId") String projectId, @Param("ids") List<String> ids, @Param("testPlanId") String testPlanId, @Param("protocols") List<String> protocols);
void setApiChangeByApiDefinitionId(@Param("apiDefinitionId") String apiDefinitionId);
List<ApiTestCase> getApiCaseForBatchSync(@Param("ids") List<String> ids);
}

View File

@ -727,14 +727,4 @@
)
</if>
</select>
<select id="getApiCaseForBatchSync" resultType="io.metersphere.api.domain.ApiTestCase">
select id, api_definition_id
from api_test_case
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -61,7 +61,7 @@ public class ApiTestCaseLogService {
OperationLogModule.API_TEST_MANAGEMENT_CASE,
request.getName());
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(request));
dto.setOriginalValue(ApiDataUtils.toJSONBytes(request));
dto.setHistory(true);
return dto;
}
@ -131,6 +131,36 @@ public class ApiTestCaseLogService {
return dto;
}
public LogDTO clearApiChangeLog(String id) {
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(apiTestCase.getProjectId());
LogDTO dto = new LogDTO(
apiTestCase.getProjectId(),
project.getOrganizationId(),
id,
null,
OperationLogType.UPDATE.name(),
OperationLogModule.API_TEST_MANAGEMENT_CASE,
Translator.get("api_test_case.clear.api_change") + '_' + apiTestCase.getName());
dto.setOriginalValue(JSON.toJSONBytes(apiTestCase));
return dto;
}
public LogDTO ignoreApiChange(String id) {
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(apiTestCase.getProjectId());
LogDTO dto = new LogDTO(
apiTestCase.getProjectId(),
project.getOrganizationId(),
id,
null,
OperationLogType.UPDATE.name(),
OperationLogModule.API_TEST_MANAGEMENT_CASE,
Translator.get("api_test_case.ignore.api_change") + '_' + apiTestCase.getName());
dto.setOriginalValue(JSON.toJSONBytes(apiTestCase));
return dto;
}
public LogDTO updateLog(ApiTestCaseUpdateRequest request) {
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(request.getId());
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(request.getId());
@ -206,6 +236,33 @@ public class ApiTestCaseLogService {
saveBatchLog(projectId, apiTestCases, operator, OperationLogType.RECOVER.name(), false, OperationLogModule.API_TEST_MANAGEMENT_RECYCLE);
}
public void batchSyncLog(Map<String, ApiTestCaseLogDTO> originMap, Map<String, ApiTestCaseLogDTO> modifiedMap) {
List<LogDTO> logs = new ArrayList<>();
originMap.forEach((id, origin) -> {
ApiTestCaseLogDTO modified = modifiedMap.get(id);
if (modified == null) {
return;
}
Project project = projectMapper.selectByPrimaryKey(origin.getProjectId());
LogDTO dto = LogDTOBuilder.builder()
.projectId(project.getId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.API_TEST_MANAGEMENT_CASE)
.method(HttpMethodConstants.POST.name())
.sourceId(id)
.content(origin.getName())
.createUser(null)
.path(OperationLogAspect.getPath())
.originalValue(ApiDataUtils.toJSONBytes(origin))
.modifiedValue(ApiDataUtils.toJSONBytes(modified))
.build().getLogDTO();
dto.setHistory(true);
logs.add(dto);
});
operationLogService.batchAdd(logs);
}
private void saveBatchLog(String projectId, List<ApiTestCase> apiTestCases, String operator, String operationType, boolean isHistory, String logModule) {
Project project = projectMapper.selectByPrimaryKey(projectId);
//取出apiTestCases所有的id为新的list
@ -241,7 +298,7 @@ public class ApiTestCaseLogService {
.sourceId(item.getId())
.content(item.getName())
.createUser(operator)
.originalValue(JSON.toJSONBytes(apiTestCaseDTO))
.originalValue(ApiDataUtils.toJSONBytes(apiTestCaseDTO))
.build().getLogDTO();
dto.setHistory(isHistory);
logs.add(dto);

View File

@ -1005,9 +1005,11 @@ public class ApiTestCaseService extends MoveNodeService {
}
public void doBatchSyncApiChange(ApiCaseBatchSyncRequest request, List<String> ids, String userId) {
List<ApiTestCase> apiTestCases = extApiTestCaseMapper.getApiCaseForBatchSync(ids);
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdIn(ids);
List<ApiTestCase> apiTestCases = apiTestCaseMapper.selectByExample(example);
Set<String> apiDefinitionIds = apiTestCases.stream().map(ApiTestCase::getApiDefinitionId).collect(Collectors.toSet());
Map<String, ApiTestCase> apiTestCaseMap = apiTestCases.stream().collect(Collectors.toMap(ApiTestCase::getApiDefinitionId, Function.identity()));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiTestCaseBlobMapper apiTestCaseBlobBatchMapper = sqlSession.getMapper(ApiTestCaseBlobMapper.class);
ApiTestCaseMapper apiTestCaseBatchMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
@ -1015,15 +1017,27 @@ public class ApiTestCaseService extends MoveNodeService {
ApiCaseSyncRequest apiCaseSyncRequest = new ApiCaseSyncRequest();
apiCaseSyncRequest.setSyncItems(request.getSyncItems());
apiCaseSyncRequest.setDeleteRedundantParam(request.getDeleteRedundantParam());
Map<String, ApiTestCaseLogDTO> originMap = new HashMap<>();
Map<String, ApiTestCaseLogDTO> modifiedMap = new HashMap<>();
ApiDefinitionBlobExample apiDefinitionBlobExample = new ApiDefinitionBlobExample();
apiDefinitionBlobExample.createCriteria().andIdIn(new ArrayList<>(apiDefinitionIds));
Map<String, ApiDefinitionBlob> apiDefinitionBlobMap = apiDefinitionBlobMapper.selectByExampleWithBLOBs(apiDefinitionBlobExample)
.stream()
.collect(Collectors.toMap(ApiDefinitionBlob::getId, Function.identity()));
try {
for (String apiDefinitionId : apiDefinitionIds) {
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinitionId);
for (ApiTestCase apiTestCase : apiTestCases) {
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMap.get(apiTestCase.getApiDefinitionId());
AbstractMsTestElement apiMsTestElement = getApiMsTestElement(apiDefinitionBlob);
ApiTestCase apiTestCase = apiTestCaseMap.get(apiDefinitionId);
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId());
AbstractMsTestElement apiTestCaseMsTestElement = getTestElement(apiTestCaseBlob);
boolean requestParamDifferent = HttpRequestParamDiffUtils.isRequestParamDiff(request.getSyncItems(), apiMsTestElement, apiTestCaseMsTestElement);
if (requestParamDifferent) {
ApiTestCaseLogDTO originCase = BeanUtils.copyBean(new ApiTestCaseLogDTO(), apiTestCase);
originCase.setRequest(apiTestCaseMsTestElement);
originMap.put(apiTestCase.getId(), originCase);
apiTestCase.setUpdateTime(System.currentTimeMillis());
apiTestCase.setUpdateUser(userId);
apiTestCase.setApiChange(false);
@ -1031,8 +1045,13 @@ public class ApiTestCaseService extends MoveNodeService {
apiTestCaseMsTestElement = HttpRequestParamDiffUtils.syncRequestDiff(apiCaseSyncRequest, apiMsTestElement, apiTestCaseMsTestElement);
apiTestCaseBlob.setRequest(ApiDataUtils.toJSONString(apiTestCaseMsTestElement).getBytes());
apiTestCaseBlobBatchMapper.updateByPrimaryKeySelective(apiTestCaseBlob);
ApiTestCaseLogDTO modifiedCase = BeanUtils.copyBean(new ApiTestCaseLogDTO(), apiTestCase);
modifiedCase.setRequest(apiTestCaseMsTestElement);
modifiedMap.put(apiTestCase.getId(), originCase);
}
}
apiTestCaseLogService.batchSyncLog(originMap, modifiedMap);
} finally {
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);

View File

@ -165,4 +165,12 @@ public class ApiDataUtils {
throw new MSException(e);
}
}
public static byte[] toJSONBytes(Object value) {
try {
return objectMapper.writeValueAsBytes(value);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -67,7 +67,7 @@ public class HttpRequestParamDiffUtils {
if (body1 == null || body2 == null) {
return true;
}
if (body1.getBodyType() != body2.getBodyType()) {
if (!StringUtils.equals(body1.getBodyType(), body2.getBodyType())) {
// 类型不一样则发生变更
return true;
}

View File

@ -75,6 +75,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@ -467,6 +468,9 @@ public class ApiTestCaseControllerTests extends BaseTest {
Assertions.assertFalse(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getApiChange());
Assertions.assertTrue(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getIgnoreApiDiff());
//校验日志
checkLog(apiTestCase.getId(), OperationLogType.UPDATE, getBasePath() + MessageFormat.format(API_CHANGE_CLEAR, apiTestCase.getId()));
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD, API_CHANGE_CLEAR, apiTestCase.getId());
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE, API_CHANGE_CLEAR, apiTestCase.getId());
@ -490,6 +494,9 @@ public class ApiTestCaseControllerTests extends BaseTest {
Assertions.assertTrue(result.getIgnoreApiDiff());
Assertions.assertFalse(result.getIgnoreApiChange());
//校验日志
checkLog(apiTestCase.getId(), OperationLogType.UPDATE, getBasePath() + MessageFormat.format(API_CHANGE_IGNORE, apiTestCase.getId(), true));
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD, API_CHANGE_IGNORE, apiTestCase.getId(), true);
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE, API_CHANGE_IGNORE, apiTestCase.getId(), false);
@ -509,6 +516,9 @@ public class ApiTestCaseControllerTests extends BaseTest {
ApiTestCase result = apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId());
Assertions.assertFalse(result.getApiChange());
//校验日志
checkLog(apiTestCase.getId(), OperationLogType.UPDATE, getBasePath() + BATCH_API_CHANGE_SYNC);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE, BATCH_API_CHANGE_SYNC, request);
}

View File

@ -228,6 +228,13 @@ public class HttpRequestParamDiffUtilsTests {
Body body1 = new Body();
Body body2 = new Body();
body1.setBodyType(Body.BodyType.FORM_DATA.name());
body1.setFormDataBody(new FormDataBody());
body2.setBodyType(Body.BodyType.FORM_DATA.name());
body2.setFormDataBody(new FormDataBody());
Assertions.assertFalse(HttpRequestParamDiffUtils.isBodyDiff(body1, body2));
body1.setBodyType(Body.BodyType.FORM_DATA.name());
body2.setBodyType(Body.BodyType.RAW.name());
Assertions.assertTrue(HttpRequestParamDiffUtils.isBodyDiff(body1, body2));