Merge branch 'master' into xsj_branch
This commit is contained in:
commit
ebd27b842b
36
pom.xml
36
pom.xml
|
@ -29,6 +29,7 @@
|
|||
<properties>
|
||||
<revision>1.0.0</revision>
|
||||
<java.version>17</java.version>
|
||||
<gzs-common.version>0.1.7-SNAPSHOT</gzs-common.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -58,6 +59,16 @@
|
|||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<version>4.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<version>13.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||
|
@ -143,7 +154,12 @@
|
|||
<dependency>
|
||||
<groupId>com.cmcc.hy</groupId>
|
||||
<artifactId>gzs-common-oss</artifactId>
|
||||
<version>0.1.6-SNAPSHOT</version>
|
||||
<version>${gzs-common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cmcc.hy</groupId>
|
||||
<artifactId>gzs-common-sign</artifactId>
|
||||
<version>${gzs-common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.logstash.logback</groupId>
|
||||
|
@ -181,6 +197,20 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
|
||||
|
@ -261,6 +291,10 @@
|
|||
<groupId>com.cmcc.hy</groupId>
|
||||
<artifactId>gzs-common-oss</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cmcc.hy</groupId>
|
||||
<artifactId>gzs-common-sign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.logstash.logback</groupId>
|
||||
<artifactId>logstash-logback-encoder</artifactId>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.cmcc.magent;
|
||||
|
||||
import com.cmcc.hy.gzs.common.sign.autoconfigure.EnableSign;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
|
@ -28,6 +30,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||
*/
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableFeignClients
|
||||
@EnableSign
|
||||
public class MiddlewareAgentApplication {
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.cmcc.magent.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* MwCoreConfig类用于配置与中间件核心相关的属性。
|
||||
*
|
||||
* <p>该类包含客户端ID和客户端密钥,用于与GZS服务进行身份验证。</p>
|
||||
*
|
||||
* <p>该配置类会在Spring容器启动时加载,并支持动态刷新配置。</p>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-03-07
|
||||
*/
|
||||
@Component
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "mw.agent")
|
||||
@Data
|
||||
public class MwCoreConfig {
|
||||
|
||||
/**
|
||||
* 内部客户端ID。
|
||||
*
|
||||
* <p>默认为"mw-open-82hsbmz8",可通过配置文件进行覆盖。</p>
|
||||
*/
|
||||
private String innerClientId = "mw-open-82hsbmz8";
|
||||
|
||||
/**
|
||||
* 内部客户端密钥。
|
||||
*
|
||||
* <p>默认为"98rnk8pz6j08fp6q",可通过配置文件进行覆盖。</p>
|
||||
*/
|
||||
private String innerClientSecret = "98rnk8pz6j08fp6q";
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.cmcc.magent.interceptor;
|
||||
|
||||
import com.cmcc.hy.gzs.common.feign.GzsSignRequestInterceptor;
|
||||
import com.cmcc.magent.config.MwCoreConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* MwSignRequestInterceptor类实现了GzsSignRequestInterceptor接口。
|
||||
*
|
||||
* <p>该类用于拦截请求并提供客户端ID和客户端密钥,用于与GZS服务的身份验证。</p>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-03-07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class MwSignRequestInterceptor implements GzsSignRequestInterceptor {
|
||||
|
||||
private final MwCoreConfig mwCoreProperties;
|
||||
|
||||
/**
|
||||
* 获取客户端ID。
|
||||
*
|
||||
* @return 客户端ID
|
||||
*/
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return mwCoreProperties.getInnerClientId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端密钥。
|
||||
*
|
||||
* @return 客户端密钥
|
||||
*/
|
||||
@Override
|
||||
public String getClientSecret() {
|
||||
return mwCoreProperties.getInnerClientSecret();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.cmcc.magent.service;
|
||||
|
||||
import com.cmcc.hy.gzs.common.result.Result;
|
||||
import com.cmcc.magent.interceptor.MwSignRequestInterceptor;
|
||||
import com.cmcc.magent.pojo.po.RegisterAgent;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* PlatformApiFeignClientService 接口定义了与平台 API 通信的核心服务功能。
|
||||
* <p>
|
||||
* 该接口包含与平台交互的关键操作,具体实现类负责与平台进行数据交互。
|
||||
* </p>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-03-10
|
||||
*/
|
||||
@FeignClient(name = "agent-portal-feign",
|
||||
url = "${service.platform-url}",
|
||||
path = "/mw/core",
|
||||
configuration = MwSignRequestInterceptor.class)
|
||||
public interface PlatformApiFeignClientService {
|
||||
|
||||
/**
|
||||
* 注册代理。
|
||||
*
|
||||
* @param agent 要注册的代理信息,包含代理的相关属性。
|
||||
* @return 返回一个 {@link Result} 对象,包含注册结果的状态和消息。
|
||||
*/
|
||||
@PostMapping(path = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
Result<String> registerAgentFeign(@RequestBody RegisterAgent agent);
|
||||
|
||||
|
||||
/**
|
||||
* 响应部署结果。
|
||||
*
|
||||
* <p>该方法用于更新指定部署的状态,服务器将根据传入的状态信息进行相应处理。</p>
|
||||
*
|
||||
* @param deploymentId 部署的唯一标识符,用于指定需要更新状态的部署。
|
||||
* @param status 部署状态,整数类型,表示当前部署的状态,如成功、失败等。
|
||||
* @return 返回一个 {@link Result} 对象,包含操作结果的状态和相关信息。
|
||||
*
|
||||
*/
|
||||
@PostMapping(path = "/innerapi/instance/update-status",
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
Result<String> responseDeploymentResultFeign(@RequestParam("deploymentId") String deploymentId, @RequestParam("status") Integer status);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package com.cmcc.magent.service;
|
||||
|
||||
import com.cmcc.hy.gzs.common.result.Result;
|
||||
import com.cmcc.magent.pojo.po.RegisterAgent;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* PlatformApiService 接口定义了与平台 API 通信的核心服务功能。
|
||||
|
@ -15,16 +15,23 @@ import java.io.IOException;
|
|||
* @since 2025-01-07
|
||||
*/
|
||||
public interface PlatformApiService {
|
||||
/**
|
||||
* 注册代理。
|
||||
*
|
||||
* @param agent 要注册的代理信息,包含代理的相关属性。
|
||||
* @return 返回一个 {@link Result} 对象,包含注册结果的状态和消息。
|
||||
*/
|
||||
Result<String> registerAgent(@RequestBody RegisterAgent agent);
|
||||
|
||||
/**
|
||||
* 注册代理(Agent)。
|
||||
* <p>
|
||||
* 该方法用于将代理实例注册到平台,并返回平台生成的响应结果。
|
||||
* </p>
|
||||
* 响应部署结果。
|
||||
*
|
||||
* <p>该方法用于更新指定部署的状态,服务器将根据传入的状态信息进行相应处理。</p>
|
||||
*
|
||||
* @param deploymentId 部署的唯一标识符,用于指定需要更新状态的部署。
|
||||
* @param status 部署状态,整数类型,表示当前部署的状态,如成功、失败等。
|
||||
* @return 返回一个 {@link Result} 对象,包含操作结果的状态和相关信息。
|
||||
*
|
||||
* @param agent 包含代理注册信息的 {@link RegisterAgent} 对象
|
||||
* @return 平台返回的结果,通常为一个 JSON 格式的字符串
|
||||
* @throws IOException 如果在处理 JSON 时发生错误
|
||||
*/
|
||||
String registerAgent(RegisterAgent agent) throws IOException;
|
||||
Result<String> responseDeploymentResult(String deploymentId, Integer status);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.cmcc.magent.misc.JsonUtils;
|
|||
import com.cmcc.magent.pojo.entry.MiddlewareData;
|
||||
import com.cmcc.magent.pojo.po.RemoteFileDetails;
|
||||
import com.cmcc.magent.service.MiddlewareManagerService;
|
||||
import com.cmcc.magent.service.PlatformApiService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -62,6 +63,9 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
|
|||
@Resource
|
||||
private OssFactory ossFactory;
|
||||
|
||||
@Resource
|
||||
private PlatformApiService platformApiService;
|
||||
|
||||
/**
|
||||
* 根据命令获取对应的文件名。
|
||||
*
|
||||
|
@ -320,6 +324,13 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
|
|||
}
|
||||
runCommand(workDir, command);
|
||||
log.info("---- Task {} Finished", data.getUid());
|
||||
}).whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
platformApiService.responseDeploymentResult(data.getUid(), 2);
|
||||
log.error("---- Task {} Finished With Exception: {}", data.getUid(), t.getMessage());
|
||||
} else {
|
||||
log.info("---- Task {} Finished: {}", data.getUid(), platformApiService.responseDeploymentResult(data.getUid(), 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -397,6 +408,13 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
|
|||
|
||||
runCommand(workDir, cmd);
|
||||
log.info("---- Task {} Finished", data.getUid());
|
||||
}).whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
platformApiService.responseDeploymentResult(data.getUid(), 2);
|
||||
log.error("---- Task {} Finished With Exception: {}", data.getUid(), t.getMessage());
|
||||
} else {
|
||||
log.info("---- Task {} Finished: {}", data.getUid(), platformApiService.responseDeploymentResult(data.getUid(), 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
package com.cmcc.magent.service.impl;
|
||||
|
||||
import com.cmcc.magent.config.PlatformServiceConfig;
|
||||
import com.cmcc.magent.misc.HttpClientUtils;
|
||||
import com.cmcc.magent.misc.JsonUtils;
|
||||
import com.cmcc.hy.gzs.common.result.Result;
|
||||
import com.cmcc.magent.pojo.po.RegisterAgent;
|
||||
import com.cmcc.magent.service.PlatformApiFeignClientService;
|
||||
import com.cmcc.magent.service.PlatformApiService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PlatformApiServiceImpl 是 {@link PlatformApiService} 的具体实现类。
|
||||
* PlatformApiServiceImpl 是 {@link PlatformApiFeignClientService} 的具体实现类。
|
||||
* <p>
|
||||
* 该类使用 与平台 API 进行交互,提供了注册代理的功能。
|
||||
* </p>
|
||||
|
@ -26,24 +24,50 @@ import java.io.IOException;
|
|||
* @since 2025 -01-07
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class PlatformApiServiceImpl implements PlatformApiService {
|
||||
@Resource
|
||||
private PlatformServiceConfig platformServiceConfig;
|
||||
private PlatformApiFeignClientService platformApiServiceFeign;
|
||||
|
||||
/**
|
||||
* 注册代理(Agent)。
|
||||
* <p>
|
||||
* 通过向平台 API 提供的注册接口("/register")发送 POST 请求,完成代理的注册操作。
|
||||
* 请求体为转换为 JSON 格式的 {@link RegisterAgent} 对象。
|
||||
* </p>
|
||||
* 注册代理。
|
||||
*
|
||||
* @param agent 包含代理注册信息的 {@link RegisterAgent} 实例
|
||||
* @return 平台返回的注册结果,通常为 JSON 格式的字符串
|
||||
* @throws IOException IO 异常
|
||||
* @param agent 要注册的代理信息,包含代理的相关属性。
|
||||
* @return 返回一个 {@link Result} 对象,包含注册结果的状态和消息。
|
||||
*/
|
||||
@Override
|
||||
public String registerAgent(RegisterAgent agent) throws IOException {
|
||||
String reqString = JsonUtils.getJson(agent);
|
||||
return HttpClientUtils.postJson(platformServiceConfig + "/register", null, reqString, null);
|
||||
public Result<String> registerAgent(RegisterAgent agent) {
|
||||
Result<String> s = null;
|
||||
|
||||
try {
|
||||
s = platformApiServiceFeign.registerAgentFeign(agent);
|
||||
} catch (Exception e) {
|
||||
log.error("Register agent client {} exception: {}", agent.getDeviceId(), e.getMessage());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应部署结果。
|
||||
*
|
||||
* <p>该方法用于更新指定部署的状态,服务器将根据传入的状态信息进行相应处理。</p>
|
||||
*
|
||||
* @param deploymentId 部署的唯一标识符,用于指定需要更新状态的部署。
|
||||
* @param status 部署状态,整数类型,表示当前部署的状态,如成功、失败等。
|
||||
* @return 返回一个 {@link Result} 对象,包含操作结果的状态和相关信息。
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public Result<String> responseDeploymentResult(String deploymentId, Integer status) {
|
||||
Result<String> s = null;
|
||||
|
||||
try {
|
||||
s = platformApiServiceFeign.responseDeploymentResultFeign(deploymentId, status);
|
||||
} catch (Exception e) {
|
||||
log.error("Response deployment {} result exception: {}", deploymentId, e.getMessage());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ protocol.crypto-type=0
|
|||
|
||||
# Platform Service
|
||||
# Manager Platform URL
|
||||
service.platform-url=http://xajhuang.com:1300
|
||||
service.platform-url=https://172.21.44.35:50443/mw/core
|
||||
# APPID
|
||||
service.platform-appid=appid
|
||||
# cluster name
|
||||
|
@ -97,3 +97,21 @@ thread.max-pool-size=10
|
|||
thread.queue-capacity=25
|
||||
thread.name-prefix=Async-
|
||||
|
||||
# Can support profiles, databases, or remote
|
||||
gzs.sign.client-details-enabled=true
|
||||
gzs.sign.client-details.'mw-open-82hsbmz8'=98rnk8pz6j08fp6q
|
||||
# Permission: Specifies the interface corresponding to client_id. If the default value is empty, there is no restriction.
|
||||
#gzs.sign.perm.'yj-yy-1234567'=/xx/xx,/xx/yy
|
||||
|
||||
# default can be configured in the rule-group, for example, gzs.sign.rule-.yj.mode =0
|
||||
# [Optional] 1: strict mode, 0: common mode (default)
|
||||
#gzs.sign.rule.default.mode=0
|
||||
# [Optional] Mandatory check list (In any mode, the following interfaces require check)
|
||||
gzs.sign.rule.default.required-list=POST:/xxx/xx,*:/xxx/yy/**
|
||||
# [Optional] Optional check list (In any mode, the following interfaces can be checked)
|
||||
#gzs.sign.rule.default.optional-list=GET:/xxx/xx,*:/xxx/yy/*
|
||||
|
||||
# [Optional] If base64 encoding is used, you can configure whether base64 encoding for url security is required in the signature algorithm based on different client_id. The default value is true
|
||||
#gzs.sign.base64-url-safe.def = true
|
||||
#gzs.sign.base64-url-safe.'as-xx-1234567' = false
|
||||
|
||||
|
|
Binary file not shown.
|
@ -48,6 +48,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
*/
|
||||
@SpringBootTest
|
||||
@DisplayName("ProtocolJsonUtils 测试类")
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ProtocolJsonUtilsTest {
|
||||
|
||||
private ProtocolResp protocolResp;
|
||||
|
|
|
@ -1,122 +1,146 @@
|
|||
package com.cmcc.magent.service.impl;
|
||||
|
||||
import com.cmcc.magent.config.PlatformServiceConfig;
|
||||
import com.cmcc.magent.misc.HttpClientUtils;
|
||||
import com.cmcc.magent.misc.JsonUtils;
|
||||
import com.cmcc.hy.gzs.common.result.Result;
|
||||
import com.cmcc.magent.pojo.po.RegisterAgent;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import com.cmcc.magent.service.PlatformApiFeignClientService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.slf4j.Logger;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 单元测试类 {@code PlatformApiServiceImplTest} 用于测试 {@link PlatformApiServiceImpl} 的功能。
|
||||
* PlatformApiServiceImplTest 类用于测试 {@link PlatformApiServiceImpl} 的功能。
|
||||
* <p>
|
||||
* 测试的主要目标是确保 {@link PlatformApiServiceImpl#registerAgent(RegisterAgent)} 方法能够正常工作,
|
||||
* 该测试类包含多个单元测试,验证与 {@link PlatformApiFeignClientService} 相关的方法的正确性。
|
||||
* </p>
|
||||
*
|
||||
* <p>测试中使用了 {@code MockWebServer} 来模拟 HTTP 请求和响应,避免依赖实际的外部服务。</p>
|
||||
*
|
||||
* <p>主要验证内容包括:</p>
|
||||
* <ul>
|
||||
* <li>是否正确构造了 HTTP 请求(如方法和路径)。</li>
|
||||
* <li>是否正确处理了 HTTP 响应并返回预期结果。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>依赖注入说明:</p>
|
||||
* <ul>
|
||||
* <li>通过 {@code @Resource} 注入被测试的 {@code PlatformApiServiceImpl}。</li>
|
||||
* <li>通过 {@code @Autowired} 注入 {@code WebClient.Builder},用于生成测试时专用的 {@code WebClient}。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-01-14
|
||||
* @since 2025-03-07
|
||||
*/
|
||||
@SpringBootTest
|
||||
@DisplayName("平台服务接口")
|
||||
@DisplayName("平台访问接口测试")
|
||||
public class PlatformApiServiceImplTest {
|
||||
|
||||
/**
|
||||
* 被测试的服务类 {@link PlatformApiServiceImpl}。
|
||||
*/
|
||||
@Resource
|
||||
@Mock
|
||||
private PlatformApiFeignClientService platformApiServiceFeign;
|
||||
|
||||
@InjectMocks
|
||||
private PlatformApiServiceImpl platformApiService;
|
||||
|
||||
@Resource
|
||||
private PlatformServiceConfig platformServiceConfig;
|
||||
|
||||
private MockedStatic<HttpClientUtils> platformMock;
|
||||
|
||||
private MockedStatic<JsonUtils> jsonMock;
|
||||
private Logger logger;
|
||||
|
||||
/**
|
||||
* 在每个测试前进行设置。
|
||||
* 创建 HttpClient 和响应的 Mock 对象,并初始化 Mockito。
|
||||
*
|
||||
* 在每个测试之前初始化 Mockito 注解。
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
public void setUp() throws NoSuchFieldException, IllegalAccessException {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
platformMock = mockStatic(HttpClientUtils.class, Mockito.CALLS_REAL_METHODS);
|
||||
jsonMock = mockStatic(JsonUtils.class);
|
||||
|
||||
logger = mock(Logger.class);
|
||||
|
||||
// 获取 MyService 的 Class 对象
|
||||
Class<?> clazz = PlatformApiServiceImpl.class;
|
||||
// 获取 log 字段
|
||||
Field logField = clazz.getDeclaredField("log");
|
||||
// 设置字段可访问
|
||||
logField.setAccessible(true);
|
||||
// 获取 Unsafe 实例
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
// 获取 log 字段的偏移量
|
||||
long offset = unsafe.staticFieldOffset(logField);
|
||||
// 获取 log 字段所属的类对象
|
||||
Object base = unsafe.staticFieldBase(logField);
|
||||
|
||||
// 使用 Unsafe 修改 log 字段的值
|
||||
unsafe.putObject(base, offset, logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在每个测试后清理资源。
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
platformMock.close();
|
||||
jsonMock.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link PlatformApiServiceImpl#registerAgent(RegisterAgent)} 方法。
|
||||
*
|
||||
* <p>验证以下内容:</p>
|
||||
* <ul>
|
||||
* <li>是否正确发送了 HTTP POST 请求到指定路径(如 {@code /register})。</li>
|
||||
* <li>是否正确处理了 HTTP 响应并返回预期的结果。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>测试流程:</p>
|
||||
* <ol>
|
||||
* <li>设置 MockWebServer 的响应内容为 {@code {"message": "Hello, World!"}}。</li>
|
||||
* <li>使用测试数据(如 {@link RegisterAgent} 对象)调用 {@code registerAgent} 方法。</li>
|
||||
* <li>验证返回值是否等于设置的响应内容。</li>
|
||||
* <li>验证发送的请求是否符合预期(如方法为 POST,路径为 /register)。</li>
|
||||
* </ol>
|
||||
* 测试在成功执行情况下,调用 responseDeploymentResult 方法返回结果。
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("设备注册接口测试")
|
||||
void testFetchData() throws IOException {
|
||||
// 准备模拟的 HTTP 响应
|
||||
String mockResponse = "Mocked Response";
|
||||
@DisplayName("部署结果响应成功")
|
||||
public void responseDeploymentResult_SuccessfulExecution_ReturnsResult() {
|
||||
String deploymentId = "12345";
|
||||
Integer status = 1;
|
||||
Result<String> expectedResponse = Result.success("Deployment updated successfully");
|
||||
|
||||
final RegisterAgent agent = RegisterAgent.builder().deviceId("123542535").build();
|
||||
when(platformApiServiceFeign.responseDeploymentResultFeign(deploymentId, status)).thenReturn(expectedResponse);
|
||||
|
||||
jsonMock.when(() -> JsonUtils.getJson(any(Object.class))).thenReturn(mockResponse);
|
||||
Result<String> actualResponse = platformApiService.responseDeploymentResult(deploymentId, status);
|
||||
|
||||
platformMock.when(() -> HttpClientUtils.postJson(platformServiceConfig + "/register", null, mockResponse, null)).thenReturn(
|
||||
"Mocked Response");
|
||||
assertNotNull(actualResponse);
|
||||
assertEquals(expectedResponse, actualResponse);
|
||||
}
|
||||
|
||||
// 调用被测试方法
|
||||
final String result = platformApiService.registerAgent(agent);
|
||||
/**
|
||||
* 测试在调用 responseDeploymentResult 方法时抛出异常,返回 null。
|
||||
*
|
||||
* @throws RuntimeException 可能抛出的异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("部署结果响应异常")
|
||||
public void responseDeploymentResult_ExceptionThrown_ReturnsNull() {
|
||||
String deploymentId = "12345";
|
||||
Integer status = 1;
|
||||
Exception e = new RuntimeException("Service exception");
|
||||
|
||||
// 验证结果
|
||||
assertThat(result).isEqualTo(mockResponse);
|
||||
when(platformApiServiceFeign.responseDeploymentResultFeign(deploymentId, status)).thenThrow(e);
|
||||
|
||||
Result<String> ret = platformApiService.responseDeploymentResult(deploymentId, status);
|
||||
|
||||
assertNull(ret);
|
||||
verify(logger).error(eq("Response deployment {} result exception: {}"), eq("12345"), eq(e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试在成功注册情况下,调用 registerAgent 方法返回成功结果。
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("注册代理成功")
|
||||
public void registerAgent_SuccessfulRegistration_ReturnsSuccessResult() {
|
||||
RegisterAgent agent = new RegisterAgent("1234567890");
|
||||
Result<String> expected = Result.success("Registration successful");
|
||||
when(platformApiServiceFeign.registerAgentFeign(agent)).thenReturn(expected);
|
||||
|
||||
Result<String> actual = platformApiService.registerAgent(agent);
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试在调用 registerAgent 方法时抛出异常,返回 null。
|
||||
*
|
||||
* @throws RuntimeException 可能抛出的异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("注册代理异常")
|
||||
public void registerAgent_ExceptionThrown_ReturnsNull() {
|
||||
RegisterAgent agent = new RegisterAgent("1234567890");
|
||||
Exception e = new RuntimeException("Registration failedxxxx");
|
||||
when(platformApiServiceFeign.registerAgentFeign(agent)).thenThrow(e);
|
||||
|
||||
Result<String> ret = platformApiService.registerAgent(agent);
|
||||
|
||||
assertNull(ret);
|
||||
verify(logger).error(eq("Register agent client {} exception: {}"), eq("1234567890"), eq(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
resourceUsageService.performTask();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
CircularQueue<ResourceUsage> resourceUsageQueue = (CircularQueue<ResourceUsage>) ReflectionTestUtils.getField(resourceUsageService,
|
||||
"resourceUsageQueue");
|
||||
assertNotNull(resourceUsageQueue, "Resource usage queue should not be null");
|
||||
|
@ -109,6 +110,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
resourceUsageService.performTask();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
CircularQueue<ResourceUsage> resourceUsageQueue = (CircularQueue<ResourceUsage>) ReflectionTestUtils.getField(resourceUsageService,
|
||||
"resourceUsageQueue");
|
||||
|
||||
|
@ -137,6 +139,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
resourceUsageService.performTask();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
CircularQueue<ResourceUsage> resourceUsageQueue = (CircularQueue<ResourceUsage>) ReflectionTestUtils.getField(resourceUsageService,
|
||||
"resourceUsageQueue");
|
||||
assertNotNull(resourceUsageQueue, "Resource usage queue should not be null");
|
||||
|
|
|
@ -56,7 +56,7 @@ protocol.crypto-type=0
|
|||
|
||||
# Platform Service
|
||||
# Manager Platform URL
|
||||
service.platform-url=http://xajhuang.com:1300
|
||||
service.platform-url=http://xajhuang.com:3006/post
|
||||
# APPID
|
||||
service.platform-appid=appid
|
||||
# cluster name
|
||||
|
@ -70,3 +70,5 @@ thread.max-pool-size=10
|
|||
thread.queue-capacity=25
|
||||
thread.name-prefix=Async-
|
||||
|
||||
gzs.sign.client-details-enabled=true
|
||||
gzs.sign.client-details.'mw-open-82hsbmz8'=98rnk8pz6j08fp6q
|
Loading…
Reference in New Issue