Add UnitTest to ActorProxyImpl and JaCoCo (coverage tool) implementation (#67)

* Change from unwrapMethodResponse to deserialize, because the response from an actor method is not wrapped in "Data" object
Add Unit test for the ActorProxy class

* #24 Implement more testing to the ActorProxyImpl and refactor how we manage the errors with Mono
#20 Add the coverage tool JaCoCo, the rules are commented at this moment in order to allow to execute the examples at this moment, if we enable the rules, the compilation fails.

* Enable rules for unit test coverage with a minimum of 0 in order to allow the developers to success compile, the minimum should be set to .8 before the projects ends

* Use the unwrapMethodResponse of the serilizer in order to deserilize actor responses.

* Reverting ActorProxyImpl.java

There is not need to change ActorProxyImpl since the previous change to not wrap it with the "data" structure was incorrect.

Co-authored-by: Artur Souza <artursouza.ms@outlook.com>
This commit is contained in:
Juan Jose Herrera 2020-01-06 12:28:53 -06:00 committed by Artur Souza
parent c571ac6ba6
commit d4c467aec5
6 changed files with 402 additions and 38 deletions

View File

@ -53,7 +53,9 @@
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<skipITs>true</skipITs>
</properties>
<build>
<plugins>
<plugin>
@ -88,6 +90,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<skipITs>${skipITs}</skipITs>
</configuration>
<executions>
<execution>
<goals>
@ -97,6 +102,55 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>CLASS</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.00</minimum>
</limit>
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.00</minimum>
</limit>
</limits>
<excludes>
<exclude>io.dapr.utils.Constants</exclude>
</excludes>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -111,22 +111,7 @@ public class ActorId extends Object implements Comparable<ActorId> {
return new ActorId(id.toString());
}
/**
* Determines whether two specified actorIds have the same id.
*
* @param id1 The first actorId to compare, or null
* @param id2 The second actorId to compare, or null.
* @return true if the id is same for both objects; otherwise, false.
*/
private static boolean equals(ActorId id1, ActorId id2) {
if (id1 == null && id2 == null) {
return true;
} else if (id2 == null || id1 == null) {
return false;
} else {
return hasEqualContent(id1, id2);
}
}
/**
* Compares if two actors have the same content.

View File

@ -67,14 +67,14 @@ class ActorProxyImpl implements ActorProxy {
public <T> Mono<T> invokeActorMethod(String methodName, Object data, Class<T> clazz) {
try {
Mono<String> result = this.daprClient.invokeActorMethod(
actorType,
actorId.toString(),
methodName,
this.wrap(data));
actorType,
actorId.toString(),
methodName,
this.wrap(data));
return result
.filter(s -> (s != null) && (!s.isEmpty()))
.map(s -> unwrap(s, clazz));
.filter(s -> (s != null) && (!s.isEmpty()))
.map(s -> unwrap(s, clazz));
} catch (IOException e) {
return Mono.error(e);
}
@ -87,8 +87,8 @@ class ActorProxyImpl implements ActorProxy {
public <T> Mono<T> invokeActorMethod(String methodName, Class<T> clazz) {
Mono<String> result = this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, null);
return result
.filter(s -> (s != null) && (!s.isEmpty()))
.map(s -> unwrap(s, clazz));
.filter(s -> (s != null) && (!s.isEmpty()))
.map(s -> unwrap(s, clazz));
}
/**
@ -107,10 +107,10 @@ class ActorProxyImpl implements ActorProxy {
public Mono<Void> invokeActorMethod(String methodName, Object data) {
try {
Mono<String> result = this.daprClient.invokeActorMethod(
actorType,
actorId.toString(),
methodName,
this.wrap(data));
actorType,
actorId.toString(),
methodName,
this.wrap(data));
return result.then();
} catch (IOException e) {
return Mono.error(e);

View File

@ -46,7 +46,7 @@ public class ActorIdTest {
List<Wrapper> values = createEqualsTestValues();
for (Wrapper w : values) {
ActorId a1 = (ActorId) w.item1;
ActorId a2 = (ActorId) w.item2;
Object a2 = w.item2;
Assert.assertEquals(w.expectedResult, a1.equals(a2));
}
}
@ -65,6 +65,7 @@ public class ActorIdTest {
List<Wrapper> list = new ArrayList<Wrapper>();
list.add(new Wrapper(new ActorId("1"), null, false));
list.add(new Wrapper(new ActorId("1"), new ActorId("1"), true));
list.add(new Wrapper(new ActorId("1"), new Object(), false));
list.add(new Wrapper(new ActorId("1"), new ActorId("2"), false));
return list;

View File

@ -0,0 +1,54 @@
package io.dapr.actors.client;
import io.dapr.actors.ActorId;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
public class ActorProxyBuilderTest {
@Test(expected = IllegalArgumentException.class)
public void buildWithNullActorId() {
new ActorProxyBuilder()
.withActorId(null)
.withActorType("test")
.withPort(20)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void buildWithEmptyActorType() {
new ActorProxyBuilder()
.withActorId(new ActorId("100"))
.withActorType("")
.withPort(20)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void buildWithNullActorType() {
new ActorProxyBuilder()
.withActorId(new ActorId("100"))
.withActorType(null)
.withPort(20)
.build();
}
@Test()
public void build() {
ActorProxy actorProxy = new ActorProxyBuilder()
.withActorId(new ActorId("100"))
.withActorType("test")
.withPort(20)
.build();
Assert.assertNotNull(actorProxy);
Assert.assertEquals("test",actorProxy.getActorType());
Assert.assertEquals("100",actorProxy.getActorId().toString());
}
}

View File

@ -4,18 +4,288 @@ import io.dapr.actors.ActorId;
import io.dapr.actors.runtime.ActorStateSerializer;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import reactor.core.publisher.Mono;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ActorProxyImplTest {
@Test()
public void constructorActorProxyTest() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = (ActorProxyHttpAsyncClient)new ActorProxyClientBuilder().buildAsyncClient();
final ActorProxyImpl actorProxy= new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Assert.assertEquals(actorProxy.getActorId().toString(),"100");
Assert.assertEquals(actorProxy.getActorType(),"myActorType");
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
final ActorStateSerializer serializer = mock(ActorStateSerializer.class);
final ActorProxyImpl actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
serializer,
actorProxyAsyncClient);
Assert.assertEquals(actorProxy.getActorId().toString(), "100");
Assert.assertEquals(actorProxy.getActorType(), "myActorType");
}
@Test()
public void invokeActorMethodWithoutDataWithReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
.thenReturn(Mono.just("{\n" +
"\t\"data\": \"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"\n" +
"}"));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<MyData> result = actorProxy.invokeActorMethod("getData", MyData.class);
MyData myData = result.block();
Assert.assertNotNull(myData);
Assert.assertEquals("valueA", myData.getPropertyA());
Assert.assertEquals("valueB", myData.getPropertyB());
}
@Test()
public void invokeActorMethodWithoutDataWithEmptyReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
.thenReturn(Mono.just(""));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<MyData> result = actorProxy.invokeActorMethod("getData", MyData.class);
MyData myData = result.block();
Assert.assertNull(myData);
}
@Test(expected = RuntimeException.class)
public void invokeActorMethodWithIncorrectReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
.thenReturn(Mono.just("{test}"));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<MyData> result = actorProxy.invokeActorMethod("getData", MyData.class);
result.doOnSuccess(x ->
Assert.fail("Not exception was throw"))
.doOnError(Throwable::printStackTrace
).block();
}
@Test()
public void invokeActorMethodSavingDataWithReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.just("{\n" +
"\t\"data\": \"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"\n" +
"}"));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
Mono<MyData> result = actorProxy.invokeActorMethod("getData", saveData, MyData.class);
MyData myData = result.block();
Assert.assertNotNull(myData);
Assert.assertEquals("valueA", myData.getPropertyA());
Assert.assertEquals("valueB", myData.getPropertyB());
}
@Test(expected = RuntimeException.class)
public void invokeActorMethodSavingDataWithIncorrectReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.just("{test}"));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
Mono<MyData> result = actorProxy.invokeActorMethod("getData", saveData, MyData.class);
result.doOnSuccess(x ->
Assert.fail("Not exception was throw"))
.doOnError(Throwable::printStackTrace
).block();
}
@Test()
public void invokeActorMethodSavingDataWithEmptyReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.just(""));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
Mono<MyData> result = actorProxy.invokeActorMethod("getData", saveData, MyData.class);
MyData myData = result.block();
Assert.assertNull(myData);
}
@Test(expected = RuntimeException.class)
public void invokeActorMethodSavingDataWithIncorrectInputType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.just("{test}"));
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
saveData.setMyData(saveData);
Mono<MyData> result = actorProxy.invokeActorMethod("getData", saveData, MyData.class);
result.doOnSuccess(x ->
Assert.fail("Not exception was throw"))
.doOnError(Throwable::printStackTrace
).block();
}
@Test()
public void invokeActorMethodWithDataWithVoidReturnType() {
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.empty());
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<Void> result = actorProxy.invokeActorMethod("getData", saveData);
Void emptyResponse = result.block();
Assert.assertNull(emptyResponse);
}
@Test(expected = RuntimeException.class)
public void invokeActorMethodWithDataWithVoidIncorrectInputType() {
MyData saveData = new MyData();
saveData.setPropertyA("valueA");
saveData.setPropertyB("valueB");
saveData.setMyData(saveData);
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNotNull()))
.thenReturn(Mono.empty());
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<Void> result = actorProxy.invokeActorMethod("getData", saveData);
Void emptyResponse = result.doOnError(Throwable::printStackTrace).block();
Assert.assertNull(emptyResponse);
}
@Test()
public void invokeActorMethodWithoutDataWithVoidReturnType() {
final ActorProxyHttpAsyncClient actorProxyAsyncClient = mock(ActorProxyHttpAsyncClient.class);
when(actorProxyAsyncClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
.thenReturn(Mono.empty());
final ActorProxy actorProxy = new ActorProxyImpl(
"myActorType",
new ActorId("100"),
new ActorStateSerializer(),
actorProxyAsyncClient);
Mono<Void> result = actorProxy.invokeActorMethod("getData");
Void emptyResponse = result.block();
Assert.assertNull(emptyResponse);
}
static class MyData {
/// Gets or sets the value for PropertyA.
private String propertyA;
/// Gets or sets the value for PropertyB.
private String propertyB;
private MyData myData;
public String getPropertyB() {
return propertyB;
}
public void setPropertyB(String propertyB) {
this.propertyB = propertyB;
}
public String getPropertyA() {
return propertyA;
}
public void setPropertyA(String propertyA) {
this.propertyA = propertyA;
}
@Override
public String toString() {
return "MyData{" +
"propertyA='" + propertyA + '\'' +
", propertyB='" + propertyB + '\'' +
'}';
}
public MyData getMyData() {
return myData;
}
public void setMyData(MyData myData) {
this.myData = myData;
}
}
}