/** * 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.schedulers; import static org.junit.Assert.fail; import java.util.*; import java.util.concurrent.*; import org.junit.*; import io.reactivex.Scheduler.Worker; import io.reactivex.disposables.CompositeDisposable; public class SchedulerLifecycleTest { @Test public void testShutdown() throws InterruptedException { tryOutSchedulers(); System.out.println("testShutdown >> Giving time threads to spin-up"); Thread.sleep(500); Set<Thread> rxThreads = new HashSet<Thread>(); for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getName().startsWith("Rx")) { rxThreads.add(t); } } Schedulers.shutdown(); System.out.println("testShutdown >> Giving time to threads to stop"); Thread.sleep(500); StringBuilder b = new StringBuilder(); for (Thread t : rxThreads) { if (t.isAlive()) { b.append("Thread " + t + " failed to shutdown\r\n"); for (StackTraceElement ste : t.getStackTrace()) { b.append(" ").append(ste).append("\r\n"); } } } if (b.length() > 0) { System.out.print(b); System.out.println("testShutdown >> Restarting schedulers..."); Schedulers.start(); // restart them anyways fail("Rx Threads were still alive:\r\n" + b); } System.out.println("testShutdown >> Restarting schedulers..."); Schedulers.start(); tryOutSchedulers(); } private void tryOutSchedulers() throws InterruptedException { final CountDownLatch cdl = new CountDownLatch(4); final Runnable countAction = new Runnable() { @Override public void run() { cdl.countDown(); } }; CompositeDisposable csub = new CompositeDisposable(); try { Worker w1 = Schedulers.computation().createWorker(); csub.add(w1); w1.schedule(countAction); Worker w2 = Schedulers.io().createWorker(); csub.add(w2); w2.schedule(countAction); Worker w3 = Schedulers.newThread().createWorker(); csub.add(w3); w3.schedule(countAction); Worker w4 = Schedulers.single().createWorker(); csub.add(w4); w4.schedule(countAction); if (!cdl.await(3, TimeUnit.SECONDS)) { fail("countAction was not run by every worker"); } } finally { csub.dispose(); } } @Test public void testStartIdempotence() throws InterruptedException { tryOutSchedulers(); System.out.println("testStartIdempotence >> giving some time"); Thread.sleep(500); Set<Thread> rxThreadsBefore = new HashSet<Thread>(); for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getName().startsWith("Rx")) { rxThreadsBefore.add(t); System.out.println("testStartIdempotence >> " + t); } } System.out.println("testStartIdempotence >> trying to start again"); Schedulers.start(); System.out.println("testStartIdempotence >> giving some time again"); Thread.sleep(500); Set<Thread> rxThreadsAfter = new HashSet<Thread>(); for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getName().startsWith("Rx")) { rxThreadsAfter.add(t); System.out.println("testStartIdempotence >>>> " + t); } } // cached threads may get dropped between the two checks rxThreadsAfter.removeAll(rxThreadsBefore); Assert.assertTrue("Some new threads appeared: " + rxThreadsAfter, rxThreadsAfter.isEmpty()); } }