@Test public void testObserveOnWithSlowConsumer() { int NUM = (int) (RxRingBuffer.SIZE * 0.2); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); incrementingIntegers(c) .observeOn(Schedulers.computation()) .map( new Func1<Integer, Integer>() { @Override public Integer call(Integer i) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return i; } }) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testObserveOnWithSlowConsumer => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(NUM, ts.getOnNextEvents().size()); assertTrue(c.get() < RxRingBuffer.SIZE * 2); }
@Test public void testZipAsync() { int NUM = (int) (RxRingBuffer.SIZE * 2.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable<Integer> zipped = Observable.zip( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation()), new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer t1, Integer t2) { return t1 + t2; } }); zipped.take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testZipAsync => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.getOnNextEvents().size()); assertTrue(c1.get() < RxRingBuffer.SIZE * 3); assertTrue(c2.get() < RxRingBuffer.SIZE * 3); }
@Test public void testZipSync() { int NUM = (int) (Observable.bufferSize() * 4.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); Observable<Integer> zipped = Observable.zip(incrementingIntegers(c1), incrementingIntegers(c2), (t1, t2) -> t1 + t2); zipped.take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testZipSync => Received: " + ts.valueCount() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.valueCount()); assertTrue(c1.get() < Observable.bufferSize() * 7); assertTrue(c2.get() < Observable.bufferSize() * 7); }
@Test public void testTakeFilterSkipChainAsync() { int NUM = (int) (Observable.bufferSize() * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); incrementingIntegers(c) .observeOn(Schedulers.computation()) .skip(10000) .filter(i -> i > 11000) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); // emit 10000 that are skipped // emit next 1000 that are filtered out // take NUM // so emitted is at least 10000+1000+NUM + extra for buffer size/threshold int expected = 10000 + 1000 + Observable.bufferSize() * 3 + Observable.bufferSize() / 2; System.out.println( "testTakeFilterSkipChain => Received: " + ts.valueCount() + " Emitted: " + c.get() + " Expected: " + expected); assertEquals(NUM, ts.valueCount()); assertTrue(c.get() < expected); }
@Test @Ignore // the test is non-deterministic and can't be made deterministic public void testFlatMapAsync() { int NUM = (int) (Observable.bufferSize() * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); incrementingIntegers(c) .subscribeOn(Schedulers.computation()) .flatMap( i -> incrementingIntegers(new AtomicInteger()) .take(10) .subscribeOn(Schedulers.computation())) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testFlatMapAsync => Received: " + ts.valueCount() + " Emitted: " + c.get() + " Size: " + Observable.bufferSize()); assertEquals(NUM, ts.valueCount()); // even though we only need 10, it will request at least Observable.bufferSize(), and then as it // drains keep requesting more // and then it will be non-deterministic when the take() causes the unsubscribe as it is // scheduled on 10 different schedulers (threads) // normally this number is ~250 but can get up to ~1200 when Observable.bufferSize() == 1024 assertTrue(c.get() <= Observable.bufferSize() * 2); }
@Test public void testMergeSync() { int NUM = (int) (RxRingBuffer.SIZE * 4.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable<Integer> merged = Observable.merge(incrementingIntegers(c1), incrementingIntegers(c2)); merged.take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println("Expected: " + NUM + " got: " + ts.getOnNextEvents().size()); System.out.println( "testMergeSync => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.getOnNextEvents().size()); // either one can starve the other, but neither should be capable of doing more than 5 batches // (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" // algoritms generally take a performance hit assertTrue(c1.get() < RxRingBuffer.SIZE * 5); assertTrue(c2.get() < RxRingBuffer.SIZE * 5); }
@Test public void testMergeAsyncThenObserveOnLoop() { for (int i = 0; i < 500; i++) { if (i % 10 == 0) { System.out.println("testMergeAsyncThenObserveOnLoop >> " + i); } // Verify there is no MissingBackpressureException int NUM = (int) (RxRingBuffer.SIZE * 4.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable<Integer> merged = Observable.merge( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); merged.observeOn(Schedulers.io()).take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testMergeAsyncThenObserveOn => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.getOnNextEvents().size()); } }
@Test public void testMergeAsyncThenObserveOn() { int NUM = (int) (RxRingBuffer.SIZE * 4.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable<Integer> merged = Observable.merge( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); merged.observeOn(Schedulers.newThread()).take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testMergeAsyncThenObserveOn => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.getOnNextEvents().size()); // either one can starve the other, but neither should be capable of doing more than 5 batches // (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" // algoritms generally take a performance hit // akarnokd => run this in a loop over 10k times and never saw values get as high as 7*SIZE, but // since observeOn delays the unsubscription non-deterministically, the test will remain // unreliable assertTrue(c1.get() < RxRingBuffer.SIZE * 7); assertTrue(c2.get() < RxRingBuffer.SIZE * 7); }
@Test public void testTakeWithErrorInObserver() { final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); Observable.just("1", "2", "three", "4") .take(3) .safeSubscribe( new Observer<String>() { @Override public void onComplete() { System.out.println("completed"); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); } @Override public void onNext(String v) { int num = Integer.parseInt(v); System.out.println(num); // doSomething(num); count.incrementAndGet(); } }); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } }
@Test public void testPublishLast() throws InterruptedException { final AtomicInteger count = new AtomicInteger(); ConnectableObservable<String> connectable = Observable.<String>create( observer -> { observer.onSubscribe(EmptySubscription.INSTANCE); count.incrementAndGet(); new Thread( () -> { observer.onNext("first"); observer.onNext("last"); observer.onComplete(); }) .start(); }) .takeLast(1) .publish(); // subscribe once final CountDownLatch latch = new CountDownLatch(1); connectable.subscribe( value -> { assertEquals("last", value); latch.countDown(); }); // subscribe twice connectable.subscribe(); Disposable subscription = connectable.connect(); assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); assertEquals(1, count.get()); subscription.dispose(); }
/** * The error from the user provided Observable is handled by the subscribe try/catch because this * is synchronous * * <p>Result: Passes */ @Test public void testCustomObservableWithErrorInObservableSynchronous() { final AtomicInteger count = new AtomicInteger(); final AtomicReference<Throwable> error = new AtomicReference<>(); // FIXME custom built??? Observable.just("1", "2") .concatWith(Observable.error(() -> new NumberFormatException())) .subscribe( new Observer<String>() { @Override public void onComplete() { System.out.println("completed"); } @Override public void onError(Throwable e) { error.set(e); System.out.println("error"); e.printStackTrace(); } @Override public void onNext(String v) { System.out.println(v); count.incrementAndGet(); } }); assertEquals(2, count.get()); assertNotNull(error.get()); if (!(error.get() instanceof NumberFormatException)) { fail("It should be a NumberFormatException"); } }
@Test public void testObserveOnWithSlowConsumer() { int NUM = (int) (Observable.bufferSize() * 0.2); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); incrementingIntegers(c) .observeOn(Schedulers.computation()) .map( i -> { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return i; }) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testObserveOnWithSlowConsumer => Received: " + ts.valueCount() + " Emitted: " + c.get()); assertEquals(NUM, ts.valueCount()); assertTrue(c.get() < Observable.bufferSize() * 2); }
@Test public void testOnStartCalledOnceViaUnsafeSubscribe() { final AtomicInteger c = new AtomicInteger(); Observable.just(1, 2, 3, 4) .take(2) .unsafeSubscribe( new Observer<Integer>() { @Override public void onStart() { c.incrementAndGet(); request(1); } @Override public void onComplete() {} @Override public void onError(Throwable e) {} @Override public void onNext(Integer t) { request(1); } }); assertEquals(1, c.get()); }
/** Handles size after put. */ private void onPut() { cnt.incrementAndGet(); int c; while ((c = cnt.get()) > max) { // Decrement count. if (cnt.compareAndSet(c, c - 1)) { try { K key = firstEntry().getKey(); V val; // Make sure that an element is removed. while ((val = super.remove(firstEntry().getKey())) == null) { // No-op. } assert val != null; GridInClosure2<K, V> lsnr = this.lsnr; // Listener notification. if (lsnr != null) lsnr.apply(key, val); } catch (NoSuchElementException e1) { e1.printStackTrace(); // Should never happen. assert false : "Internal error in grid bounded ordered set."; } } } }
/** * Poll evicted internal implementation. * * @return Evicted element. */ @Nullable private E pollEvictedInternal() { WindowHolder tup = ref.get(); AtomicInteger size = tup.size(); while (true) { int curSize = size.get(); if (curSize > maxSize) { if (size.compareAndSet(curSize, curSize - 1)) { E evt = pollInternal(tup.collection(), tup.set()); if (evt != null) return evt; else { // No actual events in queue, it means that other thread is just adding event. // return null as it is a concurrent add call. size.incrementAndGet(); return null; } } } else return null; } }
@Test(timeout = 2000) public void testOnBackpressureBuffer() { int NUM = (int) (RxRingBuffer.SIZE * 1.1); // > 1 so that take doesn't prevent buffer overflow AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); firehose(c) .takeWhile( new Func1<Integer, Boolean>() { @Override public Boolean call(Integer t1) { return t1 < 100000; } }) .onBackpressureBuffer() .observeOn(Schedulers.computation()) .map(SLOW_PASS_THRU) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testOnBackpressureBuffer => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(NUM, ts.getOnNextEvents().size()); // it buffers, so we should get the right value sequentially assertEquals(NUM - 1, ts.getOnNextEvents().get(NUM - 1).intValue()); }
@Test public void testNoBackpressureWithInitialValue() { final AtomicInteger count = new AtomicInteger(); Observable.range(1, 100) .scan( 0, new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer t1, Integer t2) { return t1 + t2; } }) .subscribe( new Observer<Integer>() { @Override public void onComplete() {} @Override public void onError(Throwable e) { fail(e.getMessage()); e.printStackTrace(); } @Override public void onNext(Integer t) { count.incrementAndGet(); } }); // we only expect to receive 101 as we'll receive all 100 + the initial value assertEquals(101, count.get()); }
public void newCharacter(CharacterEvent ce) { int oldChar2type; // Previous character not typed correctly - 1 point penalty if (ce.source == generator.get()) { oldChar2type = char2type.getAndSet(ce.character); // 接收随机字母 if (oldChar2type != -1) { score.decrementAndGet(); setScore(); } } // If character is extraneous - 1 point penalty // If character does not match - 1 point penalty else if (ce.source == typist.get()) { // 在此有个假设:即正在使用的该变量值不会被变更且程序代码完成时也是如此 // 所有已经被我们设定的具有特定值的变量就应当是那个值。 while (true) { oldChar2type = char2type.get(); // 获取上次已接收到的随机字母 if (oldChar2type != ce.character) { // ce.character是用户输入的字母,现在作比较 score.decrementAndGet(); break; } else if (char2type.compareAndSet(oldChar2type, -1)) { score.incrementAndGet(); break; } } setScore(); } }
@Test public void testFlatMapSync() { int NUM = (int) (RxRingBuffer.SIZE * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); incrementingIntegers(c) .flatMap( new Func1<Integer, Observable<Integer>>() { @Override public Observable<Integer> call(Integer i) { return incrementingIntegers(new AtomicInteger()).take(10); } }) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testFlatMapSync => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(NUM, ts.getOnNextEvents().size()); // expect less than 1 buffer since the flatMap is emitting 10 each time, so it is NUM/10 that // will be taken. assertTrue(c.get() < RxRingBuffer.SIZE); }
@Test(timeout = 10000) public void testOnBackpressureDropSynchronous() { for (int i = 0; i < 100; i++) { int NUM = (int) (RxRingBuffer.SIZE * 1.1); // > 1 so that take doesn't prevent buffer overflow AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); firehose(c).onBackpressureDrop().map(SLOW_PASS_THRU).take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); List<Integer> onNextEvents = ts.getOnNextEvents(); assertEquals(NUM, onNextEvents.size()); Integer lastEvent = onNextEvents.get(NUM - 1); System.out.println( "testOnBackpressureDrop => Received: " + onNextEvents.size() + " Emitted: " + c.get() + " Last value: " + lastEvent); // it drop, so we should get some number far higher than what would have sequentially // incremented assertTrue(NUM - 1 <= lastEvent.intValue()); } }
/** {@inheritDoc} */ @Override protected Collection<E> dequeue0(int cnt) { WindowHolder tup = ref.get(); AtomicInteger size = tup.size(); Collection<T> evts = tup.collection(); Collection<E> resCol = new ArrayList<>(cnt); while (true) { int curSize = size.get(); if (curSize > 0) { if (size.compareAndSet(curSize, curSize - 1)) { E res = pollInternal(evts, tup.set()); if (res != null) { resCol.add(res); if (resCol.size() >= cnt) return resCol; } else { size.incrementAndGet(); return resCol; } } } else return resCol; } }
@Test(timeout = 10000) public void testOnBackpressureDropWithAction() { for (int i = 0; i < 100; i++) { final AtomicInteger emitCount = new AtomicInteger(); final AtomicInteger dropCount = new AtomicInteger(); final AtomicInteger passCount = new AtomicInteger(); final int NUM = RxRingBuffer.SIZE * 3; // > 1 so that take doesn't prevent buffer overflow TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); firehose(emitCount) .onBackpressureDrop( new Action1<Integer>() { @Override public void call(Integer i) { dropCount.incrementAndGet(); } }) .doOnNext( new Action1<Integer>() { @Override public void call(Integer integer) { passCount.incrementAndGet(); } }) .observeOn(Schedulers.computation()) .map(SLOW_PASS_THRU) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); List<Integer> onNextEvents = ts.getOnNextEvents(); Integer lastEvent = onNextEvents.get(NUM - 1); System.out.println( testName.getMethodName() + " => Received: " + onNextEvents.size() + " Passed: " + passCount.get() + " Dropped: " + dropCount.get() + " Emitted: " + emitCount.get() + " Last value: " + lastEvent); assertEquals(NUM, onNextEvents.size()); // in reality, NUM < passCount assertTrue(NUM <= passCount.get()); // it drop, so we should get some number far higher than what would have sequentially // incremented assertTrue(NUM - 1 <= lastEvent.intValue()); assertTrue(0 < dropCount.get()); assertEquals(emitCount.get(), passCount.get() + dropCount.get()); } }
@Test public void testSubscribeOnScheduling() { // in a loop for repeating the concurrency in this to increase chance of failure for (int i = 0; i < 100; i++) { int NUM = (int) (RxRingBuffer.SIZE * 2.1); AtomicInteger c = new AtomicInteger(); ConcurrentLinkedQueue<Thread> threads = new ConcurrentLinkedQueue<Thread>(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); // observeOn is there to make it async and need backpressure incrementingIntegers(c, threads) .subscribeOn(Schedulers.computation()) .observeOn(Schedulers.computation()) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testSubscribeOnScheduling => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(NUM, ts.getOnNextEvents().size()); assertTrue(c.get() < RxRingBuffer.SIZE * 4); Thread first = null; for (Thread t : threads) { System.out.println("testSubscribeOnScheduling => thread: " + t); if (first == null) { first = t; } else { if (!first.equals(t)) { fail("Expected to see the same thread"); } } } System.out.println( "testSubscribeOnScheduling => Number of batch requests seen: " + threads.size()); assertTrue(threads.size() > 1); System.out.println( "-------------------------------------------------------------------------------------------"); } }
@Test public void testObserveOn() { int NUM = (int) (Observable.bufferSize() * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); incrementingIntegers(c).observeOn(Schedulers.computation()).take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println("testObserveOn => Received: " + ts.valueCount() + " Emitted: " + c.get()); assertEquals(NUM, ts.valueCount()); assertTrue(c.get() < Observable.bufferSize() * 4); }
/** * Tests that failover don't pick local node if it has been excluded from topology. * * @throws Exception If failed. */ @SuppressWarnings({"WaitNotInLoop", "UnconditionalWait", "unchecked"}) public void testFailoverTopology() throws Exception { try { Grid grid1 = startGrid(1); Grid grid2 = startGrid(2); assert grid1 != null; assert grid2 != null; grid1.compute().localDeployTask(JobTask.class, JobTask.class.getClassLoader()); try { GridComputeTaskFuture<String> fut; synchronized (mux) { fut = grid1.compute().execute(JobTask.class, null); mux.wait(); } stopAndCancelGrid(2); String res = fut.get(); info("Task result: " + res); } catch (GridException e) { info("Got unexpected grid exception: " + e); } info("Failed over: " + failCnt.get()); assert failCnt.get() == 1 : "Invalid fail over counter [expected=1, actual=" + failCnt.get() + ']'; } finally { stopGrid(1); // Stopping stopped instance just in case. stopGrid(2); } }
@Test public void testMergeAsync() { int NUM = (int) (Observable.bufferSize() * 4.1); AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); Observable<Integer> merged = Observable.merge( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); merged.take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testMergeAsync => Received: " + ts.valueCount() + " Emitted: " + c1.get() + " / " + c2.get()); assertEquals(NUM, ts.valueCount()); // either one can starve the other, but neither should be capable of doing more than 5 batches // (taking 4.1) // TODO is it possible to make this deterministic rather than one possibly starving the other? // benjchristensen => In general I'd say it's not worth trying to make it so, as "fair" // algoritms generally take a performance hit int max = Observable.bufferSize() * 7; assertTrue("" + c1.get() + " >= " + max, c1.get() < max); assertTrue("" + c2.get() + " >= " + max, c2.get() < max); }
/** @throws Exception If failed. */ @SuppressWarnings({"TooBroadScope"}) public void testAsyncListen() throws Exception { final String hello = "HELLO!"; final String bye = "BYE!"; final Ignite g = grid(0); final UUID locNodeId = g.cluster().localNode().id(); g.message() .remoteListen( null, new MessagingListenActor<String>() { @Override protected void receive(UUID nodeId, String rcvMsg) throws Throwable { if (hello.equals(rcvMsg)) { assertEquals(locNodeId, nodeId); assertEquals(hello, rcvMsg); stop(bye); } } }); final AtomicInteger cnt = new AtomicInteger(); g.message() .localListen( null, new P2<UUID, String>() { @Override public boolean apply(UUID nodeId, String msg) { if (msg.equals(bye)) cnt.incrementAndGet(); return true; } }); g.message().send(null, hello); GridTestUtils.waitForCondition( new GridAbsPredicate() { @Override public boolean apply() { return cnt.get() == g.cluster().nodes().size(); } }, 5000); assertEquals(cnt.get(), g.cluster().nodes().size()); }
@Test public void testTakeWhileToList() { final int expectedCount = 3; final AtomicInteger count = new AtomicInteger(); for (int i = 0; i < expectedCount; i++) { Observable.just(Boolean.TRUE, Boolean.FALSE) .takeWhile(v -> v) .toList() .doOnNext(booleans -> count.incrementAndGet()) .subscribe(); } assertEquals(expectedCount, count.get()); }
@Test(timeout = 10000) public void testOnBackpressureDropSynchronousWithAction() { for (int i = 0; i < 100; i++) { final AtomicInteger dropCount = new AtomicInteger(); int NUM = (int) (Observable.bufferSize() * 1.1); // > 1 so that take doesn't prevent buffer overflow AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<>(); firehose(c) .onBackpressureDrop(j -> dropCount.incrementAndGet()) .map(SLOW_PASS_THRU) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); List<Integer> onNextEvents = ts.values(); assertEquals(NUM, onNextEvents.size()); Integer lastEvent = onNextEvents.get(NUM - 1); System.out.println( "testOnBackpressureDrop => Received: " + onNextEvents.size() + " Dropped: " + dropCount.get() + " Emitted: " + c.get() + " Last value: " + lastEvent); // it drop, so we should get some number far higher than what would have sequentially // incremented assertTrue(NUM - 1 <= lastEvent.intValue()); // no drop in synchronous mode assertEquals(0, dropCount.get()); assertEquals(c.get(), onNextEvents.size()); } }
@Test public void testTakeFilterSkipChainAsync() { int NUM = (int) (RxRingBuffer.SIZE * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); incrementingIntegers(c) .observeOn(Schedulers.computation()) .skip(10000) .filter( new Func1<Integer, Boolean>() { @Override public Boolean call(Integer i) { return i > 11000; } }) .take(NUM) .subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); // emit 10000 that are skipped // emit next 1000 that are filtered out // take NUM // so emitted is at least 10000+1000+NUM + extra for buffer size/threshold int expected = 10000 + 1000 + RxRingBuffer.SIZE * 3 + RxRingBuffer.SIZE / 2; System.out.println( "testTakeFilterSkipChain => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get() + " Expected: " + expected); assertEquals(NUM, ts.getOnNextEvents().size()); assertTrue(c.get() < expected); }