feat(接口测试): 接口协议插件获取页面渲染脚本接口

This commit is contained in:
AgAngle 2024-02-06 14:08:16 +08:00 committed by Craftsman
parent a47d299de5
commit 1d71ba51d2
12 changed files with 125 additions and 34 deletions

View File

@ -7,9 +7,14 @@ import lombok.Data;
import java.util.LinkedList;
/**
*@Author: jianxing
*@CreateTime: 2023-10-30 15:08
*/
*
* <pre>
* 该对象传参时需要传入 polymorphicName 字段用于区分是哪个协议的组件
* 对应协议的组件 polymorphicName 字段调用 /api/test/protocol/{organizationId} 接口获取
* <pre>
* @Author: jianxing
* @CreateTime: 2023-10-30 15:08
*/
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "polymorphicName")
@JsonIgnoreProperties(ignoreUnknown = true)

View File

@ -7,9 +7,30 @@ package io.metersphere.plugin.api.spi;
*/
public abstract class AbstractProtocolPlugin extends AbstractApiPlugin {
private static final String DEFAULT_API_PROTOCOL_SCRIPT_ID = "api";
private static final String DEFAULT_ENVIRONMENT_PROTOCOL_SCRIPT_ID = "environment";
/**
* 返回协议名
* @return
*/
abstract public String getProtocol();
/**
* 返回接口协议主页面的脚本的ID默认为 api
* 可以重写此方法返回自定义的脚本ID
* @return
*/
public String getApiProtocolScriptId() {
return DEFAULT_API_PROTOCOL_SCRIPT_ID;
}
/**
* 返回协议环境配置页面的脚本的ID默认为 environment
* 可以重写此方法返回自定义的脚本ID
* @return
*/
public String getEnvProtocolScriptId() {
return DEFAULT_ENVIRONMENT_PROTOCOL_SCRIPT_ID;
}
}

View File

