Increased test coverage for garagemode

Bug: 191187721
Test: run CarServiceTest with code coverage
Change-Id: I0da0cb3914c19e35fc3401525d071a7cec51fca0
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 81c8c10..fdf0c05 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -16,6 +16,8 @@
 
 package com.android.car.garagemode;
 
+import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.app.job.JobScheduler;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
@@ -28,6 +30,7 @@
 
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.utils.Slogf;
@@ -116,6 +119,7 @@
     /**
      * Prints Garage Mode's status, including what jobs it is waiting for
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     void dump(PrintWriter writer) {
         mGarageMode.dump(writer);
     }
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index f315dca..5936391 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -16,6 +16,8 @@
 
 package com.android.car.garagemode;
 
+import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.app.job.JobSnapshot;
@@ -30,6 +32,7 @@
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarStatsLogHelper;
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.power.CarPowerManagementService;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
@@ -242,6 +245,7 @@
         }
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     void dump(PrintWriter writer) {
         if (!mGarageModeActive) {
             return;
diff --git a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
index ca3598a..36e4361 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
@@ -24,16 +24,21 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.car.Car;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -42,6 +47,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.car.CarLocalServices;
+import com.android.car.R;
+import com.android.car.power.CarPowerManagementService;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserService;
 
@@ -219,4 +226,87 @@
         // Verify that worker that polls running jobs from JobScheduler is scheduled.
         verify(mHandlerMock).postDelayed(any(), eq(JOB_SNAPSHOT_INITIAL_UPDATE_MS));
     }
+
+    @Test
+    public void testInitAndRelease() {
+        CarPowerManagementService mockCarPowerManagementService =
+                mock(CarPowerManagementService.class);
+
+        GarageMode garageMode = mock(GarageMode.class);
+        Controller controller = new Controller(mContextMock, mLooperMock, mWakeupPolicy,
+                mHandlerMock, garageMode);
+        CarLocalServices.addService(CarPowerManagementService.class, mockCarPowerManagementService);
+
+        controller.init();
+        controller.release();
+
+        verify(garageMode).init();
+        verify(garageMode).release();
+    }
+
+    @Test
+    public void testConstructor() {
+        Resources resourcesMock = mock(Resources.class);
+        when(mContextMock.getResources()).thenReturn(resourcesMock);
+        when(resourcesMock.getStringArray(R.array.config_garageModeCadence))
+                .thenReturn(sTemplateWakeupSchedule);
+        Controller controller = new Controller(mContextMock, mLooperMock);
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testScheduleNextWakeup() {
+        GarageMode garageMode = mock(GarageMode.class);
+
+        // Enter GarageMode only 1 time, no wake up after that
+        WakeupPolicy wakeUpPolicy = new WakeupPolicy(new String[] { "15m,1" });
+
+        Controller controller = new Controller(mContextMock, mLooperMock, wakeUpPolicy,
+                mHandlerMock, garageMode);
+        controller.setCarPowerManager(mCarPowerManagerMock);
+
+        // Imitate entering and leavimg GarageMode
+        controller.initiateGarageMode(/* future= */ null);
+
+        controller.scheduleNextWakeup();
+
+        verify(mCarPowerManagerMock).scheduleNextWakeupTime(900);
+
+        // Imitate entering Garage mode after sleep
+        controller.initiateGarageMode(/* future= */ null);
+
+        // Should be no more calls to scheduleNextWakeupTime
+        controller.scheduleNextWakeup();
+
+        Mockito.verifyNoMoreInteractions(mCarPowerManagerMock);
+    }
+
+    @Test
+    public void testOnStateChanged() {
+        GarageMode garageMode = mock(GarageMode.class);
+
+        Controller controller = Mockito.spy(new Controller(mContextMock, mLooperMock, mWakeupPolicy,
+                mHandlerMock, garageMode));
+
+        controller.onStateChanged(CarPowerStateListener.SHUTDOWN_CANCELLED, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SHUTDOWN_ENTER, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SUSPEND_ENTER, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.INVALID , null);
+        verify(controller, never()).resetGarageMode();
+    }
+
 }
diff --git a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
index 6133baf..6183549 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -36,6 +37,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.car.CarLocalServices;
+import com.android.car.power.CarPowerManagementService;
 import com.android.car.user.CarUserService;
 
 import org.junit.After;
@@ -50,6 +52,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -131,6 +134,42 @@
                 105);
     }
 
+    @Test
+    public void garageModeTestExitImmediately() throws Exception {
+        CarPowerManagementService mockCarPowerManagementService =
+                mock(CarPowerManagementService.class);
+
+        // Mock CPMS to force Garage Mode early exit
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class, mockCarPowerManagementService);
+        when(mockCarPowerManagementService.garageModeShouldExitImmediately()).thenReturn(true);
+
+        // Check exit immediately without future
+        GarageMode garageMode = new GarageMode(mController);
+        garageMode.init();
+        garageMode.enterGarageMode(/* future= */ null);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+
+        // Create new instance of GarageMode
+        garageMode = new GarageMode(mController);
+        garageMode.init();
+        // Check exit immediately with future
+        CompletableFuture<Void> future = new CompletableFuture<>();
+        garageMode.enterGarageMode(future);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+        assertThat(future.isDone()).isTrue();
+
+        // Create new instance of GarageMode
+        garageMode = new GarageMode(mController);
+        garageMode.init();
+        // Check exit immediately with completed future
+        garageMode.enterGarageMode(future);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+        assertThat(future.isDone()).isTrue();
+
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+    }
+
     private void waitForHandlerThreadToFinish(CountDownLatch latch) throws Exception {
         assertWithMessage("Latch has timed out.")
                 .that(latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();