/**
* Copyright 2014 Netflix, Inc.
*
* 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 rx.internal.operators;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import rx.Observable;
import rx.Subscription;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.observers.TestSubscriber;
public class OperatorDoOnUnsubscribeTest {
@Test
public void testDoOnUnsubscribe() throws Exception {
int subCount = 3;
final CountDownLatch upperLatch = new CountDownLatch(subCount);
final CountDownLatch lowerLatch = new CountDownLatch(subCount);
final CountDownLatch onNextLatch = new CountDownLatch(subCount);
final AtomicInteger upperCount = new AtomicInteger();
final AtomicInteger lowerCount = new AtomicInteger();
Observable<Long> longs = Observable
// The stream needs to be infinite to ensure the stream does not terminate
// before it is unsubscribed
.interval(50, TimeUnit.MILLISECONDS)
.doOnUnsubscribe(new Action0() {
// Test that upper stream will be notified for un-subscription
// from a child subscriber
@Override
public void call() {
upperLatch.countDown();
upperCount.incrementAndGet();
}
})
.doOnNext(new Action1<Long>() {
@Override
public void call(Long aLong) {
// Ensure there is at least some onNext events before un-subscription happens
onNextLatch.countDown();
}
})
.doOnUnsubscribe(new Action0() {
// Test that lower stream will be notified for a direct un-subscription
@Override
public void call() {
lowerLatch.countDown();
lowerCount.incrementAndGet();
}
});
List<Subscription> subscriptions = new ArrayList<Subscription>();
List<TestSubscriber<Long>> subscribers = new ArrayList<TestSubscriber<Long>>();
for (int i = 0; i < subCount; ++i) {
TestSubscriber<Long> subscriber = new TestSubscriber<Long>();
subscriptions.add(longs.subscribe(subscriber));
subscribers.add(subscriber);
}
onNextLatch.await();
for (int i = 0; i < subCount; ++i) {
subscriptions.get(i).unsubscribe();
// Test that unsubscribe() method is not affected in any way
subscribers.get(i).assertUnsubscribed();
}
upperLatch.await();
lowerLatch.await();
assertEquals(String.format("There should exactly %d un-subscription events for upper stream", subCount), subCount, upperCount.get());
assertEquals(String.format("There should exactly %d un-subscription events for lower stream", subCount), subCount, lowerCount.get());
}
@Test
public void testDoOnUnSubscribeWorksWithRefCount() throws Exception {
int subCount = 3;
final CountDownLatch upperLatch = new CountDownLatch(1);
final CountDownLatch lowerLatch = new CountDownLatch(1);
final CountDownLatch onNextLatch = new CountDownLatch(subCount);
final AtomicInteger upperCount = new AtomicInteger();
final AtomicInteger lowerCount = new AtomicInteger();
Observable<Long> longs = Observable
// The stream needs to be infinite to ensure the stream does not terminate
// before it is unsubscribed
.interval(50, TimeUnit.MILLISECONDS)
.doOnUnsubscribe(new Action0() {
// Test that upper stream will be notified for un-subscription
@Override
public void call() {
upperLatch.countDown();
upperCount.incrementAndGet();
}
})
.doOnNext(new Action1<Long>() {
@Override
public void call(Long aLong) {
// Ensure there is at least some onNext events before un-subscription happens
onNextLatch.countDown();
}
})
.doOnUnsubscribe(new Action0() {
// Test that lower stream will be notified for un-subscription
@Override
public void call() {
lowerLatch.countDown();
lowerCount.incrementAndGet();
}
})
.publish()
.refCount();
List<Subscription> subscriptions = new ArrayList<Subscription>();
List<TestSubscriber<Long>> subscribers = new ArrayList<TestSubscriber<Long>>();
for (int i = 0; i < subCount; ++i) {
TestSubscriber<Long> subscriber = new TestSubscriber<Long>();
subscriptions.add(longs.subscribe(subscriber));
subscribers.add(subscriber);
}
onNextLatch.await();
for (int i = 0; i < subCount; ++i) {
subscriptions.get(i).unsubscribe();
// Test that unsubscribe() method is not affected in any way
subscribers.get(i).assertUnsubscribed();
}
upperLatch.await();
lowerLatch.await();
assertEquals("There should exactly 1 un-subscription events for upper stream", 1, upperCount.get());
assertEquals("There should exactly 1 un-subscription events for lower stream", 1, lowerCount.get());
}
}