@ -38,7 +38,6 @@ public class ApiTestController {
return apiTestService.getProtocols(organizationId);
}
@GetMapping("/mock/{key}")
@Operation(summary = "获取mock数据")
public String mock(@PathVariable String key) {
@ -52,6 +51,18 @@ public class ApiTestController {
return apiExecuteService.runScript(runRequest);
}
@GetMapping("/plugin/script/{pluginId}")
@Operation(summary = "获取协议插件的的协议列表")
@RequiresPermissions(value = {
PermissionConstants.PROJECT_API_DEFINITION_READ,
PermissionConstants.PROJECT_API_DEFINITION_CASE_READ,
PermissionConstants.PROJECT_API_DEBUG_READ,
PermissionConstants.PROJECT_API_SCENARIO_READ
}, logical = Logical.OR)
public Object getApiProtocolScript(@PathVariable String pluginId) {
return apiTestService.getApiProtocolScript(pluginId);
}
@PostMapping("/plugin/form/option")
@Operation(summary = "接口测试-获取插件表单选项")
@RequiresPermissions(value = {

View File

@ -9,7 +9,7 @@ import lombok.Data;
* @CreateTime: 2023-11-06 18:25
*/
@Data
public class BinaryBody extends ApiFile{
public class BinaryBody extends ApiFile {
/**
* 描述
*/

View File

@ -6,9 +6,11 @@ import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.plugin.api.dto.ApiPluginOptionsRequest;
import io.metersphere.plugin.api.dto.ApiPluginSelectOption;
import io.metersphere.plugin.api.spi.AbstractApiPlugin;
import io.metersphere.plugin.api.spi.AbstractProtocolPlugin;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.dto.ProtocolDTO;
import io.metersphere.system.service.ApiPluginService;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.utils.ServiceUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
@ -28,6 +30,8 @@ public class ApiTestService {
@Resource
private ApiPluginService apiPluginService;
@Resource
private PluginLoadService pluginLoadService;
public List<ProtocolDTO> getProtocols(String orgId) {
List<ProtocolDTO> protocols = apiPluginService.getProtocols(orgId);
@ -48,10 +52,25 @@ public class ApiTestService {
.orElse(null);
if (pluginWrapper == null || !(pluginWrapper.getPlugin() instanceof AbstractApiPlugin)) {
// 插件不存在或者非接口插件抛出异常
ServiceUtils.checkResourceExist(null, "permission.api_plugin.name");
checkResourceExist(null);
}
ApiPluginOptionsRequest optionsRequest = BeanUtils.copyBean(new ApiPluginOptionsRequest(), request);
assert pluginWrapper != null;
return ((AbstractApiPlugin) pluginWrapper.getPlugin()).getPluginOptions(optionsRequest);
}
public Object getApiProtocolScript(String pluginId) {
PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(pluginId);
checkResourceExist(pluginWrapper);
if (pluginWrapper.getPlugin() instanceof AbstractProtocolPlugin protocolPlugin) {
return pluginLoadService.getPluginScriptContent(pluginId, protocolPlugin.getApiProtocolScriptId());
} else {
// 插件不存在或者非接口插件抛出异常
return checkResourceExist(null);
}
}
public Object checkResourceExist(PluginWrapper pluginWrapper) {
return ServiceUtils.checkResourceExist(pluginWrapper, "permission.system_plugin.name");
}
}

View File

@ -14,10 +14,7 @@ import io.metersphere.system.dto.request.PluginUpdateRequest;
import io.metersphere.system.service.PluginService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
@ -28,6 +25,7 @@ import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
@ -46,6 +44,7 @@ public class ApiTestControllerTests extends BaseTest {
protected static final String MOCK = "mock/{0}";
protected static final String CUSTOM_FUNC_RUN = "custom/func/run";
protected static final String PLUGIN_FORM_OPTION = "plugin/form/option";
protected static final String PLUGIN_SCRIPT = "plugin/script/{0}";
@Resource
private BaseResourcePoolTestService baseResourcePoolTestService;
@ -98,6 +97,7 @@ public class ApiTestControllerTests extends BaseTest {
}
@Test
@Order(10)
public void getFormOptions() throws Exception {
ApiTestPluginOptionRequest request = new ApiTestPluginOptionRequest();
request.setOrgId(DEFAULT_ORGANIZATION_ID);
@ -127,6 +127,30 @@ public class ApiTestControllerTests extends BaseTest {
}}, PLUGIN_FORM_OPTION, request);
}
@Test
@Order(11)
public void getApiProtocolScript() throws Exception {
assertErrorCode(this.requestGet(PLUGIN_SCRIPT, "aa"), NOT_FOUND);
Plugin jiraPlugin = basePluginTestService.addJiraPlugin();
assertErrorCode(this.requestGet(PLUGIN_SCRIPT, jiraPlugin.getId()), NOT_FOUND);
// @@请求成功
Plugin plugin = addTcpTestPlugin();
MvcResult mvcResult = this.requestGetWithOkAndReturn(PLUGIN_SCRIPT, plugin.getId());
Object resultData = getResultData(mvcResult, Object.class);
Assertions.assertNotNull(resultData);
basePluginTestService.deleteJiraPlugin();
pluginService.delete(plugin.getId());
// @@校验权限
requestGetPermissionsTest(new ArrayList<>() {{
add(PermissionConstants.PROJECT_API_DEFINITION_READ);
add(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
add(PermissionConstants.PROJECT_API_DEBUG_READ);
add(PermissionConstants.PROJECT_API_SCENARIO_READ);
}}, PLUGIN_SCRIPT, "11");
}
public Plugin addOptionTestPlugin() throws Exception {
PluginUpdateRequest request = new PluginUpdateRequest();
File jarFile = new File(
@ -142,4 +166,19 @@ public class ApiTestControllerTests extends BaseTest {
return pluginService.add(request, mockMultipartFile);
}
public Plugin addTcpTestPlugin() throws Exception {
PluginUpdateRequest request = new PluginUpdateRequest();
File jarFile = new File(
this.getClass().getClassLoader().getResource("file/tcp-sampler-v3.x.jar")
.getPath()
);
FileInputStream inputStream = new FileInputStream(jarFile);
MockMultipartFile mockMultipartFile = new MockMultipartFile(jarFile.getName(), jarFile.getName(), "jar", inputStream);
request.setName("测试TCP插件");
request.setGlobal(true);
request.setEnable(true);
request.setCreateUser(ADMIN.name());
return pluginService.add(request, mockMultipartFile);
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.project.service;
import io.metersphere.plugin.api.spi.AbstractProtocolPlugin;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.dto.environment.*;
@ -39,6 +40,7 @@ import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.pf4j.Plugin;
import org.pf4j.PluginWrapper;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@ -388,13 +390,17 @@ public class EnvironmentService {
public List<EnvironmentPluginScriptDTO> getPluginScripts(String projectId) {
Project project = projectService.checkProjectNotExist(projectId);
// 查询组织下有权限的接口插件ID
List<String> orgApiPluginIds = apiPluginService.getOrgApiPluginWrappers(project.getOrganizationId())
.stream()
.map(PluginWrapper::getPluginId)
.collect(Collectors.toList());
// 查询环境页面脚本
List<PluginScript> pluginScripts = pluginScriptService.getByPluginIdsAndScriptId(orgApiPluginIds, "environment");
// 查询组织下有权限的接口插件
List<PluginWrapper> orgApiPluginWrappers = apiPluginService.getOrgApiPluginWrappers(project.getOrganizationId());
// 接口协议环境脚本
List<PluginScript> pluginScripts = new ArrayList<>(orgApiPluginWrappers.size());
orgApiPluginWrappers.stream().forEach(wrapper -> {
Plugin plugin = wrapper.getPlugin();
if (plugin instanceof AbstractProtocolPlugin protocolPlugin) {
pluginScripts.add(pluginScriptService.get(wrapper.getPluginId(), protocolPlugin.getEnvProtocolScriptId()));
}
});
// 返回环境脚本列表
return pluginScripts.stream().map(pluginScript -> {

View File

@ -64,11 +64,15 @@ public class PluginScriptService {
pluginScriptMapper.deleteByExample(example);
}
public String get(String pluginId, String scriptId) {
PluginScript frontScript = pluginScriptMapper.selectByPrimaryKey(pluginId, scriptId);
public String getScriptContent(String pluginId, String scriptId) {
PluginScript frontScript = get(pluginId, scriptId);
return frontScript == null ? null : new String(frontScript.getScript());
}
public PluginScript get(String pluginId, String scriptId) {
return pluginScriptMapper.selectByPrimaryKey(pluginId, scriptId);
}
public Map<String, List<OptionDTO>> getScripteMap(List<String> pluginIds) {
if (CollectionUtils.isEmpty(pluginIds)) {
return Collections.emptyMap();
@ -83,15 +87,5 @@ public class PluginScriptService {
scriptList.add(optionDTO);
}
return scriptMap;
}
public List<PluginScript> getByPluginIdsAndScriptId(List<String> pluginIds, String scriptId) {
if (CollectionUtils.isEmpty(pluginIds)) {
return Collections.emptyList();
}
PluginScriptExample example = new PluginScriptExample();
example.createCriteria().andScriptIdEqualTo(scriptId);
return pluginScriptMapper.selectByExampleWithBLOBs(example);
}
}

View File

@ -264,7 +264,7 @@ public class PluginService {
}
public String getScript(String pluginId, String scriptId) {
return pluginScriptService.get(pluginId, scriptId);
return pluginScriptService.getScriptContent(pluginId, scriptId);
}
public void getPluginImg(String pluginId, String filePath, HttpServletResponse response) throws IOException {

View File

@ -317,10 +317,6 @@ public class PluginControllerTests extends BaseTest {
// @@请求成功
MvcResult mvcResult = this.requestGetWithOk(SCRIPT_GET, this.addPlugin.getId(), "connect").andReturn();
// 增加覆盖率
pluginScriptService.getByPluginIdsAndScriptId(List.of(), "connect");
pluginScriptService.getByPluginIdsAndScriptId(List.of(addPlugin.getId()), "connect");
// 校验数据是否正确
Assertions.assertTrue(StringUtils.isNotBlank(getResultData(mvcResult, String.class)));
// @@校验权限