Skip to content

Commit 509bce5

Browse files
🎨 补充单元测试
1 parent 6a4f0db commit 509bce5

9 files changed

Lines changed: 534 additions & 2 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package me.chanjar.weixin.channel.util;
2+
3+
import static org.testng.Assert.assertEquals;
4+
import static org.testng.Assert.assertNotNull;
5+
import static org.testng.Assert.assertTrue;
6+
import static org.testng.Assert.expectThrows;
7+
8+
import java.nio.charset.StandardCharsets;
9+
import java.util.regex.Matcher;
10+
import java.util.regex.Pattern;
11+
import javax.crypto.Cipher;
12+
import javax.crypto.spec.IvParameterSpec;
13+
import javax.crypto.spec.SecretKeySpec;
14+
import me.chanjar.weixin.channel.config.impl.WxChannelDefaultConfigImpl;
15+
import me.chanjar.weixin.common.error.WxRuntimeException;
16+
import me.chanjar.weixin.common.util.crypto.SHA1;
17+
import org.apache.commons.codec.binary.Base64;
18+
import org.testng.annotations.Test;
19+
20+
/**
21+
* {@link WxChCryptUtils} 单元测试
22+
*/
23+
public class WxChCryptUtilsTest {
24+
25+
private static final String APP_ID = "wx0000000000000002";
26+
private static final String TOKEN = "test_channel_token";
27+
/** 43 位 EncodingAESKey 占位值,非真实密钥 */
28+
private static final String AES_KEY = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY";
29+
30+
private static final Pattern ENCRYPT_PATTERN = Pattern.compile("<Encrypt><!\\[CDATA\\[(.*?)]]></Encrypt>");
31+
private static final Pattern SIGNATURE_PATTERN =
32+
Pattern.compile("<MsgSignature><!\\[CDATA\\[(.*?)]]></MsgSignature>");
33+
private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("<TimeStamp>(.*?)</TimeStamp>");
34+
private static final Pattern NONCE_PATTERN = Pattern.compile("<Nonce><!\\[CDATA\\[(.*?)]]></Nonce>");
35+
36+
private WxChCryptUtils cryptUtils() {
37+
WxChannelDefaultConfigImpl config = new WxChannelDefaultConfigImpl();
38+
config.setAppid(APP_ID);
39+
config.setToken(TOKEN);
40+
config.setAesKey(AES_KEY);
41+
return new WxChCryptUtils(config);
42+
}
43+
44+
private String group(Pattern pattern, String text) {
45+
Matcher matcher = pattern.matcher(text);
46+
assertTrue(matcher.find(), "未匹配到期望的节点:" + pattern.pattern());
47+
return matcher.group(1);
48+
}
49+
50+
@Test
51+
public void testEncryptThenDecrypt() {
52+
WxChCryptUtils cryptUtils = cryptUtils();
53+
String plainText = "<xml><ToUserName><![CDATA[" + APP_ID + "]]></ToUserName>"
54+
+ "<MsgType><![CDATA[event]]></MsgType></xml>";
55+
56+
String encryptedXml = cryptUtils.encrypt(plainText);
57+
assertNotNull(encryptedXml);
58+
59+
String encrypt = group(ENCRYPT_PATTERN, encryptedXml);
60+
String signature = group(SIGNATURE_PATTERN, encryptedXml);
61+
String timestamp = group(TIMESTAMP_PATTERN, encryptedXml);
62+
String nonce = group(NONCE_PATTERN, encryptedXml);
63+
64+
assertEquals(signature, SHA1.gen(TOKEN, timestamp, nonce, encrypt));
65+
assertEquals(cryptUtils.decryptXml(signature, timestamp, nonce, encryptedXml), plainText);
66+
}
67+
68+
@Test
69+
public void testDecryptXmlWithWrongSignature() {
70+
WxChCryptUtils cryptUtils = cryptUtils();
71+
String encryptedXml = cryptUtils.encrypt("<xml><MsgType><![CDATA[event]]></MsgType></xml>");
72+
String timestamp = group(TIMESTAMP_PATTERN, encryptedXml);
73+
String nonce = group(NONCE_PATTERN, encryptedXml);
74+
75+
expectThrows(WxRuntimeException.class,
76+
() -> cryptUtils.decryptXml("wrong_signature", timestamp, nonce, encryptedXml));
77+
}
78+
79+
@Test
80+
public void testDecryptWithSessionKey() throws Exception {
81+
byte[] keyBytes = "0123456789abcdef".getBytes(StandardCharsets.UTF_8);
82+
byte[] ivBytes = "fedcba9876543210".getBytes(StandardCharsets.UTF_8);
83+
String plainText = "{\"openid\":\"o0000000000000000000\"}";
84+
85+
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
86+
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(ivBytes));
87+
String encryptedData = Base64.encodeBase64String(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)));
88+
89+
String decrypted = WxChCryptUtils.decrypt(Base64.encodeBase64String(keyBytes), encryptedData,
90+
Base64.encodeBase64String(ivBytes));
91+
assertEquals(decrypted, plainText);
92+
}
93+
94+
@Test
95+
public void testDecryptWithInvalidSessionKey() {
96+
expectThrows(RuntimeException.class,
97+
() -> WxChCryptUtils.decrypt(Base64.encodeBase64String("short_key".getBytes(StandardCharsets.UTF_8)),
98+
"invalid", Base64.encodeBase64String("fedcba9876543210".getBytes(StandardCharsets.UTF_8))));
99+
}
100+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package me.chanjar.weixin.channel.util;
2+
3+
import static org.testng.Assert.assertEquals;
4+
import static org.testng.Assert.assertNotNull;
5+
import static org.testng.Assert.assertNull;
6+
7+
import com.fasterxml.jackson.core.type.TypeReference;
8+
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
9+
import java.io.ByteArrayInputStream;
10+
import java.io.InputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import me.chanjar.weixin.channel.bean.base.AttrInfo;
13+
import org.testng.annotations.Test;
14+
15+
/**
16+
* {@link XmlUtils} 单元测试
17+
*/
18+
public class XmlUtilsTest {
19+
20+
private static final String XML = "<AttrInfo><attr_key>这是Key</attr_key><attr_value>这是Value</attr_value></AttrInfo>";
21+
22+
@Test
23+
public void testEncode() {
24+
String xml = XmlUtils.encode(new AttrInfo("这是Key", "这是Value"));
25+
assertNotNull(xml);
26+
assertEquals(xml, XML);
27+
}
28+
29+
@Test
30+
public void testEncodeWithObjectMapper() {
31+
String xml = XmlUtils.encode(new XmlMapper(), new AttrInfo("这是Key", "这是Value"));
32+
assertNotNull(xml);
33+
assertEquals(XmlUtils.decode(xml, AttrInfo.class).getKey(), "这是Key");
34+
}
35+
36+
@Test
37+
public void testDecode() {
38+
AttrInfo info = XmlUtils.decode(XML, AttrInfo.class);
39+
assertNotNull(info);
40+
assertEquals(info.getKey(), "这是Key");
41+
assertEquals(info.getValue(), "这是Value");
42+
}
43+
44+
@Test
45+
public void testDecodeUnknownProperty() {
46+
String xml = "<AttrInfo><attr_key>k</attr_key><unknown>v</unknown></AttrInfo>";
47+
AttrInfo info = XmlUtils.decode(xml, AttrInfo.class);
48+
assertNotNull(info);
49+
assertEquals(info.getKey(), "k");
50+
assertNull(info.getValue());
51+
}
52+
53+
@Test
54+
public void testDecodeEmptyOrInvalidXml() {
55+
assertNull(XmlUtils.decode((String) null, AttrInfo.class));
56+
assertNull(XmlUtils.decode("", AttrInfo.class));
57+
assertNull(XmlUtils.decode("not a xml", AttrInfo.class));
58+
}
59+
60+
@Test
61+
public void testDecodeWithTypeReference() {
62+
AttrInfo info = XmlUtils.decode(XML, new TypeReference<AttrInfo>() {
63+
});
64+
assertNotNull(info);
65+
assertEquals(info.getValue(), "这是Value");
66+
}
67+
68+
@Test
69+
public void testDecodeInputStream() {
70+
InputStream is = new ByteArrayInputStream(XML.getBytes(StandardCharsets.UTF_8));
71+
AttrInfo info = XmlUtils.decode(is, AttrInfo.class);
72+
assertNotNull(info);
73+
assertEquals(info.getKey(), "这是Key");
74+
}
75+
}

