Using mockwebserver to test URL/URI DataHandler/DataSource - mockwebserver

I am trying to use mockwebserver to test POSTing via a Jakarta-based activation URLDataSource's outputStream.
In the jakarta.activation.DataSource, you only have "getInputStream()/getOutputStream()".
The 'getOutputStream()' method internally opens a URLConnection and gets and returns its OutputStream().
#Override
public OutputStream getOutputStream() throws IOException {
URLConnection connection = this.uri.toURL().openConnection();
connection.setDoOutput(true);
return connection.getOutputStream();
}
I can write to the output-stream with no problem. But closing the output-stream does not trigger the MockWebServer dispatcher. Since I don't have the connection in the caller, I can't call "getResponseCode()" to make the request hit the server (as in some examples I have seen).
try (OutputStream os = (new URIDataSource(mockWebServerUri)).getOutputStream()) {
IOUtils.write(testMessage, os, StandardCharsets.UTF_8);
} catch (IOException ex) {
fail ("Unable to obtain OutputStream from URIDataSource.");
}
Any suggestions on how / if I can trigger the dispatcher after closing the output-stream without having the connection?
Cheers, Jeff

Related

Apache Camel: Unit testing for file and http components

I am fairly new to Camel & just managed to implement a use case as below with 2 routes which is using file & http components. Looking for some leads on writing junits for the same. Have tried some sample test case below based on the inputs that i found on the net. Not sure if that suffices. Appreciate your help!
Implementation:
#Override
public void configure() throws Exception {
// Global Exception Handling block
onException(FileWatcherException.class).process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Exception handled");
}
}).to("file:C:/error?recursive=true").handled(true);
// Actively listen to the input folder for an incoming file
from("file:C:/input?noop=true&recursive=true&delete=true")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String fileName = exchange.getIn().getHeader("CamelFileName").toString();
exchange.getIn().setHeader("fileName", fileName);
}
})
// Call the Get endpoint with fileName as input parameter
.setHeader(Exchange.HTTP_METHOD, simple("GET"))
.toD("http://localhost:8090/fileWatcher?fileName=${header.fileName}")
.choice()
// if the API returns true, move the file to the outbox folder
.when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(constant(200)))
.to("file:C:/outbox?noop=true&recursive=true")
.endChoice()
// If the API's response code is other than 200, move the file to error folder
.otherwise()
.log("Moving the file to error folder")
.to("file:C:/error?recursive=true")
.end();
// Listen to the outbox folder for file arrival after it gets moved in the above step
from("file:C:/outbox?noop=true&recursive=true")
// Request Body for POST call is set in FileDetailsProcessor class
.process(new FileDetailsProcessor())
.marshal(jsonDataFormat)
.setHeader(Exchange.HTTP_METHOD, simple("POST"))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
// Call the Rest endpoint with fileName & filePath as RequestBody
.to("http://localhost:8090/fileWatcher")
.process(new MyProcessor())
.end();
}
Junit
#Test
public void checkFileWatcherFunctionality() throws Exception {
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
// mocking all endpoints. **QUESTION** - Is this required?
mockEndpointsAndSkip("http://localhost:8090:fileWatcher?fileName=loan.csv");
mockEndpointsAndSkip("file:C:/processing");
mockEndpointsAndSkip("file:C:/error");
mockEndpointsAndSkip("http://localhost:8090:fileWatcher");
}
});
context.start();
// **QUESTION** - This is a GET call. Expecting only the HTTP status code from it. How to check that?
getMockEndpoint("mock:http://localhost:8090:fileWatcher?fileName=abc.txt").expectedBodyReceived();
// **QUESTION** - This is a POST call. How to send request body along? Expecting only the HTTP status code from it. How to check that?
getMockEndpoint("mock:http://localhost:8090:fileWatcher").expectedBodyReceived();
// **QUESTION** - Is this the right way to check?
getMockEndpoint("mock:file:C:/processing").expectedFileExists("loan.csv");;
template.sendBodyAndHeader("file:C:/inbound", "", Exchange.FILE_NAME, "loan.csv");
// QUESTION - What can be asserted now?
}
Also - How to write test cases for negative flow (exception scenario)? Looking for suggestions.
I have managed to draft the test case. Is this the right approach or can there be a better way?
This might be more of an integration test i suppose.
The issue i see now is that the test case doesn't report at the end (success or failure), instead it keeps waiting for file arrival in the input folder. What am i missing?
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class FileWatcherRouteBuilderTest extends CamelTestSupport {
#Autowired
private TestRestTemplate restTemplate;
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return new FileWatcherRouteBuilder();
}
#Test
public void testFileCopy() throws Exception {
template.sendBodyAndHeader("file:C:/inbound", "", Exchange.FILE_NAME, "abc.csv");
// Call the GET endpoint
ResponseEntity<String> getResponse = restTemplate.getForEntity("http:localhost:8090/fileWatcher?fileName=abc.csv",
String.class);
assertTrue("Get call is unsuccessful", getResponse.getStatusCode().is2xxSuccessful());
String response = getResponse.getBody();
assertTrue(!response.isEmpty());
// The file would have moved to output folder now.
File targetFile = new File("C:/processing");
assertTrue(targetFile.isDirectory());
assertEquals(1, targetFile.listFiles().length);
// Since we need to extract the file name, doing the below step
Exchange exchange = consumer.receive("file:C:/processing");
String fileName = exchange.getIn().getHeader("CamleFileName").toString();
// RequestBody needed for POST call
FileDetails fileDetails = new FileDetails(fileName, "C:/processing/"+fileName);
HttpHeaders headers = new HttpHeaders();
HttpEntity<FileDetails> request = new HttpEntity<FileDetails>(fileDetails, headers);
// Call the POST endpoint
ResponseEntity<String> postResponse = restTemplate.postForEntity("http://localhost:8090/fileWatcher", request, String.class);
assertTrue("Post call is unsuccessful", postResponse.getStatusCode().is2xxSuccessful());
// Asserting that after both the web service calls, the file is still available in the output folder
assertEquals(1, targetFile.listFiles().length);
}
}

