差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

Both sides previous revision 前次修改
java:wiremock:fuck [2021/08/15 00:34]
tony 移除
— (目前版本)
行 1: 行 1:
-{{tag>​wiremock}} 
-====== WireMock - Record Disconnection Behavior ====== 
-===== Problem ===== 
-我有一隻待測程式(SUT)會相依於外部服務(External Service),操作流程如下:​ 
-  - SUT觸發一個async command。 
-  - 接著外部服務將會重置而導致SUT無法連線。 
-  - SUT會不停的Get去等待外部服務再次連線。 
-{{:​java:​wiremock:​wm_test_connection_reset.png|}}\\ 
-在我導入WireMock要替代外部服務並錄製腳本過程中,發現WireMock只要發生網路連線問題就會回應以下內容:​ 
-<​code>​ 
-Network failure trying to make a proxied request from WireMock to https://​10.146.125.169/​api/​v1 
-Connect to 10.146.125.169:​443 [/​10.146.125.169] failed: Connection timed out: connect 
-</​code>​ 
-{{:​java:​wiremock:​wm_test_connection_reset_and_get_500_error_code.png|}}\\ 
-\\ 
-這導致SUT接到非預期的500 status code,使工作的執行無法順利完成。本篇文章主要分享我的解決方法。(code:​ [[https://​github.com/​frank007love/​wiremock-redfish|link]]) 
-===== How to? ===== 
-(對嘗試過程沒興趣可以直接看方法2) 
-===== 方法1 ===== 
-我的第一個方法,是直接找到造成500問題的地方([[https://​github.com/​tomakehurst/​wiremock/​blob/​1e7c07e9ff845b3253c8177159775ddd070c22a4/​src/​main/​java/​com/​github/​tomakehurst/​wiremock/​http/​ProxyResponseRenderer.java|link]] ProxyResponseRenderer),修改WireMock程式碼直接retry。這會讓工作能夠繼續執行並完成。最後我透過修改錄製出來的腳本,加上長時間的response delay強迫client timeout去模擬類似情境:​ 
-<code json> 
-"​response":​ { 
-        "​status":​ 200, 
-        "​fixedDelayMilliseconds":​ 120000 
-} 
-</​code>​ 
-Note. 嘗試過在HttpClientFactory加socket timeout是沒有幫助的,這受到作業系統設定限制。 
-===== 方法2 ===== 
-後來研究了一下[[http://​wiremock.org/​docs/​extending-wiremock/​|Exteding WireMock]]內容後,覺得應該有機會可以透過擴充的方式去達到我的目的,因此有了方法2。 
-==== Extend ResponseTransformer ==== 
-首先我看上了ResponseTransformer,它可以讓你對Response加工。在[[http://​wiremock.org/​docs/​simulating-faults/​|Simulating Faults]]內容有提及WireMock模擬Fault的一些方式,其中這部分內容激起了我的靈感:​ 
-<code json> 
-{ 
-    "​request":​ { 
-        "​method":​ "​GET",​ 
-        "​url":​ "/​fault"​ 
-    }, 
-    "​response":​ { 
-        "​fault":​ "​MALFORMED_RESPONSE_CHUNK"​ 
-    } 
-} 
-</​code>​ 
-我想應該可以根據connection timed out這種特定錯誤情境,讓WireMock產生Fault的Response,在這裡我使用了Fault.CONNECTION_RESET_BY_PEER:​ 
-<code java> 
-public class SocketTimedOutResponseTransformer extends ResponseTransformer { 
  
-    @Override 
-    public Response transform(Request request, Response response, FileSource files, Parameters parameters) { 
-    if(response.getStatus()==500&&​response.getBodyAsString().contains("​timed out")) { 
-    return Response.Builder.like(response) 
-    .body(String.valueOf(Fault.CONNECTION_RESET_BY_PEER)) 
-    .fault(Fault.CONNECTION_RESET_BY_PEER).build();​ 
-    } 
-        return response; 
-    } 
- 
-    @Override 
-    public String getName() { 
-        return "​SocketTimedOutResponseTransformer";​ 
-    } 
-} 
-</​code>​ 
-response我除了模擬fault以外,也在body塞Fault.CONNECTION_RESET_BY_PEER;這是另一段故事,請讓我在下一段做說明。 
-==== Extend StubMappingTransformer ==== 
-在套用上面方法後,工作是能夠如下圖執行完畢:​\\ 
-{{:​java:​wiremock:​wm_simulate_connection_reset.png|}}\\ 
-但產生出來的腳本並不包含fault動作,也代表著無法重現整個流程。我Trace了一下WireMock程式碼,發現LoggedResponse轉為ResponseDefinition時,並沒有取用Fault欄位,這導致了資料的遺失:​\\ 
-{{:​java:​wiremock:​wm_src_apply_loggedresponse.png|}}\\ 
-因此我將腦筋動到了另外一個Extension StubMappingTransformer上。與前一個extension成對,當收到500且有Fault的ResponseDefinition時,就會把body內的字串轉為Fault並產生新的ResponseDefinition,最後塞到StubMapping讓它有辦法產生我們預期的內容:​ 
-<code java> 
-public class FaultStubMappingTransformer extends StubMappingTransformer { 
- 
- 
-    @Override 
-    public String getName() { 
-        return "​FaultStubMappingTransformer";​ 
-    } 
- 
-    private Fault getFault(ResponseDefinition responseDef) { 
-    String body = Objects.toString(responseDef.getBody(),​ ""​);​ 
-    try { 
- return Fault.valueOf(body);​ 
-    } catch (IllegalArgumentException e) { 
- return null; 
- } 
-    } 
-    ​ 
-    private void setupFaultResponseDef(StubMapping stubMapping) { 
-    ResponseDefinition responseDef = stubMapping.getResponse();​ 
-    Fault fault = getFault(responseDef);​ 
-    if( fault == null ) 
-    return; 
-     
-    ResponseDefinition faultResponseDef = ResponseDefinitionBuilder.like(responseDef).withFault(fault).build();​ 
- stubMapping.setResponse(faultResponseDef);​ 
-    } 
-    ​ 
- @Override 
- public StubMapping transform(StubMapping stubMapping,​ FileSource files, Parameters parameters) { 
- ResponseDefinition responseDef = stubMapping.getResponse();​ 
-  
- if( responseDef.getStatus() == 500) { 
- setupFaultResponseDef(stubMapping);​ 
- } 
- return stubMapping;​ 
- } 
-} 
-</​code>​ 
-最後產生的mapping file終於有fault的字眼:​ 
-<code json> 
- "​response"​ : { 
-    "​status"​ : 500, 
-    "​base64Body"​ : "​Q09OTkVDVElPTl9SRVNFVF9CWV9QRUVS",​ 
-    "​fault"​ : "​CONNECTION_RESET_BY_PEER"​ 
-  } 
-</​code>​ 
- 
-=====    ===== 
----- 
-\\ 
-~~DISQUS~~