Commit 8242735d84407c672410291a9151e6c1f5efc2f1

Authored by scholar
1 parent 2f38261d

1,腾讯云短信实现优化,去除不必要VO;

2,增加腾讯云短信功能单测,和集成单测;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClient.java
... ... @@ -2,36 +2,29 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
2 2  
3 3 import cn.hutool.core.lang.Assert;
4 4 import cn.hutool.core.util.StrUtil;
5   -import cn.hutool.http.HttpRequest;
6   -import cn.hutool.http.HttpResponse;
7 5 import cn.hutool.json.JSONArray;
8 6 import cn.hutool.json.JSONObject;
9 7 import cn.hutool.json.JSONUtil;
10 8 import cn.iocoder.yudao.framework.common.core.KeyValue;
11 9 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
12   -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  10 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
13 11 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
14 12 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
15 13 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
16 14 import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
17 15 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
18   -import com.fasterxml.jackson.annotation.JsonFormat;
19   -import com.fasterxml.jackson.annotation.JsonProperty;
20 16 import com.google.common.annotations.VisibleForTesting;
21   -import lombok.Data;
  17 +import jakarta.xml.bind.DatatypeConverter;
22 18  
23 19 import javax.crypto.Mac;
24 20 import javax.crypto.spec.SecretKeySpec;
25   -import javax.xml.bind.DatatypeConverter;
26 21 import java.nio.charset.StandardCharsets;
27 22 import java.text.SimpleDateFormat;
28   -import java.time.LocalDateTime;
29 23 import java.util.*;
30 24  
31 25 import static cn.hutool.crypto.digest.DigestUtil.sha256Hex;
32 26 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
33   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
34   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
  27 +
