Java Mutiny Multi from CompletableFuture<List<T>> - java

say you have a method:
public CompletableFuture<List<Integer>> getStuffAsync()
I want the same stream as:
Multi<Integer> stream = Multi
.createFrom().completionStage(() -> getStuffAsync())
.onItem().transformToIterable(Function.identity())
which is a stream of each integer returned by the list from the method specified at the beggining...
but without the onItem().transformToIterable(), hopefully something like:
Multi.createFrom().completionStageIterable(() -> getStuffAsync())
purely for aesthetic reasons and to save on valuable characters

You can use Multi.createFrom().iterable() and pass in the result of the CompletableFuture.
Multi<Integer> stream = Multi
.createFrom()
.iterable(getStuffAsync().get());
Alternatively use a utility method to create it.
Create this class Multi.java (or other name) in a package such as util:
package util;
import io.smallrye.mutiny.groups.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public interface Multi<T> extends io.smallrye.mutiny.Multi<T> {
static <T> io.smallrye.mutiny.Multi<T> createFromCompletionStageIterable(CompletableFuture<? extends Iterable<T>> completableFuture) {
return MultiCreate.INSTANCE.completionStage(completableFuture).onItem().transformToIterable(Function.identity());
}
}
Then you can use your custom method like this:
Multi<Integer> stream = util.Multi
.createFromCompletionStageIterable(getStuffAsync());

Related

"Implementing" base factory method in Java/Groovy lang

I'm working on a model factory that create business models from test data stores in Katalon Studio. It's been years since I seriously touched Java, especially to do any sort of generic programming.
How I'm trying to do it
I'll have some BaseModelFactory, defined to be:
import java.util.stream.Collectors
import com.kms.katalon.core.testdata.TestData
public class BaseModelFactory<T> {
public static List ModelsFrom(TestData testData) {
return testData.getAllData()
.stream()
.map { row -> this.ModelFromRow(row) }
.collect(Collectors.toList())
}
public static <T> T ModelFrom(TestData testData, int rowNum) {
return ModelFromRow(testData.getAllData().get(rowNum))
}
private static <T> T ModelFromRow(List<Object> row) {
return null
}
}
and then, whenever we have a data store that we want to create business models from, we simply create a derived factory that implements ModelsFrom. For example:
import java.text.SimpleDateFormat
import com.xxx.models.contract.ContractModel
public class ContractModelFactory extends BaseModelFactory<ContractModel> {
private static ContractModel ModelFromRow(List<Object> row) {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
return new ContractModel(
Integer.parseInt(row[0]),
row[1],
dateFormat.parse(row[2]),
dateFormat.parse(row[3]),
//...
)
}
}
OK, so what's the problem?
The problem is that, whenever I run a Test Case, with
WebUI.verifyNotEqual(
ContractModelFactory.ModelFrom(findTestData("whatever"), 1),
null
)
, where "whatever" points to a non-empty data file, it fails! When I go to debug it, I see that BaseModelFactory.ModelFromRow is getting hit, instead of the hiding static method ContractModelFactory.ModelFromRow !
How do I fix this?
DISCLAIMER: In case you didn't see it in the start of the paragraph, I am doing this in Katalon Studio environment.

Asserting properties on list elements with assertJ

