0

I'm trying to test a service method that throws a runtimeexception in a executorservice ran job. However the test doesn't seem to be catching it. I suppose because the test finishes before the executor job is finished. What is the trick to find a solution, synchronize the test or something ?

The service method

public void migrateSplitFile(String runtimeWorkspace, File jobFile, File errorFile, String inputFile) {
    ExecutorService executorService = Executors.newFixedThreadPool(maxImportJobs);
    executorService.execute(()->{
        try {
            importSingleFile(runtimeWorkspace, jobFile, errorFile, inputFile);
        } catch (IOException e) {
            throw new RuntimeException("Failed running import for file [" + inputFile + "]", e);
        }
    });
}

private void importSingleFile(String runtimeWorkspace, File jobFile, File errorFile, String inputFile) throws IOException {
    Optional<RunningJob> jobResult = importJobManager.executeImport(inputFile, runtimeWorkspace);
    if (jobResult.isPresent()) {
        RunningJob job = jobResult.get();
        fileUtils.writeStringToFile(jobFile, "Ran job [" + job.getJobId() + "] for input file [" + inputFile + "]");
    } else {
        fileUtils.writeStringToFile(errorFile, "input file [" + inputFile + "] failed to process");
    }
}

The test

@Test
void migrateSplitFileRuntimeException() {
    assertThrows(RuntimeException.class,
            () -> {
                String runtimeWorkspace = "./test";

                File testDir = new File(runtimeWorkspace + "/inputfiles");
                FileUtils.forceMkdir(testDir);
                File fakeInputFile = new File(runtimeWorkspace + "/inputfiles/test.txt");
                FileUtils.writeStringToFile(fakeInputFile, "test", "UTF-8", true);

                String inputFile = ".\\test\\inputfiles\\test.txt";

                File jobFile = new File(runtimeWorkspace + "/jobs.txt");
                File errorfile = new File(runtimeWorkspace + "/errors.txt");

                Mockito.doThrow(new Auth0Exception("")).when(importJobManager).executeImport(inputFile, runtimeWorkspace);

                auth0EngineService.migrateSplitFile(runtimeWorkspace, jobFile, errorfile, inputFile);

                FileUtils.deleteDirectory(new File(runtimeWorkspace));
            });
}

I'm open for any suggestions, before I implemented the executorservice my test was working

kenny
  • 1,157
  • 1
  • 16
  • 41
  • What is the `importJobManager`? – Boris Feb 11 '20 at 13:02
  • You could grab the futures when you submit the task, then they will throw the exception when you call get. – matt Feb 11 '20 at 14:14
  • importJobManager is just a class doing some business logic to actually do the import I'm currently experimenting with the futures to catch it but no luck yet still trying for a solution. I'm not that proficient with multithreading – kenny Feb 11 '20 at 14:32
  • I don't see how your test relates to the code above it with the executor service? Using the future.get will cause the test to wait for the task to complete and throw an exception if the task throws an exception. – matt Feb 11 '20 at 14:47

1 Answers1

1

You can use:

Future<?> f = executorService.submit(()->{
    try {
        importSingleFile(runtimeWorkspace, jobFile, errorFile, inputFile);
    } catch (IOException e) {
        throw new RuntimeException("Failed running import for file [" + inputFile + "]", e);
    }
});

Then afterwards use:

f.get();

That will throw any runtime exceptions that occurred during the execution of the task. It will also block until the task has completed.

matt
  • 10,892
  • 3
  • 22
  • 34
  • Sorry for the late reply I've been working on it all day. I tried the get call on futures but this made the whole thing blocking and the two import jobs I expect to run at the same time where each running in a way sequentially and I didn't notice any significant speed boost anymore making it multithreaded. still looking for a solution atm – kenny Feb 12 '20 at 13:06
  • 1
    @kenny In that case you might need some more information in your question. The Future#get will block and let you see the results of the executed task. If you are trying to run tests in parallel, then I think you need to step back from the task a bit. Design your tests to be run independantly, and your framework will have a parallel options. – matt Feb 14 '20 at 08:41
  • I had two days of training, monday I'm back at work and will take a step back and see if i can't find other sollutions maybe refactor some code and test that independently and take the hit that a few lines of code won't be tested, not a big fan of that though ... – kenny Feb 15 '20 at 09:05
  • 1
    We eventually decided not to run that particular piece of code multithreaded so my question became no longer relevant for the job at hand. Yet I do believe the suggested answer when put a little more time into it would have yielded the result I wanted – kenny Feb 24 '20 at 07:45