diff --git a/pom.xml b/pom.xml index d5bc245..ec11f6f 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.wnameless.spring spring-bulk-api - 0.7.1-SNAPSHOT + 0.7.4.1-SNAPSHOT spring-bulk-api Add bulk operations support to any Spring RESTful API by a single annotation @EnableBulkApi. @@ -109,6 +109,19 @@ gson test + + org.projectlombok + lombok + 1.18.12 + test + + + + com.googlecode.json-simple + json-simple + 1.1 + + diff --git a/src/main/java/com/github/wnameless/spring/bulkapi/BulkApiController.java b/src/main/java/com/github/wnameless/spring/bulkapi/BulkApiController.java index 6e2ea39..4837a20 100644 --- a/src/main/java/com/github/wnameless/spring/bulkapi/BulkApiController.java +++ b/src/main/java/com/github/wnameless/spring/bulkapi/BulkApiController.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -60,6 +61,7 @@ private BulkApiService bulkApiService() { * @throws BulkApiException * if this bulk request is invalid */ + @CrossOrigin("*") @RequestMapping(value = "${spring.bulk.api.path:/bulk}", method = POST) BulkResponse bulk(@RequestBody BulkRequest req, HttpServletRequest servReq) { return bulkApiService().bulk(req, servReq); diff --git a/src/main/java/com/github/wnameless/spring/bulkapi/BulkOperation.java b/src/main/java/com/github/wnameless/spring/bulkapi/BulkOperation.java index 0aef0e5..105e13f 100644 --- a/src/main/java/com/github/wnameless/spring/bulkapi/BulkOperation.java +++ b/src/main/java/com/github/wnameless/spring/bulkapi/BulkOperation.java @@ -32,6 +32,7 @@ public final class BulkOperation { private Map params = new LinkedHashMap(); private Map headers = new LinkedHashMap(); private boolean silent = false; + private String payload; /** * Returns the URL of this RESTful operation. @@ -128,6 +129,26 @@ public void setSilent(boolean silent) { this.silent = silent; } + /** + * Returns payload which client put in request without any change + * In addition to using the order of results, client can put a string or number to distinguish between returned results. + * + * @return payload of a RESTful operation + */ + public String getPayload() { + return payload; + } + + /** + * Sets the payload parameters of this RESTful operation. + * + * @param payload + * an arbitrary string + */ + public void setPayload(String payload) { + this.payload = payload; + } + @Override public int hashCode() { int result = 27; diff --git a/src/main/java/com/github/wnameless/spring/bulkapi/BulkResult.java b/src/main/java/com/github/wnameless/spring/bulkapi/BulkResult.java index 69302c7..f5ca4ee 100644 --- a/src/main/java/com/github/wnameless/spring/bulkapi/BulkResult.java +++ b/src/main/java/com/github/wnameless/spring/bulkapi/BulkResult.java @@ -17,6 +17,7 @@ */ package com.github.wnameless.spring.bulkapi; +import com.fasterxml.jackson.annotation.JsonInclude; import java.util.Map; /** @@ -29,6 +30,8 @@ public final class BulkResult { private int status; private String body; private Map headers; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String payload; /** * Returns the HTTP status code of a RESTful operation outcome. @@ -87,6 +90,26 @@ public void setHeaders(Map headers) { this.headers = headers; } + /** + * Returns payload which client put in request without any change + * Client can put a string or number to distinguish between returned results + * + * @return payload of a RESTful operation + */ + public String getPayload() { + return payload; + } + + /** + * Sets the payload parameters of this RESTful operation. + * + * @param payload + * an arbitrary string + */ + public void setPayload(String payload) { + this.payload = payload; + } + @Override public int hashCode() { int result = 27; diff --git a/src/main/java/com/github/wnameless/spring/bulkapi/DefaultBulkApiService.java b/src/main/java/com/github/wnameless/spring/bulkapi/DefaultBulkApiService.java index 1b577c6..0857045 100755 --- a/src/main/java/com/github/wnameless/spring/bulkapi/DefaultBulkApiService.java +++ b/src/main/java/com/github/wnameless/spring/bulkapi/DefaultBulkApiService.java @@ -17,180 +17,203 @@ */ package com.github.wnameless.spring.bulkapi; -import static com.github.wnameless.spring.bulkapi.BulkApiConfig.BULK_API_LIMIT_DEFAULT; -import static com.github.wnameless.spring.bulkapi.BulkApiConfig.BULK_API_LIMIT_KEY; -import static com.github.wnameless.spring.bulkapi.BulkApiConfig.BULK_API_PATH_DEFAULT; -import static com.github.wnameless.spring.bulkapi.BulkApiConfig.BULK_API_PATH_KEY; -import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE; -import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; - -import javax.servlet.http.HttpServletRequest; - import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.http.HttpMethod; import org.springframework.http.RequestEntity; import org.springframework.http.RequestEntity.BodyBuilder; import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpResponse; import org.springframework.util.LinkedMultiValueMap; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestTemplate; +import javax.servlet.http.HttpServletRequest; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import static com.github.wnameless.spring.bulkapi.BulkApiConfig.*; +import static org.springframework.http.HttpStatus.*; + /** - * * {@link DefaultBulkApiService} id the default implementation of * {@link BulkApiService}. - * */ public class DefaultBulkApiService implements BulkApiService { - private final ApplicationContext appCtx; - private final Environment env; - - private BulkApiValidator validator; - private URITransformer uriTransformer; - - /** - * Creates a {@link DefaultBulkApiService}. - * - * @param appCtx - * the Spring {@link ApplicationContext} - */ - public DefaultBulkApiService(ApplicationContext appCtx) { - this.appCtx = appCtx; - env = appCtx.getEnvironment(); - - String[] beanNames = appCtx.getBeanNamesForType(URITransformer.class); - if (beanNames.length > 0) { - uriTransformer = appCtx.getBean(URITransformer.class); + private final ApplicationContext appCtx; + private final Environment env; + + private BulkApiValidator validator; + private URITransformer uriTransformer; + + /** + * Creates a {@link DefaultBulkApiService}. + * + * @param appCtx the Spring {@link ApplicationContext} + */ + public DefaultBulkApiService(ApplicationContext appCtx) { + this.appCtx = appCtx; + env = appCtx.getEnvironment(); + + String[] beanNames = appCtx.getBeanNamesForType(URITransformer.class); + if (beanNames.length > 0) { + uriTransformer = appCtx.getBean(URITransformer.class); + } } - } - private BulkApiValidator validator() { - if (validator == null) validator = new BulkApiValidator(appCtx); - return validator; - } + private BulkApiValidator validator() { + if (validator == null) validator = new BulkApiValidator(appCtx); + return validator; + } - @Override - public BulkResponse bulk(BulkRequest req, HttpServletRequest servReq) { - validateBulkRequest(req, servReq); + @Override + public BulkResponse bulk(BulkRequest req, HttpServletRequest servReq) { + validateBulkRequest(req, servReq); - List results = new ArrayList<>(); - RestTemplate template = new RestTemplate(); - for (BulkOperation op : req.getOperations()) { - ComputedURIResult uriResult = computeUri(servReq, op); + List results = new ArrayList<>(); + RestTemplate template = new RestTemplate(); + template.setErrorHandler(new MyErrorHandler()); + for (BulkOperation op : req.getOperations()) { + ComputedURIResult uriResult = computeUri(servReq, op); - BodyBuilder bodyBuilder = RequestEntity.method(// - httpMethod(op.getMethod()), uriResult.getUri()); + BodyBuilder bodyBuilder = RequestEntity.method(// + httpMethod(op.getMethod()), uriResult.getUri()); - ResponseEntity rawRes = template.exchange( - requestEntity(bodyBuilder, op, uriResult.hasRequestBody()), - String.class); + ResponseEntity rawRes = null; + try { + rawRes = template.exchange( + requestEntity(bodyBuilder, op, uriResult.hasRequestBody()), + String.class); + } catch (ResourceAccessException e) { + if (e.getCause().getMessage().equals("cannot retry due to server authentication, in streaming mode")) { + throw new BulkApiException(UNAUTHORIZED, e.getMessage()); + } - if (!op.isSilent()) results.add(buildResult(rawRes)); - } + } + + if (!op.isSilent()) results.add(buildResult(rawRes, op.getPayload())); + } - return new BulkResponse(results); - } + return new BulkResponse(results); + } - private RequestEntity requestEntity(BodyBuilder bodyBuilder, - BulkOperation op, boolean requestBody) { - for (Entry header : op.getHeaders().entrySet()) { - bodyBuilder.header(header.getKey(), header.getValue()); + private RequestEntity requestEntity(BodyBuilder bodyBuilder, + BulkOperation op, boolean requestBody) { + for (Entry header : op.getHeaders().entrySet()) { + bodyBuilder.header(header.getKey(), header.getValue()); + } + + Object params; + if (requestBody) { + params = op.getParams(); + } else { + LinkedMultiValueMap lmvm = new LinkedMultiValueMap<>(); + lmvm.setAll(op.getParams()); + params = lmvm; + } + + return bodyBuilder.body(params); } - Object params; - if (requestBody) { - params = op.getParams(); - } else { - LinkedMultiValueMap lmvm = new LinkedMultiValueMap<>(); - lmvm.setAll(op.getParams()); - params = lmvm; + private ComputedURIResult computeUri(HttpServletRequest servReq, + BulkOperation op) { + String rawUrl = servReq.getRequestURL().toString(); + String rawUri = servReq.getRequestURI().toString(); + + if (op.getUrl() == null || isBulkPath(op.getUrl())) { + throw new BulkApiException(UNPROCESSABLE_ENTITY, + "Invalid URL(" + rawUri + ") exists in this bulk request"); + } + + String bulkPath = + urlify(env.getProperty(BULK_API_PATH_KEY, BULK_API_PATH_DEFAULT)); + URI uri; + try { + String servletPath = rawUrl.substring(0, rawUrl.lastIndexOf(bulkPath)); + uri = new URI(servletPath + urlify(op.getUrl())); + } catch (URISyntaxException e) { + throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL(" + + urlify(op.getUrl()) + ") exists in this bulk request"); + } + + PathValidationResult pvr = validator().validatePath(stripeQueryParam(urlify(op.getUrl())), + httpMethod(op.getMethod())); + if (!pvr.isValid()) { + throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL(" + + urlify(op.getUrl()) + ") exists in this bulk request"); + } + + if (uriTransformer != null) uri = uriTransformer.transform(uri); + return new ComputedURIResult(uri, pvr.hasRequestBody()); } - return bodyBuilder.body(params); - } + private boolean isBulkPath(String url) { + String bulkPath = + urlify(env.getProperty(BULK_API_PATH_KEY, BULK_API_PATH_DEFAULT)); + url = urlify(url); - private ComputedURIResult computeUri(HttpServletRequest servReq, - BulkOperation op) { - String rawUrl = servReq.getRequestURL().toString(); - String rawUri = servReq.getRequestURI().toString(); + return url.equals(bulkPath) || url.startsWith(bulkPath + "/"); + } - if (op.getUrl() == null || isBulkPath(op.getUrl())) { - throw new BulkApiException(UNPROCESSABLE_ENTITY, - "Invalid URL(" + rawUri + ") exists in this bulk request"); + private String urlify(String url) { + url = url.trim(); + return url.startsWith("/") ? url : "/" + url; } - String bulkPath = - urlify(env.getProperty(BULK_API_PATH_KEY, BULK_API_PATH_DEFAULT)); - URI uri; - try { - String servletPath = rawUrl.substring(0, rawUrl.lastIndexOf(bulkPath)); - uri = new URI(servletPath + urlify(op.getUrl())); - } catch (URISyntaxException e) { - throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL(" - + urlify(op.getUrl()) + ") exists in this bulk request"); + private String stripeQueryParam(String url) { + return url.split("\\?")[0]; } - PathValidationResult pvr = validator().validatePath(urlify(op.getUrl()), - httpMethod(op.getMethod())); - if (!pvr.isValid()) { - throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL(" - + urlify(op.getUrl()) + ") exists in this bulk request"); + private BulkResult buildResult(ResponseEntity rawRes, String payload) { + BulkResult res = new BulkResult(); + res.setStatus(rawRes.getStatusCodeValue()); + res.setHeaders(rawRes.getHeaders().toSingleValueMap()); + res.setBody(rawRes.getBody()); + res.setPayload(payload); + + return res; } - if (uriTransformer != null) uri = uriTransformer.transform(uri); - return new ComputedURIResult(uri, pvr.hasRequestBody()); - } - - private boolean isBulkPath(String url) { - String bulkPath = - urlify(env.getProperty(BULK_API_PATH_KEY, BULK_API_PATH_DEFAULT)); - url = urlify(url); - - return url.equals(bulkPath) || url.startsWith(bulkPath + "/"); - } - - private String urlify(String url) { - url = url.trim(); - return url.startsWith("/") ? url : "/" + url; - } - - private BulkResult buildResult(ResponseEntity rawRes) { - BulkResult res = new BulkResult(); - res.setStatus(rawRes.getStatusCodeValue()); - res.setHeaders(rawRes.getHeaders().toSingleValueMap()); - res.setBody(rawRes.getBody()); - - return res; - } - - private void validateBulkRequest(BulkRequest req, - HttpServletRequest servReq) { - int max = - env.getProperty(BULK_API_LIMIT_KEY, int.class, BULK_API_LIMIT_DEFAULT); - if (req.getOperations().size() > max) { - throw new BulkApiException(PAYLOAD_TOO_LARGE, - "Bulk operations exceed the limitation(" + max + ")"); + private void validateBulkRequest(BulkRequest req, + HttpServletRequest servReq) { + int max = + env.getProperty(BULK_API_LIMIT_KEY, int.class, BULK_API_LIMIT_DEFAULT); + if (req.getOperations().size() > max) { + throw new BulkApiException(PAYLOAD_TOO_LARGE, + "Bulk operations exceed the limitation(" + max + ")"); + } + + // Check if any invalid URL exists + for (BulkOperation op : req.getOperations()) { + computeUri(servReq, op); + } } - // Check if any invalid URL exists - for (BulkOperation op : req.getOperations()) { - computeUri(servReq, op); + private static HttpMethod httpMethod(String method) { + try { + return HttpMethod.valueOf(method.toUpperCase()); + } catch (Exception e) { + return HttpMethod.GET; + } } - } - private static HttpMethod httpMethod(String method) { - try { - return HttpMethod.valueOf(method.toUpperCase()); - } catch (Exception e) { - return HttpMethod.GET; +} + + +//This Handler created just to avoid showing error for whole operation and show error for the specific url +class MyErrorHandler implements ResponseErrorHandler { + + @Override + public void handleError(ClientHttpResponse clientHttpResponse) { } - } + @Override + public boolean hasError(ClientHttpResponse clientHttpResponse) { + return false; + } } diff --git a/src/test/java/com/github/wnameless/spring/bulkapi/test/BulkApiTest.java b/src/test/java/com/github/wnameless/spring/bulkapi/test/BulkApiTest.java index d669aab..0e43c69 100644 --- a/src/test/java/com/github/wnameless/spring/bulkapi/test/BulkApiTest.java +++ b/src/test/java/com/github/wnameless/spring/bulkapi/test/BulkApiTest.java @@ -17,24 +17,28 @@ */ package com.github.wnameless.spring.bulkapi.test; -import static com.google.code.beanmatchers.BeanMatchers.hasValidBeanConstructor; -import static com.google.code.beanmatchers.BeanMatchers.hasValidBeanToStringExcluding; -import static com.google.code.beanmatchers.BeanMatchers.hasValidGettersAndSetters; -import static org.hamcrest.CoreMatchers.allOf; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.HashMap; -import java.util.Map; - +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.wnameless.spring.bulkapi.BulkOperation; +import com.github.wnameless.spring.bulkapi.BulkRequest; +import com.github.wnameless.spring.bulkapi.BulkResponse; +import com.github.wnameless.spring.bulkapi.BulkResult; +import com.github.wnameless.spring.bulkapi.test.AppConfig.TestURITransformer; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import net.sf.rubycollect4j.Ruby; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,305 +51,333 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Base64Utils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.wnameless.spring.bulkapi.BulkOperation; -import com.github.wnameless.spring.bulkapi.BulkRequest; -import com.github.wnameless.spring.bulkapi.BulkResponse; -import com.github.wnameless.spring.bulkapi.BulkResult; -import com.github.wnameless.spring.bulkapi.test.AppConfig.TestURITransformer; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; +import java.util.HashMap; +import java.util.Map; -import net.sf.rubycollect4j.Ruby; -import nl.jqno.equalsverifier.EqualsVerifier; -import nl.jqno.equalsverifier.Warning; +import static com.google.code.beanmatchers.BeanMatchers.*; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class, - webEnvironment = WebEnvironment.RANDOM_PORT) + webEnvironment = WebEnvironment.RANDOM_PORT) public class BulkApiTest { - @LocalServerPort - int port; + @LocalServerPort + int port; + + @Value("${spring.bulk.api.path:/bulk}") + String bulkPath; + + HttpClient client = HttpClientBuilder.create().build(); + HttpPost post; + + ObjectMapper mapper = new ObjectMapper(); - @Value("${spring.bulk.api.path:/bulk}") - String bulkPath; + @Autowired + ApplicationContext appCtx; - HttpClient client = HttpClientBuilder.create().build(); - HttpPost post; + String authHeader = + "Basic " + Base64Utils.encodeToString("user:password".getBytes()); - ObjectMapper mapper = new ObjectMapper(); + @Autowired + TestURITransformer testUriTransformer; - @Autowired - ApplicationContext appCtx; + @Before + public void setUp() { + post = new HttpPost("http://localhost:" + port + bulkPath); + post.setHeader("Content-Type", "application/json"); + } + + @Test + public void testBeans() throws Exception { + assertThat(BulkOperation.class, allOf(hasValidBeanConstructor(), + hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); + EqualsVerifier.forClass(BulkOperation.class) + .suppress(Warning.NONFINAL_FIELDS).verify(); + + assertThat(BulkRequest.class, allOf(hasValidBeanConstructor(), + hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); + EqualsVerifier.forClass(BulkRequest.class).suppress(Warning.NONFINAL_FIELDS) + .verify(); + + assertThat(BulkResponse.class, allOf(hasValidBeanConstructor(), + hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); + EqualsVerifier.forClass(BulkResponse.class) + .suppress(Warning.NONFINAL_FIELDS).verify(); + + assertThat(BulkResult.class, allOf(hasValidBeanConstructor(), + hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); + EqualsVerifier.forClass(BulkResult.class).suppress(Warning.NONFINAL_FIELDS) + .verify(); + } - String authHeader = - "Basic " + Base64Utils.encodeToString("user:password".getBytes()); + private BulkRequest operationTimes(int times) { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); - @Autowired - TestURITransformer testUriTransformer; + times--; - @Before - public void setUp() { - post = new HttpPost("http://localhost:" + port + bulkPath); - post.setHeader("Content-Type", "application/json"); - } + op.setMethod("GET"); + op.setUrl("home"); + op.getHeaders().put("Authorization", authHeader); + req.getOperations().add(op); - @Test - public void testBeans() throws Exception { - assertThat(BulkOperation.class, allOf(hasValidBeanConstructor(), - hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); - EqualsVerifier.forClass(BulkOperation.class) - .suppress(Warning.NONFINAL_FIELDS).verify(); + while (times > 0) { + op = new BulkOperation(); + op.setMethod("GET"); + op.setUrl("/home"); + op.getHeaders().put("Authorization", authHeader); + req.getOperations().add(op); - assertThat(BulkRequest.class, allOf(hasValidBeanConstructor(), - hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); - EqualsVerifier.forClass(BulkRequest.class).suppress(Warning.NONFINAL_FIELDS) - .verify(); + times--; + } - assertThat(BulkResponse.class, allOf(hasValidBeanConstructor(), - hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); - EqualsVerifier.forClass(BulkResponse.class) - .suppress(Warning.NONFINAL_FIELDS).verify(); + return req; + } - assertThat(BulkResult.class, allOf(hasValidBeanConstructor(), - hasValidGettersAndSetters(), hasValidBeanToStringExcluding())); - EqualsVerifier.forClass(BulkResult.class).suppress(Warning.NONFINAL_FIELDS) - .verify(); - } + @Test + public void testBatch() throws Exception { + HttpEntity entity = new ByteArrayEntity( + mapper.writeValueAsString(operationTimes(1000)).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + String result = EntityUtils.toString(response.getEntity()); + BulkResponse res = new Gson().getAdapter(new TypeToken() { + }) + .fromJson(result); + + assertTrue(200 == Double.valueOf(res.getResults().get(0).getStatus())); + assertEquals(1000, res.getResults().size()); + } - private BulkRequest operationTimes(int times) { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); + @Test + public void testOverLimitationError() throws Exception { + HttpEntity entity = new ByteArrayEntity( + mapper.writeValueAsString(operationTimes(1001)).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); - times--; + assertEquals(413, response.getStatusLine().getStatusCode()); + } - op.setMethod("GET"); - op.setUrl("home"); - op.getHeaders().put("Authorization", authHeader); - req.getOperations().add(op); + @Test + public void testSilentMode() throws Exception { + BulkRequest req = operationTimes(1); + BulkOperation op = new BulkOperation(); + op.setMethod("GET"); + op.setUrl("/home"); + op.getHeaders().put("Authorization", authHeader); + op.setSilent(true); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + String result = EntityUtils.toString(response.getEntity()); + BulkResponse res = new Gson().getAdapter(new TypeToken() { + }) + .fromJson(result); + + assertEquals(1, res.getResults().size()); + } - while (times > 0) { - op = new BulkOperation(); - op.setMethod("GET"); - op.setUrl("/home"); - op.getHeaders().put("Authorization", authHeader); - req.getOperations().add(op); + @Test + public void testInvalidUrl() throws Exception { + BulkRequest req = operationTimes(1); + BulkOperation op = new BulkOperation(); + op.setMethod("GET"); + op.setUrl("http://0:0:0:0:0:0:0:1%0:8080/home"); + op.getHeaders().put("Authorization", authHeader); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(422 == response.getStatusLine().getStatusCode()); + } - times--; + @Test + public void bulkRequestCanNotContainBulkPathAsUrl() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl(bulkPath); + op.setMethod("GET"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(422 == response.getStatusLine().getStatusCode()); } - return req; - } - - @Test - public void testBatch() throws Exception { - HttpEntity entity = new ByteArrayEntity( - mapper.writeValueAsString(operationTimes(1000)).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - String result = EntityUtils.toString(response.getEntity()); - BulkResponse res = new Gson().getAdapter(new TypeToken() {}) - .fromJson(result); - - assertTrue(200 == Double.valueOf(res.getResults().get(0).getStatus())); - assertEquals(1000, res.getResults().size()); - } - - @Test - public void testOverLimitationError() throws Exception { - HttpEntity entity = new ByteArrayEntity( - mapper.writeValueAsString(operationTimes(1001)).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertEquals(413, response.getStatusLine().getStatusCode()); - } - - @Test - public void testSilentMode() throws Exception { - BulkRequest req = operationTimes(1); - BulkOperation op = new BulkOperation(); - op.setMethod("GET"); - op.setUrl("/home"); - op.getHeaders().put("Authorization", authHeader); - op.setSilent(true); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - String result = EntityUtils.toString(response.getEntity()); - BulkResponse res = new Gson().getAdapter(new TypeToken() {}) - .fromJson(result); - - assertEquals(1, res.getResults().size()); - } - - @Test - public void testInvalidUrl() throws Exception { - BulkRequest req = operationTimes(1); - BulkOperation op = new BulkOperation(); - op.setMethod("GET"); - op.setUrl("http://0:0:0:0:0:0:0:1%0:8080/home"); - op.getHeaders().put("Authorization", authHeader); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(422 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestCanNotContainBulkPathAsUrl() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl(bulkPath); - op.setMethod("GET"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(422 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestToComplexMapping() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("/home2/AAA/ccc"); - op.setMethod("PUT"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(200 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestToWrongMapping() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("/home2/BBB/ccc"); - op.setMethod("PUT"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(422 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestToNonBulkableMapping() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("home3"); - op.setMethod("PUT"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(422 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestWithParam() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("/home4"); - op.setMethod("POST"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - op.getParams().put("abc", "abc"); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(200 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestByRequestBodyWithNestedObject() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("/list"); - op.setMethod("POST"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - Map params = new HashMap() { - private static final long serialVersionUID = 1L; - { - put("a", Ruby.Hash.of("c", "D").toMap()); - put("b", "E"); - } - }; - op.setParams(params); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(200 == response.getStatusLine().getStatusCode()); - } - - @Test - public void bulkRequestByRequestBodyWithObject() throws Exception { - BulkRequest req = new BulkRequest(); - BulkOperation op = new BulkOperation(); - op.setUrl("list2"); - op.setMethod("POST"); - op.getHeaders().put("Authorization", - "Basic " + Base64Utils.encodeToString("user:password".getBytes())); - Map params = new HashMap() { - private static final long serialVersionUID = 1L; - { - put("a", "D"); - put("b", "E"); - } - }; - op.setParams(params); - req.getOperations().add(op); - - HttpEntity entity = - new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); - post.setEntity(entity); - HttpResponse response = client.execute(post); - - assertTrue(200 == response.getStatusLine().getStatusCode()); - } - - @Test - public void testURITransformer() { - assertTrue(testUriTransformer.isUsed()); - } + @Test + public void bulkRequestToComplexMapping() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("/home2/AAA/ccc"); + op.setMethod("PUT"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(200 == response.getStatusLine().getStatusCode()); + } + + @Test + public void bulkRequestToWrongMapping() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("/home2/BBB/ccc"); + op.setMethod("PUT"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(422 == response.getStatusLine().getStatusCode()); + } + + @Test + public void bulkRequestToNonBulkableMapping() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("home3"); + op.setMethod("PUT"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(422 == response.getStatusLine().getStatusCode()); + } + + @Test + public void bulkRequestWithParam() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("/home4"); + op.setMethod("POST"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + op.getParams().put("abc", "abc"); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(200 == response.getStatusLine().getStatusCode()); + } + + @Test + public void bulkGetRequestWithParam() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + String queryParamValue = "query_param"; + op.setUrl("/getwithparameter?abc=" + queryParamValue); + op.setMethod("GET"); + op.setPayload("requestNo:1"); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + String responseString = new BasicResponseHandler().handleResponse(response); + System.out.println(responseString); + + //region Check if status first request of bulk is 200 or 400(in case of not to having query param) + JSONParser parser = new JSONParser(); + JSONObject json = (JSONObject) parser.parse(responseString); + JSONArray slideContent = (JSONArray)json.get("results"); + JSONObject result0 = (JSONObject) slideContent.get(0); + //endregion + + assertTrue((Long)result0.get("status")==200); + } + + @Test + public void bulkRequestByRequestBodyWithNestedObject() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("/list"); + op.setMethod("POST"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + Map params = new HashMap() { + private static final long serialVersionUID = 1L; + + { + put("a", Ruby.Hash.of("c", "D").toMap()); + put("b", "E"); + } + }; + op.setParams(params); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(200 == response.getStatusLine().getStatusCode()); + } + + @Test + public void bulkRequestByRequestBodyWithObject() throws Exception { + BulkRequest req = new BulkRequest(); + BulkOperation op = new BulkOperation(); + op.setUrl("list2"); + op.setMethod("POST"); + op.getHeaders().put("Authorization", + "Basic " + Base64Utils.encodeToString("user:password".getBytes())); + Map params = new HashMap() { + private static final long serialVersionUID = 1L; + + { + put("a", "D"); + put("b", "E"); + } + }; + op.setParams(params); + req.getOperations().add(op); + + HttpEntity entity = + new ByteArrayEntity(mapper.writeValueAsString(req).getBytes("UTF-8")); + post.setEntity(entity); + HttpResponse response = client.execute(post); + + assertTrue(200 == response.getStatusLine().getStatusCode()); + } + + @Test + public void testURITransformer() { + assertTrue(testUriTransformer.isUsed()); + } } diff --git a/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController6.java b/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController6.java new file mode 100644 index 0000000..f8fcbd1 --- /dev/null +++ b/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController6.java @@ -0,0 +1,28 @@ +package com.github.wnameless.spring.bulkapi.test; + +import lombok.SneakyThrows; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.github.wnameless.spring.bulkapi.Bulkable; + +import java.io.IOException; + + +/** + * Created by Arash Moghani on 15 Jul 2020 + */ + +@Bulkable +@RestController +public class TestController6 { + + @SneakyThrows + @RequestMapping("/exception") + String exception() { + throw new IOException(); // Creating error intentionally + } + +} + + diff --git a/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController7.java b/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController7.java new file mode 100644 index 0000000..0232034 --- /dev/null +++ b/src/test/java/com/github/wnameless/spring/bulkapi/test/TestController7.java @@ -0,0 +1,26 @@ +package com.github.wnameless.spring.bulkapi.test; + +import com.github.wnameless.spring.bulkapi.Bulkable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +/** + * Created by Arash Moghani on 22 Jul 2020 + */ + +@Bulkable +@RestController +public class TestController7 { + + @RequestMapping("/getwithparameter") + String getWithParameter(@RequestParam("abc") String param) { + System.out.println(param); + return param; + + } + +} + +