35 28  
36 29 /**
37 30 * 腾讯云短信功能实现
... ... @@ -103,14 +96,15 @@ public class TencentSmsClient extends AbstractSmsClient {
103 96 body.put("TemplateId",apiTemplateId);
104 97 body.put("TemplateParamSet",ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
105 98  
106   - JSONObject JsonResponse = sendSmsRequest(body,"SendSms","2021-01-11","ap-guangzhou");
107   - SmsResponse smsResponse = getSmsSendResponse(JsonResponse);
108   -
109   - return new SmsSendRespDTO().setSuccess(smsResponse.success).setApiMsg(smsResponse.data.toString());
  99 + JSONObject JsonResponse = request(body,"SendSms","2021-01-11","ap-guangzhou");
110 100  
  101 + return new SmsSendRespDTO().setSuccess(API_CODE_SUCCESS.equals(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("Code")))
  102 + .setApiRequestId(JsonResponse.getJSONObject("Response").getStr("RequestId"))
  103 + .setSerialNo(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("SerialNo"))
  104 + .setApiMsg(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("Message"));
111 105 }
112 106  
113   - JSONObject sendSmsRequest(TreeMap<String, Object> body,String action,String version,String region) throws Exception {
  107 + JSONObject request(TreeMap<String, Object> body,String action,String version,String region) throws Exception {
114 108  
115 109 String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
116 110 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
... ... @@ -155,12 +149,9 @@ public class TencentSmsClient extends AbstractSmsClient {
155 149 headers.put("X-TC-Version", version);
156 150 headers.put("X-TC-Region", region);
157 151  
158   - HttpResponse response = HttpRequest.post("https://"+host)
159   - .addHeaders(headers)
160   - .body(JSONUtil.toJsonStr(body))
161   - .execute();
  152 + String responseBody = HttpUtils.post("https://"+host, headers, JSONUtil.toJsonStr(body));
162 153  
163   - return JSONUtil.parseObj(response.body());
  154 + return JSONUtil.parseObj(responseBody);
164 155 }
165 156  
166 157 public static byte[] hmac256(byte[] key, String msg) throws Exception {
... ... @@ -170,22 +161,20 @@ public class TencentSmsClient extends AbstractSmsClient {
170 161 return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
171 162 }
172 163  
173   - private SmsResponse getSmsSendResponse(JSONObject resJson) {
174   - SmsResponse smsResponse = new SmsResponse();
175   - JSONArray statusJson =resJson.getJSONObject("Response").getJSONArray("SendStatusSet");
176   - smsResponse.setSuccess("Ok".equals(statusJson.getJSONObject(0).getStr("Code")));
177   - smsResponse.setData(resJson);
178   - return smsResponse;
179   - }
180   -
181 164 @Override
182 165 public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
183   - List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
184   - return convertList(callback, status -> new SmsReceiveRespDTO()
185   - .setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()))
186   - .setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription())
187   - .setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime())
188   - .setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId()));
  166 +
  167 + JSONArray statuses = JSONUtil.parseArray(text);
  168 + // 字段参考
  169 + return convertList(statuses, status -> {
  170 + JSONObject statusObj = (JSONObject) status;
  171 + return new SmsReceiveRespDTO()
  172 + .setSuccess("SUCCESS".equals(statusObj.getStr("report_status"))) // 是否接收成功
  173 + .setErrorCode(statusObj.getStr("errmsg")) // 状态报告编码
  174 + .setMobile(statusObj.getStr("mobile")) // 手机号
  175 + .setReceiveTime(statusObj.getLocalDateTime("user_receive_time", null)) // 状态报告时间
  176 + .setSerialNo(statusObj.getStr("sid")); // 发送序列号
  177 + });
189 178 }
190 179  
191 180 @Override
... ... @@ -193,46 +182,20 @@ public class TencentSmsClient extends AbstractSmsClient {
193 182  
194 183 // 构建请求
195 184 TreeMap<String, Object> body = new TreeMap<>();
196   - body.put("International",0);
  185 + body.put("International",INTERNATIONAL_CHINA);
197 186 Integer[] templateIds = {Integer.valueOf(apiTemplateId)};
198 187 body.put("TemplateIdSet",templateIds);
199 188  
200   - JSONObject JsonResponse = sendSmsRequest(body,"DescribeSmsTemplateList","2021-01-11","ap-guangzhou");
201   - QuerySmsTemplateResponse smsTemplateResponse = getSmsTemplateResponse(JsonResponse);
202   - String templateId = Integer.toString(smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getTemplateId());
203   - String content = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getTemplateContent();
204   - Integer templateStatus = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getStatusCode();
205   - String auditReason = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getReviewReply();
206   -
207   - return new SmsTemplateRespDTO().setId(templateId).setContent(content)
208   - .setAuditStatus(convertSmsTemplateAuditStatus(templateStatus)).setAuditReason(auditReason);
209   - }
210   -
211   - private QuerySmsTemplateResponse getSmsTemplateResponse(JSONObject resJson) {
212   -
213   - QuerySmsTemplateResponse smsTemplateResponse = new QuerySmsTemplateResponse();
  189 + JSONObject JsonResponse = request(body,"DescribeSmsTemplateList","2021-01-11","ap-guangzhou");
  190 + System.out.println("JsonResponse======"+JsonResponse);
214 191  
215   - smsTemplateResponse.setRequestId(resJson.getJSONObject("Response").getStr("RequestId"));
  192 + JSONObject TemplateStatusSet = JsonResponse.getJSONObject("Response").getJSONArray("DescribeTemplateStatusSet").getJSONObject(0);
  193 + String content = TemplateStatusSet.get("TemplateContent").toString();
  194 + int templateStatus = Integer.parseInt(TemplateStatusSet.get("StatusCode").toString());
  195 + String auditReason = TemplateStatusSet.get("ReviewReply").toString();
216 196  
217   - smsTemplateResponse.setDescribeTemplateStatusSet(new ArrayList<>());
218   -
219   - QuerySmsTemplateResponse.TemplateInfo templateInfo = new QuerySmsTemplateResponse.TemplateInfo();
220   -
221   - Object statusObject = resJson.getJSONObject("Response").getJSONArray("DescribeTemplateStatusSet").getFirst();
222   -
223   - JSONObject statusJSON = new JSONObject(statusObject);
224   -
225   - templateInfo.setTemplateContent(statusJSON.get("TemplateContent").toString());
226   -
227   - templateInfo.setStatusCode(Integer.parseInt(statusJSON.get("StatusCode").toString()));
228   -
229   - templateInfo.setReviewReply(statusJSON.get("ReviewReply").toString());
230   -
231   - templateInfo.setTemplateId(Integer.parseInt(statusJSON.get("TemplateId").toString()));
232   -
233   - smsTemplateResponse.getDescribeTemplateStatusSet().add(templateInfo);
234   -
235   - return smsTemplateResponse;
  197 + return new SmsTemplateRespDTO().setId(apiTemplateId).setContent(content)
  198 + .setAuditStatus(convertSmsTemplateAuditStatus(templateStatus)).setAuditReason(auditReason);
236 199 }
237 200  
238 201 @VisibleForTesting
... ... @@ -244,113 +207,4 @@ public class TencentSmsClient extends AbstractSmsClient {
244 207 default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
245 208 }
246 209 }
247   -
248   - @Data
249   - public static class SmsResponse {
250   -
251   - /**
252   - * 是否成功
253   - */
254   - private boolean success;
255   -
256   - /**
257   - * 厂商原返回体
258   - */
259   - private Object data;
260   -
261   - }
262   -
263   -
264   - /**
265   - * <p>类名: QuerySmsTemplateResponse
266   - * <p>说明: sms模板查询返回信息
267   - *
268   - * @author :scholar
269   - * 2024/07/17 0:25
270   - **/
271   - @Data
272   - public static class QuerySmsTemplateResponse {
273   - private List<TemplateInfo> DescribeTemplateStatusSet;
274   - private String RequestId;
275   - @Data
276   - static class TemplateInfo {
277   - private String TemplateName;
278   - private Integer TemplateId;
279   - private Integer International;
280   - private String ReviewReply;
281   - private long CreateTime;
282   - private String TemplateContent;
283   - private Integer StatusCode;
284   - }
285   - }
286   -
287   - @Data
288   - private static class SmsReceiveStatus {
289   -
290   - /**
291   - * 短信接受成功 code
292   - */
293   - public static final String SUCCESS_CODE = "SUCCESS";
294   -
295   - /**
296   - * 用户实际接收到短信的时间
297   - */
298   - @JsonProperty("user_receive_time")
299   - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
300   - private LocalDateTime receiveTime;
301   -
302   - /**
303   - * 国家(或地区)码
304   - */
305   - @JsonProperty("nationcode")
306   - private String nationCode;
307   -
308   - /**
309   - * 手机号码
310   - */
311   - private String mobile;
312   -
313   - /**
314   - * 实际是否收到短信接收状态,SUCCESS(成功)、FAIL(失败)
315   - */
316   - @JsonProperty("report_status")
317   - private String status;
318   -
319   - /**
320   - * 用户接收短信状态码错误信息
321   - */
322   - @JsonProperty("errmsg")
323   - private String errCode;
324   -
325   - /**
326   - * 用户接收短信状态描述
327   - */
328   - @JsonProperty("description")
329   - private String description;
330   -
331   - /**
332   - * 本次发送标识 ID(与发送接口返回的SerialNo对应)
333   - */
334   - @JsonProperty("sid")
335   - private String serialNo;
336   -
337   - /**
338   - * 用户的 session 内容(与发送接口的请求参数 SessionContext 一致)
339   - */
340   - @JsonProperty("ext")
341   - private SessionContext sessionContext;
342   -
343   - }
344   -
345   - @VisibleForTesting
346   - @Data
347   - static class SessionContext {
348   -
349   - /**
350   - * 发送短信记录id
351   - */
352   - private Long logId;
353   -
354   - }
355   -
356   -}
  210 +}
