package io.kaif.mobile.view.daemon;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import android.test.AndroidTestCase;
import io.kaif.mobile.event.debate.CreateDebateFailedEvent;
import io.kaif.mobile.event.debate.CreateDebateSuccessEvent;
import io.kaif.mobile.event.debate.CreateLocalDebateEvent;
import io.kaif.mobile.model.Debate;
import io.kaif.mobile.model.DebateNode;
import io.kaif.mobile.model.LocalDebate;
import io.kaif.mobile.model.Vote;
import io.kaif.mobile.service.CommaSeparatedParam;
import io.kaif.mobile.service.DebateService;
import io.kaif.mobile.service.VoteService;
import io.kaif.mobile.test.ModelFixture;
import io.kaif.mobile.view.viewmodel.DebateViewModel;
import rx.Observable;
public class DebateDaemonTest extends AndroidTestCase implements ModelFixture {
@Mock
private VoteService mockVoteService;
@Mock
private DebateService mockDebateService;
private DebateDaemon daemon;
@Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
daemon = new DebateDaemon(mockDebateService, mockVoteService);
}
public void testListDebates() {
final String articleId = "aId";
DebateNode d111 = new DebateNode(debate(articleId, "d111", "d11", 3), emptyList());
DebateNode d11 = new DebateNode(debate(articleId, "d11", "d1", 2), singletonList(d111));
DebateNode d12 = new DebateNode(debate(articleId, "d12", "d1", 2), emptyList());
DebateNode d21 = new DebateNode(debate(articleId, "d21", "d2", 2), emptyList());
DebateNode d1 = new DebateNode(debate(articleId, "d1", null, 1), asList(d11, d12));
DebateNode d2 = new DebateNode(debate(articleId, "d2", null, 1), singletonList(d21));
DebateNode root = new DebateNode(null, asList(d1, d2));
when(mockDebateService.getDebateTree("aId")).thenReturn(Observable.just(root));
when(mockVoteService.listDebateVotes(CommaSeparatedParam.of(Arrays.asList("d1",
"d11",
"d111",
"d12",
"d2",
"d21")))).thenReturn(Observable.just(asList(upVote("d1"),
emptyVote("d111"),
downVote("d2"))));
final List<DebateViewModel> result = daemon.listDebates("aId").toBlocking().single();
final DebateViewModel firstDebate = result.get(0);
assertEquals("aId", firstDebate.getArticleId());
assertEquals("content", firstDebate.getContent());
assertNotNull(firstDebate.getCreateTime());
assertEquals("d1", firstDebate.getDebateId());
assertEquals("tester", firstDebate.getDebaterName());
assertEquals(0L, firstDebate.getDownVote());
assertNotNull(firstDebate.getLastUpdateTime());
assertEquals(1, firstDebate.getLevel());
assertNull(firstDebate.getParentDebateId());
assertEquals(0L, firstDebate.getUpVote());
assertEquals("programming", firstDebate.getZone());
assertEquals(Vote.VoteState.UP, firstDebate.getCurrentVoeState());
assertEquals(2, result.get(1).getLevel());
assertEquals("d1", result.get(1).getParentDebateId());
assertEquals(Vote.VoteState.EMPTY, result.get(2).getCurrentVoeState());
assertEquals(Vote.VoteState.DOWN, result.get(4).getCurrentVoeState());
}
public void testDebates() throws InterruptedException {
when(mockDebateService.debate(new DebateService.CreateDebateEntry("aId",
"pId",
"test"))).thenReturn(Observable.just(new Debate("aId",
"debateId",
"zone",
"pId",
1,
"test",
"fooName",
0L,
0L,
new Date(),
new Date())));
Future<CreateLocalDebateEvent> f1 = Future.create(daemon.getSubject(CreateLocalDebateEvent.class));
Future<CreateDebateSuccessEvent> f2 = Future.create(daemon.getSubject(CreateDebateSuccessEvent.class));
daemon.debate("aId", "pId", 1, "test");
LocalDebate localDebate = f1.await(3, TimeUnit.SECONDS).getLocalDebate();
assertNotNull(localDebate.getLocalDebateId());
assertEquals("aId", localDebate.getArticleId());
assertEquals("test", localDebate.getContent());
assertEquals(1, localDebate.getLevel());
assertEquals("pId", localDebate.getParentDebateId());
Debate debate = f2.await(3, TimeUnit.SECONDS).getDebate();
assertEquals("debateId", debate.getDebateId());
assertEquals("aId", debate.getArticleId());
assertEquals("zone", debate.getZone());
assertEquals("pId", debate.getParentDebateId());
assertEquals(1, debate.getLevel());
assertEquals("test", debate.getContent());
assertEquals("fooName", debate.getDebaterName());
assertEquals(0L, debate.getUpVote());
assertEquals(0L, debate.getDownVote());
}
public void testDebates_failed() throws InterruptedException {
when(mockDebateService.debate(new DebateService.CreateDebateEntry("aId",
"pId",
"test"))).thenReturn(Observable.error(new IOException("failed")));
Future<CreateLocalDebateEvent> f1 = Future.create(daemon.getSubject(CreateLocalDebateEvent.class));
Future<CreateDebateFailedEvent> f2 = Future.create(daemon.getSubject(CreateDebateFailedEvent.class));
daemon.debate("aId", "pId", 1, "test");
LocalDebate localDebate = f1.await(3, TimeUnit.SECONDS).getLocalDebate();
String localId = f2.await(3, TimeUnit.SECONDS).getLocalId();
assertEquals(localDebate.getLocalDebateId(), localId);
}
private static class Future<T> {
AtomicReference<T> ref;
CountDownLatch latch;
static <T> Future<T> create(Observable<T> observable) {
AtomicReference<T> ref = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
observable.subscribe(event -> {
ref.set(event);
latch.countDown();
});
return new Future<>(latch, ref);
}
public Future(CountDownLatch latch, AtomicReference<T> ref) {
this.latch = latch;
this.ref = ref;
}
public T await(long timeout, TimeUnit unit) throws InterruptedException {
if (latch.await(timeout, unit)) {
return ref.get();
}
return null;
}
}
}