package io.nextop.test.rx; import io.nextop.Id; import io.nextop.rx.RxManaged; import io.nextop.rx.RxManager; import junit.framework.TestCase; import rx.functions.Action1; import rx.functions.Func2; import rx.internal.util.SubscriptionList; import rx.subjects.BehaviorSubject; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class RxManagerTest extends TestCase { // TODO isSend peek, isSend more get/update // TODO isSend cache ejection public void testLifecycle() { final int[] callCount = {0}; final int[] startUpdateCount = {0}; final int[] stopUpdateCount = {0}; final int[] closeCount = {0}; class TestManaged extends RxManaged { TestManaged(Id id) { super(id); } @Override public void close() { ++closeCount[0]; } } class TestManager extends RxManager<TestManaged> { @Override protected TestManaged create(Id id) { return new TestManaged(id); } @Override protected void startUpdates(TestManaged m, final RxState state) { ++startUpdateCount[0]; state.sync(); } @Override protected void stopUpdates(Id id) { ++stopUpdateCount[0]; } } int n = 16; int d = 4; List<Id> ids = new ArrayList<Id>(n); for (int i = 0; i < n; ++i) { ids.add(Id.create()); } TestManager manager = new TestManager(); SubscriptionList subscriptions; subscriptions = new SubscriptionList(); for (Id id : ids) { for (int i = 0; i < d; ++i) { subscriptions.add(manager.get(id).subscribe(new Action1<RxManaged>() { @Override public void call(RxManaged m) { ++callCount[0]; } })); } } assertEquals(n, startUpdateCount[0]); assertEquals(0, stopUpdateCount[0]); assertEquals(d * n, callCount[0]); assertEquals(0, closeCount[0]); subscriptions.unsubscribe(); assertEquals(n, stopUpdateCount[0]); // because of the cache, none should be closed assertEquals(0, closeCount[0]); // subscribe again, check that the same managed objects are used subscriptions = new SubscriptionList(); for (Id id : ids) { for (int i = 0; i < d; ++i) { subscriptions.add(manager.get(id).subscribe(new Action1<RxManaged>() { @Override public void call(RxManaged m) { ++callCount[0]; } })); } } assertEquals(2 * n, startUpdateCount[0]); assertEquals(n, stopUpdateCount[0]); assertEquals(2 * d * n, callCount[0]); assertEquals(0, closeCount[0]); subscriptions.unsubscribe(); assertEquals(2 * n, stopUpdateCount[0]); // because of the cache, none should be closed assertEquals(0, closeCount[0]); manager.clear(); assertEquals(n, closeCount[0]); } public void testSync() { // isSend that notifications come after sync() final BehaviorSubject<Boolean> syncGate = BehaviorSubject.create(); final int[] callCount = {0}; class TestManager extends RxManager<RxManaged> { @Override protected RxManaged create(Id id) { return new RxManaged(id); } @Override protected void startUpdates(RxManaged m, final RxState state) { syncGate.subscribe(new Action1<Boolean>() { @Override public void call(Boolean sync) { if (sync) { state.sync(); } } }); } } int n = 16; List<Id> ids = new ArrayList<Id>(n); for (int i = 0; i < n; ++i) { ids.add(Id.create()); } TestManager manager = new TestManager(); for (Id id : ids) { manager.get(id).subscribe(new Action1<RxManaged>() { @Override public void call(RxManaged m) { ++callCount[0]; } }); } assertEquals(0, callCount[0]); syncGate.onNext(true); assertEquals(n, callCount[0]); } public void testUpdateClobber() { // isSend notifications on updates // when updates are dispatched inside of updates final BehaviorSubject<Boolean> syncGate = BehaviorSubject.create(); final int[] callCount = {0}; final int[] updateCount = {0}; class TestManager extends RxManager<RxManaged> { @Override protected RxManaged create(Id id) { return new RxManaged(id); } @Override protected void startUpdates(RxManaged m, final RxState state) { syncGate.subscribe(new Action1<Boolean>() { @Override public void call(Boolean sync) { if (sync) { state.sync(); } } }); } void updateOne(Id id) { update(id, new Func2<RxManaged, RxState, RxManaged>() { @Override public RxManaged call(RxManaged m, RxState state) { ++updateCount[0]; return null; } }); } } int n = 16; int d = 4; int r = 5; List<Id> ids = new ArrayList<Id>(n); for (int i = 0; i < n; ++i) { ids.add(Id.create()); } final TestManager manager = new TestManager(); for (final Id id : ids) { for (int i = 0; i < d; ++i) { final int[] rc = {r}; manager.get(id).subscribe(new Action1<RxManaged>() { @Override public void call(RxManaged m) { ++callCount[0]; if (0 < rc[0]) { --rc[0]; manager.updateOne(id); } } }); } } assertEquals(0, updateCount[0]); assertEquals(0, callCount[0]); syncGate.onNext(true); assertEquals(n * r * d, updateCount[0]); int c = 0; for (int i = 0; i < d; ++i) { // (i + 1) subscribers per id gets called 'r' times c += 1 + r * (i + 1); } c *= n; assertEquals(c, callCount[0]); } }