/** * 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()); } }