Why can't cover the test case for the lambda function? - java

Here is my function for which I wrote a mockito test case which returns the list of github repositores matching a given topic using: https://javadoc.io/doc/org.eclipse.mylyn.github/org.eclipse.egit.github.core/2.1.5/index.html
githubService is an object of the class GithubService that contains the method getReposByTopics.
public CompletionStage<Result> getReposByTopics(String topic_name) {
CompletionStage<Result> results = cache
.getOrElseUpdate((topic_name + ".getReposByTopics"),
() -> githubService.getReposByTopics(topic_name)
.thenApplyAsync(repository -> ok(views.html.topics.render(repository))));
return results;
}
The Test case is:
#Test
public void getReposByTopicsTest()
{
running(provideApplication(), () -> {
when(cache.getOrElseUpdate(any(),any())).thenReturn(searchedRepositoriesObject());
CompletionStage<Result> repositories = githubController.getReposByTopics("mocktopic");
assertTrue(repositories.toCompletableFuture().isDone());
});
}
/**
*
* mock object for testing getReposByTopicsTest
* #author Trusha Patel
* #return CompletionStage<Object> represents the async response containing the process stage of SearchedRepository
*/
private CompletionStage<Object> searchedRepositoriesObject(){
return CompletableFuture.supplyAsync(() -> {
SearchedRepositoryDetails searchedRepositoryDetails = new SearchedRepositoryDetails();
List<SearchRepository> searchItem = new ArrayList<>();
SearchRepository searchMock1 = mock(SearchRepository.class);
when(searchMock1.getOwner()).thenReturn("user1");
when(searchMock1.getName()).thenReturn("repo1");
SearchRepository searchMock2 = mock(SearchRepository.class);
when(searchMock2.getOwner()).thenReturn("user2");
when(searchMock2.getName()).thenReturn("repo2");
searchItem.add(searchMock1);
searchItem.add(searchMock2);
searchedRepositoryDetails.setRepos(searchItem);
return searchedRepositoryDetails;
});
}
}
My jacoco test coverage never covers the lambda..
The same happens with the other function where instead of mocking the cache, i mock the function:
public CompletionStage<Result> getRepositoryDetails(String userName, String repositoryName) {
CompletionStage<Result> results = cache
.getOrElseUpdate((userName +"."+repositoryName),
() -> githubService.getRepositoryDetails(userName, repositoryName)
.thenApplyAsync(repository -> ok(views.html.repository.render(repository))));
return results;
}
Test case:
public void getRepositoryDetailsTest()
{
running(provideApplication(), () -> {
when(githubService.getRepositoryDetails(anyString(),anyString())).thenReturn(repositoryDetails());
CompletionStage<Result> repositoryDetails = githubController.getRepositoryDetails("play", "play");
try {
Result result = repositoryDetails.toCompletableFuture().get();
assertEquals(HttpStatus.SC_OK,result.status());
assertTrue(contentAsString(result).contains("MockRepoName"));
assertEquals("text/html",result.contentType().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
}
private CompletionStage<RepositoryDetails> repositoryDetails(){
return CompletableFuture.supplyAsync( () -> {
RepositoryDetails repositoryDetails = new RepositoryDetails();
Repository repository = new Repository();
repository.setName("MockRepoName");
repositoryDetails.setRepository(repository);
return repositoryDetails;
});
}

Related

Wait for the end of subscribe method before returning value in Flux java

I am developing a custom Spring cloud gateway predicate factory that will take decision based on some value in the request body.
I have written the following code.
public class OperatorIdPredicateFactory extends AbstractRoutePredicateFactory<OperatorIdPredicateFactory.Config> {
public OperatorIdPredicateFactory(Class<Config> configClass) {
super(configClass);
}
#Override
public Predicate<ServerWebExchange> apply(Config config) {
return (ServerWebExchange webExchange) -> {
return webExchange.getRequest().getBody().as((Flux<DataBuffer> body) ->{
var returnValue = new Object() {boolean value = false;}; // wrapper anonymous class for return value;
body.subscribe((DataBuffer buffer) ->{
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
String requestJson = charBuffer.toString();
ObjectMapper mapper = new ObjectMapper();
RouteRequestPayload requestPayload = null;
try {
requestPayload = mapper.readValue(requestJson, RouteRequestPayload.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
if(config.getPtoId().equalsIgnoreCase(requestPayload.getRouteRequest().getOperatorId()))
returnValue.value = true;
});
return returnValue.value;
});
};
}
// config class
}
But the problem is that the method is returning before the subscribe method finishes.
How can I make sure that the subscribe method finished before returning the value.

Wait for a CompletableFuture to be complete, then return a different value?

I have a CompletableFuture<Void> that calls an asynchronous method whose return type I can't change, or anything about it.
I want to wait for this method to be complete (I manually complete it), and then return a String value, how would I do this?
public String getServer(Player p) {
FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
sendUTF(p, "GetServer");
try {
Thread.sleep(10000); //so the future doesnt complete itself
} catch (Exception e) {
e.printStackTrace();
}
}), p.getUniqueId().toString());
serverSet.add(f);
String server = "";
//server isn't final so I can't use it in the lambda
f.getFutureVoid().whenComplete(v -> server = f.getServer());
return server;
}
public class FutureServer {
private CompletableFuture<Void> futureVoid;
private String s;
private String uuid;
public FutureServer(CompletableFuture<Void> futureVoid, String uuid) {
this.futureVoid = futureVoid;
this.uuid = uuid;
}
public String getUuid() {
return uuid;
}
public CompletableFuture<Void> getFutureVoid() {
return futureVoid;
}
public boolean hasServer() {
return s != null;
}
public void setServer(String s) {
this.s = s;
}
public String getServer() {
return s;
}
}
I want to set string to equal FutureServer#getServer() (own method), but I need to wait until the CompletableFuture<Void> is completed. What do I do?
This is the method that gets called async and is unchangeable... the method I use that calls this other method asynchronously is sendUTF().
#Override
public void onPluginMessageReceived(String s, Player p, byte[] bytes) {
if (!s.equals("BungeeCord")) return;
ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
String subChannel = in.readUTF();
switch(subChannel) {
case "GetServer":
String server = in.readUTF();
serverSet.stream().filter(f -> f.getUuid().equals(p.getUniqueId().toString())).findFirst().ifPresent(f -> {
f.setServer(server); //getting the string I need and placing it into this object
f.getFutureVoid().complete(null); //completing the void future manually
});
break;
}
}
You could do this:
final AtomicReference<String> server = new AtomicReference<>("");
f.getFutureVoid().whenComplete(v -> server.set(f.getServer())).get(/* maybe add a timeout */);
return server.get();
The simplest solution is simply to join() on that future, either with:
public String getServer(Player p) {
FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
sendUTF(p, "GetServer");
try {
Thread.sleep(10000); //so the future doesnt complete itself
} catch (Exception e) {
e.printStackTrace();
}
}), p.getUniqueId().toString());
serverSet.add(f);
return f.getFutureVoid().thenApply(v -> f.getServer()).join();
}
which can easily be transformed to return a CompletableFuture<String> instead by removing the .join(), or also:
public String getServer(Player p) {
FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
sendUTF(p, "GetServer");
try {
Thread.sleep(10000); //so the future doesnt complete itself
} catch (Exception e) {
e.printStackTrace();
}
}), p.getUniqueId().toString());
serverSet.add(f);
f.getFutureVoid().join();
return f.getServer();
}

