diff --git a/build.gradle b/build.gradle index 4b26d80ba..d6de806f4 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { ext { jacocoVersion = '0.8.6' retrofitVersion = '2.9.0' - okhttpVersion = '4.7.2' + okhttpVersion = '4.9.0' oltuVersion = '1.0.1' fineractJavaProjects = subprojects.findAll{ [ @@ -107,9 +107,6 @@ allprojects { dependency 'org.springframework.security.oauth:spring-security-oauth2:2.5.0.RELEASE' dependency 'org.apache.openjpa:openjpa:3.1.2' // when upgrading, also change OpenJPA version repeated above in buildscript! - dependency 'com.squareup.retrofit:retrofit:1.9.0' - dependency 'com.squareup.okhttp:okhttp:2.7.5' - dependency 'com.squareup.okhttp:okhttp-urlconnection:2.7.5' dependency 'com.google.guava:guava:30.0-jre' dependency 'com.google.code.gson:gson:2.8.6' dependency 'org.apache.commons:commons-email:1.5' diff --git a/fineract-client/src/main/java/org/apache/fineract/client/util/FineractClient.java b/fineract-client/src/main/java/org/apache/fineract/client/util/FineractClient.java index 5d18a54f1..ab12819b1 100644 --- a/fineract-client/src/main/java/org/apache/fineract/client/util/FineractClient.java +++ b/fineract-client/src/main/java/org/apache/fineract/client/util/FineractClient.java @@ -453,7 +453,7 @@ public final class FineractClient { } }; - SSLContext sslContext = SSLContext.getInstance("SSL"); + SSLContext sslContext = SSLContext.getInstance("SSL"); // TODO "SSL" or "TLS" as in hooks.processor.ProcessorHelper? sslContext.init(null, new TrustManager[] { insecureX509TrustManager }, new SecureRandom()); SSLSocketFactory insecureSslSocketFactory = sslContext.getSocketFactory(); diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle index a50d0ef75..1a3a5e27b 100644 --- a/fineract-provider/dependencies.gradle +++ b/fineract-provider/dependencies.gradle @@ -45,12 +45,13 @@ dependencies { 'com.google.guava:guava', 'com.google.code.gson:gson', 'com.sun.jersey:jersey-core', - 'com.squareup.retrofit:retrofit', 'jakarta.jms:jakarta.jms-api', 'jakarta.management.j2ee:jakarta.management.j2ee-api', 'jakarta.validation:jakarta.validation-api', - 'com.squareup.okhttp:okhttp', - 'com.squareup.okhttp:okhttp-urlconnection', + + 'com.squareup.retrofit2:retrofit', + 'com.squareup.okhttp3:okhttp', + 'com.squareup.okhttp3:okhttp-urlconnection', 'org.apache.commons:commons-email', 'org.apache.commons:commons-lang3', diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/listener/FineractHookListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/listener/FineractHookListener.java index 0694678d7..2bc6a8738 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/listener/FineractHookListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/listener/FineractHookListener.java @@ -29,12 +29,16 @@ import org.apache.fineract.infrastructure.hooks.processor.HookProcessorProvider; import org.apache.fineract.infrastructure.hooks.service.HookReadPlatformService; import org.apache.fineract.infrastructure.security.service.TenantDetailsService; import org.apache.fineract.useradministration.domain.AppUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class FineractHookListener implements HookListener { + private static final Logger LOG = LoggerFactory.getLogger(FineractHookListener.class); + private final HookProcessorProvider hookProcessorProvider; private final HookReadPlatformService hookReadPlatformService; private final TenantDetailsService tenantDetailsService; @@ -49,7 +53,6 @@ public class FineractHookListener implements HookListener { @Override public void onApplicationEvent(final HookEvent event) { - final String tenantIdentifier = event.getTenantIdentifier(); final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier); ThreadLocalContextUtil.setTenant(tenant); @@ -67,8 +70,12 @@ public class FineractHookListener implements HookListener { for (final Hook hook : hooks) { final HookProcessor processor = this.hookProcessorProvider.getProcessor(hook); - processor.process(hook, appUser, payload, entityName, actionName, tenantIdentifier, authToken); + try { + processor.process(hook, appUser, payload, entityName, actionName, tenantIdentifier, authToken); + } catch (Throwable e) { + LOG.error("Hook {} failed in HookProcessor {} for tenantIdentifier/user {}/{}, entityName: {}, actionName: {}, payload {} ", + hook.getId(), processor.getClass().getSimpleName(), tenantIdentifier, appUser, entityName, actionName, payload, e); + } } } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/HookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/HookProcessor.java index 976619f2b..74d0d2fc7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/HookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/HookProcessor.java @@ -24,6 +24,6 @@ import org.apache.fineract.useradministration.domain.AppUser; public interface HookProcessor { void process(Hook hook, AppUser appUser, String payload, String entityName, String actionName, String tenantIdentifier, - String authToken); + String authToken) throws Exception; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java index 29392c1d3..142a352d4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.infrastructure.hooks.processor; -import com.squareup.okhttp.OkHttpClient; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -26,23 +25,39 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import okhttp3.OkHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import retrofit.Callback; -import retrofit.RestAdapter; -import retrofit.RetrofitError; -import retrofit.client.OkClient; -import retrofit.client.Response; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Retrofit; @Service public final class ProcessorHelper { + // Nota bene: Similar code to insecure HTTPS is also in Fineract Client's + // org.apache.fineract.client.util.FineractClient.Builder.insecure() + private static final Logger LOG = LoggerFactory.getLogger(ProcessorHelper.class); + @SuppressWarnings("unused") + private static final X509TrustManager insecureX509TrustManager = new X509TrustManager() { + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + }; + /** * Configure HTTP client to be "insecure", as in skipping host SSL certificate verification. While this can be * useful during development e.g. when using self-signed certificates, it should never be enabled in production (due @@ -60,43 +75,23 @@ public final class ProcessorHelper { } private OkHttpClient createClient() { - final OkHttpClient client = new OkHttpClient(); + var okBuilder = new OkHttpClient.Builder(); if (insecureHttpClient) { - configureInsecureClient(client); + configureInsecureClient(okBuilder); } - return client; + return okBuilder.build(); } - private void configureInsecureClient(final OkHttpClient client) { - client.setSslSocketFactory(insecureSSLContext.getSocketFactory()); - - final HostnameVerifier hostnameVerifier = new HostnameVerifier() { - - @Override - public boolean verify(final String hostname, final SSLSession session) { - return true; - } - }; - client.setHostnameVerifier(hostnameVerifier); + private void configureInsecureClient(final OkHttpClient.Builder okBuilder) { + okBuilder.sslSocketFactory(insecureSSLContext.getSocketFactory(), insecureX509TrustManager); + HostnameVerifier insecureHostnameVerifier = (hostname, session) -> true; + okBuilder.hostnameVerifier(insecureHostnameVerifier); } private SSLContext createInsecureSSLContext() throws NoSuchAlgorithmException, KeyManagementException { - final TrustManager[] certs = new TrustManager[] { new X509TrustManager() { - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - @Override - public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {} - - @Override - public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {} - } }; - - SSLContext insecureSSLContext = SSLContext.getInstance("TLS"); - insecureSSLContext.init(null, certs, new SecureRandom()); + SSLContext insecureSSLContext = SSLContext.getInstance("TLS"); // TODO "TLS" or "SSL" as in + // FineractClient.Builder? + insecureSSLContext.init(null, new TrustManager[] { insecureX509TrustManager }, new SecureRandom()); return insecureSSLContext; } @@ -105,20 +100,23 @@ public final class ProcessorHelper { return new Callback() { @Override - public void success(final Object o, final Response response) { - LOG.info("URL: {} - Status: {}", url, response.getStatus()); + public void onResponse(@SuppressWarnings("unused") Call call, retrofit2.Response response) { + LOG.info("URL: {} - Status: {}", url, response.code()); } @Override - public void failure(final RetrofitError retrofitError) { - LOG.error("URL: {} - RetrofitError occured", url, retrofitError); + public void onFailure(@SuppressWarnings("unused") Call call, Throwable t) { + LOG.error("URL: {} - Retrofit failure occured", url, t); } }; } public WebHookService createWebHookService(final String url) { final OkHttpClient client = createClient(); - final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setClient(new OkClient(client)).build(); - return restAdapter.create(WebHookService.class); + final Retrofit.Builder retrofitBuilder = new Retrofit.Builder(); + retrofitBuilder.baseUrl(url); + retrofitBuilder.client(client); + final Retrofit retrofit = retrofitBuilder.build(); + return retrofit.create(WebHookService.class); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java index 7f7234b1b..d6290056a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java @@ -34,18 +34,16 @@ import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.template.service.TemplateMergeService; import org.apache.fineract.useradministration.domain.AppUser; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import retrofit.Callback; +import retrofit2.Callback; @Service public class TwilioHookProcessor implements HookProcessor { - private static final Logger LOG = LoggerFactory.getLogger(TwilioHookProcessor.class); - private final HookConfigurationRepository hookConfigurationRepository; private final TemplateMergeService templateMergeService; private final ClientRepositoryWrapper clientRepositoryWrapper; @@ -63,7 +61,7 @@ public class TwilioHookProcessor implements HookProcessor { @Override public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName, - final String actionName, final String tenantIdentifier, final String authToken) { + final String actionName, final String tenantIdentifier, final String authToken) throws IOException { final SmsProviderData smsProviderData = new SmsProviderData(hook.getHookConfig()); @@ -72,7 +70,7 @@ public class TwilioHookProcessor implements HookProcessor { @SuppressWarnings("unchecked") private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName, - final String tenantIdentifier, final String authToken, final Hook hook) { + final String tenantIdentifier, final String authToken, final Hook hook) throws IOException { final WebHookService service = processorHelper.createWebHookService(smsProviderData.getUrl()); @@ -85,7 +83,7 @@ public class TwilioHookProcessor implements HookProcessor { smsProviderData.setEndpoint(System.getProperty("baseUrl")); smsProviderData.setTenantId(tenantIdentifier); smsProviderData.setMifosToken(authToken); - apiKey = service.sendSmsBridgeConfigRequest(smsProviderData); + apiKey = service.sendSmsBridgeConfigRequest(smsProviderData).execute().body(); final HookConfiguration apiKeyEntry = HookConfiguration.createNew(hook, "string", apiKeyName, apiKey); this.hookConfigurationRepository.save(apiKeyEntry); } @@ -102,34 +100,30 @@ public class TwilioHookProcessor implements HookProcessor { } else { json = JsonParser.parseString(payload).getAsJsonObject(); } - service.sendSmsBridgeRequest(entityName, actionName, tenantIdentifier, apiKey, json, callback); + service.sendSmsBridgeRequest(entityName, actionName, tenantIdentifier, apiKey, json).enqueue(callback); } - } - private JsonObject processUgdTemplate(final String payload, final Hook hook, final String authToken) { + private JsonObject processUgdTemplate(final String payload, final Hook hook, final String authToken) + throws JsonParseException, JsonMappingException, IOException { JsonObject json = null; - try { - @SuppressWarnings("unchecked") - final HashMap map = new ObjectMapper().readValue(payload, HashMap.class); - map.put("BASE_URI", System.getProperty("baseUrl")); - if (map.containsKey("clientId")) { - final Long clientId = Long.valueOf(Integer.toString((int) map.get("clientId"))); - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - final String mobileNo = client.mobileNo(); - if (mobileNo != null && !mobileNo.isEmpty()) { - this.templateMergeService.setAuthToken(authToken); - final String compiledMessage = this.templateMergeService.compile(hook.getUgdTemplate(), map).replace("

", "") - .replace("

", ""); - final Map jsonMap = new HashMap<>(); - jsonMap.put("mobileNo", mobileNo); - jsonMap.put("message", compiledMessage); - final String jsonString = new Gson().toJson(jsonMap); - json = JsonParser.parseString(jsonString).getAsJsonObject(); - } + @SuppressWarnings("unchecked") + final HashMap map = new ObjectMapper().readValue(payload, HashMap.class); + map.put("BASE_URI", System.getProperty("baseUrl")); + if (map.containsKey("clientId")) { + final Long clientId = Long.valueOf(Integer.toString((int) map.get("clientId"))); + final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + final String mobileNo = client.mobileNo(); + if (mobileNo != null && !mobileNo.isEmpty()) { + this.templateMergeService.setAuthToken(authToken); + final String compiledMessage = this.templateMergeService.compile(hook.getUgdTemplate(), map).replace("

", "") + .replace("

", ""); + final Map jsonMap = new HashMap<>(); + jsonMap.put("mobileNo", mobileNo); + jsonMap.put("message", compiledMessage); + final String jsonString = new Gson().toJson(jsonMap); + json = JsonParser.parseString(jsonString).getAsJsonObject(); } - } catch (IOException e) { - LOG.error("Problem occurred in processUgdTemplate function", e); } return json; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java index 556e2cc84..796f9d807 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java @@ -32,7 +32,7 @@ import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import retrofit.Callback; +import retrofit2.Callback; @Service public class WebHookProcessor implements HookProcessor { @@ -78,11 +78,11 @@ public class WebHookProcessor implements HookProcessor { if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) { final JsonObject json = JsonParser.parseString(payload).getAsJsonObject(); - service.sendJsonRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, json, callback); + service.sendJsonRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, json).enqueue(callback); } else { Map map = new HashMap<>(); map = new Gson().fromJson(payload, map.getClass()); - service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map, callback); + service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map).enqueue(callback); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java index c4eaed46d..a3dc8fd36 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java @@ -21,14 +21,13 @@ package org.apache.fineract.infrastructure.hooks.processor; import com.google.gson.JsonObject; import java.util.Map; import org.apache.fineract.infrastructure.hooks.processor.data.SmsProviderData; -import retrofit.Callback; -import retrofit.client.Response; -import retrofit.http.Body; -import retrofit.http.FieldMap; -import retrofit.http.FormUrlEncoded; -import retrofit.http.GET; -import retrofit.http.Header; -import retrofit.http.POST; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.POST; public interface WebHookService { @@ -40,27 +39,25 @@ public interface WebHookService { // Ping @GET("/") - Response sendEmptyRequest(); + Call sendEmptyRequest(); // Template - Web @POST("/") - void sendJsonRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, - @Header(TENANT_HEADER) String tenantHeader, @Header(ENDPOINT_HEADER) String endpointHeader, @Body JsonObject result, - Callback callBack); + Call sendJsonRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, + @Header(TENANT_HEADER) String tenantHeader, @Header(ENDPOINT_HEADER) String endpointHeader, @Body JsonObject result); @FormUrlEncoded @POST("/") - void sendFormRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, + Call sendFormRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, @Header(TENANT_HEADER) String tenantHeader, @Header(ENDPOINT_HEADER) String endpointHeader, - @FieldMap Map params, Callback callBack); + @FieldMap Map params); // Template - SMS Bridge @POST("/") - void sendSmsBridgeRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, - @Header(TENANT_HEADER) String tenantHeader, @Header(API_KEY_HEADER) String apiKeyHeader, @Body JsonObject result, - Callback callBack); + Call sendSmsBridgeRequest(@Header(ENTITY_HEADER) String entityHeader, @Header(ACTION_HEADER) String actionHeader, + @Header(TENANT_HEADER) String tenantHeader, @Header(API_KEY_HEADER) String apiKeyHeader, @Body JsonObject result); @POST("/configuration") - String sendSmsBridgeConfigRequest(@Body SmsProviderData config); + Call sendSmsBridgeConfigRequest(@Body SmsProviderData config); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java index eebea943e..52296074b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java @@ -30,6 +30,7 @@ import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.webT import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -67,7 +68,6 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import retrofit.RetrofitError; @Service public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatformService { @@ -282,15 +282,10 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf if (conf.getFieldName().equals(payloadURLName)) { try { final WebHookService service = processorHelper.createWebHookService(fieldValue); - service.sendEmptyRequest(); - } catch (RetrofitError re) { - // Swallow error if it's because of method not supported or - // if url throws 404 - required for integration test, - // url generated on 1st POST request - if (re.getResponse() == null) { - String errorMessage = "url.invalid"; - baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); - } + service.sendEmptyRequest().execute(); + } catch (IOException re) { + String errorMessage = "url.invalid"; + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); } } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/HookIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/HookIntegrationTest.java index 1a45b4fbf..489098b55 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/HookIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/HookIntegrationTest.java @@ -61,21 +61,16 @@ public class HookIntegrationTest { @Test public void shouldSendOfficeCreationNotification() { // Subject to https://echo-webhook.herokuapp.com being up - // See - // http://www.jamesward.com/2014/06/11/testing-webhooks-was-a-pain-so-i-fixed-the-glitch + // See http://www.jamesward.com/2014/06/11/testing-webhooks-was-a-pain-so-i-fixed-the-glitch final String uniqueId = UUID.randomUUID().toString(); - final String payloadURL = "http://echo-webhook.herokuapp.com:80/" + uniqueId + "?"; + final String payloadURL = "http://echo-webhook.herokuapp.com:80/" + uniqueId + "/"; final Integer hookId = this.hookHelper.createHook(payloadURL); Assertions.assertNotNull(hookId); final Integer createdOfficeID = this.officeHelper.createOffice("01 January 2012"); Assertions.assertNotNull(createdOfficeID); try { - - /** - * sleep for a three seconds after each failure to increase the likelihood of the previous request for - * creating office completing - **/ - + // sleep for a three seconds after each failure to increase the likelihood of the previous request for + // creating office completing for (int i = 0; i < 6; i++) { try { final String json = RestAssured.get(payloadURL.replace("?", "")).asString(); @@ -98,12 +93,11 @@ public class HookIntegrationTest { } finally { this.hookHelper.deleteHook(hookId.longValue()); } - } @Test public void createUpdateAndDeleteHook() { - final String payloadURL = "http://echo-webhook.herokuapp.com:80/Z7RXoCBdLSFMDrpn?"; + final String payloadURL = "http://echo-webhook.herokuapp.com:80/Z7RXoCBdLSFMDrpn/"; final String updateURL = "http://localhost"; Long hookId = this.hookHelper.createHook(payloadURL).longValue(); @@ -116,6 +110,5 @@ public class HookIntegrationTest { this.hookHelper.deleteHook(hookId); this.hookHelper.verifyDeleteHook(hookId); LOG.info("---------------------SUCCESSFULLY DELETED AND VERIFIED HOOK------------------------- {}", hookId); - } }