diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/ui/src/com/android/car/calendar/CarCalendarUiTest.java | 19 | ||||
-rw-r--r-- | tests/unit/src/com/android/car/calendar/common/EventsLiveDataTest.java | 223 |
2 files changed, 154 insertions, 88 deletions
diff --git a/tests/ui/src/com/android/car/calendar/CarCalendarUiTest.java b/tests/ui/src/com/android/car/calendar/CarCalendarUiTest.java index d342e3d..e591a80 100644 --- a/tests/ui/src/com/android/car/calendar/CarCalendarUiTest.java +++ b/tests/ui/src/com/android/car/calendar/CarCalendarUiTest.java @@ -98,6 +98,9 @@ public class CarCalendarUiTest { private List<Object[]> mTestEventRows; + // If set to true fake dependencies will not be set and the real provider will be used. + private boolean mDoNotSetFakeDependencies; + // These can be set in the test thread and read on the main thread. private volatile CountDownLatch mEventChangesLatch; @@ -105,9 +108,12 @@ public class CarCalendarUiTest { public void setUp() { ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleCallback); mTestEventRows = new ArrayList<>(); + mDoNotSetFakeDependencies = false; } private void onActivityLifecycleChanged(Activity activity, Stage stage) { + if (mDoNotSetFakeDependencies) return; + if (stage.equals(Stage.PRE_ON_CREATE)) { setActivityDependencies((CarCalendarActivity) activity); } else if (stage.equals(Stage.CREATED)) { @@ -156,9 +162,18 @@ public class CarCalendarUiTest { } @Test - public void calendar_titleShows() { + public void withFakeDependencies_titleShows() { try (ActivityScenario<CarCalendarActivity> ignored = - ActivityScenario.launch(CarCalendarActivity.class)) { + ActivityScenario.launch(CarCalendarActivity.class)) { + onView(withText(R.string.app_name)).check(matches(isDisplayed())); + } + } + + @Test + public void withoutFakeDependencies_titleShows() { + mDoNotSetFakeDependencies = true; + try (ActivityScenario<CarCalendarActivity> ignored = + ActivityScenario.launch(CarCalendarActivity.class)) { onView(withText(R.string.app_name)).check(matches(isDisplayed())); } } diff --git a/tests/unit/src/com/android/car/calendar/common/EventsLiveDataTest.java b/tests/unit/src/com/android/car/calendar/common/EventsLiveDataTest.java index ff00e8d..79b5e29 100644 --- a/tests/unit/src/com/android/car/calendar/common/EventsLiveDataTest.java +++ b/tests/unit/src/com/android/car/calendar/common/EventsLiveDataTest.java @@ -21,6 +21,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static java.time.temporal.ChronoUnit.HOURS; @@ -138,12 +140,11 @@ public class EventsLiveDataTest { @Test @UiThreadTest public void addObserver_queryMade() throws InterruptedException { - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); - mEventsLiveData.observeForever((value) -> latch.countDown()); + // Observing triggers content to be read. + mEventsLiveData.observeForever((unused) -> { /* Do nothing */ }); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + mTestContentProvider.awaitCalendarQuery(); assertThat(mTestContentProvider.mTestEventCursor).isNotNull(); } @@ -151,49 +152,63 @@ public class EventsLiveDataTest { @Test @UiThreadTest public void addObserver_contentObserved() throws InterruptedException { - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); - mEventsLiveData.observeForever((value) -> latch.countDown()); + // Observing triggers content to be read. + mEventsLiveData.observeForever((unused) -> { /* Do nothing */ }); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + mTestContentProvider.awaitCalendarQuery(); - assertThat(mTestContentProvider.mTestEventCursor.mLastContentObserver).isNotNull(); + awaitAndAssertDone(mTestContentProvider.mTestEventCursor.mRegisterContentObserverLatch); } @Test - @UiThreadTest - public void removeObserver_contentNotObserved() throws InterruptedException { - // Expect onChanged when we observe, when the data is read, and when we stop observing. - final CountDownLatch latch = new CountDownLatch(2); - Observer<ImmutableList<Event>> observer = (value) -> latch.countDown(); - mEventsLiveData.observeForever(observer); + public void addObserver_observerCalled() throws InterruptedException { + // Observing triggers content to be read. + Observer<ImmutableList<Event>> mockObserver = mock(Observer.class); + runOnMain(() -> mEventsLiveData.observeForever(mockObserver)); - // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + // TODO(jdp) This method of verifying an async behaviour is easier to read. + verify(mockObserver, timeout(1000).times(1)).onChanged(any()); + } - final CountDownLatch latch2 = new CountDownLatch(1); - mEventsLiveData.removeObserver(observer); + @Test + public void addTwoObservers_bothObserversCalled() throws InterruptedException { + // Observing triggers content to be read. + Observer<ImmutableList<Event>> mockObserver1 = mock(Observer.class); + runOnMain(() -> mEventsLiveData.observeForever(mockObserver1)); + Observer<ImmutableList<Event>> mockObserver2 = mock(Observer.class); + runOnMain(() -> mEventsLiveData.observeForever(mockObserver2)); + + verify(mockObserver1, timeout(1000).times(1)).onChanged(any()); + verify(mockObserver2, timeout(1000).times(1)).onChanged(any()); + } - // Wait for the observer to be unregistered on the background thread. - latch2.await(5, TimeUnit.SECONDS); + @Test + public void removeObserver_contentNotObserved() throws InterruptedException { + // Observing triggers content to be read. + Observer<ImmutableList<Event>> observer = (unused) -> { /* Do nothing */ }; + runOnMain(() -> mEventsLiveData.observeForever(observer)); + + // Wait for the data to be read on the background thread. + mTestContentProvider.awaitCalendarQuery(); - assertThat(mTestContentProvider.mTestEventCursor.mLastContentObserver).isNull(); + awaitAndAssertDone(mTestContentProvider.mTestEventCursor.mRegisterContentObserverLatch); + runOnMain(() -> mEventsLiveData.removeObserver(observer)); + awaitAndAssertDone(mTestContentProvider.mTestEventCursor.mUnregisterContentObserverLatch); } @Test public void addObserver_oneEventResult() throws InterruptedException { - mTestContentProvider.addRow(buildTestRowWithDuration(CURRENT_DATE_TIME, 1)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + // Expect onChanged to be called for when the data is read. + CountDownLatch latch = new CountDownLatch(1); // Must add observer on main thread. runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); ImmutableList<Event> events = mEventsLiveData.getValue(); assertThat(events).isNotNull(); @@ -213,12 +228,14 @@ public class EventsLiveDataTest { } @Test - public void changeCursorData_onChangedCalled() throws InterruptedException { - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch initializeCountdownLatch = new CountDownLatch(2); + public void notifyDataChange_dataNotChanged_onChangedNotCalled() throws InterruptedException { + mTestContentProvider.addRow(buildTestRow()); + + // Expect onChanged to be called for when the data is read. + CountDownLatch initializeCountdownLatch = new CountDownLatch(1); - // Expect the same init callbacks as above but with an extra when the data is updated. - CountDownLatch changeCountdownLatch = new CountDownLatch(3); + // Expect the same callback as above but with an extra when the data is updated. + CountDownLatch changeCountdownLatch = new CountDownLatch(2); // Must add observer on main thread. runOnMain( @@ -231,32 +248,54 @@ public class EventsLiveDataTest { })); // Wait for the data to be read on the background thread. - initializeCountdownLatch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(initializeCountdownLatch); - // Signal that the content has changed. + // Signal that the content has changed but do not update the data. mTestContentProvider.mTestEventCursor.signalDataChanged(); // Wait for the changed data to be read on the background thread. - changeCountdownLatch.await(5, TimeUnit.SECONDS); - } - - private void runOnMain(Runnable runnable) { - InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable); + awaitAndAssertNotDone(changeCountdownLatch); } @Test - public void addObserver_updateScheduled() throws InterruptedException { - mTestHandler.setExpectedMessageCount(2); + public void notifyDataChange_dataChanged_onChangedCalled() throws InterruptedException { + mTestContentProvider.addRow(buildTestRow()); + + // Expect onChanged to be called for when the data is read. + CountDownLatch initializeCountdownLatch = new CountDownLatch(1); + + // Expect the same callback as above but with an extra when the data is updated. + CountDownLatch changeCountdownLatch = new CountDownLatch(2); // Must add observer on main thread. runOnMain( () -> mEventsLiveData.observeForever( + // Count down both latches when data is changed. (value) -> { - /* Do nothing */ + initializeCountdownLatch.countDown(); + changeCountdownLatch.countDown(); })); - mTestHandler.awaitExpectedMessages(5); + // Wait for the data to be read on the background thread. + awaitAndAssertDone(initializeCountdownLatch); + + // Change the data and signal that the content has changed. + mTestContentProvider.addRow(buildTestRowWithTitle("Another event")); + mTestContentProvider.mTestEventCursor.signalDataChanged(); + + // Wait for the changed data to be read on the background thread. + awaitAndAssertDone(changeCountdownLatch); + } + + @Test + public void addObserver_updateScheduled() throws InterruptedException { + mTestHandler.setExpectedMessageCount(2); + + // Must add observer on main thread. + runOnMain(() -> mEventsLiveData.observeForever((unused) -> { /* Do nothing */ })); + + mTestHandler.awaitExpectedMessages(); // Show that a message was scheduled for the future. assertThat(mTestHandler.mLastUptimeMillis).isAtLeast(SystemClock.uptimeMillis()); @@ -265,13 +304,14 @@ public class EventsLiveDataTest { @Test public void noCalendars_valueNull() throws InterruptedException { mTestContentProvider.mAddFakeCalendar = false; + mTestContentProvider.addRow(buildTestRow()); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + // Expect onChanged to be called for when the data is read. + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); assertThat(mEventsLiveData.getValue()).isNull(); } @@ -280,15 +320,9 @@ public class EventsLiveDataTest { @UiThreadTest public void noCalendars_contentObserved() throws InterruptedException { mTestContentProvider.mAddFakeCalendar = false; - - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); - mEventsLiveData.observeForever((value) -> latch.countDown()); - - // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); - - assertThat(mTestContentProvider.mTestEventCursor.mLastContentObserver).isNotNull(); + mEventsLiveData.observeForever((unused) -> { /* Do nothing */ }); + mTestContentProvider.awaitCalendarQuery(); + awaitAndAssertDone(mTestContentProvider.mTestEventCursor.mRegisterContentObserverLatch); } @Test @@ -296,13 +330,12 @@ public class EventsLiveDataTest { // Replace the default event with one that lasts 24 hours. mTestContentProvider.addRow(buildTestRowWithDuration(CURRENT_DATE_TIME, 24)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); // Expect an event for the 2 parts of the split event instance. assertThat(mEventsLiveData.getValue()).hasSize(2); @@ -314,13 +347,12 @@ public class EventsLiveDataTest { int hours = 48; mTestContentProvider.addRow(buildTestRowWithDuration(CURRENT_DATE_TIME, hours)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); Event middlePartEvent = mEventsLiveData.getValue().get(1); @@ -338,13 +370,12 @@ public class EventsLiveDataTest { mTestContentProvider.addRow(buildTestRowWithDuration(twoHoursAfterCurrentTime, 1)); mTestContentProvider.addRow(buildTestRowWithDuration(CURRENT_DATE_TIME, 1)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); ImmutableList<Event> events = mEventsLiveData.getValue(); @@ -357,17 +388,17 @@ public class EventsLiveDataTest { @Test public void multipleEvents_resultsSortedTitle() throws InterruptedException { // Replace the default event with two that are out of time order. - mTestContentProvider.addRow(buildTestRowWithTitle(CURRENT_DATE_TIME, "Title B")); - mTestContentProvider.addRow(buildTestRowWithTitle(CURRENT_DATE_TIME, "Title A")); - mTestContentProvider.addRow(buildTestRowWithTitle(CURRENT_DATE_TIME, "Title C")); + mTestContentProvider.addRow(buildTestRowWithTitle("Title B")); + mTestContentProvider.addRow(buildTestRowWithTitle("Title A")); + mTestContentProvider.addRow(buildTestRowWithTitle("Title C")); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + // Expect onChanged to be called for when the data is read. + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); ImmutableList<Event> events = mEventsLiveData.getValue(); @@ -383,13 +414,13 @@ public class EventsLiveDataTest { CURRENT_DATE_TIME.withZoneSameLocal(ZoneId.of("UTC")).truncatedTo(ChronoUnit.DAYS); mTestContentProvider.addRow(buildTestRowAllDay(utcMidnightStart)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + // Expect onChanged to be called when the data is read. + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); ImmutableList<Event> events = mEventsLiveData.getValue(); @@ -407,22 +438,35 @@ public class EventsLiveDataTest { // Set the time to 23:XX in the BERLIN_ZONE_ID which will be after the event end time. mTestClock.setTime(CURRENT_DATE_TIME.with(ChronoField.HOUR_OF_DAY, 23)); - // Expect onChanged to be called for when we start to observe and when the data is read. - CountDownLatch latch = new CountDownLatch(2); + // Expect onChanged to be called for when the data is read. + CountDownLatch latch = new CountDownLatch(1); runOnMain(() -> mEventsLiveData.observeForever((value) -> latch.countDown())); // Wait for the data to be read on the background thread. - latch.await(5, TimeUnit.SECONDS); + awaitAndAssertDone(latch); // Show that the event is included even though its end time is before the current time. assertThat(mEventsLiveData.getValue()).isNotEmpty(); } + private void runOnMain(Runnable runnable) { + InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable); + } + + private static void awaitAndAssertDone(CountDownLatch latch) throws InterruptedException { + assertThat(latch.await(2, TimeUnit.SECONDS)).isTrue(); + } + + private static void awaitAndAssertNotDone(CountDownLatch latch) throws InterruptedException { + assertThat(latch.await(2, TimeUnit.SECONDS)).isFalse(); + } + private static class TestContentProvider extends MockContentProvider { TestEventCursor mTestEventCursor; boolean mAddFakeCalendar = true; List<Object[]> mEventRows = new ArrayList<>(); + CountDownLatch mCalendarQueryLatch = new CountDownLatch(1); TestContentProvider(Context context) { super(context); @@ -449,14 +493,20 @@ public class EventsLiveDataTest { if (mAddFakeCalendar) { calendarsCursor.addRow(new String[] {"Test value"}); } + mCalendarQueryLatch.countDown(); return calendarsCursor; } throw new IllegalStateException("Unexpected query uri " + uri); } + void awaitCalendarQuery() throws InterruptedException { + awaitAndAssertDone(mCalendarQueryLatch); + } + static class TestEventCursor extends MatrixCursor { final Uri mUri; - ContentObserver mLastContentObserver; + CountDownLatch mRegisterContentObserverLatch = new CountDownLatch(1); + CountDownLatch mUnregisterContentObserverLatch = new CountDownLatch(1); TestEventCursor(Uri uri) { super( @@ -477,13 +527,13 @@ public class EventsLiveDataTest { @Override public void registerContentObserver(ContentObserver observer) { super.registerContentObserver(observer); - mLastContentObserver = observer; + mRegisterContentObserverLatch.countDown(); } @Override public void unregisterContentObserver(ContentObserver observer) { super.unregisterContentObserver(observer); - mLastContentObserver = null; + mUnregisterContentObserverLatch.countDown(); } void signalDataChanged() { @@ -519,8 +569,8 @@ public class EventsLiveDataTest { mCountDownLatch = new CountDownLatch(expectedMessageCount); } - void awaitExpectedMessages(int seconds) throws InterruptedException { - mCountDownLatch.await(seconds, TimeUnit.SECONDS); + void awaitExpectedMessages() throws InterruptedException { + awaitAndAssertDone(mCountDownLatch); } @Override @@ -573,10 +623,7 @@ public class EventsLiveDataTest { } static long addHoursAndTruncate(ZonedDateTime dateTime, int hours) { - return dateTime.truncatedTo(HOURS) - .plus(Duration.ofHours(hours)) - .toInstant() - .toEpochMilli(); + return dateTime.truncatedTo(HOURS).plus(Duration.ofHours(hours)).toInstant().toEpochMilli(); } static Object[] buildTestRowWithDuration(ZonedDateTime startDateTime, int eventDurationHours) { @@ -588,8 +635,12 @@ public class EventsLiveDataTest { return buildTestRowWithDuration(startDateTime, 24, EVENT_TITLE, true); } - static Object[] buildTestRowWithTitle(ZonedDateTime startDateTime, String title) { - return buildTestRowWithDuration(startDateTime, 1, title, EVENT_ALL_DAY); + static Object[] buildTestRowWithTitle(String title) { + return buildTestRowWithDuration(CURRENT_DATE_TIME, 1, title, EVENT_ALL_DAY); + } + + static Object[] buildTestRow() { + return buildTestRowWithDuration(CURRENT_DATE_TIME, 1, EVENT_TITLE, EVENT_ALL_DAY); } static Object[] buildTestRowWithDuration( |