Java/ test & operation after timeout - java

I hava a test, with:
#test(timeout = 50000)
I want to do some operations if the test fails because the timeout, and only then.
I try the next:
#Test(timeout=60000)
public void test1() {
try{
// code
}
catch(Exception e){
//operations after time out
}
}
But it doesn't work. Any help?

It's not possible to do what you described here with JUnit's timeout parameter because it doesn't provide a callback to handle the operations after it has timed out.
But, you can certainly write your own test harness to do just that. In the below example, I want the code to execute within one second but my actual code execution takes 2 seconds. In this case, we catch the TimeoutException and you can perform your additional operation within that catch block.
#Test
public void testMe() {
// test must finish within one second
int expectedExecutionInSeconds = 1;
RunnableFuture<String> runnableFuture = new FutureTask<String>(new Callable<String>() {
public String call() throws Exception {
// your actual code goes in here
Thread.sleep(2000);
return "ok";
}
});
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnableFuture);
try {
String result = runnableFuture.get(expectedExecutionInSeconds, TimeUnit.SECONDS);
assertEquals("ok", result);
}
catch (TimeoutException ex) {
// stop code
runnableFuture.cancel(true);
System.out.println("do other stuff");
}
catch (Exception e) {
fail("other stuff is failing");
}
executorService.shutdown();
}

Related

Async API using Future never completes [duplicate]

This question already has answers here:
FutureTask get vs run, task never finishes
(3 answers)
Closed 9 months ago.
I try to make an API aysnchronous as:
Future<Integer> fASync(int x) {
return new FutureTask(() -> {
try {
Thread.sleep(new Random().nextInt(1, 3) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x * x;
});
}
..then I try to use it:
Future<Integer> asyncCall = fASync(x);
asyncCall .get();
But this never completes and call just blocks.
Is this not correct way of making your API asynchronous?
You have declared a FutureTask but haven't actually run it so a call to asyncCall.get() will block forever.
Here is your example with extra logging and adding a step to execute the task in a new ExecutorService.
static FutureTask<Integer> fASync(int x) {
System.out.println("fASync("+x+") called");
return new FutureTask<>(() -> {
System.out.println("fASync("+x+") FutureTask has started");
try {
Thread.sleep(new Random().nextInt(1, 3) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("fASync("+x+") FutureTask has ended");
return x * x;
});
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newFixedThreadPool(1);
FutureTask<Integer> task = fASync(5);
// MUST execute the task or task.get() will block forever
exec.execute(task);
System.out.println("task.get()="+task.get());
exec.shutdown();
exec.awaitTermination(1, TimeUnit.DAYS);
System.out.println("ENDED");
}
If you enable the exec.execute(task); line it will print these messages and complete task.get(), instead of printing the first line only and no response from task.get():
fASync(5) called
fASync(5) FutureTask has started
fASync(5) FutureTask has ended
task.get()=25
ENDED

In Java, how to test a private code running in parallel with executor service wrapped in public method

I had an existing non-parallel code that we recently made concurrent by using executor service. Adding concurrency ensured limit the number of requests sent to another API in our scenario. So we are calling an external service and limiting requests, waiting for all requests to complete so as merge the responses later before sending the final response.
I am stuck on how to add a unit test/mock test to such a code, considering the private method is parallelized. I have added below my code structure to explain my situation.
I am trying to test here
#Test
public void processRequest() {
...
}
Code
int MAX_BULK_SUBREQUEST_SIZE = 10;
public void processRequest() {
...
// call to private method
ResponseList responseList = sendRequest(requestList);
}
private void sendRequest(List<..> requestList) {
List<Response> responseList = new ArrayList<>();
ExecutorService executorService = Executors.newFixedThreadPool(10);
int numOfSubRequests = requestList.size();
for (int i = 0; i < numOfSubRequests; i += MAX_BULK_SUBREQUEST_SIZE) {
List<Request> requestChunk;
if (i + MAX_BULK_SUBREQUEST_SIZE >= numOfSubRequests) {
requestChunk = requestList.subList(i, numOfSubRequests);
} else {
requestChunk = requestList.subList(i, i + MAX_BULK_SUBREQUEST_SIZE);
}
// parallelization
executorService.submit(() -> {
Response responseChunk = null;
try {
responseChunk = callService(requestChunk); // private method
} catch (XYZException e) {
...
try {
throw new Exception("Internal Server Error");
} catch (Exception ex) {
...
}
}
responseList.add(responseChunk);
});
}
executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) {..}
}
return responseList;
}
private Response callService(..) {
// call to public method1
method1(..);
// call to public method2
method2(..);
}
I was able to do so with unit tests and adding a mockito verify on how many times a method is called. If it's running in parallel after chunkifying, then the method will be called more than once equal to number of chunks it's going to process.

java8 asynchronous method CompletableFuture.runAsync doesn't run

very basic code to run asynchronous method.
when I run the following code the runAsync doesn't run.
what I'm missing?
the result run only the sync code .
public class Main {
public static void main(String[] args) {
runAsync("run async command ans wait 10000");
System.out.println("sync commands ");
}
public static void runAsync(String inputStr) {
CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
});
}
}
I expect to get first the "sync commands" then the "async command "
but get only the sync message
Your task will run in some other Thread(by default in a Thread from ForkJoinPool) and you are not waiting for it to finish - the main Thread ends before your async task is executed/submitted. You can call CompletableFuture::join to wait for it to finish and it will block the main Thread until it finishes :
CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
}).join(); //here call the join
or like :
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
//...
});
cf.join();
You need to wait for the async task to be completed by using join, for example:
public static void main(String[] args) {
CompletableFuture<Void> future = runAsync("run async command ans wait 10000");
future.join();
System.out.println("sync commands ");
}
public static CompletableFuture<Void> runAsync(String inputStr) {
return CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
});
}
It does run, but it runs on another thread and you're not waiting or doing anything with the result. As Javadoc of CompletableFuture.runAsync() says:
Returns a new CompletableFuture that is asynchronously completed by a
task running in the ForkJoinPool.commonPool() after it runs the given
action.
runAsync() is useful for tasks that don't return anything. If you want a result from it you should use supplyAsync() which returns a CompletableFuture<T>
Then you can get the result from it:
// Run a task specified by a Supplier object asynchronously
CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
#Override
public String get() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
}
});
// Block and get the result of the Future
String result = future.get();
System.out.println(result);