Continue subscribing for data even after exception using rx notifications

In the below code the subscriber stops recieving data whenever there is a timeout exception. How can I make sure that the subscriber does not stop when there is exception.
public class ReactiveDataService
{
private static String[] quotes = {"ITEM1", "ITEM2", "ITEM3"};
public Observable<Notification<String>> getStreamData()
{
return Observable.create(subscriber -> {
if(!subscriber.isUnsubscribed())
{
Stream<String> streams = Arrays.stream(quotes);
streams.map(quote -> quote.toString()).filter(quote -> quote!=null)
.forEach(q -> {
subscriber.onNext(Notification.createOnNext(q));
try
{
Random rand = new Random();
Integer i = (rand.nextInt(5)+1)*1000;
Thread.sleep(i);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
});
}
subscriber.onCompleted();
});
}
}
public class ReactiveResource
{
public static void main(String args[])
{
Observable<Notification<String>> watcher = new ReactiveResource().getData()
.timeout(4, TimeUnit.SECONDS)
.doOnError(failure -> System.out.println("Error:" + failure.getCause()))
.onErrorResumeNext(th -> {
return Observable.just(Notification.createOnError(new TimeoutException("Timed Out!")));
});
watcher.subscribe(
ReactiveResource::callBack,
ReactiveResource::errorCallBack,
ReactiveResource::completeCallBack
);
}
public static Action1 callBack(Notification<String> data)
{
System.out.println(data.getValue());
return null;
}
public static void errorCallBack(Throwable throwable)
{
System.out.println(throwable instanceof TimeoutException);
System.out.println(throwable);
}
public static void completeCallBack()
{
System.out.println("On completed successfully");
}
private Observable<Notification<String>> getData()
{
return new ReactiveDataService().getStreamData();
}
You can combine publish, mergeWith and timer to achieve this effect:
static <T> ObservableTransformer<T, T> onTimeoutKeepAlive(
long timeout, TimeUnit unit, Scheduler scheduler, T keepAliveItem) {
return upstream ->
upstream.publish(o ->
o.mergeWith(
Observable.timer(timeout, unit, scheduler)
.map(t -> keepAliveItem)
.takeUntil(o)
.repeat()
.takeUntil(o.ignoreElements().toObservable())
)
);
}
usage:
source
.compose(onTimeoutKeepAlive(
10, TimeUnit.SECONDS, Schedulers.computation(),
Notification.createOnError(new TimeoutException())
))
.subscribe(/* ... */);

Unit testing a void method with Redis async command in java

I'm trying to write a unit test for the following function.
responseHandler and ErrorHandler are both methods that are passes using the Command Pattern
and are used to continue the program's flow.
futureCommand is a lettuce object (Redis implementation in java).
I'm having difficulties with how to test this method since is both using a future and does not return anything.
public void getOfferData(EventRequestContext<? extends BaseEvent> ctx, int offerId, ResponseHandler<T1Offer> responseHandler,
ErrorHandler<Throwable> errorHandler) throws Exception {
String redisKey = keyPrefix + offerId;
RedisFuture<List<String>> futureCommand = connectionWrapper.getHashValues(redisKey, getRequiredParams());
futureCommand.thenAccept(valuesList -> {
TrackerScheduler.processT1GenreicPool.execute(ctx, () -> {
Map<String, String> resultMap = reconstructMapValues(valuesList, getRequiredParams(), redisKey, ctx);
T1Offer offerData;
if(!resultMap.isEmpty()) {
offerData = new T1Offer(resultMap);
} else {
offerData = new T1Offer();
}
if(!offerData.isValid()) {
errorHandler.onError(new Exception("Invalid fields in offerData"));
} else {
responseHandler.onResponse(offerData);
}
});
});
}
My best attempt was to send the assertion using the responseHandler method like this:
#Test
public void getOfferData_offerFullData_parseSuccess() throws Exception {
T1ClickOfferDao.instance.getOfferData(null, Integer.parseInt(OFF_ID), resultOffer -> {
Assert.assertEquals("", resultOffer.getActivationDate());
}, error -> {
});
}
but the Test context is finished before the future is evaluated. And even if I Threas.sleep for a second - the assertion does not affect the test result.
How about
#Test
public void getOfferData_offerFullData_parseSuccess() throws Exception {
final String lock = new String("lock");
T1ClickOfferDao.instance.getOfferData(null, Integer.parseInt(OFF_ID), resultOffer -> {
Assert.assertEquals("", resultOffer.getActivationDate());
synchronized(lock){
lock.notifyAll();
}
}, error -> {
});
synchronized(lock){
try{
lock.wait(1000*2);
} catch (InterruptedException ex) {
fail("Timeout");
}
}
}

Mocking functional interface call in java

I have a method implementation that calls a functional interface (Java 8) and I am trying to write a unit test for it. Here is the method I want to test:
// Impl
public Optional<ExternalRelease> getStagedRelease(AccessParams accessParams) throws DigitalIngestionException {
String resourcesPath=getReleaseResourcesPath(accessParams).orElseThrow(() -> new ValidationException(WRONG_ACCESS_CONTEXT_EXCEPTION));
String ddexFilePath=getReleaseDdexPath(accessParams).get();
if( stageDataManager.directoryExists(resourcesPath) ) {
List<Track> tracks = getTracks(accessParams).
orElse(new ArrayList<>());
ExternalRelease externalRelease = null;
//Verify if lite XML already exists
if( stageDataManager.fileExists(ddexFilePath) ) {
//Load externalRelease values
String liteDdex = stageDataManager.loadFileContent(ddexFilePath).
orElseThrow(() -> new ProcessException("Lite DDEX content couldn't be read."));
externalRelease = ddexManagerExecutor( (ddexManager) -> ddexManager.getExternalReleaseFromLiteDdex(liteDdex) ).
orElseThrow(() -> new ProcessException("External release couldn't be parsed from Lite DDEX."));
externalRelease.setTracks(tracks);
return Optional.ofNullable(externalRelease);
} else {
//Create lite ddex if it doesn't exist
ExternalRelease releaseFromTracks=getReleaseFromTracks(tracks);
String liteDdex = ddexManagerExecutor( (ddexManager) -> ddexManager.getLiteDdexFromAccessParamsAndExternalRelease(accessParams, releaseFromTracks)).
orElseThrow(() -> new ProcessException("Lite DDEX content couldn't be generated."));
stageDataManager.writeStringInFile(ddexFilePath, liteDdex);
return Optional.ofNullable(releaseFromTracks);
}
} else {
return Optional.empty();
}
}
Note the line within the second IF
externalRelease = ddexManagerExecutor( (ddexManager) -> ddexManager.getExternalReleaseFromLiteDdex(liteDdex) ).orElseThrow(() -> new ProcessException("External release couldn't be parsed from Lite DDEX."));`
The ddexManagerExecutor is a functional interface using java 8 features:
public interface ddexManagerConsumer<R> {
R process(DdexManager ddexManager) throws ProcessException;
}
private <R> R ddexManagerExecutor(ddexManagerConsumer<R> action) throws ProcessException {
DdexManager ddexManager = null;
try {
ddexManager = (DdexManager) ddexManagerPool.getTarget();
return action.process(ddexManager);
} catch (Exception e) {
throw new ProcessException("Error while accessing to ddexManager pool.");
} finally {
try {
ddexManagerPool.releaseTarget(ddexManager);
} catch (Exception e) {
log.error("Error while releasing ddexManager instance.", e);
}
}
}
So in my unit tests, which I am trying to do the following,
#Test
public void getStagedReleaseTest_whenFileDoesNoExist() throws Exception{
AccessParams accessParams = getDefaultAccessParams();
File file = new File("src/test/resources/testTrack.mp3");
String xml="<xml/>";
accessParams.setFileName("testTrack.mp3");
accessParams.setReleaseSlug("test-release-slug");
Optional<List<File>> mockFileList = Optional.of(Arrays.asList(file));
when(mockedStageDataManager.directoryExists(any())).thenReturn(true);
when(mockedStageDataManager.getResources(anyString(), any())).thenReturn(mockFileList);
when(mockedStageDataManager.fileExists(anyString())).thenReturn(false);
when(mockedStageDataManager.loadFileContent(anyString())).thenReturn(Optional.of(xml));
when(mockedDdexManager.getLiteDdexFromAccessParamsAndExternalRelease(any(), any())).thenReturn(Optional.of(xml));
DigitalIngestionServiceImpl serviceSpy = spy(service);
Optional<ExternalRelease> externalRelease = serviceSpy.getStagedRelease(accessParams);
Assert.assertNotNull(externalRelease);
}
This breaks my unit test since I am not mocking the call for the private functional interface. I am simply accounting for mocking the following inner line:
ddexManager.getExternalReleaseFromLiteDdex(liteDdex)
But none for the functional interface call that calls the above method. Any clue how to achieve that ?
You can mock ddexManagerPool.getTarget() in order to return a mocked DdexManager that will return what you want when calling getExternalReleaseFromLiteDdex

Categories