how to create PACT for multipart/form-data uploading cdc test - unit-testing

I`m trying to create cdc test for uploading file verifying. I use DIUS library. I do not find any examples how to work with .withFileUpload() in DIUS. My code for pact is next:
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) throws Exception {
DslPart responseBody = new PactDslJsonBody()
.stringType("resource", DESTINATION_FILENAME)
.stringType("requestId", null)
.stringType("code", "201")
.array("response")
.closeArray()
.asBody();
return builder.given("UploadOperation")
.uponReceiving("Upload operation")
.path("/files/upload")
.matchQuery("overwrite", "true")
.matchQuery("destination_filename", DESTINATION_FILENAME)
.withFileUpload("file",
".gitignore",
"multipart/form-data",
new byte[]{11,44,66,123,66}) // some bytes
.willRespondWith()
.status(201)
.body(responseBody)
.toPact();
}
Code for pact creation and verification:
#Test
#PactVerification
public void doTest() throws IOException {
String url = String.format("Http://localhost:%d/files/upload?overwrite=true&destination_filename=%s", PORT, DESTINATION_FILENAME);
// HttpEntity for request
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", new byte[]{11,44,66,123,66},
ContentType.create("multipart/form-data"), ".gitignore")
.build();
// I make the request and get an answer
HttpResponse response = Request.Put(url)
.addHeader("Content-Type", "multipart/form-data;
boundary=j72BRjsEynnAqDw43KTlsjxoKWsjdF_tl6N5")
.body(multipart)
.execute()
.returnResponse();
String json = EntityUtils.toString(response.getEntity());
System.out.println("json=" + json);
JSONObject jsonObject = new JSONObject(json);
assertTrue(jsonObject.getString("code").equals("201"));
assertTrue(response.getStatusLine().getStatusCode() == 201);}
but when I run the test i get: json={"error": Missing start boundary}
java.lang.AssertionError: Pact Test function failed with an exception, possibly due to ExpectedButNotReceived(expectedRequests=[ method: PUT
path: /files/upload
query: [destination_filename:[test], overwrite:[true]]
headers: [Content-Type:multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p]
matchers: MatchingRules(rules={query=Category(name=query, matchingRules={overwrite=MatchingRuleGroup(rules=[RegexMatcher(regex=true, example=null)], ruleLogic=AND), destination_filename=MatchingRuleGroup(rules=[RegexMatcher(regex=test, example=null)], ruleLogic=AND)}), header=Category(name=header, matchingRules={Content-Type=MatchingRuleGroup(rules=[RegexMatcher(regex=multipart/form-data;(\s*charset=[^;]*;)?\s*boundary=.*, example=multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p)], ruleLogic=AND)}), path=Category(name=path, matchingRules={})})
generators: Generators(categories={})
body: OptionalBody(state=PRESENT, value=--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p
Content-Disposition: form-data; name="file"; filename=".gitignore"
Content-Type: multipart/form-data
,B{B
--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p--
)])
...
Caused by: org.json.JSONException: JSONObject["code"] not found.
Whats wrong in my code? I suppose something wrong with Content type, with 'boundary' part. But I dont know how to specify arbitrary boundary.
Maybe anybody knows another library where multipart/form-data uploading requests realized.
Thanks.

I found the solution from test example in DIUS library
contentType in .withFileUpload() and accordingly in .addBinaryBody() methods shouldn`t be "multipart/form-data". It may be "form-data" for example.
.addHeader in request method is not necessary because content type was already defined in body.

Related

how to extract response as json from http ng-builder

