pkuwm commented on a change in pull request #1013:
URL: https://github.com/apache/helix/pull/1013#discussion_r426227730



##########
File path: 
helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientImpl.java
##########
@@ -130,6 +131,11 @@ protected HttpResponse post(String url, Map<String, 
String> payloads) throws IOE
       LOG.info("Executing request: {}, headers: {}, entity: {}", 
postRequest.getRequestLine(),
           postRequest.getAllHeaders(), postRequest.getEntity());
       return _httpClient.execute(postRequest);
+    } catch (ConnectTimeoutException e) {
+      LOG.error(
+          "Failed to perform customized health check due to 
ConnectTimeoutException for endpoint {}.",
+          url, e);
+      throw e;

Review comment:
       What's the purpose of logging and throwing exception?
   
   By checking the calling stack, I don't think it is necessary. 
`ConnectTimeoutException` also extends `IOException` which is already caught. 
The upper method `getHealthStatusFromRest` catches this exception and logs. If 
you log and throw here, there would be two error messages which are confusing 
and redundant. Eg, in the test you write, we would see the error log in our 
test output if we set logging level to print errors. And it is quite confusing.

##########
File path: helix-common/src/main/java/org/apache/helix/SystemPropertyKeys.java
##########
@@ -78,4 +78,7 @@
   // System Property Metadata Store Directory Server endpoint key
   public static final String MSDS_SERVER_ENDPOINT_KEY =
       MetadataStoreRoutingConstants.MSDS_SERVER_ENDPOINT_KEY;
+
+  // System property for request timeout
+  public static final String HTTP_REQUEST_TIMEOUT = "http.request.timeout";

Review comment:
       +1. There are other places like MSDS that also have timeout config. This 
should be narrow down to helix rest or even stoppable.

##########
File path: 
helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientFactory.java
##########
@@ -32,10 +36,13 @@
  */
 public class CustomRestClientFactory {
   private static final Logger LOG = 
LoggerFactory.getLogger(CustomRestClientFactory.class);
+  private static final int DEFAULT_HTTP_REQUEST_TIMEOUT = 60 * 1000;
+  private static final int _httpRequestTimeout = 
HelixUtil.getSystemPropertyAsInt(
+      SystemPropertyKeys.HTTP_REQUEST_TIMEOUT, DEFAULT_HTTP_REQUEST_TIMEOUT);
 
   private static CustomRestClient INSTANCE = null;

Review comment:
       It seems we should also change this to make it `volatile` so it is safe 
for double lock checking. But we should do it in another PR. Reference: 
https://github.com/apache/helix/issues/1014

##########
File path: 
helix-rest/src/main/java/org/apache/helix/rest/client/CustomRestClientFactory.java
##########
@@ -32,10 +36,13 @@
  */
 public class CustomRestClientFactory {
   private static final Logger LOG = 
LoggerFactory.getLogger(CustomRestClientFactory.class);
+  private static final int DEFAULT_HTTP_REQUEST_TIMEOUT = 60 * 1000;
+  private static final int _httpRequestTimeout = 
HelixUtil.getSystemPropertyAsInt(

Review comment:
       Could combine `DEFAULT_HTTP_REQUEST_TIMEOUT` and this, right? And also 
this var is static final, would be better to name it a constant?
   
   Back from your test, if we don't make this a constant but a local var in 
get(), we could avoid the `MockCustomRestClientFactory` by resetting the 
instance using reflection.

##########
File path: 
helix-rest/src/test/java/org/apache/helix/rest/client/TestCustomRestClient.java
##########
@@ -145,6 +150,19 @@ public void testPostRequestFormat() throws IOException {
     Assert.assertEquals(json.get("data").asText(), "{}");
   }
 
+  @Test(expectedExceptions = ConnectTimeoutException.class)
+  public void testPostRequestSmallTimeout() throws IOException {
+    // Set 1 ms to cause timeout for requests
+    System.setProperty(SystemPropertyKeys.HTTP_REQUEST_TIMEOUT, "1");
+    // a popular echo server that echos all the inputs
+    final String echoServer = "http://httpbin.org/post";;
+    CustomRestClient _customRestClient = MockCustomRestClientFactory.get();
+    _customRestClient.getInstanceStoppableCheck(echoServer, 
Collections.emptyMap());

Review comment:
       This is unnecessary as the exception is thrown from `post()`. I suggest 
using `try...catch` so it is easier to know which code is tested. With 
`expectedExceptions`, it is not easy to know which line of code is expected to 
throw the exception as this method has multiple lines and API calls. If calling 
`_customRestClient.getInstanceStoppableCheck`, it is more like an integration 
test not a unit test. And as you state in the method name 
`testPostRequestSmallTimeout`, it is supposed to be testing the `post()`, right?

##########
File path: 
helix-rest/src/test/java/org/apache/helix/rest/client/TestCustomRestClient.java
##########
@@ -161,4 +179,35 @@ protected JsonNode getJsonObject(HttpResponse 
httpResponse) throws IOException {
       return new ObjectMapper().readTree(_jsonResponse);
     }
   }
+
+  /**
+   * This MockCustomRestClientFactory is necessary to have for testing because 
once an INSTANCE is
+   * initialized in CustomRestClientFactory while running "mvn test" , it will 
no re-initialize the
+   * INSTANCE with new HelixProperty. Hence this class makes sure that new 
CustomRestClient will be
+   * created with the timeout set to the new value.
+   */
+  private static class MockCustomRestClientFactory extends 
CustomRestClientFactory {

Review comment:
       This mock class implements the almost the same logic of the parent 
class. The cons are:
   - duplicate code
   - difficult to maintain. if the parent class changes its logic, it is not 
easy to find this mock class and change this logic. If this child class is not 
changed, the test is actually testing the child class, not the logic in parent 
class.
   
   There is a trick to avoid this duplicate and unnecessary mock class. We 
could use Java reflection to change the class's internal state, so the 
singleton would be re-initialized. And to be able to make the new instance use 
the new system property, the system property variable needs to be in a local 
one in `get()`.
   
   ```
   // reset the singleton instance.
   Field instance = Parent.class.getDeclaredField("INSTANCE");
   instance.setAccessible(true);
   instance.set(null, null);
   ```

##########
File path: 
helix-rest/src/test/java/org/apache/helix/rest/client/TestCustomRestClient.java
##########
@@ -145,6 +150,19 @@ public void testPostRequestFormat() throws IOException {
     Assert.assertEquals(json.get("data").asText(), "{}");
   }
 
+  @Test(expectedExceptions = ConnectTimeoutException.class)
+  public void testPostRequestSmallTimeout() throws IOException {
+    // Set 1 ms to cause timeout for requests
+    System.setProperty(SystemPropertyKeys.HTTP_REQUEST_TIMEOUT, "1");
+    // a popular echo server that echos all the inputs
+    final String echoServer = "http://httpbin.org/post";;

Review comment:
       I don't think it is a good idea to connect to an external host/service 
for testing. What if my testing machine doesn't have network? Are we still 
going to get the expected exception? The answer is no. Instead, something else 
like `UnknownHostException` would be thrown. And this test does not achieve the 
purpose.
   
   In a unit test, and in this case, I would not want to actually connect to a 
real REST server. Connecting to a real server is technically more an 
integration test. Though we have a local server started in `AbstractTestClass`, 
I would suggest mocking the timeout scenario for this unit test instead of 
connecting to a real server.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to