weixin-java-channel/src/test/resources/testng.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@
88
<class name="me.chanjar.weixin.open.bean.result.WxFastMaBeenSetCategoryResultTest"/>-->
99
</classes>
1010
</test>
11+
<test name="Util_Test">
12+
<classes>
13+
<class name="me.chanjar.weixin.channel.util.JsonUtilsTest"/>
14+
<class name="me.chanjar.weixin.channel.util.XmlUtilsTest"/>
15+
<class name="me.chanjar.weixin.channel.util.WxChCryptUtilsTest"/>
16+
<class name="me.chanjar.weixin.channel.util.ResponseUtilsTest"/>
17+
</classes>
18+
</test>
1119
</suite>

weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxFastMaCanSetCategoryResult.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.gson.annotations.SerializedName;
44
import lombok.Data;
55
import lombok.EqualsAndHashCode;
6+
import org.apache.commons.lang3.math.NumberUtils;
67

78
import java.util.List;
89

@@ -16,11 +17,29 @@
1617
@EqualsAndHashCode(callSuper = false)
1718
public class WxFastMaCanSetCategoryResult extends WxOpenResult {
1819
private static final long serialVersionUID = -2469386233538980102L;
19-
@SerializedName("errcode")
20-
private int errCode;
2120
@SerializedName("categories_list")
2221
private CategoriesListBean categoriesList;
2322

23+
/**
24+
* 错误码,已弃用,未来将删除
25+
*
26+
* @see WxOpenResult#getErrcode() 应使用此方法
27+
*/
28+
@Deprecated
29+
public int getErrCode() {
30+
return NumberUtils.toInt(this.errcode);
31+
}
32+
33+
/**
34+
* 错误码,已弃用,未来将删除
35+
*
36+
* @see WxOpenResult#setErrcode(String) 应使用此方法
37+
*/
38+
@Deprecated
39+
public void setErrCode(int errCode) {
40+
this.errcode = String.valueOf(errCode);
41+
}
42+
2443
@Data
2544
public static class CategoriesListBean {
2645
private List<CategoriesBean> categories;
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package me.chanjar.weixin.open.bean.message;
2+
3+
import me.chanjar.weixin.common.util.crypto.SHA1;
4+
import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage;
5+
import me.chanjar.weixin.open.util.WxOpenCryptUtil;
6+
import org.testng.annotations.Test;
7+
8+
import java.io.ByteArrayInputStream;
9+
import java.io.InputStream;
10+
import java.nio.charset.StandardCharsets;
11+
import java.util.regex.Matcher;
12+
import java.util.regex.Pattern;
13+
14+
import static org.testng.Assert.assertEquals;
15+
import static org.testng.Assert.assertNotNull;
16+
import static org.testng.Assert.assertTrue;
17+
18+
/**
19+
* {@link WxOpenXmlMessage} 单元测试
20+
*/
21+
public class WxOpenXmlMessageTest {
22+
23+
private static final String COMPONENT_APP_ID = "wx0000000000000001";
24+
private static final String COMPONENT_TOKEN = "test_component_token";
25+
/** 43 位 EncodingAESKey 占位值,非真实密钥 */
26+
private static final String COMPONENT_AES_KEY = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY";
27+
28+
private static final Pattern ENCRYPT_PATTERN = Pattern.compile("<Encrypt><!\\[CDATA\\[(.*?)]]></Encrypt>");
29+
private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("<TimeStamp>(.*?)</TimeStamp>");
30+
private static final Pattern NONCE_PATTERN = Pattern.compile("<Nonce><!\\[CDATA\\[(.*?)]]></Nonce>");
31+
32+
private static final String VERIFY_TICKET_XML = "<xml>\n"
33+
+ " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n"
34+
+ " <CreateTime>1413192605</CreateTime>\n"
35+
+ " <InfoType><![CDATA[component_verify_ticket]]></InfoType>\n"
36+
+ " <ComponentVerifyTicket><![CDATA[ticket@@@abcdefg]]></ComponentVerifyTicket>\n"
37+
+ "</xml>";
38+
39+
private WxOpenInMemoryConfigStorage config() {
40+
WxOpenInMemoryConfigStorage config = new WxOpenInMemoryConfigStorage();
41+
config.setComponentAppId(COMPONENT_APP_ID);
42+
config.setComponentToken(COMPONENT_TOKEN);
43+
config.setComponentAesKey(COMPONENT_AES_KEY);
44+
return config;
45+
}
46+
47+
private String group(Pattern pattern, String text) {
48+
Matcher matcher = pattern.matcher(text);
49+
assertTrue(matcher.find(), "未匹配到期望的节点:" + pattern.pattern());
50+
return matcher.group(1);
51+
}
52+
53+
@Test
54+
public void testFromXmlComponentVerifyTicket() {
55+
WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(VERIFY_TICKET_XML);
56+
assertNotNull(message);
57+
assertEquals(message.getAppId(), COMPONENT_APP_ID);
58+
assertEquals(message.getCreateTime(), Long.valueOf(1413192605L));
59+
assertEquals(message.getInfoType(), "component_verify_ticket");
60+
assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg");
61+
}
62+
63+
@Test
64+
public void testFromXmlAuthorized() {
65+
String xml = "<xml>\n"
66+
+ " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n"
67+
+ " <CreateTime>1413192760</CreateTime>\n"
68+
+ " <InfoType><![CDATA[authorized]]></InfoType>\n"
69+
+ " <AuthorizerAppid><![CDATA[wx0000000000000002]]></AuthorizerAppid>\n"
70+
+ " <AuthorizationCode><![CDATA[auth_code_value]]></AuthorizationCode>\n"
71+
+ " <AuthorizationCodeExpiredTime>600</AuthorizationCodeExpiredTime>\n"
72+
+ " <PreAuthCode><![CDATA[pre_auth_code_value]]></PreAuthCode>\n"
73+
+ "</xml>";
74+
75+
WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(xml);
76+
assertNotNull(message);
77+
assertEquals(message.getInfoType(), "authorized");
78+
assertEquals(message.getAuthorizerAppid(), "wx0000000000000002");
79+
assertEquals(message.getAuthorizationCode(), "auth_code_value");
80+
assertEquals(message.getAuthorizationCodeExpiredTime(), Long.valueOf(600L));
81+
assertEquals(message.getPreAuthCode(), "pre_auth_code_value");
82+
}
83+
84+
@Test
85+
public void testFromXmlFastRegisterWeApp() {
86+
String xml = "<xml>\n"
87+
+ " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n"
88+
+ " <CreateTime>1535442403</CreateTime>\n"
89+
+ " <InfoType><![CDATA[notify_third_fasteregister]]></InfoType>\n"
90+
+ " <appid>wx0000000000000003</appid>\n"
91+
+ " <status>0</status>\n"
92+
+ " <auth_code>auth_code_value</auth_code>\n"
93+
+ " <msg><![CDATA[OK]]></msg>\n"
94+
+ " <info>\n"
95+
+ " <name><![CDATA[тест]]></name>\n"
96+
+ " </info>\n"
97+
+ "</xml>";
98+
99+
WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(xml);
100+
assertNotNull(message);
101+
assertEquals(message.getSubAppId(), "wx0000000000000003");
102+
assertEquals(message.getRegistAppId(), "wx0000000000000003");
103+
assertEquals(message.getStatus(), 0);
104+
assertEquals(message.getAuthCode(), "auth_code_value");
105+
assertEquals(message.getMsg(), "OK");
106+
assertNotNull(message.getInfo());
107+
assertEquals(message.getInfo().getName(), "тест");
108+
}
109+
110+
@Test
111+
public void testFromXmlInputStream() {
112+
InputStream is = new ByteArrayInputStream(VERIFY_TICKET_XML.getBytes(StandardCharsets.UTF_8));
113+
WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(is);
114+
assertNotNull(message);
115+
assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg");
116+
}
117+
118+
@Test
119+
public void testFromEncryptedXml() {
120+
WxOpenInMemoryConfigStorage config = config();
121+
String encryptedXml = new WxOpenCryptUtil(config).encrypt(VERIFY_TICKET_XML);
122+
123+
String encrypt = group(ENCRYPT_PATTERN, encryptedXml);
124+
String timestamp = group(TIMESTAMP_PATTERN, encryptedXml);
125+
String nonce = group(NONCE_PATTERN, encryptedXml);
126+
String signature = SHA1.gen(COMPONENT_TOKEN, timestamp, nonce, encrypt);
127+
128+
WxOpenXmlMessage message = WxOpenXmlMessage.fromEncryptedXml(encryptedXml, config, timestamp, nonce, signature);
129+
assertNotNull(message);
130+
assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg");
131+
assertEquals(message.getContext(), VERIFY_TICKET_XML);
132+
133+
InputStream is = new ByteArrayInputStream(encryptedXml.getBytes(StandardCharsets.UTF_8));
134+
WxOpenXmlMessage fromStream = WxOpenXmlMessage.fromEncryptedXml(is, config, timestamp, nonce, signature);
135+
assertNotNull(fromStream);
136+
assertEquals(fromStream.getInfoType(), "component_verify_ticket");
137+
}
138+
}

weixin-java-open/src/test/java/me/chanjar/weixin/open/bean/result/WxFastMaCanSetCategoryResultTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
44
import org.testng.annotations.Test;
55

6+
import static org.testng.Assert.assertEquals;
67
import static org.testng.Assert.assertNotNull;
8+
import static org.testng.Assert.assertTrue;
79

810

911
public class WxFastMaCanSetCategoryResultTest {
@@ -73,6 +75,10 @@ public void testFromJson() throws Exception {
7375

7476
assertNotNull(res);
7577
assertNotNull(res.getCategoriesList());
78+
assertEquals(res.getErrcode(), "0");
79+
assertEquals(res.getErrmsg(), "ok");
80+
assertEquals(res.getErrCode(), 0);
81+
assertTrue(res.isSuccess());
7682
System.out.println(res);
7783
}
7884

0 commit comments

Comments
 (0)