357 211 \ No newline at end of file
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientTests.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.KeyValue;
  4 +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
  5 +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
  6 +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
  7 +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
  8 +import org.junit.jupiter.api.Disabled;
  9 +import org.junit.jupiter.api.Test;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * 各种 {@link SmsClientTests 集成测试
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public class SmsClientTests {
  19 +
  20 + @Test
  21 + @Disabled
  22 + public void testHuaweiSmsClient_sendSms() throws Throwable {
  23 + SmsChannelProperties properties = new SmsChannelProperties()
  24 + .setApiKey("123")
  25 + .setApiSecret("456")
  26 + .setSignature("runpu");
  27 + HuaweiSmsClient client = new HuaweiSmsClient(properties);
  28 + // 准备参数
  29 + Long sendLogId = System.currentTimeMillis();
  30 + String mobile = "15601691323";
  31 + String apiTemplateId = "xx test01";
  32 + List<KeyValue<String, Object>> templateParams = List.of(new KeyValue<>("code", "1024"));
  33 + // 调用
  34 + SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
  35 + // 打印结果
  36 + System.out.println(smsSendRespDTO);
  37 + }
  38 +
  39 + // ========== 阿里云 ==========
  40 +
  41 + @Test
  42 + @Disabled
  43 + public void testAliyunSmsClient_getSmsTemplate() throws Throwable {
  44 + SmsChannelProperties properties = new SmsChannelProperties()
  45 + .setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
  46 + .setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz");
  47 + AliyunSmsClient client = new AliyunSmsClient(properties);
  48 + // 准备参数
  49 + String apiTemplateId = "SMS_207945135";
  50 + // 调用
  51 + SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
  52 + // 打印结果
  53 + System.out.println(template);
  54 + }
  55 +
  56 + @Test
  57 + @Disabled
  58 + public void testAliyunSmsClient_sendSms() throws Throwable {
  59 + SmsChannelProperties properties = new SmsChannelProperties()
  60 + .setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
  61 + .setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
  62 + .setSignature("runpu");
  63 + AliyunSmsClient client = new AliyunSmsClient(properties);
  64 + // 准备参数
  65 + Long sendLogId = System.currentTimeMillis();
  66 + String mobile = "15601691323";
  67 + String apiTemplateId = "SMS_207945135";
  68 + // 调用
  69 + SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, List.of(new KeyValue<>("code", "1024")));
  70 + // 打印结果
  71 + System.out.println(sendRespDTO);
  72 + }
  73 +
  74 + @Test
  75 + @Disabled
  76 + public void testAliyunSmsClient_parseSmsReceiveStatus() {
  77 + SmsChannelProperties properties = new SmsChannelProperties()
  78 + .setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
  79 + .setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz");
  80 + AliyunSmsClient client = new AliyunSmsClient(properties);
  81 + // 准备参数
  82 + String text = "[\n" +
  83 + " {\n" +
  84 + " \"phone_number\" : \"13900000001\",\n" +
  85 + " \"send_time\" : \"2017-01-01 11:12:13\",\n" +
  86 + " \"report_time\" : \"2017-02-02 22:23:24\",\n" +
  87 + " \"success\" : true,\n" +
  88 + " \"err_code\" : \"DELIVERED\",\n" +
  89 + " \"err_msg\" : \"用户接收成功\",\n" +
  90 + " \"sms_size\" : \"1\",\n" +
  91 + " \"biz_id\" : \"12345\",\n" +
  92 + " \"out_id\" : \"67890\"\n" +
  93 + " }\n" +
  94 + "]";
  95 + // mock 方法
  96 +
  97 + // 调用
  98 + List<SmsReceiveRespDTO> statuses = client.parseSmsReceiveStatus(text);
  99 + // 打印结果
  100 + System.out.println(statuses);
  101 + }
  102 +
  103 + // ========== 腾讯云 ==========
  104 +
  105 + @Test
  106 + @Disabled
  107 + public void testTencentSmsClient_sendSms() throws Throwable {
  108 + SmsChannelProperties properties = new SmsChannelProperties()
  109 + .setApiKey("LTAI5tAicJAxaSFiZuGGeXHR 1428926523")
  110 + .setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
  111 + .setSignature("芋道源码");
  112 + TencentSmsClient client = new TencentSmsClient(properties);
  113 + // 准备参数
  114 + Long sendLogId = System.currentTimeMillis();
  115 + String mobile = "15601691323";
  116 + String apiTemplateId = "2136358";
  117 + // 调用
  118 + SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, List.of(new KeyValue<>("code", "1024")));
  119 + // 打印结果
  120 + System.out.println(sendRespDTO);
  121 + }
  122 +
  123 + @Test
  124 + @Disabled
  125 + public void testTencentSmsClient_getSmsTemplate() throws Throwable {
  126 + SmsChannelProperties properties = new SmsChannelProperties()
  127 + .setApiKey("LTAI5tAicJAxaSFiZuGGeXHR 1428926523")
  128 + .setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
  129 + .setSignature("芋道源码");
  130 + TencentSmsClient client = new TencentSmsClient(properties);
  131 + // 准备参数
  132 + String apiTemplateId = "2136358";
  133 + // 调用
  134 + SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
  135 + // 打印结果
  136 + System.out.println(template);
  137 + }
  138 +}
  139 +
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClientTest.java
1 1 package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
2 2  
3   -import cn.hutool.core.util.ReflectUtil;
4 3 import cn.iocoder.yudao.framework.common.core.KeyValue;
5   -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
6   -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7   -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
8 5 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
9 6 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
10 7 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
... ... @@ -12,24 +9,19 @@ import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateR
12 9 import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
13 10 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
14 11 import com.google.common.collect.Lists;
15   -import com.tencentcloudapi.sms.v20210111.SmsClient;
16   -import com.tencentcloudapi.sms.v20210111.models.DescribeSmsTemplateListResponse;
17   -import com.tencentcloudapi.sms.v20210111.models.DescribeTemplateListStatus;
18   -import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
19   -import com.tencentcloudapi.sms.v20210111.models.SendStatus;
  12 +
