-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
test: 为覆盖率最低的 weixin-java-open、weixin-java-channel 补充单元测试 #4080
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
devin-ai-integration
wants to merge
3
commits into
develop
Choose a base branch
from
devin/1785468833-add-unit-tests
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+534
−2
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
100 changes: 100 additions & 0 deletions
100
weixin-java-channel/src/test/java/me/chanjar/weixin/channel/util/WxChCryptUtilsTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package me.chanjar.weixin.channel.util; | ||
|
|
||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.Assert.assertNotNull; | ||
| import static org.testng.Assert.assertTrue; | ||
| import static org.testng.Assert.expectThrows; | ||
|
|
||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
| import javax.crypto.Cipher; | ||
| import javax.crypto.spec.IvParameterSpec; | ||
| import javax.crypto.spec.SecretKeySpec; | ||
| import me.chanjar.weixin.channel.config.impl.WxChannelDefaultConfigImpl; | ||
| import me.chanjar.weixin.common.error.WxRuntimeException; | ||
| import me.chanjar.weixin.common.util.crypto.SHA1; | ||
| import org.apache.commons.codec.binary.Base64; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| /** | ||
| * {@link WxChCryptUtils} 单元测试 | ||
| */ | ||
| public class WxChCryptUtilsTest { | ||
|
|
||
| private static final String APP_ID = "wx0000000000000002"; | ||
| private static final String TOKEN = "test_channel_token"; | ||
| /** 43 位 EncodingAESKey 占位值,非真实密钥 */ | ||
| private static final String AES_KEY = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY"; | ||
|
|
||
| private static final Pattern ENCRYPT_PATTERN = Pattern.compile("<Encrypt><!\\[CDATA\\[(.*?)]]></Encrypt>"); | ||
| private static final Pattern SIGNATURE_PATTERN = | ||
| Pattern.compile("<MsgSignature><!\\[CDATA\\[(.*?)]]></MsgSignature>"); | ||
| private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("<TimeStamp>(.*?)</TimeStamp>"); | ||
| private static final Pattern NONCE_PATTERN = Pattern.compile("<Nonce><!\\[CDATA\\[(.*?)]]></Nonce>"); | ||
|
|
||
| private WxChCryptUtils cryptUtils() { | ||
| WxChannelDefaultConfigImpl config = new WxChannelDefaultConfigImpl(); | ||
| config.setAppid(APP_ID); | ||
| config.setToken(TOKEN); | ||
| config.setAesKey(AES_KEY); | ||
| return new WxChCryptUtils(config); | ||
| } | ||
|
|
||
| private String group(Pattern pattern, String text) { | ||
| Matcher matcher = pattern.matcher(text); | ||
| assertTrue(matcher.find(), "未匹配到期望的节点:" + pattern.pattern()); | ||
| return matcher.group(1); | ||
| } | ||
|
|
||
| @Test | ||
| public void testEncryptThenDecrypt() { | ||
| WxChCryptUtils cryptUtils = cryptUtils(); | ||
| String plainText = "<xml><ToUserName><![CDATA[" + APP_ID + "]]></ToUserName>" | ||
| + "<MsgType><![CDATA[event]]></MsgType></xml>"; | ||
|
|
||
| String encryptedXml = cryptUtils.encrypt(plainText); | ||
| assertNotNull(encryptedXml); | ||
|
|
||
| String encrypt = group(ENCRYPT_PATTERN, encryptedXml); | ||
| String signature = group(SIGNATURE_PATTERN, encryptedXml); | ||
| String timestamp = group(TIMESTAMP_PATTERN, encryptedXml); | ||
| String nonce = group(NONCE_PATTERN, encryptedXml); | ||
|
|
||
| assertEquals(signature, SHA1.gen(TOKEN, timestamp, nonce, encrypt)); | ||
| assertEquals(cryptUtils.decryptXml(signature, timestamp, nonce, encryptedXml), plainText); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecryptXmlWithWrongSignature() { | ||
| WxChCryptUtils cryptUtils = cryptUtils(); | ||
| String encryptedXml = cryptUtils.encrypt("<xml><MsgType><![CDATA[event]]></MsgType></xml>"); | ||
| String timestamp = group(TIMESTAMP_PATTERN, encryptedXml); | ||
| String nonce = group(NONCE_PATTERN, encryptedXml); | ||
|
|
||
| expectThrows(WxRuntimeException.class, | ||
| () -> cryptUtils.decryptXml("wrong_signature", timestamp, nonce, encryptedXml)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecryptWithSessionKey() throws Exception { | ||
| byte[] keyBytes = "0123456789abcdef".getBytes(StandardCharsets.UTF_8); | ||
| byte[] ivBytes = "fedcba9876543210".getBytes(StandardCharsets.UTF_8); | ||
| String plainText = "{\"openid\":\"o0000000000000000000\"}"; | ||
|
|
||
| Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | ||
| cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(ivBytes)); | ||
| String encryptedData = Base64.encodeBase64String(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8))); | ||
|
|
||
| String decrypted = WxChCryptUtils.decrypt(Base64.encodeBase64String(keyBytes), encryptedData, | ||
| Base64.encodeBase64String(ivBytes)); | ||
| assertEquals(decrypted, plainText); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecryptWithInvalidSessionKey() { | ||
| expectThrows(RuntimeException.class, | ||
| () -> WxChCryptUtils.decrypt(Base64.encodeBase64String("short_key".getBytes(StandardCharsets.UTF_8)), | ||
| "invalid", Base64.encodeBase64String("fedcba9876543210".getBytes(StandardCharsets.UTF_8)))); | ||
| } | ||
| } | ||
75 changes: 75 additions & 0 deletions
75
weixin-java-channel/src/test/java/me/chanjar/weixin/channel/util/XmlUtilsTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package me.chanjar.weixin.channel.util; | ||
|
|
||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.Assert.assertNotNull; | ||
| import static org.testng.Assert.assertNull; | ||
|
|
||
| import com.fasterxml.jackson.core.type.TypeReference; | ||
| import com.fasterxml.jackson.dataformat.xml.XmlMapper; | ||
| import java.io.ByteArrayInputStream; | ||
| import java.io.InputStream; | ||
| import java.nio.charset.StandardCharsets; | ||
| import me.chanjar.weixin.channel.bean.base.AttrInfo; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| /** | ||
| * {@link XmlUtils} 单元测试 | ||
| */ | ||
| public class XmlUtilsTest { | ||
|
|
||
| private static final String XML = "<AttrInfo><attr_key>这是Key</attr_key><attr_value>这是Value</attr_value></AttrInfo>"; | ||
|
|
||
| @Test | ||
| public void testEncode() { | ||
| String xml = XmlUtils.encode(new AttrInfo("这是Key", "这是Value")); | ||
| assertNotNull(xml); | ||
| assertEquals(xml, XML); | ||
| } | ||
|
|
||
| @Test | ||
| public void testEncodeWithObjectMapper() { | ||
| String xml = XmlUtils.encode(new XmlMapper(), new AttrInfo("这是Key", "这是Value")); | ||
| assertNotNull(xml); | ||
| assertEquals(XmlUtils.decode(xml, AttrInfo.class).getKey(), "这是Key"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecode() { | ||
| AttrInfo info = XmlUtils.decode(XML, AttrInfo.class); | ||
| assertNotNull(info); | ||
| assertEquals(info.getKey(), "这是Key"); | ||
| assertEquals(info.getValue(), "这是Value"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecodeUnknownProperty() { | ||
| String xml = "<AttrInfo><attr_key>k</attr_key><unknown>v</unknown></AttrInfo>"; | ||
| AttrInfo info = XmlUtils.decode(xml, AttrInfo.class); | ||
| assertNotNull(info); | ||
| assertEquals(info.getKey(), "k"); | ||
| assertNull(info.getValue()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecodeEmptyOrInvalidXml() { | ||
| assertNull(XmlUtils.decode((String) null, AttrInfo.class)); | ||
| assertNull(XmlUtils.decode("", AttrInfo.class)); | ||
| assertNull(XmlUtils.decode("not a xml", AttrInfo.class)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecodeWithTypeReference() { | ||
| AttrInfo info = XmlUtils.decode(XML, new TypeReference<AttrInfo>() { | ||
| }); | ||
| assertNotNull(info); | ||
| assertEquals(info.getValue(), "这是Value"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testDecodeInputStream() { | ||
| InputStream is = new ByteArrayInputStream(XML.getBytes(StandardCharsets.UTF_8)); | ||
| AttrInfo info = XmlUtils.decode(is, AttrInfo.class); | ||
| assertNotNull(info); | ||
| assertEquals(info.getKey(), "这是Key"); | ||
| } | ||
| } |
138 changes: 138 additions & 0 deletions
138
weixin-java-open/src/test/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessageTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| package me.chanjar.weixin.open.bean.message; | ||
|
|
||
| import me.chanjar.weixin.common.util.crypto.SHA1; | ||
| import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage; | ||
| import me.chanjar.weixin.open.util.WxOpenCryptUtil; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| import java.io.ByteArrayInputStream; | ||
| import java.io.InputStream; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.Assert.assertNotNull; | ||
| import static org.testng.Assert.assertTrue; | ||
|
|
||
| /** | ||
| * {@link WxOpenXmlMessage} 单元测试 | ||
| */ | ||
| public class WxOpenXmlMessageTest { | ||
|
|
||
| private static final String COMPONENT_APP_ID = "wx0000000000000001"; | ||
| private static final String COMPONENT_TOKEN = "test_component_token"; | ||
| /** 43 位 EncodingAESKey 占位值,非真实密钥 */ | ||
| private static final String COMPONENT_AES_KEY = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY"; | ||
|
|
||
| private static final Pattern ENCRYPT_PATTERN = Pattern.compile("<Encrypt><!\\[CDATA\\[(.*?)]]></Encrypt>"); | ||
| private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("<TimeStamp>(.*?)</TimeStamp>"); | ||
| private static final Pattern NONCE_PATTERN = Pattern.compile("<Nonce><!\\[CDATA\\[(.*?)]]></Nonce>"); | ||
|
|
||
| private static final String VERIFY_TICKET_XML = "<xml>\n" | ||
| + " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n" | ||
| + " <CreateTime>1413192605</CreateTime>\n" | ||
| + " <InfoType><![CDATA[component_verify_ticket]]></InfoType>\n" | ||
| + " <ComponentVerifyTicket><![CDATA[ticket@@@abcdefg]]></ComponentVerifyTicket>\n" | ||
| + "</xml>"; | ||
|
|
||
| private WxOpenInMemoryConfigStorage config() { | ||
| WxOpenInMemoryConfigStorage config = new WxOpenInMemoryConfigStorage(); | ||
| config.setComponentAppId(COMPONENT_APP_ID); | ||
| config.setComponentToken(COMPONENT_TOKEN); | ||
| config.setComponentAesKey(COMPONENT_AES_KEY); | ||
| return config; | ||
| } | ||
|
|
||
| private String group(Pattern pattern, String text) { | ||
| Matcher matcher = pattern.matcher(text); | ||
| assertTrue(matcher.find(), "未匹配到期望的节点:" + pattern.pattern()); | ||
| return matcher.group(1); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFromXmlComponentVerifyTicket() { | ||
| WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(VERIFY_TICKET_XML); | ||
| assertNotNull(message); | ||
| assertEquals(message.getAppId(), COMPONENT_APP_ID); | ||
| assertEquals(message.getCreateTime(), Long.valueOf(1413192605L)); | ||
| assertEquals(message.getInfoType(), "component_verify_ticket"); | ||
| assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFromXmlAuthorized() { | ||
| String xml = "<xml>\n" | ||
| + " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n" | ||
| + " <CreateTime>1413192760</CreateTime>\n" | ||
| + " <InfoType><![CDATA[authorized]]></InfoType>\n" | ||
| + " <AuthorizerAppid><![CDATA[wx0000000000000002]]></AuthorizerAppid>\n" | ||
| + " <AuthorizationCode><![CDATA[auth_code_value]]></AuthorizationCode>\n" | ||
| + " <AuthorizationCodeExpiredTime>600</AuthorizationCodeExpiredTime>\n" | ||
| + " <PreAuthCode><![CDATA[pre_auth_code_value]]></PreAuthCode>\n" | ||
| + "</xml>"; | ||
|
|
||
| WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(xml); | ||
| assertNotNull(message); | ||
| assertEquals(message.getInfoType(), "authorized"); | ||
| assertEquals(message.getAuthorizerAppid(), "wx0000000000000002"); | ||
| assertEquals(message.getAuthorizationCode(), "auth_code_value"); | ||
| assertEquals(message.getAuthorizationCodeExpiredTime(), Long.valueOf(600L)); | ||
| assertEquals(message.getPreAuthCode(), "pre_auth_code_value"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFromXmlFastRegisterWeApp() { | ||
| String xml = "<xml>\n" | ||
| + " <AppId><![CDATA[" + COMPONENT_APP_ID + "]]></AppId>\n" | ||
| + " <CreateTime>1535442403</CreateTime>\n" | ||
| + " <InfoType><![CDATA[notify_third_fasteregister]]></InfoType>\n" | ||
| + " <appid>wx0000000000000003</appid>\n" | ||
| + " <status>0</status>\n" | ||
| + " <auth_code>auth_code_value</auth_code>\n" | ||
| + " <msg><![CDATA[OK]]></msg>\n" | ||
| + " <info>\n" | ||
| + " <name><![CDATA[тест]]></name>\n" | ||
| + " </info>\n" | ||
| + "</xml>"; | ||
|
|
||
| WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(xml); | ||
| assertNotNull(message); | ||
| assertEquals(message.getSubAppId(), "wx0000000000000003"); | ||
| assertEquals(message.getRegistAppId(), "wx0000000000000003"); | ||
| assertEquals(message.getStatus(), 0); | ||
| assertEquals(message.getAuthCode(), "auth_code_value"); | ||
| assertEquals(message.getMsg(), "OK"); | ||
| assertNotNull(message.getInfo()); | ||
| assertEquals(message.getInfo().getName(), "тест"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFromXmlInputStream() { | ||
| InputStream is = new ByteArrayInputStream(VERIFY_TICKET_XML.getBytes(StandardCharsets.UTF_8)); | ||
| WxOpenXmlMessage message = WxOpenXmlMessage.fromXml(is); | ||
| assertNotNull(message); | ||
| assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFromEncryptedXml() { | ||
| WxOpenInMemoryConfigStorage config = config(); | ||
| String encryptedXml = new WxOpenCryptUtil(config).encrypt(VERIFY_TICKET_XML); | ||
|
|
||
| String encrypt = group(ENCRYPT_PATTERN, encryptedXml); | ||
| String timestamp = group(TIMESTAMP_PATTERN, encryptedXml); | ||
| String nonce = group(NONCE_PATTERN, encryptedXml); | ||
| String signature = SHA1.gen(COMPONENT_TOKEN, timestamp, nonce, encrypt); | ||
|
|
||
| WxOpenXmlMessage message = WxOpenXmlMessage.fromEncryptedXml(encryptedXml, config, timestamp, nonce, signature); | ||
| assertNotNull(message); | ||
| assertEquals(message.getComponentVerifyTicket(), "ticket@@@abcdefg"); | ||
| assertEquals(message.getContext(), VERIFY_TICKET_XML); | ||
|
|
||
| InputStream is = new ByteArrayInputStream(encryptedXml.getBytes(StandardCharsets.UTF_8)); | ||
| WxOpenXmlMessage fromStream = WxOpenXmlMessage.fromEncryptedXml(is, config, timestamp, nonce, signature); | ||
| assertNotNull(fromStream); | ||
| assertEquals(fromStream.getInfoType(), "component_verify_ticket"); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weixin-java-channel/pom.xml:131-133同样固定使用src/test/resources/testng.xml,而该 suite 的<classes>在weixin-java-channel/src/test/resources/testng.xml:5-9中没有任何启用的测试类;按 Surefire suite XML 语义(https://maven.apache.org/surefire-archives/surefire-3.5.4/maven-surefire-plugin/examples/testng.html#using-suite-xml-files),启用常规mvn -pl weixin-java-channel -am test时既不会执行这个类,也不会执行同 PR 新增的XmlUtilsTest,导致新增 Channel 单测没有回归保护。请将新增类加入 suite,或移除suiteXmlFiles让默认扫描生效。Useful? React with 👍 / 👎.