第一次感受到改原始碼解決 BUG 的樂趣
因目前公司內部對http介面自動化,dubbo介面自動化都是使用指令碼來管理,技術棧還分java 和python ,內部對接很不方便,為了降低使用門檻,提升介面測試效率,所以決定在原有的功能用例管理平臺新增介面自動化來統一管理。
MeterSphere
首先吹一波MeterSphere,個人覺得目前最好,功能最完善的介面自動化平臺,專案還在持續更新,並且有開源版,大家有興趣可以看一下專案程式碼https://github.com/metersphere/
個人對於這個平臺Http介面測試的部分理解:
通過前端的入參將其封裝成JMeter能識別的 .jmx檔案,再通過JMeter的開放API去執行.jmx檔案。這裡不得不說 該專案成員對JMeter非常熟悉,拋棄了jmeter難用的GUI,實現了一套非常好用UI,MeterSphere牛皮。
移植MeterSphere部分功能
因為只需要介面測試的功能,所以只移介面測試部分。首先要做的就是在本地部署MeterSphere,官方文件只有docker部署教程,沒有windows下搭建的教程,而且sql檔案還分別放在不同的檔案下面,這無疑增加了二次開發 的成本。
最後我在linux下部署專案,然後將sql匯出,在application.properties新增資料庫配置,註釋了原專案中的部分程式碼,在windows 下成功啟動,並且移植了介面測試模組的功能,然後,在測試的時候發現Dubbo介面無法成功呼叫,於是便有了第一次修改原始碼的操作......
發現問題:dubbo介面測試報錯
MeterSphere這裡對Dubbo的配置很多,原本想簡化測試,這一套配置填下去,感覺比原有的方式還要麻煩,於是這裡我便將配置預設寫死,因為公司目前使用zk做註冊中心,其他的consumer&Service、Config Service這個配置也無需使用人員去配置。
但是當我填入對應的引數,請求dubbo介面的時候,問題就出現了
Failed to check the status of the service xxx.xxx.xxx . No provider available for the service
一直報錯找不到對應的服務,而我用現有的指令碼請求是能夠成功的,確認了環境沒有問題之後,我想可能是Dubbo版本的原因
定位問題:dubbo版本
先來看兩張圖
我在maven倉庫裡面搜出來結果可以發現,Dubbo是在2.7.x版本被apache收錄,2.6.x的版本 groupId是com.alibaba。
於是在專案中找到對應依賴,果然版本對不上,我們系統目前使用的Dubbo是2.5.x,阿里的版本。而這兩個版本連線ZK的方式也不同,老版本是通過
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
</dependency>
新版本則是使用
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
確定問題就是版本問,於是便開始了改原始碼
解決問題:修改jmeter-plugins-for-apache-dubbo外掛程式碼
Jmeter支援Dubbo介面需要jmeter-plugins-for-apache-dubbo這個三方外掛支援,官方目前使用的是2.7.12不適合我們系統
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>jmeter-plugins-dubbo</artifactId>
<version>2.7.12</version>
</dependency>
於是我將其修改為官方提供的1.3.x,發現呼叫Dubbo介面還是失敗,無法找到對應的服務。
最後我將1.3.x三方包下載到本地,研究其泛化呼叫的程式碼,發現其中很大一部分程式碼其實是對不同註冊中心如:zookeeper、nacos、redis的支援,而公司目前使用的zookeeper,我完全可以將這些不用的程式碼註釋掉,自己封裝一套泛化呼叫的邏輯,
@SuppressWarnings({"unchecked", "rawtypes"})
private Object callDubbo(SampleResult res) {
try {
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("remoteInvoke");
applicationConfig.setVersion("");
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setFile("/tmp/dubbo.cachr");
String address = getAddress();
registryConfig.setAddress(address);
registryConfig.setProtocol("zookeeper");
reference.setApplication(applicationConfig);
reference.setRegistry(registryConfig);
// 弱型別介面名
String interfaceName = getInterface();
reference.setInterface(interfaceName);
reference.setVersion("1.0.0");
// 宣告為泛化介面
reference.setGeneric(true);
reference.setProtocol("dubbo");
//不重試,重試會造成資料重複執行
reference.setRetries(0);
reference.setTimeout(10000);
String methodName = getMethod();
if (StringUtils.isBlank(methodName)) {
res.setSuccessful(false);
return ErrorCode.MISS_METHOD.getMessage();
}
// 用org.apache.dubboinfo.rpc.service.GenericService可以替代所有介面引用
GenericService genericService = reference.get();
if (genericService == null) {
res.setSuccessful(false);
return MessageFormat.format(ErrorCode.GENERIC_SERVICE_IS_NULL.getMessage(), interfaceName);
}
String[] parameterTypes = null;
Object[] parameterValues = null;
List<MethodArgument> args = getMethodArgs();
List<String> paramterTypeList = new ArrayList<String>();;
List<Object> parameterValuesList = new ArrayList<Object>();;
for(MethodArgument arg : args) {
ClassUtils.parseParameter(paramterTypeList, parameterValuesList, arg);
}
parameterTypes = paramterTypeList.toArray(new String[paramterTypeList.size()]);
parameterValues = parameterValuesList.toArray(new Object[parameterValuesList.size()]);
Object result = null;
try {
result = genericService.$invoke(methodName, parameterTypes, parameterValues);
res.setSuccessful(true);
} catch (Exception e) {
log.error("RpcException:", e);
//TODO
//當介面返回異常時,sample標識為successful,通過響應內容做斷言來判斷是否標識sample錯誤,因為sample的錯誤會統計到用例的error百分比內。
//比如介面有一些校驗性質的異常,不代表這個操作是錯誤的,這樣就可以靈活的判斷,不至於正常的校驗返回導致測試用例error百分比的不真實
res.setSuccessful(true);
result = e;
}
return result;
} catch (Exception e) {
log.error("UnknownException:", e);
res.setSuccessful(false);
return e;
} finally {
//TODO 不能在sample結束時destroy
// if (registry != null) {
// registry.destroyAll();
// }
// reference.destroy();
}
}
最後,將程式碼打成jar包,通過maven離線呼叫
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>jmeter-plugins-dubbo</artifactId>
<version>1.3.8</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/jmeter-plugins-dubbo-1.3.8.jar</systemPath>
</dependency>
終於請求成功
結語
正當我幻想著給MeterSphere提交issure,並提交pr,成為一個熱門開源專案的貢獻者,從此走上人生巔峰時。我發現MeterSphere專案上的提交記錄赫然寫著 :
"fix: 修復dubbo客戶端v2.7.7以上版本在進行泛化呼叫server端為v2.6.x以前版本時出現No Provider錯誤"
BUG其實在兩個月前被解決了...
雖然沒能成為MeterSphere 的貢獻者,但是第一次通過修改原始碼來解決BUG,還是很有成就感的。
相關文章
- 閱讀原始碼的樂趣原始碼
- 遊戲,一個有樂趣的、解決問題的過程遊戲
- 製作遊戲的遊戲:創作樂趣的樂趣遊戲
- 一個即將寫入MySQL原始碼的官方bug解決之路MySql原始碼
- 探索TiDB Lightning的原始碼來解決發現的bugTiDB原始碼
- 推薦網站Project Euler:思考的樂趣&計算的樂趣網站Project
- 簡評《嘎吱作響》——解決謎題是否意味著樂趣
- 解決GAT首頁亂碼Bug
- 【演算法的樂趣】演算法
- 網路娛樂遊戲直播原始碼解決方案,開發基礎功能模組詳解遊戲原始碼
- 重拾 CSS 的樂趣(下)CSS
- 重拾 CSS 的樂趣(上)CSS
- 維護程式的那些樂趣
- 享受工具帶來的樂趣
- iOS 解決MJPhotoBrowser的bugiOS
- 樂趣在於思考
- 享受工作樂趣(轉)
- 敲程式碼是件痛苦還是有樂趣的事?
- ArrayList原始碼(改)(查)原始碼
- 原始碼安全加密解決方案原始碼加密
- SwiftUI Picker 如何通過新增accessibility解決訪問ProgressView crash bug (教程含原始碼)SwiftUIView原始碼
- 常見BUG解決
- 改bug時踩的坑
- Polygon 年度遊戲之《巴巴是你》:解讀純粹的遊戲樂趣Go遊戲
- 原始碼防洩密解決之道原始碼
- bug 11890804 的解決
- 【原始碼】Redis exists命令bug分析原始碼Redis
- 遊戲不應該只有樂趣遊戲
- DRF-Throttle元件原始碼分析及改編原始碼元件原始碼
- DRF-Permission元件原始碼分析及改編原始碼元件原始碼
- BUG 解決記錄 一
- jdk 原始碼的一個BUG,大家來看看JDK原始碼
- Delphi 6 SOAP 原始碼中的BUG修正 (轉)原始碼
- 音樂社交化和音樂模式的改變模式
- 愛上數學的理由——評《思考的樂趣》
- Java我的三個月——OOP的樂趣 (轉)JavaOOP
- 原始碼防洩密解決之道(二)原始碼
- kewastUnPackStats(): oracle 11.2.0.1的bug解決方法ASTOracle