/* * Copyright (C) 2015 The Android Open Source Project * * 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 Lice`nse 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 androidx.test.rule; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.runner.JUnitCore.runClasses; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.SystemClock; import androidx.annotation.NonNull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.Result; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @LargeTest public class ServiceTestRuleTest { public static class TestService extends Service { private final IBinder binder = new Binder(); @Override public IBinder onBind(Intent intent) { return binder; } } public static class ServiceThatCantBeBoundTo extends Service { @Override public IBinder onBind(Intent intent) { // returns null so clients can not bind to the service return null; } } public static class ServiceThatIsNotDefinedInManifest extends Service { // This service is not declared in the manifest on purpose @Override public IBinder onBind(Intent intent) { // returns null so clients can not bind to the service return null; } } public static class TimeoutService extends Service { @Override public IBinder onBind(Intent intent) { SystemClock.sleep(100); return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { SystemClock.sleep(100); return super.onStartCommand(intent, flags, startId); } } public static class StartedServiceLifecycleTest { private static StringBuilder log = new StringBuilder(); @Rule public final ServiceTestRule serviceRule = new ServiceTestRule() { @Override public void beforeService() { log.append("beforeService "); } @Override public void startService(@NonNull Intent intent) throws TimeoutException { log.append("startService "); } @Override public IBinder bindService(@NonNull Intent intent) throws TimeoutException { log.append("bindService "); return null; } @Override public void afterService() { log.append("afterService "); } @Override void shutdownService() throws TimeoutException { log.append("shutdownService "); } }; @Before public void before() { log.append("before "); } @After public void after() { log.append("after "); } @Test public void dummyTestToLaunchService() throws TimeoutException { log.append("test "); serviceRule.startService(new Intent()); fail("This is a dummy test to start a service"); } } @Test public void checkLifecycleOfStartedService() { Result result = runClasses(StartedServiceLifecycleTest.class); assertEquals(1, result.getFailureCount()); assertThat( result.getFailures().get(0).getMessage(), is("This is a dummy test to start a service")); assertThat( StartedServiceLifecycleTest.log.toString(), is("beforeService before test startService after shutdownService afterService ")); } public static class BoundServiceLifecycleTest { private static StringBuilder log = new StringBuilder(); @Rule public final ServiceTestRule serviceRule = new ServiceTestRule() { @Override public void beforeService() { log.append("beforeService "); } @Override public void startService(@NonNull Intent intent) throws TimeoutException { log.append("startService "); } @Override public IBinder bindService(@NonNull Intent intent) throws TimeoutException { log.append("bindService "); return null; } @Override public void afterService() { log.append("afterService "); } @Override public void shutdownService() { log.append("shutdownService "); } }; @Before public void before() { log.append("before "); } @After public void after() { log.append("after "); } @Test public void dummyTestToLaunchService() throws TimeoutException { log.append("test "); serviceRule.bindService(new Intent()); fail("This is a dummy test to bind to a service"); } } @Test public void checkLifecycleOfBoundService() { Result result = runClasses(BoundServiceLifecycleTest.class); assertEquals(1, result.getFailureCount()); assertThat( result.getFailures().get(0).getMessage(), is("This is a dummy test to bind to a service")); assertThat( BoundServiceLifecycleTest.log.toString(), is("beforeService before test bindService after shutdownService afterService ")); } public static class TimedOutServiceTest { @Rule public final ServiceTestRule serviceRule = ServiceTestRule.withTimeout(50, TimeUnit.MILLISECONDS); @Rule public final ExpectedException thrown = ExpectedException.none(); @Test public void verifyStartServiceTimeout() throws TimeoutException { thrown.expect(TimeoutException.class); thrown.expectMessage("Waited for 50 MILLISECONDS, but service was never connected"); // TimeoutService takes >= 100 milliseconds to start. serviceRule.startService(new Intent(getApplicationContext(), TimeoutService.class)); } @Test public void verifyBindServiceTimeout() throws TimeoutException { thrown.expect(TimeoutException.class); thrown.expectMessage("Waited for 50 MILLISECONDS, but service was never connected"); // TimeoutService takes >= 100 milliseconds to bind. serviceRule.bindService(new Intent(getApplicationContext(), TimeoutService.class)); } } @Test public void checkServiceTimeoutLogic() { Result result = runClasses(TimedOutServiceTest.class); // since we're catching exception inside the test, nothing should report failure assertEquals(0, result.getFailureCount()); } @Rule public final ServiceTestRule serviceRule = new ServiceTestRule(); @Test public void verifySuccessfulServiceStart() throws TimeoutException { serviceRule.startService(new Intent(getApplicationContext(), TestService.class)); assertTrue("The service was not started", serviceRule.serviceStarted); assertTrue("The service was not bound", serviceRule.serviceBound); } @Test public void verifySuccessfulServiceBind() throws TimeoutException { serviceRule.bindService(new Intent(getApplicationContext(), TestService.class)); assertTrue("The service was not bound", serviceRule.serviceBound); assertFalse("The service started instead of bound", serviceRule.serviceStarted); } @Test public void serviceCanBeBoundTwice() throws TimeoutException { Intent intent = new Intent(getApplicationContext(), TestService.class); IBinder firstBinder = serviceRule.bindService(intent); assertNotNull("Service failed to bind 1/2", firstBinder); IBinder secondBinder = serviceRule.bindService(intent); assertNotNull("Service failed to bind 2/2", secondBinder); } @Test public void serviceCanBindAfterUnbind() throws TimeoutException { Intent intent = new Intent(getApplicationContext(), TestService.class); IBinder firstBinder = serviceRule.bindService(intent); assertNotNull("Service failed to bind 1/2", firstBinder); serviceRule.unbindService(); IBinder secondBinder = serviceRule.bindService(intent); assertNotNull("Service failed to bind 2/2", secondBinder); } @Test public void serviceThatCantBeBoundTo() { Intent intent = new Intent(getApplicationContext(), ServiceThatCantBeBoundTo.class); try { serviceRule.startService(intent); fail("TimeoutException was not thrown"); } catch (TimeoutException e) { // expected } } @Test public void serviceThatIsNotDefinedInManifest() throws TimeoutException { Intent intent = new Intent(getApplicationContext(), ServiceThatIsNotDefinedInManifest.class); assertFalse(serviceRule.bindServiceAndWait(intent, null, 123)); } }