20 13 import org.junit.jupiter.api.Test;
21 14 import org.mockito.InjectMocks;
22   -import org.mockito.Mock;
  15 +import org.mockito.MockedStatic;
23 16  
24 17 import java.time.LocalDateTime;
25   -import java.util.ArrayList;
26 18 import java.util.List;
27 19  
28   -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
29 20 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
30 21 import static org.junit.jupiter.api.Assertions.*;
31   -import static org.mockito.ArgumentMatchers.argThat;
32   -import static org.mockito.Mockito.when;
  22 +import static org.mockito.ArgumentMatchers.*;
  23 +import static org.mockito.ArgumentMatchers.anyString;
  24 +import static org.mockito.Mockito.mockStatic;
33 25  
34 26 /**
35 27 * {@link TencentSmsClient} 的单元测试
... ... @@ -46,9 +38,6 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
46 38 @InjectMocks
47 39 private TencentSmsClient smsClient = new TencentSmsClient(properties);
48 40  
49   - @Mock
50   - private SmsClient client;
51   -
52 41 @Test
53 42 public void testDoInit() {
54 43 // 准备参数
... ... @@ -56,103 +45,92 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
56 45  
57 46 // 调用
58 47 smsClient.doInit();
59   - // 断言
60   - assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "client"));
61   - }
62   -
63   - @Test
64   - public void testRefresh() {
65   - // 准备参数
66   - SmsChannelProperties p = new SmsChannelProperties()
67   - .setApiKey(randomString() + " " + randomString()) // 随机一个 apiKey,避免构建报错
68   - .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错
69   - .setSignature("芋道源码");
70   - // 调用
71   - smsClient.refresh(p);
72   - // 断言
73   - assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "client"));
74 48 }
75 49  
76 50 @Test
77 51 public void testDoSendSms_success() throws Throwable {
78   - // 准备参数
79   - Long sendLogId = randomLongId();
80   - String mobile = randomString();
81   - String apiTemplateId = randomString();
82   - List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
83   - new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
84   - String requestId = randomString();
85   - String serialNo = randomString();
86   - // mock 方法
87   - SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> {
88   - o.setRequestId(requestId);
89   - SendStatus[] sendStatuses = new SendStatus[1];
90   - o.setSendStatusSet(sendStatuses);
91   - SendStatus sendStatus = new SendStatus();
92   - sendStatuses[0] = sendStatus;
93   - sendStatus.setCode(TencentSmsClient.API_CODE_SUCCESS);
94   - sendStatus.setMessage("send success");
95   - sendStatus.setSerialNo(serialNo);
96   - });
97   - when(client.SendSms(argThat(request -> {
98   - assertEquals(mobile, request.getPhoneNumberSet()[0]);
99   - assertEquals(properties.getSignature(), request.getSignName());
100   - assertEquals(apiTemplateId, request.getTemplateId());
101   - assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)),
102   - toJsonString(request.getTemplateParamSet()));
103   - assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId"));
104   - return true;
105   - }))).thenReturn(response);
106 52  
107   - // 调用
108   - SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
109   - // 断言
110   - assertTrue(result.getSuccess());
111   - assertEquals(response.getRequestId(), result.getApiRequestId());
112   - assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
113   - assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
114   - assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
  53 + try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
  54 + // 准备参数
  55 + Long sendLogId = randomLongId();
  56 + String mobile = randomString();
  57 + String apiTemplateId = randomString();
  58 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  59 + new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
  60 +
  61 + // mock 方法
  62 + httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
  63 + .thenReturn(
  64 + "{\n" +
  65 + " \"Response\": {\n" +
  66 + " \"SendStatusSet\": [\n" +
  67 + " {\n" +
  68 + " \"SerialNo\": \"5000:1045710669157053657849499619\",\n" +
  69 + " \"PhoneNumber\": \"+8618511122233\",\n" +
  70 + " \"Fee\": 1,\n" +
  71 + " \"SessionContext\": \"test\",\n" +
  72 + " \"Code\": \"Ok\",\n" +
  73 + " \"Message\": \"send success\",\n" +
  74 + " \"IsoCode\": \"CN\"\n" +
  75 + " },\n" +
  76 + " ],\n" +
  77 + " \"RequestId\": \"a0aabda6-cf91-4f3e-a81f-9198114a2279\"\n" +
  78 + " }\n" +
  79 + "}"
  80 + );
  81 +
  82 + // 调用
  83 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
  84 + apiTemplateId, templateParams);
  85 + // 断言
  86 + assertTrue(result.getSuccess());
  87 + assertEquals("5000:1045710669157053657849499619", result.getSerialNo());
  88 + assertEquals("a0aabda6-cf91-4f3e-a81f-9198114a2279", result.getApiRequestId());
  89 + assertEquals("send success", result.getApiMsg());
  90 +
  91 + }
115 92 }
116 93  
117 94 @Test
118 95 public void testDoSendSms_fail() throws Throwable {
119   - // 准备参数
120   - Long sendLogId = randomLongId();
121   - String mobile = randomString();
122   - String apiTemplateId = randomString();
123   - List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
124   - new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
125   - String requestId = randomString();
126   - String serialNo = randomString();
127   - // mock 方法
128   - SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> {
129   - o.setRequestId(requestId);
130   - SendStatus[] sendStatuses = new SendStatus[1];
131   - o.setSendStatusSet(sendStatuses);
132   - SendStatus sendStatus = new SendStatus();
133   - sendStatuses[0] = sendStatus;
134   - sendStatus.setCode("ERROR");
135   - sendStatus.setMessage("send success");
136   - sendStatus.setSerialNo(serialNo);
137   - });
138   - when(client.SendSms(argThat(request -> {
139   - assertEquals(mobile, request.getPhoneNumberSet()[0]);
140   - assertEquals(properties.getSignature(), request.getSignName());
141   - assertEquals(apiTemplateId, request.getTemplateId());
142   - assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)),
143   - toJsonString(request.getTemplateParamSet()));
144   - assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId"));
145   - return true;
146   - }))).thenReturn(response);
147   -
148   - // 调用
149   - SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
150   - // 断言
151   - assertFalse(result.getSuccess());
152   - assertEquals(response.getRequestId(), result.getApiRequestId());
153   - assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
154   - assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
155   - assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
  96 + try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
  97 + // 准备参数
  98 + Long sendLogId = randomLongId();
  99 + String mobile = randomString();
  100 + String apiTemplateId = randomString();
  101 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  102 + new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
  103 +
  104 + // mock 方法
  105 + httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
  106 + .thenReturn(
  107 + "{\n" +
  108 + " \"Response\": {\n" +
  109 + " \"SendStatusSet\": [\n" +
  110 + " {\n" +
  111 + " \"SerialNo\": \"5000:1045710669157053657849499619\",\n" +
  112 + " \"PhoneNumber\": \"+8618511122233\",\n" +
  113 + " \"Fee\": 1,\n" +
  114 + " \"SessionContext\": \"test\",\n" +
  115 + " \"Code\": \"ERROR\",\n" +
  116 + " \"Message\": \"send success\",\n" +
  117 + " \"IsoCode\": \"CN\"\n" +
  118 + " },\n" +
  119 + " ],\n" +
  120 + " \"RequestId\": \"a0aabda6-cf91-4f3e-a81f-9198114a2279\"\n" +
  121 + " }\n" +
  122 + "}"
  123 + );
  124 +
  125 + // 调用
  126 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
  127 + apiTemplateId, templateParams);
  128 + // 断言
  129 + assertFalse(result.getSuccess());
  130 + assertEquals("5000:1045710669157053657849499619", result.getSerialNo());
  131 + assertEquals("a0aabda6-cf91-4f3e-a81f-9198114a2279", result.getApiRequestId());
  132 + assertEquals("send success", result.getApiMsg());
  133 + }
156 134 }
157 135  
158 136 @Test
... ... @@ -170,7 +148,6 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
170 148 " \"ext\": {\"logId\":\"67890\"}\n" +
171 149 " }\n" +
172 150 "]";
173   - // mock 方法
174 151  
175 152 // 调用
176 153 List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
... ... @@ -178,41 +155,45 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
178 155 assertEquals(1, statuses.size());
179 156 assertTrue(statuses.get(0).getSuccess());
180 157 assertEquals("DELIVRD", statuses.get(0).getErrorCode());
181   - assertEquals("用户短信送达成功", statuses.get(0).getErrorMsg());
182 158 assertEquals("13900000001", statuses.get(0).getMobile());
183 159 assertEquals(LocalDateTime.of(2015, 10, 17, 8, 3, 4), statuses.get(0).getReceiveTime());
184 160 assertEquals("12345", statuses.get(0).getSerialNo());
185   - assertEquals(67890L, statuses.get(0).getLogId());
186 161 }
187 162  
188 163 @Test
189 164 public void testGetSmsTemplate() throws Throwable {
190   - // 准备参数
191   - Long apiTemplateId = randomLongId();
192   - String requestId = randomString();
193   -
194   - // mock 方法
195   - DescribeSmsTemplateListResponse response = randomPojo(DescribeSmsTemplateListResponse.class, o -> {
196   - DescribeTemplateListStatus[] describeTemplateListStatuses = new DescribeTemplateListStatus[1];
197   - DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus();
198   - templateStatus.setTemplateId(apiTemplateId);
199   - templateStatus.setStatusCode(0L);// 设置模板通过
200   - describeTemplateListStatuses[0] = templateStatus;
201   - o.setDescribeTemplateStatusSet(describeTemplateListStatuses);
202   - o.setRequestId(requestId);
203   - });
204   - when(client.DescribeSmsTemplateList(argThat(request -> {
205   - assertEquals(apiTemplateId, request.getTemplateIdSet()[0]);
206   - return true;
207   - }))).thenReturn(response);
208 165  
209   - // 调用
210   - SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId.toString());
211   - // 断言
212   - assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getId());
213   - assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getContent());
214   - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
215   - assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getAuditReason());
  166 + try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
  167 +
  168 + // 准备参数
  169 + String apiTemplateId = "1122";
  170 +
  171 + // mock 方法
  172 + httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
  173 + .thenReturn("{ \"Response\": {\n" +
  174 + " \"DescribeTemplateStatusSet\": [\n" +
  175 + " {\n" +
  176 + " \"TemplateName\": \"验证码\",\n" +
  177 + " \"TemplateId\": 1122,\n" +
  178 + " \"International\": 0,\n" +
  179 + " \"ReviewReply\": \"审批备注\",\n" +
  180 + " \"CreateTime\": 1617379200,\n" +
  181 + " \"TemplateContent\": \"您的验证码是{1}\",\n" +
  182 + " \"StatusCode\": 0\n" +
  183 + " },\n" +
  184 + " \n" +
  185 + " ],\n" +
  186 + " \"RequestId\": \"f36e4f00-605e-49b1-ad0d-bfaba81c7325\"\n" +
  187 + " }}");
  188 +
  189 + // 调用
  190 + SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId);
  191 + // 断言
  192 + assertEquals("1122", result.getId());
  193 + assertEquals("您的验证码是{1}", result.getContent());
  194 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
  195 + assertEquals("审批备注", result.getAuditReason());
  196 + }
216 197 }
217 198  
218 199 @Test
... ...