Apache HttpComponents CookieStore Not Storing Cookies

I'm using HttpComponents 4.5.2 and I'm trying to store cookies as I need to use them for login and other requests. The code works fine whilst the application is still running, but the problem here is when I restart it, the cookies that were supposed to be stored in CookieStore are not there. Here's what I've written:
public static void main( String[] args ) throws InterruptedException
{
RequestConfig globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.STANDARD).build();
BasicCookieStore cookieStore = new BasicCookieStore();
HttpClientContext context = HttpClientContext.create();
context.setCookieStore(cookieStore);
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
.setDefaultRequestConfig(globalConfig)
.setDefaultCookieStore(cookieStore)
.build();
httpclient.start();
login(httpclient, context);
}
public static void login(CloseableHttpAsyncClient httpClient, HttpClientContext context) throws InterruptedException
{
JSONObject json = new JSONObject("{ email : blahblahblah1, password : blahblahblah2 }");
StringEntity requestEntity = new StringEntity(
json.toString(),
ContentType.APPLICATION_JSON);
HttpPost postMethod = new HttpPost("http://localhost:8080/login");
postMethod.setEntity(requestEntity);
final CountDownLatch latch = new CountDownLatch(1);
httpClient.execute(postMethod, context, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response) {
latch.countDown();
System.out.println(postMethod.getRequestLine() + "->" + response.getStatusLine());
//System.out.println(context.getCookieStore().getCookies().size());
}
public void failed(final Exception ex) {
latch.countDown();
System.out.println(postMethod.getRequestLine() + "->" + ex);
}
public void cancelled() {
latch.countDown();
System.out.println(postMethod.getRequestLine() + " cancelled");
}
});
latch.await();
}
I've read the HttpComponents documentation and the section 3.5 about cookies says:
HttpClient can work with any physical representation of a persistent cookie store that implements the CookieStore interface. The default CookieStore implementation called BasicCookieStore is a simple implementation backed by a java.util.ArrayList. Cookies stored in an BasicClientCookie object are lost when the container object get garbage collected. Users can provide more complex implementations if necessary
So I'm wondering if it's left to it's users to implement some kind of structure that can effectively store cookies or if I'm missing something.
Yes, using BasicCookieStore backed by ArrayList means that when your jvm exists, the data there is being lost just like any ArrayList in memory.
BasicCookieStore class also implements Serializable so you can use that to persist it to disk and restore back on your app startup if the file was there.
You can borrow some code from the tests verifying that flow TestBasicCookieStore#testSerialization.

How to make JSON PUT request through Codename one API

I'm not able top figure out JSON put request from codename one api. I didnt find any example to make this request.
Questions:
1. I'm not sure whether I have to send the content length parameter. If yes, how can I send that?
2. I have to send the request body with just "true" nothing else. There is no key and value to use req.addArgument() method.
3. Do I have to use buildRequestBody() method to override the request. Can you provide an example?
4. How to verify the result after receiving the response.
Any help can be appreciated.
Thanks.
Please find the code below.
req.setUrl(identityUrl );
req.setPost(false);
req.setHttpMethod("PUT");
req.setContentType("application/json");
req.addRequestHeader("authorization", token);
req.addArgument("Content-Length", "4");
req.setReadResponseForErrors(true);
InfiniteProgress ip = new InfiniteProgress();
Dialog d = ip.showInifiniteBlocking();
NetworkManager.getInstance().addToQueueAndWait(req);
d.dispose();
JSONParser parser = new JSONParser();
Map map2 = null;
try {
map2 = parser.parseJSON(new InputStreamReader(new ByteArrayInputStream(req.getResponseData()), "UTF-8"));
} catch (IOException ex) {
ex.printStackTrace();
}
If you want the content to be embedded wholly you need to override the buildRequestBody method. Notice that post needs to be true for the body to be called.
I don't think you need content-length:
req = new ConnectionRequest(identityUrl) {
protected void buildRequestBody(OutputStream os) throws IOException {
os.write(json.getBytes("UTF-8"));
}
protected void readResponse(InputStream input) throws IOException {
map2 = parser.parseJSON(new InputStreamReader(input, "UTF-8"));
}
protected void postResponse() {
// response completed, this is called on the EDT do the application logic here...
}
};
req.setPost(true);
req.setHttpMethod("PUT");
req.setContentType("application/json");
req.addRequestHeader("authorization", token);
req.setReadResponseForErrors(true);
InfiniteProgress ip = new InfiniteProgress();
Dialog d = ip.showInifiniteBlocking();
req.setDisposeOnCompletion(d);
NetworkManager.getInstance().addToQueue(req);
Notice that I no longer need to close streams or handle IOException as the connection request does everything for me. Also notice the read/build methods are called on the network threads and not on the EDT so you need to do the rest of the flow in the postResponse.

