1 package com.android.server.location;
2 
3 import static com.google.common.truth.Truth.assertThat;
4 
5 import static org.mockito.Mockito.doReturn;
6 
7 import android.os.Looper;
8 import android.platform.test.annotations.Presubmit;
9 import android.util.NtpTrustedTime;
10 
11 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
12 import com.android.server.testing.FrameworkRobolectricTestRunner;
13 import com.android.server.testing.SystemLoaderPackages;
14 
15 import org.junit.Before;
16 import org.junit.Test;
17 import org.junit.runner.RunWith;
18 import org.mockito.Mock;
19 import org.mockito.MockitoAnnotations;
20 import org.robolectric.RuntimeEnvironment;
21 import org.robolectric.annotation.Config;
22 import org.robolectric.shadows.ShadowLooper;
23 import org.robolectric.shadows.ShadowSystemClock;
24 
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.TimeUnit;
27 
28 /**
29  * Unit tests for {@link NtpTimeHelper}.
30  */
31 @RunWith(FrameworkRobolectricTestRunner.class)
32 @Config(
33         manifest = Config.NONE,
34         sdk = 27
35 )
36 @SystemLoaderPackages({"com.android.server.location"})
37 @Presubmit
38 public class NtpTimeHelperTest {
39 
40     private static final long MOCK_NTP_TIME = 1519930775453L;
41     @Mock
42     private NtpTrustedTime mMockNtpTrustedTime;
43     private NtpTimeHelper mNtpTimeHelper;
44     private CountDownLatch mCountDownLatch;
45 
46     @Before
setUp()47     public void setUp() throws Exception {
48         MockitoAnnotations.initMocks(this);
49         mCountDownLatch = new CountDownLatch(1);
50         InjectNtpTimeCallback callback =
51                 (time, timeReference, uncertainty) -> {
52                     assertThat(time).isEqualTo(MOCK_NTP_TIME);
53                     mCountDownLatch.countDown();
54                 };
55         mNtpTimeHelper = new NtpTimeHelper(RuntimeEnvironment.application,
56                 Looper.myLooper(),
57                 callback, mMockNtpTrustedTime);
58     }
59 
60     @Test
handleInjectNtpTime_cachedAgeLow_injectTime()61     public void handleInjectNtpTime_cachedAgeLow_injectTime() throws InterruptedException {
62         doReturn(NtpTimeHelper.NTP_INTERVAL - 1).when(mMockNtpTrustedTime).getCacheAge();
63         doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime();
64 
65         mNtpTimeHelper.retrieveAndInjectNtpTime();
66 
67         waitForTasksToBePostedOnHandlerAndRunThem();
68         assertThat(mCountDownLatch.await(2, TimeUnit.SECONDS)).isTrue();
69     }
70 
71     @Test
handleInjectNtpTime_injectTimeFailed_injectTimeDelayed()72     public void handleInjectNtpTime_injectTimeFailed_injectTimeDelayed()
73             throws InterruptedException {
74         doReturn(NtpTimeHelper.NTP_INTERVAL + 1).when(mMockNtpTrustedTime).getCacheAge();
75         doReturn(false).when(mMockNtpTrustedTime).forceRefresh();
76 
77         mNtpTimeHelper.retrieveAndInjectNtpTime();
78         waitForTasksToBePostedOnHandlerAndRunThem();
79         assertThat(mCountDownLatch.await(2, TimeUnit.SECONDS)).isFalse();
80 
81         doReturn(true).when(mMockNtpTrustedTime).forceRefresh();
82         doReturn(1L).when(mMockNtpTrustedTime).getCacheAge();
83         doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime();
84         ShadowSystemClock.sleep(NtpTimeHelper.RETRY_INTERVAL);
85 
86         waitForTasksToBePostedOnHandlerAndRunThem();
87         assertThat(mCountDownLatch.await(2, TimeUnit.SECONDS)).isTrue();
88     }
89 
90     /**
91      * Since a thread is created in {@link NtpTimeHelper#retrieveAndInjectNtpTime} and the task to
92      * be verified is posted in the thread, we have to wait for the task to be posted and then it
93      * can be run.
94      */
waitForTasksToBePostedOnHandlerAndRunThem()95     private void waitForTasksToBePostedOnHandlerAndRunThem() throws InterruptedException {
96         mCountDownLatch.await(1, TimeUnit.SECONDS);
97         ShadowLooper.runUiThreadTasks();
98     }
99 }
100 
101