The URI myresourceUrl when hit in browser shows the json content in browser.
Requirement:
Need to use the get method of httpbuilder-ng to call GET of URI and response should have the content as json.
This json file will be necessary as input for another task.
How to achieve this. Do we need any parser to get the returned response as json using http-builder-ng.
Expected response format:
{"name":"Abc","info":{"age":45,"height":"5.5"}}
Tried the below get request using:
// setting the request URI
HttpBuilder http = HttpBuilder.configure(config -> {
config.getRequest().setUri(myresourceUrl);
});
String response = http.get(LazyMap.class, cfg -> {
cfg.getRequest().getUri().setPath(myPath);
}).toString();
Actual format we are getting:
{name:Abc,info:{age:45,height:5.5}}
How to get the response indicated above in expected response format.
First, confirm that you http request is indeed returning a JSON response. If so, you can use the gson library. Try
import com.google.code.gson;
String response = gson.toJSON(http.get(LazyMap.class, cfg -> {
cfg.getRequest().getUri().setPath(myPath);
}));
By default a content-type of "application/json" will be parsed rather than returned as a String. You need to define a custom parser for the content-type. I put together an example using a fake server that returns "application/json" content and then shows how to return it as a string in HttpBuilder-NG:
import com.stehno.ersatz.ErsatzServer;
import groovyx.net.http.HttpBuilder;
import static com.stehno.ersatz.ContentType.APPLICATION_JSON;
import static groovyx.net.http.NativeHandlers.Parsers.textToString;
public class Runner {
public static void main(final String[] args) {
final ErsatzServer server = new ErsatzServer();
server.expectations(expects -> {
expects.get("/something").responder(response -> {
response.body("{\"name\":\"Abc\",\"info\":{\"age\":45,\"height\":\"5.5\"}}", APPLICATION_JSON);
});
});
final String response = HttpBuilder.configure(cfg -> {
cfg.getRequest().setUri(server.getHttpUrl());
cfg.getResponse().parser("application/json", (chainedHttpConfig, fromServer) -> textToString(chainedHttpConfig, fromServer));
}).get(String.class, cfg -> {
cfg.getRequest().getUri().setPath("/something");
});
System.out.println(response);
System.exit(0);
}
}
Note the cfg.getResponse().parser("application/json", (chainedHttpConfig, fromServer) -> textToString(chainedHttpConfig, fromServer)); line which is where the parsing happens (overrides the default behavior) - see also the import import static groovyx.net.http.NativeHandlers.Parsers.textToString;.

SpringBootTest - Test exception when request is invalid

