/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package io.reactivex.internal.schedulers;
import static io.reactivex.Flowable.just;
import static io.reactivex.Flowable.merge;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.concurrent.Callable;
import org.junit.Test;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Scheduler;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.schedulers.TestScheduler;
import io.reactivex.subscribers.TestSubscriber;
public class SchedulerWhenTest {
@Test
public void testAsyncMaxConcurrent() {
TestScheduler tSched = new TestScheduler();
SchedulerWhen sched = maxConcurrentScheduler(tSched);
TestSubscriber<Long> tSub = TestSubscriber.create();
asyncWork(sched).subscribe(tSub);
tSub.assertValueCount(0);
tSched.advanceTimeBy(0, SECONDS);
tSub.assertValueCount(0);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(2);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(4);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(5);
tSub.assertComplete();
sched.dispose();
}
@Test
public void testAsyncDelaySubscription() {
final TestScheduler tSched = new TestScheduler();
SchedulerWhen sched = throttleScheduler(tSched);
TestSubscriber<Long> tSub = TestSubscriber.create();
asyncWork(sched).subscribe(tSub);
tSub.assertValueCount(0);
tSched.advanceTimeBy(0, SECONDS);
tSub.assertValueCount(0);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(1);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(1);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(2);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(2);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(3);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(3);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(4);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(4);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(5);
tSub.assertComplete();
sched.dispose();
}
@Test
public void testSyncMaxConcurrent() {
TestScheduler tSched = new TestScheduler();
SchedulerWhen sched = maxConcurrentScheduler(tSched);
TestSubscriber<Long> tSub = TestSubscriber.create();
syncWork(sched).subscribe(tSub);
tSub.assertValueCount(0);
tSched.advanceTimeBy(0, SECONDS);
// since all the work is synchronous nothing is blocked and its all done
tSub.assertValueCount(5);
tSub.assertComplete();
sched.dispose();
}
@Test
public void testSyncDelaySubscription() {
final TestScheduler tSched = new TestScheduler();
SchedulerWhen sched = throttleScheduler(tSched);
TestSubscriber<Long> tSub = TestSubscriber.create();
syncWork(sched).subscribe(tSub);
tSub.assertValueCount(0);
tSched.advanceTimeBy(0, SECONDS);
tSub.assertValueCount(1);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(2);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(3);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(4);
tSched.advanceTimeBy(1, SECONDS);
tSub.assertValueCount(5);
tSub.assertComplete();
sched.dispose();
}
private Flowable<Long> asyncWork(final Scheduler sched) {
return Flowable.range(1, 5).flatMap(new Function<Integer, Flowable<Long>>() {
@Override
public Flowable<Long> apply(Integer t) {
return Flowable.timer(1, SECONDS, sched);
}
});
}
private Flowable<Long> syncWork(final Scheduler sched) {
return Flowable.range(1, 5).flatMap(new Function<Integer, Flowable<Long>>() {
@Override
public Flowable<Long> apply(Integer t) {
return Flowable.defer(new Callable<Flowable<Long>>() {
@Override
public Flowable<Long> call() {
return Flowable.just(0l);
}
}).subscribeOn(sched);
}
});
}
private SchedulerWhen maxConcurrentScheduler(TestScheduler tSched) {
SchedulerWhen sched = new SchedulerWhen(new Function<Flowable<Flowable<Completable>>, Completable>() {
@Override
public Completable apply(Flowable<Flowable<Completable>> workerActions) {
Flowable<Completable> workers = workerActions.map(new Function<Flowable<Completable>, Completable>() {
@Override
public Completable apply(Flowable<Completable> actions) {
return Completable.concat(actions);
}
});
return Completable.merge(workers, 2);
}
}, tSched);
return sched;
}
private SchedulerWhen throttleScheduler(final TestScheduler tSched) {
SchedulerWhen sched = new SchedulerWhen(new Function<Flowable<Flowable<Completable>>, Completable>() {
@Override
public Completable apply(Flowable<Flowable<Completable>> workerActions) {
Flowable<Completable> workers = workerActions.map(new Function<Flowable<Completable>, Completable>() {
@Override
public Completable apply(Flowable<Completable> actions) {
return Completable.concat(actions);
}
});
return Completable.concat(workers.map(new Function<Completable, Completable>() {
@Override
public Completable apply(Completable worker) {
return worker.delay(1, SECONDS, tSched);
}
}));
}
}, tSched);
return sched;
}
@Test(timeout = 1000)
public void testRaceConditions() {
Scheduler comp = Schedulers.computation();
Scheduler limited = comp.when(new Function<Flowable<Flowable<Completable>>, Completable>() {
@Override
public Completable apply(Flowable<Flowable<Completable>> t) {
return Completable.merge(Flowable.merge(t, 10));
}
});
merge(just(just(1).subscribeOn(limited).observeOn(comp)).repeat(1000)).blockingSubscribe();
}
}