Execute a method after a certain amount of time using ExecutorService

I have the following code:
ExecutorService executor = Executors.newSingleThreadExecutor()
Future<String> future = executor.submit(new Callable<String>() {
#Override
String call() throws Exception {
stream.filter(fq)
return null
}
})
try {
future.get(4, TimeUnit.MINUTES)
}
Once the 4 minutes are over I want to execute another method. Where would I put this code?
Catch the TimeoutException and put your code in the catch block.
try {
future.get(4, TimeUnit.MINUTES)
} catch(TimeoutException e) {
//call your method code here, it will be called only if the operation times out
myMethod();
}

Telling a ThreadPoolExecutor when it should go ahead or not

I have to send a set of files to several computers through a certain port. The fact is that, each time that the method that sends the files is called, the destination data (address and port) is calculated. Therefore, using a loop that creates a thread for each method call, and surround the method call with a try-catch statement for a BindException to process the situation of the program trying to use a port which is already in use (different destination addresses may receive the message through the same port) telling the thread to wait some seconds and then restart to retry, and keep trying until the exception is not thrown (the shipping is successfully performed).
I didn't know why (although I could guess it when I first saw it), Netbeans warned me about that sleeping a Thread object inside a loop is not the best choice. Then I googled a bit for further information and found this link to another stackoverflow post, which looked so interesting (I had never heard of the ThreadPoolExecutor class). I've been reading both that link and the API in order to try to improve my program, but I'm not yet pretty sure about how am I supposed to apply that in my program. Could anybody give a helping hand on this please?
EDIT: The important code:
for (Iterator<String> it = ConnectionsPanel.list.getSelectedValuesList().iterator(); it.hasNext();) {
final String x = it.next();
new Thread() {
#Override
public void run() {
ConnectionsPanel.singleAddVideos(x);
}
}.start();
}
private static void singleAddVideos(String connName) {
String newVideosInfo = "";
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
newVideosInfo = newVideosInfo.concat(it.next().toString());
}
try {
MassiveDesktopClient.sendMessage("hi", connName);
if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) {
MassiveDesktopClient.sendMessage(newVideosInfo, connName);
}
} catch (BindException ex) {
MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber());
try {
Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000);
} catch (InterruptedException ex1) {
JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
ConnectionsPanel.singleAddVideos(connName);
return;
}
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
try {
MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName);
} catch (BindException ex) {
MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber());
try {
Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000);
} catch (InterruptedException ex1) {
JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
ConnectionsPanel.singleAddVideos(connName);
return;
}
}
}
Your question is not very clear - I understand that you want to rerun your task until it succeeds (no BindException). To do that, you could:
try to run your code without catching the exception
capture the exception from the future
reschedule the task a bit later if it fails
A simplified code would be as below - add error messages and refine as needed:
public static void main(String[] args) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(corePoolSize);
final String x = "video";
Callable<Void> yourTask = new Callable<Void>() {
#Override
public Void call() throws BindException {
ConnectionsPanel.singleAddVideos(x);
return null;
}
};
Future f = scheduler.submit(yourTask);
boolean added = false; //it will retry until success
//you might use an int instead to retry
//n times only and avoid the risk of infinite loop
while (!added) {
try {
f.get();
added = true; //added set to true if no exception caught
} catch (ExecutionException e) {
if (e.getCause() instanceof BindException) {
scheduler.schedule(yourTask, 3, TimeUnit.SECONDS); //reschedule in 3 seconds
} else {
//another exception was thrown => handle it
}
}
}
}
public static class ConnectionsPanel {
private static void singleAddVideos(String connName) throws BindException {
String newVideosInfo = "";
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
newVideosInfo = newVideosInfo.concat(it.next().toString());
}
MassiveDesktopClient.sendMessage("hi", connName);
if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) {
MassiveDesktopClient.sendMessage(newVideosInfo, connName);
}
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName);
}
}
}

Categories