diff --git a/janet/build.gradle b/janet/build.gradle index cfc4cc7..40569a5 100644 --- a/janet/build.gradle +++ b/janet/build.gradle @@ -1,5 +1,4 @@ apply plugin: 'java' -apply plugin: 'provided-base' apply plugin: 'maven' sourceCompatibility = 1.6 @@ -21,5 +20,8 @@ artifacts { } dependencies { - provided 'io.reactivex:rxjava:+' + compile 'io.reactivex:rxjava:1.1.1' + + testCompile 'junit:junit:4.12' + testCompile 'org.mockito:mockito-core:1.10.19' } diff --git a/janet/src/main/java/io/techery/janet/ActionPipe.java b/janet/src/main/java/io/techery/janet/ActionPipe.java index 9c7fb1c..0ad1dfb 100644 --- a/janet/src/main/java/io/techery/janet/ActionPipe.java +++ b/janet/src/main/java/io/techery/janet/ActionPipe.java @@ -160,7 +160,7 @@ public Observable> createObservable(final A action) { * * @param action prepared action to send */ - public Observable createActionObservable(A action) { + public Observable createObservableSuccess(A action) { return createObservable(action).compose(new ActionStateToActionTransformer()); } diff --git a/janet/src/main/java/io/techery/janet/Janet.java b/janet/src/main/java/io/techery/janet/Janet.java index 2ec2119..84b1418 100644 --- a/janet/src/main/java/io/techery/janet/Janet.java +++ b/janet/src/main/java/io/techery/janet/Janet.java @@ -118,7 +118,13 @@ private Observable> send(final A action) { @Override public void call() { doSend(action); } - })); + })) + .takeUntil(new Func1() { + @Override public Boolean call(ActionState actionState) { + return actionState.status == ActionState.Status.SUCCESS + || actionState.status == ActionState.Status.FAIL; + } + }); } private void doSend(A action) { diff --git a/janet/src/test/java/io/techery/janet/JanetTest.java b/janet/src/test/java/io/techery/janet/JanetTest.java new file mode 100644 index 0000000..22f6a69 --- /dev/null +++ b/janet/src/test/java/io/techery/janet/JanetTest.java @@ -0,0 +1,198 @@ +package io.techery.janet; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.List; + +import io.techery.janet.helper.ActionStateSubscriber; +import rx.functions.Action0; +import rx.observers.TestSubscriber; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +public class JanetTest { + + + private Janet janet; + private ActionService service; + private ActionPipe actionPipe; + + @Before + public void setup() throws JanetException { + service = spy(ActionService.class); + when(service.getSupportedAnnotationType()).thenReturn(MockAction.class); + doAnswer(new SuccessAnswer(service)).when(service).sendInternal(any(ActionHolder.class)); + janet = new Janet.Builder().addService(service).build(); + actionPipe = janet.createPipe(TestAction.class); + } + + @Test + public void createObservable() { + TestSubscriber> subscriber = new TestSubscriber>(); + actionPipe.createObservable(new TestAction()).subscribe(subscriber); + assertSubscriberWithStates(subscriber); + } + + @Test + public void sendWithObserve() { + TestSubscriber> subscriber = new TestSubscriber>(); + actionPipe.observe().subscribe(subscriber); + actionPipe.send(new TestAction()); + subscriber.unsubscribe(); + assertSubscriberWithStates(subscriber); + } + + @Test + public void sendWithObserveWithReplay() { + TestSubscriber> subscriber = new TestSubscriber>(); + actionPipe.observeWithReplay() + .subscribe(subscriber); + actionPipe.send(new TestAction()); + subscriber.unsubscribe(); + assertSubscriberWithStates(subscriber); + + subscriber = new TestSubscriber>(); + actionPipe.observeWithReplay().subscribe(subscriber); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + } + + @Test + public void createObservableSuccess() { + TestSubscriber subscriber = new TestSubscriber(); + TestAction action = new TestAction(); + actionPipe.createObservableSuccess(action).subscribe(subscriber); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + subscriber.assertValue(action); + } + + @Test + public void sendWithObserveSuccess() { + TestSubscriber subscriber = new TestSubscriber(); + TestAction action = new TestAction(); + actionPipe.observeSuccess().subscribe(subscriber); + actionPipe.send(action); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + subscriber.assertValue(action); + } + + @Test + public void sendWithObserveSuccessWithReplay() { + TestSubscriber subscriber = new TestSubscriber(); + TestAction action = new TestAction(); + actionPipe.observeSuccessWithReplay().subscribe(subscriber); + actionPipe.send(action); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + subscriber.assertValue(action); + + subscriber = new TestSubscriber(); + actionPipe.observeSuccessWithReplay() + .subscribe(subscriber); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + subscriber.assertValue(action); + } + + @Test + public void cancelAfterSend() { + final TestAction action = new TestAction(); + TestSubscriber> subscriber = new TestSubscriber>( + new ActionStateSubscriber() + .onStart(new Action0() { + @Override public void call() { + actionPipe.cancel(action); + } + })); + actionPipe.createObservable(action).subscribe(subscriber); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + } + + @Test + public void clearReplays() { + actionPipe.send(new TestAction()); + actionPipe.clearReplays(); + TestSubscriber> subscriber = new TestSubscriber>(); + actionPipe.observeWithReplay().subscribe(subscriber); + subscriber.unsubscribe(); + subscriber.assertNoErrors(); + subscriber.assertNoValues(); + subscriber.assertUnsubscribed(); + } + + @Test + public void statusFail() throws JanetException { + TestSubscriber> subscriber = new TestSubscriber>(); + doThrow(JanetException.class).when(service).sendInternal(any(ActionHolder.class)); + actionPipe.createObservable(new TestAction()).subscribe(subscriber); + subscriber.unsubscribe(); + assertSubscriberWithSingleValue(subscriber); + assertStatusCount(subscriber.getOnNextEvents(), ActionState.Status.FAIL, 1); + } + + + private static void assertSubscriberWithStates(TestSubscriber> subscriber) { + subscriber.assertNoErrors(); + subscriber.assertValueCount(4); + subscriber.assertUnsubscribed(); + List> values = subscriber.getOnNextEvents(); + assertStatusCount(values, ActionState.Status.START, 1); + assertStatusCount(values, ActionState.Status.PROGRESS, 2); + assertStatusCount(values, ActionState.Status.SUCCESS, 1); + } + + private static void assertSubscriberWithSingleValue(TestSubscriber subscriber) { + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertUnsubscribed(); + } + + private static void assertStatusCount(List> values, ActionState.Status status, int count) { + int i = 0; + for (ActionState state : values) { + if (status == state.status) { + i++; + } + } + if (i != count) { + throw new AssertionError("Number of events with status " + status + " differ; expected: " + count + ", actual: " + i); + } + } + + @MockAction + private static class TestAction {} + + @Target(TYPE) + @Retention(RUNTIME) + private @interface MockAction {} + + private static class SuccessAnswer implements Answer { + + private final ActionService service; + + private SuccessAnswer(ActionService service) {this.service = service;} + + @Override public Void answer(InvocationOnMock invocation) throws Throwable { + ActionHolder holder = (ActionHolder) invocation.getArguments()[0]; + service.callback.onStart(holder); + service.callback.onProgress(holder, 1); + service.callback.onProgress(holder, 99); + service.callback.onSuccess(holder); + return null; + } + } +}