I have a working hamcrest assertion:
assertThat(mylist, contains(
containsString("15"),
containsString("217")));
The intended behavior is:
mylist == asList("Abcd15", "217aB") => success
myList == asList("Abcd15", "218") => failure
How can I migrate this expression to assertJ. Of course there exist naive solutions, like asserting on the first and second value, like this:
assertThat(mylist.get(0)).contains("15");
assertThat(mylist.get(1)).contains("217");
But these are assertions on the list elements, not on the list. Trying asserts on the list restricts me to very generic functions. So maybe it could be only resolved with a custom assertion, something like the following would be fine:
assertThat(mylist).elements()
.next().contains("15")
.next().contains("217")
But before I write a custom assert, I would be interested in how others would solve this problem?
Edit: One additional non-functional requirement is, that the test should be easily extendible by additional contstraints. In Hamcrest it is quite easy to express additional constraints, e.g.
assertThat(mylist, contains(
emptyString(), //additional element
allOf(containsString("08"), containsString("15")), //extended constraint
containsString("217"))); // unchanged
Tests being dependent on the list index will have to be renumbered for this example, Tests using a custom condition will have to rewrite the complete condition (note that the constraints in allOf are not restricted to substring checks).
For this kind of assertions Hamcrest is superior to AssertJ, you can mimic Hamcrest with Conditions but you need to write them as there are none provided out of the box in AssertJ (assertJ philosphy is not to compete with Hamcrest on this aspect).
In the next AssertJ version (soon to be released!), you will be able to reuse Hamcrest Matcher to build AssertJ conditions, example:
Condition<String> containing123 = new HamcrestCondition<>(containsString("123"));
// assertions succeed
assertThat("abc123").is(containing123);
assertThat("def456").isNot(containing123);
As a final note, this suggestion ...
assertThat(mylist).elements()
.next().contains("15")
.next().contains("217")
... unfortunately can't work because of generics limitation, although you know that you have a List of String, Java generics are not powerful enough to choose a specific type (StringAssert) depending on another (String), this means you can only perform Object assertion on the elements but not String assertion.
-- edit --
Since 3.13.0 one can use asInstanceOf to get specific type assertions, this is useful if the declared type is Object but the runtime type is more specific.
Example:
// Given a String declared as an Object
Object value = "Once upon a time in the west";
// With asInstanceOf, we switch to specific String assertion by specifying the InstanceOfAssertFactory for String
assertThat(value).asInstanceOf(InstanceOfAssertFactories.STRING)
.startsWith("Once");`
see https://assertj.github.io/doc/#assertj-core-3.13.0-asInstanceOf
AssertJ v3.19.0 or newer: use satisfiesExactly.
AssertJ v3.19.0, released in 2021, has added a satisfiesExactly method.
So you can write:
assertThat(mylist)
.satisfiesExactly(item1 -> assertThat(item1).contains("15"),
item2 -> assertThat(item2).contains("217"));
You can add more assertions to individual elements if need be:
assertThat(mylist)
.satisfiesExactly(item1 -> assertThat(item1)
.contains("08")
.contains("15"),
item2 -> assertThat(item2).contains("217"));
In comparison to the technique that uses a next() chain, this one also checks the list size for you. As an added benefit, it lets you use whatever lambda parameter you like, so it’s easier to read and to keep track of which element you’re in.
You can use anyMatch
assertThat(mylist)
.anyMatch(item -> item.contains("15"))
.anyMatch(item -> item.contains("217"))
but unfortunately the failure message cannot tell you internals about the expectations
Expecting any elements of:
<["Abcd15", "218"]>
to match given predicate but none did.
The closest I've found is to write a "ContainsSubstring" condition, and a static method to create one, and use
assertThat(list).has(containsSubstring("15", atIndex(0)))
.has(containsSubstring("217", atIndex(1)));
But maybe you should simply write a loop:
List<String> list = ...;
List<String> expectedSubstrings = Arrays.asList("15", "217");
for (int i = 0; i < list.size(); i++) {
assertThat(list.get(i)).contains(expectedSubstrings.get(i));
}
Or to write a parameterized test, so that each element is tested on each substring by JUnit itself.
You can do the following:
List<String> list1 = Arrays.asList("Abcd15", "217aB");
List<String> list2 = Arrays.asList("Abcd15", "218");
Comparator<String> containingSubstring = (o1, o2) -> o1.contains(o2) ? 0 : 1;
assertThat(list1).usingElementComparator(containingSubstring).contains("15", "217"); // passes
assertThat(list2).usingElementComparator(containingSubstring).contains("15", "217"); // fails
The error it gives is:
java.lang.AssertionError:
Expecting:
<["Abcd15", "218"]>
to contain:
<["15", "217"]>
but could not find:
<["217"]>
In fact, you must implements your own Condition in assertj for checking the collection containing the substrings in order. for example:
assertThat(items).has(containsExactly(
stream(subItems).map(it -> containsSubstring(it)).toArray(Condition[]::new)
));
What's approach did I choose to meet your requirements? write a contract test case, and then implements the feature that the assertj doesn't given, here is my test case for the hamcrest contains(containsString(...)) adapt to assertj containsExactly as below:
import org.assertj.core.api.Assertions;
import org.assertj.core.api.Condition;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Collection;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
#RunWith(Parameterized.class)
public class MatchersTest {
private final SubstringExpectation expectation;
public MatchersTest(SubstringExpectation expectation) {
this.expectation = expectation;
}
#Parameters
public static List<SubstringExpectation> parameters() {
return asList(MatchersTest::hamcrest, MatchersTest::assertj);
}
private static void assertj(Collection<? extends String> items, String... subItems) {
Assertions.assertThat(items).has(containsExactly(stream(subItems).map(it -> containsSubstring(it)).toArray(Condition[]::new)));
}
private static Condition<String> containsSubstring(String substring) {
return new Condition<>(s -> s.contains(substring), "contains substring: \"%s\"", substring);
}
#SuppressWarnings("unchecked")
private static <C extends Condition<? super T>, T extends Iterable<? extends E>, E> C containsExactly(Condition<E>... conditions) {
return (C) new Condition<T>("contains exactly:" + stream(conditions).map(it -> it.toString()).collect(toList())) {
#Override
public boolean matches(T items) {
int size = 0;
for (E item : items) {
if (!matches(item, size++)) return false;
}
return size == conditions.length;
}
private boolean matches(E item, int i) {
return i < conditions.length && conditions[i].matches(item);
}
};
}
private static void hamcrest(Collection<? extends String> items, String... subItems) {
assertThat(items, contains(stream(subItems).map(Matchers::containsString).collect(toList())));
}
#Test
public void matchAll() {
expectation.checking(asList("foo", "bar"), "foo", "bar");
}
#Test
public void matchAllContainingSubSequence() {
expectation.checking(asList("foo", "bar"), "fo", "ba");
}
#Test
public void matchPartlyContainingSubSequence() {
try {
expectation.checking(asList("foo", "bar"), "fo");
fail();
} catch (AssertionError expected) {
assertThat(expected.getMessage(), containsString("\"bar\""));
}
}
#Test
public void matchAgainstWithManySubstrings() {
try {
expectation.checking(asList("foo", "bar"), "fo", "ba", "<many>");
fail();
} catch (AssertionError expected) {
assertThat(expected.getMessage(), containsString("<many>"));
}
}
private void fail() {
throw new IllegalStateException("should failed");
}
interface SubstringExpectation {
void checking(Collection<? extends String> items, String... subItems);
}
}
However, you down to use chained Conditions rather than the assertj fluent api, so I suggest you to try use the hamcrest instead. in other words, if you use this style in assertj you must write many Conditions or adapt hamcrest Matchers to assertj Condition.

How do I mock an Event Handler?

I wrote an event handler for Stash to send out messages via a messaging bus architecture. Here's an example of one from my fedmsgEventListener class:
#EventListener
public void opened(PullRequestOpenedEvent event)
{
HashMap<String, Object> message = prExtracter(event);
String originProjectKey = ((HashMap<String, Object>)message.get("source")).get("project_key").toString();
String originRepo = ((HashMap<String, Object>)message.get("source")).get("repository").toString();
String topic = originProjectKey + "." + originRepo + ".pullrequest.opened";
sendMessage(topic, message);
}
It gets an event, extracts information out of it, constructs a topic based on the information in the event, and invokes a method to send the message. I need to write unit tests for all of these event handlers.
Here is the class that runs the first test I am attempting to implement:
import org.junit.Test;
import com.cray.stash.MyPluginComponent;
import com.cray.stash.MyPluginComponentImpl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class MyComponentUnitTest
{
#Test
public void testMyName()
{
MyPluginComponent component = new MyPluginComponentImpl(null);
assertTrue(component.openPullRequest().contains(".pullrequest.opened"));
}
}
and then here is the class and method that the test calls:
import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.stash.event.pull.*;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
public class MyPluginComponentImpl implements MyPluginComponent
{
#Mock private PullRequestEvent event;
#Mock private PullRequestOpenedEvent opened;
#Mock private FedmsgEventListener fedmsgEventListener;
public MyPluginComponentImpl(ApplicationProperties applicationProperties)
{
this.applicationProperties = applicationProperties;
}
public String openPullRequest()
{
fedmsgEventListener.opened(opened);
return fedmsgEventListener.getTopic();
}
}
As of now, the method throws a NullPointerException because the fedmsgEventListener and the PullRequestEvent are both mocked objects and therefore null.
Is this the best way to go about unit testing this scenario? From a high level, this is all I want to do: trigger the event, see that the topic got changed to a string including a certain string.
You are using Mockito completely wrong. Sorry. First of all, #Mock doesn't work without using initMocks or MockitoJUnitRunner, but I wouldn't do it that way anyway. A mock is not null; you should be able to call methods on mocks; in your case you didn't initialize / create the mocks and that's why they were null.
First, identify the class you're trying to test. It looks like it's FedmsgEventListener here. Then, interact with a real instance of that class using mock objects and data structures instead of real objects that have dependencies and so forth. Note, I am using Hamcrest 1.3 here.
A mocking based test is built up in three phases:
Create - Create your mocks, and then state that "when" an interaction with that mock occurs, do something.
Interact - Interact with your objects in the way you're trying to test.
Verify - Use Mockito.verify and JUnit/Hamcrest assert methods to ensure that things worked the way you expected.
You might do something like this:
import static org.mockito.Mockito.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
private HashMap<String, Object> createMessageDetails(String project_key, String repository) {
HashMap<String, Object> details = new HashMap<>();
details.put("project_key", project_key);
details.put("repository", repository);
return details;
}
public class FedmsgEventListenerTest {
#Test
public void testOpened() {
// when
PullRequestOpenedEvent event = mock(PullRequestOpenedEvent.class);
when(event.someMethodForPrExtracterYouHaventShownMe()).thenReturn(createMessageDetails("myKey", "myRepo"));
// then
FedmsgEventListener listener = new FedmsgEventListener();
listener.opened(event);
// verify
assertThat(event.getTopic(), containsString(".pullrequest.opened"));
verify(event).someMethodForPrExtracterYouHaventShownMe();
}
}
This code is probably not exactly what you need, but you haven't shown me enough of the code you're trying to test for me to get it exactly right. However, I think this should be enough to get you started.
As an aside, if you aren't able to create a real instance of your class with mocked dependencies, then that is a code smell and your code should be refactored. This is one reason why statics are such a bad idea, because if your code is accessing global state via statics then you have to set up the global state with your statics. Make your class able to work with mock dependencies, pass them as arguments to the constructor, specify the mock behavior with when, and then assert / verify the results.

Compose multiple promises into one promise PlayFramework 2.4

I am trying to learn the Play Framework 2.4. I am trying to get the time it takes to access different webpages asynchronously using Promise. Below is the code for that:
final long start = System.currentTimeMillis();
F.Function<WSResponse,Long> timing = new F.Function<WSResponse, Long>() {
#Override
public Long apply(WSResponse wsResponse) throws Throwable {
return System.currentTimeMillis()-start;
}
};
F.Promise<Long> google = ws.url("http://www.google.com").get().map(timing);
F.Promise<Long> yahoo = ws.url("http://www.yahoo.com").get().map(timing);
F.Promise<Long> bing = ws.url("http://www.bing.com").get().map(timing);
As you can see I am using the get function to get the requested pages and putting the result in a Future Promise. Then I convert/map it to long. What I am not able to do is how do I compose these three promises into one and once all of the three promises are redeemed convert/map it to json and return the result. In earlier versions of Play it could have been done by F.Promise.waitAll(google,yahoo,bing).map(...) however I am unable to do it in Play 2.4. Please advice
EDIT1: Based on the answer below i used sequence like below:
return F.Promise.sequence(google, yahoo, bing).map(new F.Function<List<Long>, Result>() {
#Override
public Result apply(List<Long> longs) throws Throwable {
Map<String, Long> data = new HashMap<String, Long>();
data.put("google", google.get());
data.put("yahoo", yahoo.get());
data.put("bing", bing.get());
return ok(Json.toJson(data));
}
});
However, i am getting error that google.get() method cannot be resolved and that Json cannot be applied. What am i missing here?
EDIT 2. The Json error was fixed by using return ok((JsonNode) Json.toJson((Writes<Object>) data)); However, i am still not able to resolve the earlier error that google.get() method cannot be resolved in the line data.put("google", google.get());
EDIT 3. It seems Play2.4 has no get() method which returns the value of a Promise once it has been redeemed. What should i use then?
waitAll has been replaced with F.Promise.sequence.
From the docs
public static <A> F.Promise<java.util.List<A>> sequence(java.lang.Iterable<F.Promise<A>> promises)
Combine the given promises into a single promise for the list of results. The sequencing operations are performed in the default ExecutionContext.
Parameters:
promises - The promises to combine
Returns:
A single promise whose methods act on the list of redeemed promises
Update
Regarding the second half of the question, you don't need to call .get() because the promises have already completed.
In fact, you can get rid of the individual promise variables and just pass them directly into the sequence. The resulting list will contain results in the same order (Google first, then Yahoo, then Bing, in this case).
The whole thing should look something like this:
package controllers;
import java.util.HashMap;
import java.util.Map;
import play.libs.F;
import play.libs.Json;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Results;
public class Application extends Controller {
public F.Promise<Result> index() {
final long start = System.currentTimeMillis();
final F.Function<WSResponse,Long> timing = response -> System.currentTimeMillis() - start;
return F.Promise.sequence(WS.url("http://www.google.com").get().map(timing),
WS.url("http://www.yahoo.com").get().map(timing),
WS.url("http://www.bing.com").get().map(timing))
.map(list -> {
Map<String, Long> data = new HashMap<>();
data.put("google", list.get(0));
data.put("yahoo", list.get(1));
data.put("bing", list.get(2));
return data;
})
.map(Json::toJson)
.map(Results::ok);
}
}
Finally, since Play 2.4 requires Java 8, this is a good opportunity to play around with lambdas!

Counting method invocations in Unit tests

What is the best way to count method invocations in a Unit Test. Do any of the testing frameworks allow that?
It sounds like you may want to be using the .expects(1) type methods that mock frameworks usually provide.
Using mockito, if you were testing a List and wanted to verify that clear was called 3 times and add was called at least once with these parameters you do the following:
List mock = mock(List.class);
someCodeThatInteractsWithMock();
verify(mock, times(3)).clear();
verify(mock, atLeastOnce()).add(anyObject());
Source - MockitoVsEasyMock
In Mockito you can do something like this:
YourService serviceMock = Mockito.mock(YourService.class);
// code using YourService
// details of all invocations including methods and arguments
Collection<Invocation> invocations = Mockito.mockingDetails(serviceMock).getInvocations();
// just a number of calls of any mock's methods
int numberOfCalls = invocations.size();
Given an example class "RoleRepository" with a single method "getRole(String user)" which would return a role.
Assuming you have declared this object as Mock or Spy and you want to check whether the method getRole(String) is called for once a time.
You would do something like: Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class RoleRepositoryTest {
#Spy
private RoleRepository roleRepository = new RoleRepository();
#Test
public void test() {
roleRepository.getRole("toto");
Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
}
public static class RoleRepository {
public String getRole(String user) {
return "MyRole";
}
}
}
You can count number of method invocation by using interface Answer in Mockito.
ConnectionPool mockedConnectionPool = mock(ConnectionPool.class);
final int[] counter = new int[1];
when(mockedConnectionPool.getConnection()).then(new Answer<Connection>() {
#Override
public Connection answer(InvocationOnMock invocation) throws Throwable {
counter[0]++;
return conn;
}
});
// some your code
assertTrue(counter[0] == 1);
Depending on what methods you want to count, you can create a test config, with a #Before advice matching your class / package / method:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MethodCounterAspect {
private int counter = 0 // or inject the Counter object into this aspect
#Pointcut( "execution( * com.sample.your.package.*.*(..) )" )
public void methodsToCount() {}
#Before("methodsToCount()")
public void execute() throws Throwable {
counter++; // or update the counter injected into this aspect..
}
// get the counter
}
You can use vanilla AspectJ or Spring AOP via above or XML configs if you find it easier.
You can create different pointcuts / aspect if you need to.
It sounds like you may want a test spy. See, for example, Mockito.spy().
You've got a few options
1) Add some special code which counts invocations in the function. It will work, but it's not a great solution.
2) After you run your unit tests, check the code coverage. Most coverage tools will count invocations but they are really designed for post-processing.
3) Use a profiler. A profiler will let you count how many times a function is invoked. This is a very manual process so it's not really designed for unit testing.
A better solution would be to check that output is what you expect rather than checking how it works internally.

Categories