Exception handling and constructors

I am writing data to a file, when I write this data I want to do it so that if the file does not open it will give the user a message saying that something whent wrong. The way I do this is by calling the method to write, if it fails it returns false. That way I can prompt the user to do something to check what has happened.
However when I create the object I cant return anything from the constructor so I am a bit stumped about what I should do.
public class Writetofile {
BufferedWriter writer = null;
public Writetofile(String[]details) throws IOException{
String machine= details[0];
String date=details[1];
String start_time = details[2];
try{
File new_cal= new File("C:\\Activity_Calibrator\\log\\"+machine+"\\"+machine+date+".txt");
new_cal.getParentFile().mkdir();
FileWriter fwriter = new FileWriter(new_cal);
writer = new BufferedWriter(fwriter);
writer.write("Linear Calibratiton for " + machine + " carried out " + date+" ./n");
writer.close();
}
catch(Exception e){ in here I would like to be able to send a message back to m
code so that it can tell the user to check the folder etc}
}
when I call the record data if something goes wrong it will return a false to the calling class. and I can put a message.
public boolean recordData(String record) throws IOException{
try{
writer.append(record);
writer.close();
return true;
}
catch(Exception e){
return false;
}
}
}
}
A constructor should not DO anything. A constructor is an initialization phase closely tied to the allocation of an object.
Throwing exceptions, or doing anything in a constructor that might throw an exception is to be avoided.
Java does not separate the phases of allocation and initialization, no code, especially IO code should be in a constructor.

JMS MessageCreator.createMessage() in Grails

I am trying to implement jms to my grails application.
I have several JMS consumer in a spring based enviroment listining
on an ActiveMQ broker. I wrote a simple test commandline client which creates
messages and receives them in an request response manner.
Here is the snippet that sends a MapMessage in Spring JMS way.
This works for me as long I am in my spring world.
final String corrID = UUID.randomUUID().toString();
asyncJmsTemplate.send("test.RequestQ", new MessageCreator()
{
public Message createMessage(Session session) throws JMSException {
try {
MapMessage msg = session.createMapMessage();
msg.setStringProperty("json", mapper.writeValueAsString(List<of some objects>));
msg.setJMSCorrelationID(corrID);
msg.setJMSReplyTo(session.createQueue("test.ReplyQ"));
return msg;
} catch (JsonGenerationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
});
BUT when I tried to implement this methods to my grails test app
I receive some METHOD_DEF exceptions. Sending simple TextMessages
via the jmsTemplate.convertAndSende(Queue, Message) provided by
the JMS Plugin works.
Can any one help me? Is this a common problem?
Cheers Hans
Not actually trying this out, I have to believe this is a syntax problem. What you're really doing with that anonymous class is passing a closure containing all the MessageCreator code into the constructor for the MessageCreator class. In Groovy, closures can be passed as the last argument to a function merely by placing it after the function name or the parenthesized first arguments.
SomeFunction( arg1, arg2) { some code }
is the same as
SomeFunction( arg1, arg2, { some code } )
What you really want is to convert the closure into an anonymous instance of a MessageCreator, which I believe you can accomplish by:
asyncJmsTemplate.send("test.RequestQ",
{ code in the anonymous block } as MessageCreator );
I found this on StackOverflow, actually, though it's a poorly created question. Read all the responses, and you should see something relevant: Best groovy closure idiom replacing java inner classes?
I have had the same problems and here is my working solution:
I have created a new class MyMessageCreator in the src folder which implements the origin JMS MessageCreator interface.
With this I can create a new MyMessageCreator object and can call the createMessage(Session session) function to generate a new message.
To get the session object I use the jmsTemplate.
public class MyMessageCreator implements MessageCreator {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createMapMessage();
}
}
Here is the relevant groovy code:
Session session = jmsTemplate.getConnectionFactory().createConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)
MapMessage msg = new MyMessageCreator().createMessage(session);
Hope this helps,
Mirko