I developed an API using web-flux which is working fine when I make request using POSTMAN. My code is:
Controller:
#PostMapping("/post", produces = ["application/xml"])
fun post(#Valid request: RequestData): Mono<Response> {
return Mono.just(request)
...
...
...
}
dto:
data class RequestData(
#get:NotBlank
#get:Email
val email: String = "",
)
So whenever I pass invalid email via POSTMAN, I'm catching the exception like below and its working:
#ExceptionHandler
fun bindingExceptionHandler(e: WebExchangeBindException) = "Custom Error Message"
But now when I write UT(#WebFluxTest) for this case (Invalid emaid), It failed.
#Test
fun testWhenInvalidEmail() {
// Request body
val email = "invalidemail"
val request = LinkedMultiValueMap<String, String>()
request.add("email", email)
webTestClient.post().uri("/post")
.body(BodyInserters.fromFormData(request))
.exchange()
.expectStatus().isOk
}
When I debug this, I found that my exceptionHandler not coming into picture when request coming through unit test. I'm using application/x-www-form-urlencoded content type in POST request.
Please let me know where I'm doing wrong.
I followed this question as well but didn't work.
As mentioned on another related question, this has been fixed in Spring Boot 2.1.0.
Also, you shouldn't have to build WebTestClient yourself but instead inject it in your test class (see reference documentation about that):
#RunWith(SpringRunner.class)
#WebFluxTest(MyValidationController.class)
public class MyValidationControllerTests {
#Autowired
private WebTestClient webClient;
#Test
public void testWhenInvalidEmail() {
//...
}
}

swift 3 alamofire - get request gives response serialization failed

I'm using devise on ruby on rails for authentication. Taking it one step at a time, I have disabled the cookie authentication in order to test retrieving results prior to authentication.
If I go to my browser and navigate to the url that Alamofire is visiting, I get results in JSON format like this :
{"id":250,"name":null,"username":"walker","bio":null,"gender":null,"birth_date":null,"profile_image_url":null}
I'm requesting the alamofire request like this:
Alamofire.request(requestPath, method: .get, parameters: [:], encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in
if (response.result.isFailure) {
completion(false, "")
} else {
if let result = response.result.value {
completion(true, result)
}
}
}
This is all inside of another method which simply provides with a completion handler as you can see inside of the completion handler of the Alamofire request.
I get an error every single time.
The error says:
responseSerializationFailed : ResponseSerializationFailureReason
What am i doing wrong?
This error indicates that your response is not a JSON formatted data(or something wrong with your API Response), try to use something like post man to check your API response and to make sure every thing is ok before requesting with to swift

404 error while invoking a method in webservice

I am pretty new to webservice. I am using spring mvc and webservice to upload a file to the server. In the spring controller I tried to add the parameters in a multivalue map like the one below
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("caption", "Test Caption");
formData.add("file",new FileSystemResource("/home/mytxt");
formData.add("jsonData",imageJson);
my httpheader and httpentity looks like the one below
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
final HttpEntity<MultiValueMap<String,Object>> requestEntity = new HttpEntity<>(
formData, requestHeaders);
in the service side my method looks like
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
#FormDataParam("file") InputStream uploadedInputStream ) throws IOException
{
return null;
}
up to this point everything is fine, but when I use the method like the one below, the method is not invoked
#POST
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition content)
throws IOException
{
}
client code is
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("caption", "Test Caption");
formData.add("file",new FileSystemResource("/home/txt"));
formData.add("jsonData",imageJson);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
final HttpEntity<MultiValueMap<String,Object>> requestEntity = new HttpEntity<>(
formData, requestHeaders);
responseFromService = this.baseAdapter.makeRequest(HttpMethod.POST,
requestEntity, relativeURL, String.class,true);
BaseAdapter class uses Spring RestTemplate to post the url.
I want to get all the parameters present in the map in controller to be passed to the method in the service side. Can any one help me in fixing the issue? Any help is appreciated.
I see you have specified two #FormDataParam("file") annotation,on two different argument,i think it should be applied to only one.
#POST
#Path("/addImage")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response copyFromLocal(
InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition content)
throws IOException {
}

How to I unit test a #future method that uses a callout?

I have a trigger that fires when an opportunity is updated, as part of that I need to call our API with some detail from the opportunity.
As per many suggestions on the web I've created a class that contains a #future method to make the callout.
I'm trying to catch an exception that gets thrown in the #future method, but the test method isn't seeing it.
The class under test looks like this:
public with sharing class WDAPIInterface {
public WDAPIInterface() {
}
#future(callout=true) public static void send(String endpoint, String method, String body) {
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse response = http.send(req);
if(response.getStatusCode() != 201) {
System.debug('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
throw new WDAPIException('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
}
}
}
here's the unit test:
#isTest static void test_exception_is_thrown_on_unexpected_response() {
try {
WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
WDAPIInterface.send('https://example.com', 'POST', '{}');
} catch (WDAPIException ex) {
return;
}
System.assert(false, 'Expected WDAPIException to be thrown, but it wasnt');
}
Now, I've read that the way to test #future methods is to surround the call with Test.startTest() & Test.endTest(), however when I do that I get another error:
METHOD RESULT
test_exception_is_thrown_on_unexpected_response : Skip
MESSAGE
Methods defined as TestMethod do not support Web service callouts, test skipped
So the question is, how do I unit test a #future method that makes an callout?
The callout is getting skipped because the HttpCalloutMock isn't being used.
I assume that WDHttpCalloutMock implements HttpCalloutMock?
If so, a call to Test.setMock should have it return the mocked response to the callout.
WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
Test.setMock(HttpCalloutMock.class, mockResponse);
WDAPIInterface.send('https://example.com', 'POST', '{}');
Incidentally, the Salesforce StackExchange site is a great place to ask Salesforce specific questions.