|
28 | 28 | import java.util.ArrayList;
|
29 | 29 | import java.util.Arrays;
|
30 | 30 | import java.util.List;
|
31 |
| -import java.util.concurrent.CountDownLatch; |
32 |
| -import java.util.concurrent.TimeUnit; |
33 |
| -import java.util.concurrent.atomic.AtomicReference; |
| 31 | +import java.util.concurrent.*; |
| 32 | +import java.util.concurrent.atomic.*; |
34 | 33 |
|
35 | 34 | import org.junit.Test;
|
36 | 35 | import org.mockito.InOrder;
|
37 | 36 |
|
38 |
| -import rx.Observable; |
39 | 37 | import rx.Observable.OnSubscribe;
|
40 |
| -import rx.Observer; |
41 |
| -import rx.Subscriber; |
42 |
| -import rx.Subscription; |
| 38 | +import rx.*; |
| 39 | +import rx.functions.Func1; |
43 | 40 | import rx.internal.util.RxRingBuffer;
|
44 | 41 | import rx.observers.TestSubscriber;
|
45 | 42 | import rx.schedulers.Schedulers;
|
46 | 43 | import rx.schedulers.TestScheduler;
|
| 44 | +import rx.subjects.Subject; |
47 | 45 | import rx.subscriptions.BooleanSubscription;
|
48 | 46 |
|
49 | 47 | public class OperatorConcatTest {
|
@@ -485,11 +483,11 @@ public boolean isUnsubscribed() {
|
485 | 483 | private final T seed;
|
486 | 484 | private final int size;
|
487 | 485 |
|
488 |
| - public TestObservable(@SuppressWarnings("unchecked") T... values) { |
| 486 | + public TestObservable(T... values) { |
489 | 487 | this(null, null, values);
|
490 | 488 | }
|
491 | 489 |
|
492 |
| - public TestObservable(CountDownLatch once, CountDownLatch okToContinue, @SuppressWarnings("unchecked") T... values) { |
| 490 | + public TestObservable(CountDownLatch once, CountDownLatch okToContinue, T... values) { |
493 | 491 | this.values = Arrays.asList(values);
|
494 | 492 | this.size = this.values.size();
|
495 | 493 | this.once = once;
|
@@ -718,4 +716,54 @@ public void call(Subscriber<? super String> s) {
|
718 | 716 | ts.assertReceivedOnNext(Arrays.asList("hello", "hello"));
|
719 | 717 | }
|
720 | 718 |
|
| 719 | + @Test(timeout = 10000) |
| 720 | + public void testIssue2890NoStackoverflow() throws InterruptedException { |
| 721 | + final ExecutorService executor = Executors.newFixedThreadPool(2); |
| 722 | + final Scheduler sch = Schedulers.from(executor); |
| 723 | + |
| 724 | + Func1<Integer, Observable<Integer>> func = new Func1<Integer, Observable<Integer>>() { |
| 725 | + @Override |
| 726 | + public Observable<Integer> call(Integer t) { |
| 727 | + Observable<Integer> observable = Observable.just(t) |
| 728 | + .subscribeOn(sch) |
| 729 | + ; |
| 730 | + Subject<Integer, Integer> subject = BufferUntilSubscriber.create(); |
| 731 | + observable.subscribe(subject); |
| 732 | + return subject; |
| 733 | + } |
| 734 | + }; |
| 735 | + |
| 736 | + int n = 5000; |
| 737 | + final AtomicInteger counter = new AtomicInteger(); |
| 738 | + |
| 739 | + Observable.range(1, n).concatMap(func).subscribe(new Subscriber<Integer>() { |
| 740 | + @Override |
| 741 | + public void onNext(Integer t) { |
| 742 | + // Consume after sleep for 1 ms |
| 743 | + try { |
| 744 | + Thread.sleep(1); |
| 745 | + } catch (InterruptedException e) { |
| 746 | + // ignored |
| 747 | + } |
| 748 | + if (counter.getAndIncrement() % 100 == 0) { |
| 749 | + System.out.print("testIssue2890NoStackoverflow -> "); |
| 750 | + System.out.println(counter.get()); |
| 751 | + }; |
| 752 | + } |
| 753 | + |
| 754 | + @Override |
| 755 | + public void onCompleted() { |
| 756 | + executor.shutdown(); |
| 757 | + } |
| 758 | + |
| 759 | + @Override |
| 760 | + public void onError(Throwable e) { |
| 761 | + executor.shutdown(); |
| 762 | + } |
| 763 | + }); |
| 764 | + |
| 765 | + executor.awaitTermination(12000, TimeUnit.MILLISECONDS); |
| 766 | + |
| 767 | + assertEquals(n, counter.get()); |
| 768 | + } |
721 | 769 | }
|
0 commit comments