@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 testMergeAsync() { 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.take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testMergeAsync => 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 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 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); }
@Setup public void setup() { source = Single.just(1); flatmapped = source.flatMap( new Func1<Integer, Single<Integer>>() { @Override public Single<Integer> call(Integer t) { return Single.just(t); } }); flatmapped = source.flatMap( new Func1<Integer, Single<Integer>>() { @Override public Single<Integer> call(Integer t) { return source; } }); sourceObserveOn = source.observeOn(Schedulers.computation()); sourceSubscribeOn = source.subscribeOn(Schedulers.computation()); // ---------- scheduledExecutor = Executors.newScheduledThreadPool(1); Scheduler s = Schedulers.from(scheduledExecutor); sourceObserveOnScheduledExecutor = source.observeOn(s); sourceSubscribeOnScheduledExecutor = source.subscribeOn(s); // ---------- executor = Executors.newSingleThreadExecutor(); Scheduler se = Schedulers.from(executor); sourceObserveOnExecutor = source.observeOn(se); sourceSubscribeOnExecutor = source.subscribeOn(se); // -------- // Scheduler fj = Schedulers.from(ForkJoinPool.commonPool()); // sourceObserveOnFJ = source.observeOn(fj); // sourceSubscribeOnFJ = source.subscribeOn(fj); }
@Test public void testInterruptTerminalEventAwaitTimed() { TestSubscriber<Integer> ts = TestSubscriber.create(); final Thread t0 = Thread.currentThread(); Worker w = Schedulers.computation().createWorker(); try { w.schedule( new Action0() { @Override public void call() { t0.interrupt(); } }, 200, TimeUnit.MILLISECONDS); try { ts.awaitTerminalEvent(5, TimeUnit.SECONDS); fail("Did not interrupt wait!"); } catch (RuntimeException ex) { if (!(ex.getCause() instanceof InterruptedException)) { fail("The cause is not InterruptedException! " + ex.getCause()); } } } finally { w.unsubscribe(); } }
private HttpImageGetter continueBind(final TextView view, final String html, final Object id) { CharSequence encoded = HtmlUtils.encode(html, loading); if (containsImages(html)) rawHtmlCache.put(id, encoded); else { rawHtmlCache.remove(id); fullHtmlCache.put(id, encoded); return show(view, encoded); } if (TextUtils.isEmpty(encoded)) return hide(view); show(view, encoded); view.setTag(id); Observable.just(html) .subscribeOn(Schedulers.computation()) .map( new Func1<String, CharSequence>() { @Override public CharSequence call(String htmlString) { return HtmlUtils.encode(htmlString, HttpImageGetter.this); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new ObserverAdapter<CharSequence>() { @Override public void onNext(CharSequence htmlCharSequence) { fullHtmlCache.put(id, htmlCharSequence); if (id.equals(view.getTag())) { show(view, htmlCharSequence); } } }); return this; }
@Test public void testInterruptTerminalEventAwaitAndUnsubscribe() { TestSubscriber<Integer> ts = TestSubscriber.create(); final Thread t0 = Thread.currentThread(); Worker w = Schedulers.computation().createWorker(); try { w.schedule( new Action0() { @Override public void call() { t0.interrupt(); } }, 200, TimeUnit.MILLISECONDS); ts.awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS); if (!ts.isUnsubscribed()) { fail("Did not unsubscribe!"); } } finally { w.unsubscribe(); } }
private void fetchGitHubSearch(@NonNull final String searchString) { Preconditions.checkNotNull(searchString, "Search String cannot be null."); Log.d(TAG, "fetchGitHubSearch(" + searchString + ")"); if (requestMap.containsKey(searchString.hashCode()) && !requestMap.get(searchString.hashCode()).isUnsubscribed()) { Log.d(TAG, "Found an ongoing request for repository " + searchString); return; } final String uri = gitHubRepositorySearchStore.getUriForKey(searchString).toString(); Subscription subscription = createNetworkObservable(searchString) .subscribeOn(Schedulers.computation()) .map( (repositories) -> { final List<Integer> repositoryIds = new ArrayList<>(); for (GitHubRepository repository : repositories) { gitHubRepositoryStore.put(repository); repositoryIds.add(repository.getId()); } return new GitHubRepositorySearch(searchString, repositoryIds); }) .doOnCompleted(() -> completeRequest(uri)) .doOnError(doOnError(uri)) .subscribe( gitHubRepositorySearchStore::put, e -> Log.e( TAG, "Error fetching GitHub repository search for '" + searchString + "'", e)); requestMap.put(searchString.hashCode(), subscription); startRequest(uri); }
/** * Make sure we get a MissingBackpressureException propagated through when we have a fast temporal * (hot) producer. */ @Test public void testHotOperatorBackpressure() { TestSubscriber<String> ts = new TestSubscriber<String>(); Observable.timer(0, 1, TimeUnit.MICROSECONDS) .observeOn(Schedulers.computation()) .map( new Func1<Long, String>() { @Override public String call(Long t1) { System.out.println(t1); try { Thread.sleep(100); } catch (InterruptedException e) { } return t1 + " slow value"; } }) .subscribe(ts); ts.awaitTerminalEvent(); System.out.println("Errors: " + ts.getOnErrorEvents()); assertEquals(1, ts.getOnErrorEvents().size()); assertEquals(MissingBackpressureException.class, ts.getOnErrorEvents().get(0).getClass()); }
private Observable<Void> handleHystrixRequest(final HttpServerResponse<O> response) { writeHeaders(response); final Subject<Void, Void> subject = PublishSubject.create(); final MultipleAssignmentSubscription subscription = new MultipleAssignmentSubscription(); Subscription actionSubscription = Observable.timer(0, interval, TimeUnit.MILLISECONDS, Schedulers.computation()) .subscribe( new Action1<Long>() { @Override public void call(Long tick) { if (!response.getChannel().isOpen()) { subscription.unsubscribe(); return; } try { writeMetric(JsonMapper.toJson(metrics), response); } catch (Exception e) { subject.onError(e); } } }); subscription.set(actionSubscription); return subject; }
@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()); }
/** * Attempts to confirm that when pauses exist between events, the ScheduledObserver does not lose * or reorder any events since the scheduler will not block, but will be re-scheduled when it * receives new events after each pause. * * <p>This is non-deterministic in proving success, but if it ever fails (non-deterministically) * it is a sign of potential issues as thread-races and scheduling should not affect output. */ @Test public void testObserveOnOrderingConcurrency() { final AtomicInteger count = new AtomicInteger(); final int _multiple = 99; Observable.range(1, 10000) .map( new Func1<Integer, Integer>() { @Override public Integer call(Integer t1) { if (randomIntFrom0to100() > 98) { try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } return t1 * _multiple; } }) .observeOn(Schedulers.computation()) .toBlocking() .forEach( new Action1<Integer>() { @Override public void call(Integer t1) { assertEquals(count.incrementAndGet() * _multiple, t1.intValue()); assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); } }); }
/** Confirm that running on a ThreadPoolScheduler allows multiple threads but is still ordered. */ @Test public void testObserveOnWithThreadPoolScheduler() { final AtomicInteger count = new AtomicInteger(); final int _multiple = 99; Observable.range(1, 100000) .map( new Func1<Integer, Integer>() { @Override public Integer call(Integer t1) { return t1 * _multiple; } }) .observeOn(Schedulers.computation()) .toBlocking() .forEach( new Action1<Integer>() { @Override public void call(Integer t1) { assertEquals(count.incrementAndGet() * _multiple, t1.intValue()); assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); } }); }
@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 @SuppressWarnings("unchecked") public void testOrdering() throws InterruptedException { Observable<String> obs = Observable.just("one", null, "two", "three", "four"); Observer<String> observer = mock(Observer.class); InOrder inOrder = inOrder(observer); TestSubscriber<String> ts = new TestSubscriber<String>(observer); obs.observeOn(Schedulers.computation()).subscribe(ts); ts.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS); if (ts.getOnErrorEvents().size() > 0) { for (Throwable t : ts.getOnErrorEvents()) { t.printStackTrace(); } fail("failed with exception"); } inOrder.verify(observer, times(1)).onNext("one"); inOrder.verify(observer, times(1)).onNext(null); inOrder.verify(observer, times(1)).onNext("two"); inOrder.verify(observer, times(1)).onNext("three"); inOrder.verify(observer, times(1)).onNext("four"); inOrder.verify(observer, times(1)).onCompleted(); inOrder.verifyNoMoreInteractions(); }
/** https://github.com/ReactiveX/RxJava/issues/1147 */ @Test public void testRaceForTerminalState() { final List<Integer> expected = Arrays.asList(1); for (int i = 0; i < 100000; i++) { TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable.just(1).subscribeOn(Schedulers.computation()).cache().subscribe(ts); ts.awaitTerminalEvent(); ts.assertReceivedOnNext(expected); ts.assertTerminalEvent(); } }
@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()); } }
public static void main(String[] args) { Object signal = new Object(); synchronized (signal) { PublishSubject<String> subject = PublishSubject.create(); subject.subscribe( (letter) -> { System.out.println("Subscribe 1: " + letter); ThreadUtils.sleep(500); if (letter.equals("eta")) { synchronized (signal) { signal.notify(); } } }); Observable.from(DataGenerator.generateGreekAlphabet()) .subscribeOn(Schedulers.computation()) .subscribe( (letter) -> { subject.onNext(letter); }, (t) -> { subject.onError(t); }, () -> { System.out.println("Subscriber 1: Completed"); subject.onCompleted(); synchronized (signal) { signal.notify(); } }); ThreadUtils.wait(signal); subject.subscribe( (letter) -> { System.out.println("Subscribe 2: " + letter); }, (t) -> { subject.onError(t); }, () -> { System.out.println("Subscriber 2: Completed"); }); ThreadUtils.wait(signal); } System.exit(0); }
@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) (RxRingBuffer.SIZE * 2.1); AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); incrementingIntegers(c).observeOn(Schedulers.computation()).take(NUM).subscribe(ts); ts.awaitTerminalEvent(); ts.assertNoErrors(); System.out.println( "testObserveOn => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(NUM, ts.getOnNextEvents().size()); assertTrue(c.get() < RxRingBuffer.SIZE * 4); }
@Test(timeout = 2000) public void testFirehoseFailsAsExpected() { AtomicInteger c = new AtomicInteger(); TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); firehose(c).observeOn(Schedulers.computation()).map(SLOW_PASS_THRU).subscribe(ts); ts.awaitTerminalEvent(); System.out.println( "testFirehoseFailsAsExpected => Received: " + ts.getOnNextEvents().size() + " Emitted: " + c.get()); assertEquals(1, ts.getOnErrorEvents().size()); assertTrue(ts.getOnErrorEvents().get(0) instanceof MissingBackpressureException); }
private Observable<String> loadData() { // wait 3 seconds in background thread // then strings are observed on main thread return Observable.create( new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { SystemClock.sleep(3000); subscriber.onNext(new Date().toString()); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()); }
@Test public void testFlatMapTransformsMaxConcurrentNormal() { final int m = 2; final AtomicInteger subscriptionCount = new AtomicInteger(); Observable<Integer> onNext = compose( Observable.from(Arrays.asList(1, 2, 3)).observeOn(Schedulers.computation()), subscriptionCount, m) .subscribeOn(Schedulers.computation()); Observable<Integer> onCompleted = compose(Observable.from(Arrays.asList(4)), subscriptionCount, m) .subscribeOn(Schedulers.computation()); Observable<Integer> onError = Observable.from(Arrays.asList(5)); Observable<Integer> source = Observable.from(Arrays.asList(10, 20, 30)); @SuppressWarnings("unchecked") Observer<Object> o = mock(Observer.class); TestSubscriber<Object> ts = new TestSubscriber<Object>(o); source.flatMap(just(onNext), just(onError), just0(onCompleted), m).subscribe(ts); ts.awaitTerminalEvent(1, TimeUnit.SECONDS); ts.assertNoErrors(); ts.assertTerminalEvent(); verify(o, times(3)).onNext(1); verify(o, times(3)).onNext(2); verify(o, times(3)).onNext(3); verify(o).onNext(4); verify(o).onCompleted(); verify(o, never()).onNext(5); verify(o, never()).onError(any(Throwable.class)); }
@Test public void testOnErrorCutsAheadOfOnNext() { final PublishSubject<Long> subject = PublishSubject.create(); final AtomicLong counter = new AtomicLong(); TestSubscriber<Long> ts = new TestSubscriber<Long>( new Observer<Long>() { @Override public void onCompleted() {} @Override public void onError(Throwable e) {} @Override public void onNext(Long t) { // simulate slow consumer to force backpressure failure try { Thread.sleep(1); } catch (InterruptedException e) { } } }); subject.observeOn(Schedulers.computation()).subscribe(ts); // this will blow up with backpressure while (counter.get() < 102400) { subject.onNext(counter.get()); counter.incrementAndGet(); } ts.awaitTerminalEvent(); assertEquals(1, ts.getOnErrorEvents().size()); assertTrue(ts.getOnErrorEvents().get(0) instanceof MissingBackpressureException); // assert that the values are sequential, that cutting in didn't allow skipping some but // emitting others. // example [0, 1, 2] not [0, 1, 4] assertTrue( ts.getOnNextEvents().size() == ts.getOnNextEvents().get(ts.getOnNextEvents().size() - 1) + 1); // we should emit the error without emitting the full buffer size assertTrue(ts.getOnNextEvents().size() < RxRingBuffer.SIZE); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); a = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1); Observable.range(0, limit) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(integer -> a.add(integer.toString())); setListAdapter(a); getListView() .setOnScrollListener( new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) {} @Override public void onScroll( AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { t.setText( "f:" + firstVisibleItem + " vc:" + visibleItemCount + " tc:" + totalItemCount); if (totalItemCount >= limit && (firstVisibleItem > totalItemCount - 2 * visibleItemCount)) { int count = 2 * visibleItemCount; limit = totalItemCount + count; Observable.range(totalItemCount, count) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( integer -> { a.add(integer.toString()); t.append("+" + integer.toString()); }); } } }); }
@Test(timeout = 30000) public void flatMapRangeMixedAsyncLoop() { for (int i = 0; i < 2000; i++) { if (i % 10 == 0) { System.out.println("flatMapRangeAsyncLoop > " + i); } TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable.range(0, 1000) .flatMap( new Func1<Integer, Observable<Integer>>() { final Random rnd = new Random(); @Override public Observable<Integer> call(Integer t) { Observable<Integer> r = Observable.just(t); if (rnd.nextBoolean()) { r = r.asObservable(); } return r; } }) .observeOn(Schedulers.computation()) .subscribe(ts); ts.awaitTerminalEvent(2500, TimeUnit.MILLISECONDS); if (ts.getOnCompletedEvents().isEmpty()) { System.out.println(ts.getOnNextEvents().size()); } ts.assertTerminalEvent(); ts.assertNoErrors(); List<Integer> list = ts.getOnNextEvents(); if (list.size() < 1000) { Set<Integer> set = new HashSet<Integer>(list); for (int j = 0; j < 1000; j++) { if (!set.contains(j)) { System.out.println(j + " missing"); } } } assertEquals(1000, list.size()); } }
/** 进入APP倒计时 使用RxJava进行异步处理 每秒调用一次enterMain */ public void startTiming() { // 订阅事件,每秒判断一次是否进入APP,并刷新UI展示 Subscription subscription = Observable.interval(TIME_SECOND, TimeUnit.SECONDS) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( new Action1<Long>() { @Override public void call(Long aLong) { // aLong代表interval调用次数 enterApp(aLong); Log.d("test leak", aLong + ""); } }); // 将 订阅事件 加入 subscription集合(Set),用于与Activity生命周期绑定,onDestroy时解除事件注册 compositeSubscription.add(subscription); }
@Ignore // don't care for any reordering @Test(timeout = 10000) public void flatMapRangeAsyncLoop() { for (int i = 0; i < 2000; i++) { if (i % 10 == 0) { System.out.println("flatMapRangeAsyncLoop > " + i); } TestSubscriber<Integer> ts = new TestSubscriber<Integer>(); Observable.range(0, 1000) .flatMap( new Func1<Integer, Observable<Integer>>() { @Override public Observable<Integer> call(Integer t) { return Observable.just(t); } }) .observeOn(Schedulers.computation()) .subscribe(ts); ts.awaitTerminalEvent(2500, TimeUnit.MILLISECONDS); if (ts.getOnCompletedEvents().isEmpty()) { System.out.println(ts.getOnNextEvents().size()); } ts.assertTerminalEvent(); ts.assertNoErrors(); List<Integer> list = ts.getOnNextEvents(); assertEquals(1000, list.size()); boolean f = false; for (int j = 0; j < list.size(); j++) { if (list.get(j) != j) { System.out.println(j + " " + list.get(j)); f = true; } } if (f) { Assert.fail("Results are out of order!"); } } }
@Test(timeout = 10000) public void testOnBackpressureDrop() { long t = System.currentTimeMillis(); for (int i = 0; i < 100; i++) { // stop the test if we are getting close to the timeout because slow machines // may not get through 100 iterations if (System.currentTimeMillis() - t > TimeUnit.SECONDS.toMillis(9)) { break; } 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() .observeOn(Schedulers.computation()) .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()); } }