From 7d1bf7fb398373dd9bc9a44b884bc2801cc86218 Mon Sep 17 00:00:00 2001 From: Albert Kong Date: Mon, 26 Sep 2022 23:23:43 +0000 Subject: All confirmation dialogs. Test: manual & atest http://screen/BPfF3mWaJvaq8GG Fixes: 242242693 Fixes: 235138016 Fixes: 229721429 Fixes: 229723367 Fixes: 248564600 Change-Id: I229acacd1a9ee835a89dc8ca49c7fcae211f38e6 --- adservices/apk/tests/Android.bp | 1 + adservices/apk/tests/AndroidManifest.xml | 6 +- .../AdServicesSettingsActivityWrapper.java | 2 +- .../ui/settings/SettingsActivityTest.java | 108 +----- .../settings/SettingsActivityUiAutomatorTest.java | 420 +++++++++++++++++++++ 5 files changed, 426 insertions(+), 111 deletions(-) create mode 100644 adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/Android.bp b/adservices/apk/tests/Android.bp index 87d856b5db..ea3ca36497 100644 --- a/adservices/apk/tests/Android.bp +++ b/adservices/apk/tests/Android.bp @@ -41,6 +41,7 @@ android_test { "SettingsLibSettingsTheme", "SettingsLibCollapsingToolbarBaseActivity", "SettingsLibMainSwitchPreference", + "androidx.test.uiautomator_uiautomator", ], libs: [ "android.test.base", diff --git a/adservices/apk/tests/AndroidManifest.xml b/adservices/apk/tests/AndroidManifest.xml index 762070c5fb..02ccbed911 100644 --- a/adservices/apk/tests/AndroidManifest.xml +++ b/adservices/apk/tests/AndroidManifest.xml @@ -28,10 +28,10 @@ + android:theme="@style/Theme.SubSettingsBase"> - - + + diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java index c58e51e53c..a0a034e700 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java @@ -29,6 +29,6 @@ import com.android.adservices.ui.settings.viewmodels.TopicsViewModel; */ public class AdServicesSettingsActivityWrapper extends AdServicesSettingsActivity { public AdServicesSettingsActivityWrapper() { - super(new SettingsActivityTest().generateMockedViewModelProvider()); + super(new SettingsActivityUiAutomatorTest().generateMockedViewModelProvider()); } } diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java index de13095766..73987f2fc7 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java @@ -28,9 +28,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; import android.content.Context; import android.graphics.Rect; @@ -42,8 +39,6 @@ import android.widget.ScrollView; import android.widget.Switch; import androidx.core.widget.NestedScrollView; -import androidx.lifecycle.ViewModelProvider; -import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.PerformException; import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; @@ -53,17 +48,10 @@ import androidx.test.espresso.util.HumanReadables; import androidx.test.ext.junit.rules.ActivityScenarioRule; import com.android.adservices.api.R; -import com.android.adservices.data.topics.Topic; import com.android.adservices.service.common.BackgroundJobsManager; -import com.android.adservices.service.consent.App; -import com.android.adservices.service.consent.ConsentManager; import com.android.adservices.ui.settings.fragments.AdServicesSettingsMainFragment; -import com.android.adservices.ui.settings.viewmodels.AppsViewModel; -import com.android.adservices.ui.settings.viewmodels.MainViewModel; -import com.android.adservices.ui.settings.viewmodels.TopicsViewModel; import com.android.dx.mockito.inline.extended.ExtendedMockito; -import com.google.common.collect.ImmutableList; import junit.framework.AssertionFailedError; @@ -73,19 +61,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; /** Tests for {@link AdServicesSettingsActivity}. */ public class SettingsActivityTest { - static ViewModelProvider sViewModelProvider = Mockito.mock(ViewModelProvider.class); - static ConsentManager sConsentManager; + private MockitoSession mStaticMockSession; private static final class NestedScrollToAction implements ViewAction { @@ -149,60 +132,6 @@ public class SettingsActivityTest { public ActivityScenarioRule mRule = new ActivityScenarioRule<>(AdServicesSettingsActivityWrapper.class); - /** - * This is used by {@link AdServicesSettingsActivityWrapper}. Provides a mocked {@link - * ViewModelProvider} that serves mocked view models, which use a mocked {@link ConsentManager}, - * which gives mocked data. - * - * @return the mocked {@link ViewModelProvider} - */ - public ViewModelProvider generateMockedViewModelProvider() { - sConsentManager = - spy(ConsentManager.getInstance(ApplicationProvider.getApplicationContext())); - List tempList = new ArrayList<>(); - tempList.add(Topic.create(10001, 1, 1)); - tempList.add(Topic.create(10002, 1, 1)); - tempList.add(Topic.create(10003, 1, 1)); - ImmutableList topicsList = ImmutableList.copyOf(tempList); - doReturn(topicsList).when(sConsentManager).getKnownTopicsWithConsent(); - - tempList = new ArrayList<>(); - tempList.add(Topic.create(10004, 1, 1)); - tempList.add(Topic.create(10005, 1, 1)); - ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); - doReturn(blockedTopicsList).when(sConsentManager).getTopicsWithRevokedConsent(); - - List appTempList = new ArrayList<>(); - appTempList.add(App.create("app1")); - appTempList.add(App.create("app2")); - ImmutableList appsList = ImmutableList.copyOf(appTempList); - doReturn(appsList).when(sConsentManager).getKnownAppsWithConsent(); - - appTempList = new ArrayList<>(); - appTempList.add(App.create("app3")); - ImmutableList blockedAppsList = ImmutableList.copyOf(appTempList); - doReturn(blockedAppsList).when(sConsentManager).getAppsWithRevokedConsent(); - - doNothing().when(sConsentManager).resetTopicsAndBlockedTopics(); - try { - doNothing().when(sConsentManager).resetAppsAndBlockedApps(); - } catch (IOException e) { - e.printStackTrace(); - } - doNothing().when(sConsentManager).resetMeasurement(); - - TopicsViewModel topicsViewModel = - new TopicsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - AppsViewModel appsViewModel = - new AppsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - MainViewModel mainViewModel = - new MainViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - doReturn(topicsViewModel).when(sViewModelProvider).get(TopicsViewModel.class); - doReturn(mainViewModel).when(sViewModelProvider).get(MainViewModel.class); - doReturn(appsViewModel).when(sViewModelProvider).get(AppsViewModel.class); - return sViewModelProvider; - } - @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -251,41 +180,6 @@ public class SettingsActivityTest { .check(matches(isDisplayed())); } - /** Test if {@link MainViewModel} works if Activity is recreated (simulates rotate phone). */ - @Test - public void test_MainViewModel_getConsent() { - giveConsentIfNeeded(); - onView(withId(R.id.main_fragment)) - .check( - matches( - hasDescendant( - Matchers.allOf( - withClassName(Matchers.is(Switch.class.getName())), - isChecked())))); - onView(withText(R.string.settingsUI_privacy_sandbox_beta_switch_title)) - .perform(nestedScrollTo(), click()); - - mRule.getScenario().recreate(); - onView(withId(R.id.main_fragment)) - .check( - matches( - hasDescendant( - Matchers.allOf( - withClassName(Matchers.is(Switch.class.getName())), - Matchers.not(isChecked()))))); - - // Give consent back - onView(withText(R.string.settingsUI_privacy_sandbox_beta_switch_title)) - .perform(nestedScrollTo(), click()); - onView(withId(R.id.main_fragment)) - .check( - matches( - hasDescendant( - Matchers.allOf( - withClassName(Matchers.is(Switch.class.getName())), - isChecked())))); - } - /** * Test if the Topics button in the main fragment opens the topics fragment, and the back button * returns to the main fragment. diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java new file mode 100644 index 0000000000..aba98d62fe --- /dev/null +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2022 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 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 com.android.adservices.ui.settings; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; + +import androidx.lifecycle.ViewModelProvider; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiScrollable; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; + +import com.android.adservices.api.R; +import com.android.adservices.data.topics.Topic; +import com.android.adservices.service.PhFlags; +import com.android.adservices.service.common.BackgroundJobsManager; +import com.android.adservices.service.consent.App; +import com.android.adservices.service.consent.ConsentManager; +import com.android.adservices.ui.settings.viewmodels.AppsViewModel; +import com.android.adservices.ui.settings.viewmodels.MainViewModel; +import com.android.adservices.ui.settings.viewmodels.TopicsViewModel; +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import com.google.common.collect.ImmutableList; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class SettingsActivityUiAutomatorTest { + private static final String BASIC_SAMPLE_PACKAGE = "android.test.adservices.ui.SETTINGS"; + private static final int LAUNCH_TIMEOUT = 5000; + private static UiDevice sDevice; + private static Context sContext; + private static Intent sIntent; + static ViewModelProvider sViewModelProvider = Mockito.mock(ViewModelProvider.class); + static ConsentManager sConsentManager; + private MockitoSession mStaticMockSession; + private PhFlags mPhFlags; + + /** + * This is used by {@link AdServicesSettingsActivityWrapper}. Provides a mocked {@link + * ViewModelProvider} that serves mocked view models, which use a mocked {@link ConsentManager}, + * which gives mocked data. + * + * @return the mocked {@link ViewModelProvider} + */ + public ViewModelProvider generateMockedViewModelProvider() { + sConsentManager = + spy(ConsentManager.getInstance(ApplicationProvider.getApplicationContext())); + List tempList = new ArrayList<>(); + tempList.add(Topic.create(10001, 1, 1)); + tempList.add(Topic.create(10002, 1, 1)); + tempList.add(Topic.create(10003, 1, 1)); + ImmutableList topicsList = ImmutableList.copyOf(tempList); + doReturn(topicsList).when(sConsentManager).getKnownTopicsWithConsent(); + + tempList = new ArrayList<>(); + tempList.add(Topic.create(10004, 1, 1)); + tempList.add(Topic.create(10005, 1, 1)); + ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); + doReturn(blockedTopicsList).when(sConsentManager).getTopicsWithRevokedConsent(); + + List appTempList = new ArrayList<>(); + appTempList.add(App.create("app1")); + appTempList.add(App.create("app2")); + ImmutableList appsList = ImmutableList.copyOf(appTempList); + doReturn(appsList).when(sConsentManager).getKnownAppsWithConsent(); + + appTempList = new ArrayList<>(); + appTempList.add(App.create("app3")); + ImmutableList blockedAppsList = ImmutableList.copyOf(appTempList); + doReturn(blockedAppsList).when(sConsentManager).getAppsWithRevokedConsent(); + + doNothing().when(sConsentManager).resetTopicsAndBlockedTopics(); + doNothing().when(sConsentManager).resetTopics(); + doNothing().when(sConsentManager).revokeConsentForTopic(any(Topic.class)); + doNothing().when(sConsentManager).restoreConsentForTopic(any(Topic.class)); + try { + doNothing().when(sConsentManager).resetAppsAndBlockedApps(); + doNothing().when(sConsentManager).resetApps(); + doNothing().when(sConsentManager).revokeConsentForApp(any(App.class)); + doNothing().when(sConsentManager).restoreConsentForApp(any(App.class)); + } catch (IOException e) { + e.printStackTrace(); + } + doNothing().when(sConsentManager).resetMeasurement(); + + TopicsViewModel topicsViewModel = + new TopicsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); + AppsViewModel appsViewModel = + new AppsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); + MainViewModel mainViewModel = + new MainViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); + doReturn(topicsViewModel).when(sViewModelProvider).get(TopicsViewModel.class); + doReturn(mainViewModel).when(sViewModelProvider).get(MainViewModel.class); + doReturn(appsViewModel).when(sViewModelProvider).get(AppsViewModel.class); + return sViewModelProvider; + } + + @BeforeClass + public static void classSetup() { + // Initialize UiDevice instance + sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + + // Launch the app + sContext = ApplicationProvider.getApplicationContext(); + sIntent = new Intent(BASIC_SAMPLE_PACKAGE); + sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } + + @Before + public void setup() throws UiObjectNotFoundException, IOException { + MockitoAnnotations.initMocks(this); + mStaticMockSession = + ExtendedMockito.mockitoSession() + .spyStatic(PhFlags.class) + .spyStatic(BackgroundJobsManager.class) + .strictness(Strictness.WARN) + .initMocks(this) + .startMocking(); + ExtendedMockito.doNothing() + .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); + mPhFlags = spy(PhFlags.getInstance()); + doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled(); + ExtendedMockito.doReturn(mPhFlags).when(PhFlags::getInstance); + + // Start from the home screen + sDevice.pressHome(); + + // Wait for launcher + final String launcherPackage = sDevice.getLauncherPackageName(); + assertThat(launcherPackage).isNotNull(); + sDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT); + + // launch + sContext.startActivity(sIntent); + + // Wait for the app to appear + sDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT); + + // set consent to true if not + UiObject mainSwitch = + sDevice.findObject(new UiSelector().className("android.widget.Switch")); + assertThat(mainSwitch.exists()).isTrue(); + if (!mainSwitch.isChecked()) mainSwitch.click(); + assertThat(mainSwitch.isChecked()).isTrue(); + } + + @After + public void teardown() { + if (mStaticMockSession != null) { + mStaticMockSession.finishMocking(); + } + } + + private void scrollToAndClick(int resId) throws UiObjectNotFoundException { + UiScrollable scrollView = + new UiScrollable( + new UiSelector().scrollable(true).className("android.widget.ScrollView")); + UiObject element = + sDevice.findObject( + new UiSelector().childSelector(new UiSelector().text(getString(resId)))); + scrollView.scrollIntoView(element); + element.click(); + } + + private UiObject getElement(int resId) { + return sDevice.findObject(new UiSelector().text(getString(resId))); + } + + private UiObject getElement(int resId, int index) { + return sDevice.findObject(new UiSelector().text(getString(resId)).instance(index)); + } + + @Test + public void optOutDialogTest() throws UiObjectNotFoundException { + UiObject mainSwitch = + sDevice.findObject(new UiSelector().className("android.widget.Switch")); + assertThat(mainSwitch.exists()).isTrue(); + + // click switch + mainSwitch.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_opt_out_title); + UiObject positiveText = getElement(R.string.settingsUI_dialog_opt_out_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + assertThat(mainSwitch.isChecked()).isFalse(); + + // reset to opted in + mainSwitch.click(); + assertThat(mainSwitch.isChecked()).isTrue(); + + // click switch + mainSwitch.click(); + dialogTitle = getElement(R.string.settingsUI_dialog_opt_out_title); + UiObject negativeText = getElement(R.string.settingsUI_dialog_negative_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(negativeText.exists()).isTrue(); + + // cancel + negativeText.click(); + assertThat(mainSwitch.isChecked()).isTrue(); + } + + @Test + public void blockTopicDialogTest() throws UiObjectNotFoundException { + // open topics view + scrollToAndClick(R.string.settingsUI_topics_title); + UiObject blockTopicText = getElement(R.string.settingsUI_block_topic_title, 0); + assertThat(blockTopicText.exists()).isTrue(); + + // click block + blockTopicText.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_block_topic_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_block_topic_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + blockTopicText = getElement(R.string.settingsUI_block_topic_title, 0); + assertThat(blockTopicText.exists()).isTrue(); + + // click block again + blockTopicText.click(); + dialogTitle = getElement(R.string.settingsUI_dialog_block_topic_message); + UiObject negativeText = getElement(R.string.settingsUI_dialog_negative_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(negativeText.exists()).isTrue(); + + // cancel and verify it has still only been called once + negativeText.click(); + verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + } + + @Test + public void unblockTopicDialogTest() throws UiObjectNotFoundException { + // open topics view + scrollToAndClick(R.string.settingsUI_topics_title); + + // open blocked topics view + scrollToAndClick(R.string.settingsUI_blocked_topics_title); + UiObject unblockTopicText = getElement(R.string.settingsUI_unblock_topic_title, 0); + assertThat(unblockTopicText.exists()).isTrue(); + + // click unblock + unblockTopicText.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_unblock_topic_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_unblock_topic_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).restoreConsentForTopic(any(Topic.class)); + unblockTopicText = getElement(R.string.settingsUI_unblock_topic_title, 0); + assertThat(unblockTopicText.exists()).isTrue(); + } + + @Test + public void resetTopicDialogTest() throws UiObjectNotFoundException { + // open topics view + scrollToAndClick(R.string.settingsUI_topics_title); + + // click reset + scrollToAndClick(R.string.settingsUI_reset_topics_title); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_reset_topic_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_reset_topic_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).resetTopics(); + + // click reset again + scrollToAndClick(R.string.settingsUI_reset_topics_title); + dialogTitle = getElement(R.string.settingsUI_dialog_reset_topic_message); + UiObject negativeText = getElement(R.string.settingsUI_dialog_negative_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(negativeText.exists()).isTrue(); + + // cancel and verify it has still only been called once + negativeText.click(); + verify(sConsentManager).resetTopics(); + } + + @Test + public void blockAppDialogTest() throws UiObjectNotFoundException, IOException { + // open apps view + scrollToAndClick(R.string.settingsUI_apps_title); + UiObject blockAppText = getElement(R.string.settingsUI_block_app_title, 0); + assertThat(blockAppText.exists()).isTrue(); + + // click block + blockAppText.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_block_app_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_block_app_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).revokeConsentForApp(any(App.class)); + blockAppText = getElement(R.string.settingsUI_block_app_title, 0); + assertThat(blockAppText.exists()).isTrue(); + + // click block again + blockAppText.click(); + dialogTitle = getElement(R.string.settingsUI_dialog_block_app_message); + UiObject negativeText = getElement(R.string.settingsUI_dialog_negative_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(negativeText.exists()).isTrue(); + + // cancel and verify it has still only been called once + negativeText.click(); + verify(sConsentManager).revokeConsentForApp(any(App.class)); + } + + @Test + public void unblockAppDialogTest() throws UiObjectNotFoundException, IOException { + // open apps view + scrollToAndClick(R.string.settingsUI_apps_title); + + // open blocked apps view + scrollToAndClick(R.string.settingsUI_blocked_apps_title); + UiObject unblockAppText = getElement(R.string.settingsUI_unblock_app_title, 0); + assertThat(unblockAppText.exists()).isTrue(); + + // click unblock + unblockAppText.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_unblock_app_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_unblock_app_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).restoreConsentForApp(any(App.class)); + unblockAppText = getElement(R.string.settingsUI_unblock_app_title, 0); + assertThat(unblockAppText.exists()).isTrue(); + } + + @Test + public void resetAppDialogTest() throws UiObjectNotFoundException, IOException { + // open apps view + scrollToAndClick(R.string.settingsUI_apps_title); + + // click reset + scrollToAndClick(R.string.settingsUI_reset_apps_title); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_reset_app_message); + UiObject positiveText = getElement(R.string.settingsUI_dialog_reset_app_positive_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(positiveText.exists()).isTrue(); + + // confirm + positiveText.click(); + verify(sConsentManager).resetApps(); + + // click reset again + scrollToAndClick(R.string.settingsUI_reset_apps_title); + dialogTitle = getElement(R.string.settingsUI_dialog_reset_app_message); + UiObject negativeText = getElement(R.string.settingsUI_dialog_negative_text); + assertThat(dialogTitle.exists()).isTrue(); + assertThat(negativeText.exists()).isTrue(); + + // cancel and verify it has still only been called once + negativeText.click(); + verify(sConsentManager).resetApps(); + } + + private String getString(int resourceId) { + return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); + } +} -- cgit v1.2.3 From 10fa707bb99c7b49eec433a729c8eeece2ffb2e5 Mon Sep 17 00:00:00 2001 From: Albert Kong Date: Thu, 29 Sep 2022 18:21:18 +0000 Subject: Added feature disable tests for UI dialogs. Test: atest Bug: 248564600 Change-Id: I1a4b5b0b057c657b0d45d00e3ef5989cb4e04209 --- .../settings/SettingsActivityUiAutomatorTest.java | 76 +++++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java index aba98d62fe..e5a643f4a6 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java @@ -54,7 +54,6 @@ import com.google.common.collect.ImmutableList; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -68,11 +67,10 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public class SettingsActivityUiAutomatorTest { - private static final String BASIC_SAMPLE_PACKAGE = "android.test.adservices.ui.SETTINGS"; + private static final String PRIVACY_SANDBOX_TEST_PACKAGE = + "android.test.adservices.ui.SETTINGS"; private static final int LAUNCH_TIMEOUT = 5000; private static UiDevice sDevice; - private static Context sContext; - private static Intent sIntent; static ViewModelProvider sViewModelProvider = Mockito.mock(ViewModelProvider.class); static ConsentManager sConsentManager; private MockitoSession mStaticMockSession; @@ -138,17 +136,6 @@ public class SettingsActivityUiAutomatorTest { return sViewModelProvider; } - @BeforeClass - public static void classSetup() { - // Initialize UiDevice instance - sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - - // Launch the app - sContext = ApplicationProvider.getApplicationContext(); - sIntent = new Intent(BASIC_SAMPLE_PACKAGE); - sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - @Before public void setup() throws UiObjectNotFoundException, IOException { MockitoAnnotations.initMocks(this); @@ -165,6 +152,9 @@ public class SettingsActivityUiAutomatorTest { doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled(); ExtendedMockito.doReturn(mPhFlags).when(PhFlags::getInstance); + // Initialize UiDevice instance + sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + // Start from the home screen sDevice.pressHome(); @@ -173,11 +163,15 @@ public class SettingsActivityUiAutomatorTest { assertThat(launcherPackage).isNotNull(); sDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT); - // launch - sContext.startActivity(sIntent); + // launch app + Context context = ApplicationProvider.getApplicationContext(); + Intent intent = new Intent(PRIVACY_SANDBOX_TEST_PACKAGE); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); // Wait for the app to appear - sDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT); + sDevice.wait( + Until.hasObject(By.pkg(PRIVACY_SANDBOX_TEST_PACKAGE).depth(0)), LAUNCH_TIMEOUT); // set consent to true if not UiObject mainSwitch = @@ -414,6 +408,52 @@ public class SettingsActivityUiAutomatorTest { verify(sConsentManager).resetApps(); } + @Test + public void disableDialogFeatureTest() throws UiObjectNotFoundException { + doReturn(false).when(mPhFlags).getUIDialogsFeatureEnabled(); + UiObject mainSwitch = + sDevice.findObject(new UiSelector().className("android.widget.Switch")); + assertThat(mainSwitch.exists()).isTrue(); + + // click switch + mainSwitch.click(); + UiObject dialogTitle = getElement(R.string.settingsUI_dialog_opt_out_title); + assertThat(dialogTitle.exists()).isFalse(); + assertThat(mainSwitch.isChecked()).isFalse(); + + // click switch again + mainSwitch.click(); + assertThat(mainSwitch.isChecked()).isTrue(); + + // open topics view + scrollToAndClick(R.string.settingsUI_topics_title); + UiObject blockTopicText = getElement(R.string.settingsUI_block_topic_title, 0); + assertThat(blockTopicText.exists()).isTrue(); + + // block topic + blockTopicText.click(); + dialogTitle = getElement(R.string.settingsUI_dialog_block_topic_message); + assertThat(dialogTitle.exists()).isFalse(); + verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + + // reset topic + scrollToAndClick(R.string.settingsUI_reset_topics_title); + dialogTitle = getElement(R.string.settingsUI_dialog_reset_topic_message); + assertThat(dialogTitle.exists()).isFalse(); + verify(sConsentManager).resetTopics(); + + // open unblock topic view + scrollToAndClick(R.string.settingsUI_blocked_topics_title); + UiObject unblockTopicText = getElement(R.string.settingsUI_unblock_topic_title, 0); + assertThat(unblockTopicText.exists()).isTrue(); + + // click unblock + unblockTopicText.click(); + dialogTitle = getElement(R.string.settingsUI_dialog_unblock_topic_message); + assertThat(dialogTitle.exists()).isFalse(); + verify(sConsentManager).restoreConsentForTopic(any(Topic.class)); + } + private String getString(int resourceId) { return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); } -- cgit v1.2.3 From 6c95d7b41e80ec1c245f083ff99c8e9fd68d1951 Mon Sep 17 00:00:00 2001 From: Albert Kong Date: Thu, 29 Sep 2022 16:12:16 +0000 Subject: Added "More" button for detailed notification. Test: atest & manual Fixes: 245995347 Change-Id: I5a071916d67ef2311484ee9499ff841a9b9cd404 --- .../ui/notifications/NotificationActivityTest.java | 12 -- .../NotificationActivityUiAutomatorTest.java | 141 +++++++++++++++++++++ 2 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java index e02dab4b08..3a6eb22d77 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java @@ -16,7 +16,6 @@ package com.android.adservices.ui.notifications; import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -89,17 +88,6 @@ public class NotificationActivityTest { checkConsentNotificationFragmentIsDisplayed(); } - @Test - public void test_ConsentNotificationConfirmationFragment_isDisplayed() { - launchEUActivity(); - checkConsentNotificationFragmentIsDisplayed(); - - onView(withId(R.id.rightControlButton)).perform(click()); - - onView(withId(R.id.consent_notification_accept_confirmation_view)) - .check(matches(isDisplayed())); - } - private void checkConsentNotificationFragmentIsDisplayed() { onView(withText(R.string.notificationUI_header_title)).check(matches(isDisplayed())); } diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java new file mode 100644 index 0000000000..a48af7f977 --- /dev/null +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 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 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 com.android.adservices.ui.notifications; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.content.Intent; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; + +import com.android.adservices.api.R; +import com.android.adservices.service.PhFlags; +import com.android.adservices.service.common.BackgroundJobsManager; +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.io.IOException; + +@RunWith(AndroidJUnit4.class) +public class NotificationActivityUiAutomatorTest { + private static final String NOTIFICATION_TEST_PACKAGE = + "android.test.adservices.ui.NOTIFICATIONS"; + private static final int LAUNCH_TIMEOUT = 5000; + private static Context sContext; + private static UiDevice sDevice; + private static Intent sIntent; + private MockitoSession mStaticMockSession; + private PhFlags mPhFlags; + + @Before + public void setup() throws UiObjectNotFoundException, IOException { + MockitoAnnotations.initMocks(this); + mStaticMockSession = + ExtendedMockito.mockitoSession() + .spyStatic(PhFlags.class) + .spyStatic(BackgroundJobsManager.class) + .strictness(Strictness.WARN) + .initMocks(this) + .startMocking(); + ExtendedMockito.doNothing() + .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); + mPhFlags = spy(PhFlags.getInstance()); + doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled(); + ExtendedMockito.doReturn(mPhFlags).when(PhFlags::getInstance); + + // Initialize UiDevice instance + sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + + // Start from the home screen + sDevice.pressHome(); + + // Wait for launcher + final String launcherPackage = sDevice.getLauncherPackageName(); + assertThat(launcherPackage).isNotNull(); + sDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT); + + // Create intent + sContext = ApplicationProvider.getApplicationContext(); + sIntent = new Intent(NOTIFICATION_TEST_PACKAGE); + sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } + + private void startActivity(boolean isEUActivity) { + // Send intent + sIntent.putExtra("isEUDevice", isEUActivity); + sContext.startActivity(sIntent); + + // Wait for the app to appear + sDevice.wait(Until.hasObject(By.pkg(NOTIFICATION_TEST_PACKAGE).depth(0)), LAUNCH_TIMEOUT); + } + + @After + public void teardown() { + if (mStaticMockSession != null) { + mStaticMockSession.finishMocking(); + } + } + + private UiObject getElement(int resId) { + return sDevice.findObject(new UiSelector().text(getString(resId))); + } + + @Test + public void moreButtonTest() throws UiObjectNotFoundException, InterruptedException { + startActivity(true); + UiObject leftControlButton = + getElement(R.string.notificationUI_left_control_button_text_eu); + UiObject rightControlButton = + getElement(R.string.notificationUI_right_control_button_text_eu); + UiObject moreButton = getElement(R.string.notificationUI_more_button_text); + assertThat(leftControlButton.exists()).isFalse(); + assertThat(rightControlButton.exists()).isFalse(); + assertThat(moreButton.exists()).isTrue(); + + while (moreButton.exists()) { + moreButton.click(); + Thread.sleep(2000); + } + assertThat(leftControlButton.exists()).isTrue(); + assertThat(rightControlButton.exists()).isTrue(); + assertThat(moreButton.exists()).isFalse(); + } + + private String getString(int resourceId) { + return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); + } +} -- cgit v1.2.3 From 2da66b7e60362e02a65ed536f22b46f60cf9bee6 Mon Sep 17 00:00:00 2001 From: Bo Zhao Date: Wed, 5 Oct 2022 22:39:16 +0000 Subject: add a button showing blocked list of topics/apps for empty state of non-blocked Fixes: 240227392 Test: Manual test https://drive.google.com/file/d/1TMDTVW8kuNWlDQAN75JuytYLebNhutuT/view?usp=sharing The button is funcational.The button text in disabled state is not implemented because of pending approval and color of button text may not be accurate. Change-Id: Ieab7e400b943142640135f3a7b8ec3818648c825 --- .../settings/SettingsActivityUiAutomatorTest.java | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java index e5a643f4a6..1a09a6661c 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java @@ -207,6 +207,33 @@ public class SettingsActivityUiAutomatorTest { return sDevice.findObject(new UiSelector().text(getString(resId)).instance(index)); } + /** + * Test for the Button to show blocked topics when the list of Topics is Empty The Button should + * be disabled if blocked topics is empty + * + * @throws UiObjectNotFoundException + */ + @Test + public void blockedTopicsWhenEmptyStateButtonTest() throws UiObjectNotFoundException { + // Return an empty topics list + doReturn(ImmutableList.of()).when(sConsentManager).getKnownTopicsWithConsent(); + // Return a non-empty blocked topics list + List tempList = new ArrayList<>(); + tempList.add(Topic.create(10004, 1, 1)); + tempList.add(Topic.create(10005, 1, 1)); + ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); + doReturn(blockedTopicsList).when(sConsentManager).getTopicsWithRevokedConsent(); + // navigate to topics page + scrollToAndClick(R.string.settingsUI_topics_title); + UiObject blockedTopicsWhenEmptyStateButton = + sDevice.findObject( + new UiSelector() + .className("android.widget.Button") + .text(getString(R.string.settingsUI_blocked_topics_title))); + + assertThat(blockedTopicsWhenEmptyStateButton.isEnabled()).isTrue(); + } + @Test public void optOutDialogTest() throws UiObjectNotFoundException { UiObject mainSwitch = -- cgit v1.2.3 From b9ce3ad78b8a72db97a672dbd04fc175ad0c6c3c Mon Sep 17 00:00:00 2001 From: Albert Kong Date: Fri, 7 Oct 2022 21:55:25 +0000 Subject: Refactor Adservices into separate activities for each view. Fixes: 239868474 Test: atest & manual Change-Id: Ifb6af90637d2447b69c1887c420efc059a1b48f0 --- adservices/apk/tests/AndroidManifest.xml | 56 +++- .../ui/notifications/NotificationActivityTest.java | 4 +- .../AdServicesSettingsActivityWrapper.java | 34 --- .../ui/settings/SettingsActivityTest.java | 317 --------------------- .../settings/SettingsActivityUiAutomatorTest.java | 146 ++++------ 5 files changed, 115 insertions(+), 442 deletions(-) delete mode 100644 adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java delete mode 100644 adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/AndroidManifest.xml b/adservices/apk/tests/AndroidManifest.xml index 02ccbed911..a4b13001ec 100644 --- a/adservices/apk/tests/AndroidManifest.xml +++ b/adservices/apk/tests/AndroidManifest.xml @@ -24,13 +24,57 @@ - + - - + android:name="com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity" + android:exported="true" + android:theme="@style/Theme.SubSettingsBase"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java index 3a6eb22d77..325c9b6e64 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java @@ -30,7 +30,7 @@ import androidx.test.core.app.ActivityScenario; import com.android.adservices.api.R; import com.android.adservices.service.common.BackgroundJobsManager; -import com.android.adservices.ui.settings.AdServicesSettingsActivity; +import com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity; import com.android.adservices.ui.settings.fragments.AdServicesSettingsMainFragment; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.dx.mockito.inline.extended.StaticMockitoSession; @@ -72,7 +72,7 @@ public class NotificationActivityTest { /** * Test if {@link AdServicesSettingsMainFragment} is displayed in {@link - * AdServicesSettingsActivity}. + * AdServicesSettingsMainActivity}. */ @Test public void test_FragmentContainer_isDisplayed() { diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java deleted file mode 100644 index a0a034e700..0000000000 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/AdServicesSettingsActivityWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2022 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 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 com.android.adservices.ui.settings; - -import com.android.adservices.service.PhFlags; -import com.android.adservices.ui.settings.viewmodels.TopicsViewModel; - - -/** - * Wrapper class for {@link AdServicesSettingsActivity} used for testing purposes only. Instantiates - * a {@link AdServicesSettingsActivity} with the custom constructor that can be passed a a mocked - * view model provider. This is needed because the some view models (such as the {@link - * TopicsViewModel}) will ultimately need to call {@link PhFlags} to read system settings, which - * requires the READ_DEVICE_CONFIG permission that is only granted to the real PP API process and - * not the process used for the test application. - */ -public class AdServicesSettingsActivityWrapper extends AdServicesSettingsActivity { - public AdServicesSettingsActivityWrapper() { - super(new SettingsActivityUiAutomatorTest().generateMockedViewModelProvider()); - } -} diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java deleted file mode 100644 index 73987f2fc7..0000000000 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityTest.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (C) 2022 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 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 com.android.adservices.ui.settings; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.Espresso.pressBack; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; -import static androidx.test.espresso.matcher.ViewMatchers.isChecked; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; -import static androidx.test.espresso.matcher.ViewMatchers.withClassName; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.mockito.Mockito.any; - -import android.content.Context; -import android.graphics.Rect; -import android.util.Log; -import android.view.View; -import android.widget.HorizontalScrollView; -import android.widget.ListView; -import android.widget.ScrollView; -import android.widget.Switch; - -import androidx.core.widget.NestedScrollView; -import androidx.test.espresso.PerformException; -import androidx.test.espresso.UiController; -import androidx.test.espresso.ViewAction; -import androidx.test.espresso.action.ViewActions; -import androidx.test.espresso.matcher.ViewMatchers; -import androidx.test.espresso.util.HumanReadables; -import androidx.test.ext.junit.rules.ActivityScenarioRule; - -import com.android.adservices.api.R; -import com.android.adservices.service.common.BackgroundJobsManager; -import com.android.adservices.ui.settings.fragments.AdServicesSettingsMainFragment; -import com.android.dx.mockito.inline.extended.ExtendedMockito; - - -import junit.framework.AssertionFailedError; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.MockitoAnnotations; -import org.mockito.MockitoSession; -import org.mockito.quality.Strictness; - - -/** Tests for {@link AdServicesSettingsActivity}. */ -public class SettingsActivityTest { - - private MockitoSession mStaticMockSession; - - private static final class NestedScrollToAction implements ViewAction { - private static final String TAG = - androidx.test.espresso.action.ScrollToAction.class.getSimpleName(); - - @Override - public Matcher getConstraints() { - return Matchers.allOf( - ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), - ViewMatchers.isDescendantOfA( - Matchers.anyOf( - ViewMatchers.isAssignableFrom(NestedScrollView.class), - ViewMatchers.isAssignableFrom(ScrollView.class), - ViewMatchers.isAssignableFrom(HorizontalScrollView.class), - ViewMatchers.isAssignableFrom(ListView.class)))); - } - - @Override - public void perform(UiController uiController, View view) { - if (isDisplayingAtLeast(90).matches(view)) { - Log.i(TAG, "View is already displayed. Returning."); - return; - } - Rect rect = new Rect(); - view.getDrawingRect(rect); - if (!view.requestRectangleOnScreen(rect, true /* immediate */)) { - Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled."); - } - uiController.loopMainThreadUntilIdle(); - if (!isDisplayingAtLeast(90).matches(view)) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause( - new RuntimeException( - "Scrolling to view was attempted, but the view is not " - + "displayed")) - .build(); - } - } - - @Override - public String getDescription() { - return "scroll to"; - } - } - - private static ViewAction nestedScrollTo() { - return ViewActions.actionWithAssertions(new NestedScrollToAction()); - } - - /** - * {@link ActivityScenarioRule} is a JUnit {@link Rule @Rule} to launch your activity under - * test. - * - *

Rules are interceptors which are executed for each test method and are important building - * blocks of Junit tests. - */ - @Rule - public ActivityScenarioRule mRule = - new ActivityScenarioRule<>(AdServicesSettingsActivityWrapper.class); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mStaticMockSession = - ExtendedMockito.mockitoSession() - .spyStatic(BackgroundJobsManager.class) - .strictness(Strictness.WARN) - .initMocks(this) - .startMocking(); - ExtendedMockito.doNothing() - .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); - } - - @After - public void teardown() { - if (mStaticMockSession != null) { - mStaticMockSession.finishMocking(); - } - } - - /** - * Test if {@link AdServicesSettingsMainFragment} is displayed in {@link - * AdServicesSettingsActivity}. - */ - @Test - public void test_FragmentContainer_isDisplayed() { - giveConsentIfNeeded(); - onView(withId(R.id.fragment_container_view)).check(matches(isDisplayed())); - } - - /** - * Test if the strings (settingsUI_topics_title, settingsUI_apps_title, - * settingsUI_main_view_title) are displayed in {@link AdServicesSettingsMainFragment}. - */ - @Test - public void test_MainFragmentView_isDisplayed() { - giveConsentIfNeeded(); - onView(withText(R.string.settingsUI_privacy_sandbox_beta_switch_title)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - onView(withText(R.string.settingsUI_topics_title)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - onView(withText(R.string.settingsUI_apps_title)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - } - - /** - * Test if the Topics button in the main fragment opens the topics fragment, and the back button - * returns to the main fragment. - */ - @Test - public void test_TopicsView() { - giveConsentIfNeeded(); - - assertMainFragmentDisplayed(); - - onView(withText(R.string.settingsUI_topics_title)).perform(nestedScrollTo(), click()); - - assertTopicsFragmentDisplayed(); - - pressBack(); - - assertMainFragmentDisplayed(); - } - - /** - * Test if the Topics button in the main fragment opens the topics fragment, and the back button - * returns to the main fragment. - */ - @Test - public void test_BlockedTopicsView() { - giveConsentIfNeeded(); - - assertMainFragmentDisplayed(); - - onView(withText(R.string.settingsUI_topics_title)).perform(nestedScrollTo(), click()); - - assertTopicsFragmentDisplayed(); - - onView(withId(R.id.blocked_topics_button)).perform(nestedScrollTo(), click()); - - assertBlockedTopicsFragmentDisplayed(); - - pressBack(); - - assertTopicsFragmentDisplayed(); - - pressBack(); - - assertMainFragmentDisplayed(); - } - - /** - * Test if the Topics button in the main fragment opens the topics fragment, and the back button - * returns to the main fragment. - */ - @Test - public void test_AppsView() { - giveConsentIfNeeded(); - - assertMainFragmentDisplayed(); - - onView(withText(R.string.settingsUI_apps_title)).perform(nestedScrollTo(), click()); - - assertAppsFragmentDisplayed(); - - pressBack(); - - assertMainFragmentDisplayed(); - } - - /** - * Test if the Topics button in the main fragment opens the topics fragment, and the back button - * returns to the main fragment. - */ - @Test - public void test_BlockedAppsView() { - giveConsentIfNeeded(); - - assertMainFragmentDisplayed(); - - onView(withText(R.string.settingsUI_apps_title)).perform(nestedScrollTo(), click()); - - assertAppsFragmentDisplayed(); - - onView(withId(R.id.blocked_apps_button)).perform(nestedScrollTo(), click()); - - assertBlockedAppsFragmentDisplayed(); - - pressBack(); - - assertAppsFragmentDisplayed(); - - pressBack(); - - assertMainFragmentDisplayed(); - } - - private void assertMainFragmentDisplayed() { - onView(withText(R.string.settingsUI_main_view_subtitle)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - } - - private void assertTopicsFragmentDisplayed() { - onView(withText(R.string.settingsUI_topics_view_subtitle)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - } - - private void assertAppsFragmentDisplayed() { - onView(withText(R.string.settingsUI_apps_view_subtitle)) - .perform(nestedScrollTo()) - .check(matches(isDisplayed())); - } - - private void assertBlockedTopicsFragmentDisplayed() { - onView(withId(R.id.blocked_topics_list)).check(matches(isDisplayed())); - } - - private void assertBlockedAppsFragmentDisplayed() { - onView(withId(R.id.blocked_apps_list)).check(matches(isDisplayed())); - } - - private void giveConsentIfNeeded() { - try { - onView(withId(R.id.main_fragment)) - .check( - matches( - hasDescendant( - Matchers.allOf( - withClassName( - Matchers.is(Switch.class.getName())), - isChecked())))); - } catch (AssertionFailedError e) { - // Give consent - onView(withText(R.string.settingsUI_privacy_sandbox_beta_switch_title)) - .perform(nestedScrollTo(), click()); - } - } -} diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java index 1a09a6661c..d093295b76 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java @@ -45,9 +45,6 @@ import com.android.adservices.service.PhFlags; import com.android.adservices.service.common.BackgroundJobsManager; import com.android.adservices.service.consent.App; import com.android.adservices.service.consent.ConsentManager; -import com.android.adservices.ui.settings.viewmodels.AppsViewModel; -import com.android.adservices.ui.settings.viewmodels.MainViewModel; -import com.android.adservices.ui.settings.viewmodels.TopicsViewModel; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.google.common.collect.ImmutableList; @@ -57,7 +54,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -67,82 +63,64 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public class SettingsActivityUiAutomatorTest { - private static final String PRIVACY_SANDBOX_TEST_PACKAGE = - "android.test.adservices.ui.SETTINGS"; + private static final String PRIVACY_SANDBOX_TEST_PACKAGE = "android.test.adservices.ui.MAIN"; private static final int LAUNCH_TIMEOUT = 5000; private static UiDevice sDevice; static ViewModelProvider sViewModelProvider = Mockito.mock(ViewModelProvider.class); static ConsentManager sConsentManager; private MockitoSession mStaticMockSession; private PhFlags mPhFlags; + private ConsentManager mConsentManager; - /** - * This is used by {@link AdServicesSettingsActivityWrapper}. Provides a mocked {@link - * ViewModelProvider} that serves mocked view models, which use a mocked {@link ConsentManager}, - * which gives mocked data. - * - * @return the mocked {@link ViewModelProvider} - */ - public ViewModelProvider generateMockedViewModelProvider() { - sConsentManager = + @Before + public void setup() throws UiObjectNotFoundException, IOException { + // prepare objects used by static mocking + mConsentManager = spy(ConsentManager.getInstance(ApplicationProvider.getApplicationContext())); List tempList = new ArrayList<>(); tempList.add(Topic.create(10001, 1, 1)); tempList.add(Topic.create(10002, 1, 1)); tempList.add(Topic.create(10003, 1, 1)); ImmutableList topicsList = ImmutableList.copyOf(tempList); - doReturn(topicsList).when(sConsentManager).getKnownTopicsWithConsent(); + doReturn(topicsList).when(mConsentManager).getKnownTopicsWithConsent(); tempList = new ArrayList<>(); tempList.add(Topic.create(10004, 1, 1)); tempList.add(Topic.create(10005, 1, 1)); ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); - doReturn(blockedTopicsList).when(sConsentManager).getTopicsWithRevokedConsent(); + doReturn(blockedTopicsList).when(mConsentManager).getTopicsWithRevokedConsent(); List appTempList = new ArrayList<>(); appTempList.add(App.create("app1")); appTempList.add(App.create("app2")); ImmutableList appsList = ImmutableList.copyOf(appTempList); - doReturn(appsList).when(sConsentManager).getKnownAppsWithConsent(); + doReturn(appsList).when(mConsentManager).getKnownAppsWithConsent(); appTempList = new ArrayList<>(); appTempList.add(App.create("app3")); ImmutableList blockedAppsList = ImmutableList.copyOf(appTempList); - doReturn(blockedAppsList).when(sConsentManager).getAppsWithRevokedConsent(); + doReturn(blockedAppsList).when(mConsentManager).getAppsWithRevokedConsent(); - doNothing().when(sConsentManager).resetTopicsAndBlockedTopics(); - doNothing().when(sConsentManager).resetTopics(); - doNothing().when(sConsentManager).revokeConsentForTopic(any(Topic.class)); - doNothing().when(sConsentManager).restoreConsentForTopic(any(Topic.class)); + doNothing().when(mConsentManager).resetTopicsAndBlockedTopics(); + doNothing().when(mConsentManager).resetTopics(); + doNothing().when(mConsentManager).revokeConsentForTopic(any(Topic.class)); + doNothing().when(mConsentManager).restoreConsentForTopic(any(Topic.class)); try { - doNothing().when(sConsentManager).resetAppsAndBlockedApps(); - doNothing().when(sConsentManager).resetApps(); - doNothing().when(sConsentManager).revokeConsentForApp(any(App.class)); - doNothing().when(sConsentManager).restoreConsentForApp(any(App.class)); + doNothing().when(mConsentManager).resetAppsAndBlockedApps(); + doNothing().when(mConsentManager).resetApps(); + doNothing().when(mConsentManager).revokeConsentForApp(any(App.class)); + doNothing().when(mConsentManager).restoreConsentForApp(any(App.class)); } catch (IOException e) { e.printStackTrace(); } - doNothing().when(sConsentManager).resetMeasurement(); - - TopicsViewModel topicsViewModel = - new TopicsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - AppsViewModel appsViewModel = - new AppsViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - MainViewModel mainViewModel = - new MainViewModel(ApplicationProvider.getApplicationContext(), sConsentManager); - doReturn(topicsViewModel).when(sViewModelProvider).get(TopicsViewModel.class); - doReturn(mainViewModel).when(sViewModelProvider).get(MainViewModel.class); - doReturn(appsViewModel).when(sViewModelProvider).get(AppsViewModel.class); - return sViewModelProvider; - } + doNothing().when(mConsentManager).resetMeasurement(); - @Before - public void setup() throws UiObjectNotFoundException, IOException { - MockitoAnnotations.initMocks(this); + // Static mocking mStaticMockSession = ExtendedMockito.mockitoSession() .spyStatic(PhFlags.class) .spyStatic(BackgroundJobsManager.class) + .spyStatic(ConsentManager.class) .strictness(Strictness.WARN) .initMocks(this) .startMocking(); @@ -151,6 +129,8 @@ public class SettingsActivityUiAutomatorTest { mPhFlags = spy(PhFlags.getInstance()); doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled(); ExtendedMockito.doReturn(mPhFlags).when(PhFlags::getInstance); + ExtendedMockito.doReturn(mConsentManager) + .when(() -> ConsentManager.getInstance(any(Context.class))); // Initialize UiDevice instance sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); @@ -207,31 +187,8 @@ public class SettingsActivityUiAutomatorTest { return sDevice.findObject(new UiSelector().text(getString(resId)).instance(index)); } - /** - * Test for the Button to show blocked topics when the list of Topics is Empty The Button should - * be disabled if blocked topics is empty - * - * @throws UiObjectNotFoundException - */ - @Test - public void blockedTopicsWhenEmptyStateButtonTest() throws UiObjectNotFoundException { - // Return an empty topics list - doReturn(ImmutableList.of()).when(sConsentManager).getKnownTopicsWithConsent(); - // Return a non-empty blocked topics list - List tempList = new ArrayList<>(); - tempList.add(Topic.create(10004, 1, 1)); - tempList.add(Topic.create(10005, 1, 1)); - ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); - doReturn(blockedTopicsList).when(sConsentManager).getTopicsWithRevokedConsent(); - // navigate to topics page - scrollToAndClick(R.string.settingsUI_topics_title); - UiObject blockedTopicsWhenEmptyStateButton = - sDevice.findObject( - new UiSelector() - .className("android.widget.Button") - .text(getString(R.string.settingsUI_blocked_topics_title))); - - assertThat(blockedTopicsWhenEmptyStateButton.isEnabled()).isTrue(); + private String getString(int resourceId) { + return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); } @Test @@ -283,7 +240,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + verify(mConsentManager).revokeConsentForTopic(any(Topic.class)); blockTopicText = getElement(R.string.settingsUI_block_topic_title, 0); assertThat(blockTopicText.exists()).isTrue(); @@ -296,7 +253,7 @@ public class SettingsActivityUiAutomatorTest { // cancel and verify it has still only been called once negativeText.click(); - verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + verify(mConsentManager).revokeConsentForTopic(any(Topic.class)); } @Test @@ -318,7 +275,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).restoreConsentForTopic(any(Topic.class)); + verify(mConsentManager).restoreConsentForTopic(any(Topic.class)); unblockTopicText = getElement(R.string.settingsUI_unblock_topic_title, 0); assertThat(unblockTopicText.exists()).isTrue(); } @@ -337,7 +294,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).resetTopics(); + verify(mConsentManager).resetTopics(); // click reset again scrollToAndClick(R.string.settingsUI_reset_topics_title); @@ -348,7 +305,7 @@ public class SettingsActivityUiAutomatorTest { // cancel and verify it has still only been called once negativeText.click(); - verify(sConsentManager).resetTopics(); + verify(mConsentManager).resetTopics(); } @Test @@ -367,7 +324,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).revokeConsentForApp(any(App.class)); + verify(mConsentManager).revokeConsentForApp(any(App.class)); blockAppText = getElement(R.string.settingsUI_block_app_title, 0); assertThat(blockAppText.exists()).isTrue(); @@ -380,7 +337,7 @@ public class SettingsActivityUiAutomatorTest { // cancel and verify it has still only been called once negativeText.click(); - verify(sConsentManager).revokeConsentForApp(any(App.class)); + verify(mConsentManager).revokeConsentForApp(any(App.class)); } @Test @@ -402,7 +359,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).restoreConsentForApp(any(App.class)); + verify(mConsentManager).restoreConsentForApp(any(App.class)); unblockAppText = getElement(R.string.settingsUI_unblock_app_title, 0); assertThat(unblockAppText.exists()).isTrue(); } @@ -421,7 +378,7 @@ public class SettingsActivityUiAutomatorTest { // confirm positiveText.click(); - verify(sConsentManager).resetApps(); + verify(mConsentManager).resetApps(); // click reset again scrollToAndClick(R.string.settingsUI_reset_apps_title); @@ -432,7 +389,7 @@ public class SettingsActivityUiAutomatorTest { // cancel and verify it has still only been called once negativeText.click(); - verify(sConsentManager).resetApps(); + verify(mConsentManager).resetApps(); } @Test @@ -461,13 +418,13 @@ public class SettingsActivityUiAutomatorTest { blockTopicText.click(); dialogTitle = getElement(R.string.settingsUI_dialog_block_topic_message); assertThat(dialogTitle.exists()).isFalse(); - verify(sConsentManager).revokeConsentForTopic(any(Topic.class)); + verify(mConsentManager).revokeConsentForTopic(any(Topic.class)); // reset topic scrollToAndClick(R.string.settingsUI_reset_topics_title); dialogTitle = getElement(R.string.settingsUI_dialog_reset_topic_message); assertThat(dialogTitle.exists()).isFalse(); - verify(sConsentManager).resetTopics(); + verify(mConsentManager).resetTopics(); // open unblock topic view scrollToAndClick(R.string.settingsUI_blocked_topics_title); @@ -478,10 +435,33 @@ public class SettingsActivityUiAutomatorTest { unblockTopicText.click(); dialogTitle = getElement(R.string.settingsUI_dialog_unblock_topic_message); assertThat(dialogTitle.exists()).isFalse(); - verify(sConsentManager).restoreConsentForTopic(any(Topic.class)); + verify(mConsentManager).restoreConsentForTopic(any(Topic.class)); } - private String getString(int resourceId) { - return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); + /** + * Test for the Button to show blocked topics when the list of Topics is Empty The Button should + * be disabled if blocked topics is empty + * + * @throws UiObjectNotFoundException + */ + @Test + public void blockedTopicsWhenEmptyStateButtonTest() throws UiObjectNotFoundException { + // Return an empty topics list + doReturn(ImmutableList.of()).when(mConsentManager).getKnownTopicsWithConsent(); + // Return a non-empty blocked topics list + List tempList = new ArrayList<>(); + tempList.add(Topic.create(10004, 1, 1)); + tempList.add(Topic.create(10005, 1, 1)); + ImmutableList blockedTopicsList = ImmutableList.copyOf(tempList); + doReturn(blockedTopicsList).when(mConsentManager).getTopicsWithRevokedConsent(); + // navigate to topics page + scrollToAndClick(R.string.settingsUI_topics_title); + UiObject blockedTopicsWhenEmptyStateButton = + sDevice.findObject( + new UiSelector() + .className("android.widget.Button") + .text(getString(R.string.settingsUI_blocked_topics_title))); + + assertThat(blockedTopicsWhenEmptyStateButton.isEnabled()).isTrue(); } } -- cgit v1.2.3 From f5ea731707f3d8b2132bb91ea4d6dc1328822fae Mon Sep 17 00:00:00 2001 From: Albert Kong Date: Tue, 18 Oct 2022 21:50:37 +0000 Subject: Converted to UIAutomator for notification tests. Test: atest Bug: 254333010 Change-Id: I2e639964cb01575cdb943360ae125ae02b9f7fdf --- .../ConsentNotificationTriggerTest.java | 65 +++++++++++++- .../ui/notifications/NotificationActivityTest.java | 100 --------------------- .../NotificationActivityUiAutomatorTest.java | 50 ++++++++--- 3 files changed, 99 insertions(+), 116 deletions(-) delete mode 100644 adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java index 31bba31bc8..9d81f09d65 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java @@ -30,8 +30,15 @@ import android.content.Context; import android.content.pm.PackageManager; import androidx.core.app.NotificationManagerCompat; +import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; import com.android.adservices.api.R; import com.android.adservices.service.consent.ConsentManager; @@ -48,6 +55,8 @@ import org.mockito.quality.Strictness; @RunWith(AndroidJUnit4.class) public class ConsentNotificationTriggerTest { private static final String NOTIFICATION_CHANNEL_ID = "PRIVACY_SANDBOX_CHANNEL"; + private static final int LAUNCH_TIMEOUT = 5000; + private static UiDevice sDevice; @Mock private NotificationManagerCompat mNotificationManagerCompat; @Mock private ConsentManager mConsentManager; @@ -59,10 +68,12 @@ public class ConsentNotificationTriggerTest { @Before public void setUp() { mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + // Initialize UiDevice instance + sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); } @Test - public void testEuNotification() throws InterruptedException { + public void testEuNotification() throws InterruptedException, UiObjectNotFoundException { MockitoAnnotations.initMocks(this); mStaticMockSession = ExtendedMockito.mockitoSession() @@ -87,14 +98,32 @@ public class ConsentNotificationTriggerTest { .isEqualTo(expectedTitle); assertThat(notification.extras.getCharSequence(Notification.EXTRA_TEXT)) .isEqualTo(expectedContent); - Thread.sleep(5000); // wait 5s to make sure that Notification disappears. + + sDevice.openNotification(); + sDevice.wait(Until.hasObject(By.pkg("com.android.systemui")), LAUNCH_TIMEOUT); + UiObject scroller = + sDevice.findObject( + new UiSelector() + .packageName("com.android.systemui") + .resourceId( + "com.android.systemui:id/notification_stack_scroller")); + assertThat(scroller.exists()).isTrue(); + UiSelector notificationCardSelector = + new UiSelector().text(getString(R.string.notificationUI_notification_title_eu)); + UiObject notificationCard = scroller.getChild(notificationCardSelector); + assertThat(notificationCard.exists()).isTrue(); + + notificationCard.click(); + Thread.sleep(LAUNCH_TIMEOUT); + UiObject title = getElement(R.string.notificationUI_header_title_eu); + assertThat(title.exists()).isTrue(); } finally { mStaticMockSession.finishMocking(); } } @Test - public void testNonEuNotifications() throws InterruptedException { + public void testNonEuNotifications() throws InterruptedException, UiObjectNotFoundException { MockitoAnnotations.initMocks(this); mStaticMockSession = ExtendedMockito.mockitoSession() @@ -124,7 +153,27 @@ public class ConsentNotificationTriggerTest { .isEqualTo(expectedTitle); assertThat(notification.extras.getCharSequence(Notification.EXTRA_TEXT)) .isEqualTo(expectedContent); - Thread.sleep(5000); // wait 5s to make sure that Notification disappears. + + sDevice.openNotification(); + sDevice.wait(Until.hasObject(By.pkg("com.android.systemui")), LAUNCH_TIMEOUT); + + UiObject scroller = + sDevice.findObject( + new UiSelector() + .packageName("com.android.systemui") + .resourceId( + "com.android.systemui:id/notification_stack_scroller")); + assertThat(scroller.exists()).isTrue(); + UiObject notificationCard = + scroller.getChild( + new UiSelector() + .text(getString(R.string.notificationUI_notification_title))); + assertThat(notificationCard.exists()).isTrue(); + + notificationCard.click(); + Thread.sleep(LAUNCH_TIMEOUT); + UiObject title = getElement(R.string.notificationUI_header_title); + assertThat(title.exists()).isTrue(); } finally { mStaticMockSession.finishMocking(); } @@ -154,4 +203,12 @@ public class ConsentNotificationTriggerTest { mStaticMockSession.finishMocking(); } } + + private String getString(int resourceId) { + return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); + } + + private UiObject getElement(int resId) { + return sDevice.findObject(new UiSelector().text(getString(resId))); + } } diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java deleted file mode 100644 index 325c9b6e64..0000000000 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2022 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 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 com.android.adservices.ui.notifications; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.mockito.ArgumentMatchers.any; - -import android.content.Context; -import android.content.Intent; - -import androidx.test.core.app.ActivityScenario; - -import com.android.adservices.api.R; -import com.android.adservices.service.common.BackgroundJobsManager; -import com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity; -import com.android.adservices.ui.settings.fragments.AdServicesSettingsMainFragment; -import com.android.dx.mockito.inline.extended.ExtendedMockito; -import com.android.dx.mockito.inline.extended.StaticMockitoSession; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.MockitoAnnotations; -import org.mockito.quality.Strictness; - -/** Tests for {@link ConsentNotificationActivity}. */ -public class NotificationActivityTest { - private static final String NOTIFICATION_INTENT = "android.test.adservices.ui.NOTIFICATIONS"; - private StaticMockitoSession mStaticMockSession; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mStaticMockSession = - ExtendedMockito.mockitoSession() - .spyStatic(BackgroundJobsManager.class) - .strictness(Strictness.WARN) - .initMocks(this) - .startMocking(); - ExtendedMockito.doNothing() - .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); - - Intent mIntent = new Intent(NOTIFICATION_INTENT); - mIntent.putExtra("isEUDevice", false); - ActivityScenario.launch(mIntent); - } - - @After - public void teardown() { - if (mStaticMockSession != null) { - mStaticMockSession.finishMocking(); - } - } - - /** - * Test if {@link AdServicesSettingsMainFragment} is displayed in {@link - * AdServicesSettingsMainActivity}. - */ - @Test - public void test_FragmentContainer_isDisplayed() { - onView(withId(R.id.fragment_container_view)).check(matches(isDisplayed())); - } - - /** - * Test if {@link ConsentNotificationFragment} is displayed in {@link - * ConsentNotificationActivity}. - */ - @Test - public void test_ConsentNotificationFragment_isDisplayed() { - checkConsentNotificationFragmentIsDisplayed(); - } - - private void checkConsentNotificationFragmentIsDisplayed() { - onView(withText(R.string.notificationUI_header_title)).check(matches(isDisplayed())); - } - - private void launchEUActivity() { - Intent mIntent = new Intent(NOTIFICATION_INTENT); - mIntent.putExtra("isEUDevice", true); - ActivityScenario.launch(mIntent); - } -} diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java index a48af7f977..f7017b1c72 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java @@ -94,15 +94,6 @@ public class NotificationActivityUiAutomatorTest { sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } - private void startActivity(boolean isEUActivity) { - // Send intent - sIntent.putExtra("isEUDevice", isEUActivity); - sContext.startActivity(sIntent); - - // Wait for the app to appear - sDevice.wait(Until.hasObject(By.pkg(NOTIFICATION_TEST_PACKAGE).depth(0)), LAUNCH_TIMEOUT); - } - @After public void teardown() { if (mStaticMockSession != null) { @@ -110,12 +101,30 @@ public class NotificationActivityUiAutomatorTest { } } - private UiObject getElement(int resId) { - return sDevice.findObject(new UiSelector().text(getString(resId))); + @Test + public void moreButtonTest() throws UiObjectNotFoundException, InterruptedException { + startActivity(true); + UiObject leftControlButton = + getElement(R.string.notificationUI_left_control_button_text_eu); + UiObject rightControlButton = + getElement(R.string.notificationUI_right_control_button_text_eu); + UiObject moreButton = getElement(R.string.notificationUI_more_button_text); + assertThat(leftControlButton.exists()).isFalse(); + assertThat(rightControlButton.exists()).isFalse(); + assertThat(moreButton.exists()).isTrue(); + + while (moreButton.exists()) { + moreButton.click(); + Thread.sleep(2000); + } + assertThat(leftControlButton.exists()).isTrue(); + assertThat(rightControlButton.exists()).isTrue(); + assertThat(moreButton.exists()).isFalse(); } @Test - public void moreButtonTest() throws UiObjectNotFoundException, InterruptedException { + public void acceptedConfirmationScreenTest() + throws UiObjectNotFoundException, InterruptedException { startActivity(true); UiObject leftControlButton = getElement(R.string.notificationUI_left_control_button_text_eu); @@ -133,9 +142,26 @@ public class NotificationActivityUiAutomatorTest { assertThat(leftControlButton.exists()).isTrue(); assertThat(rightControlButton.exists()).isTrue(); assertThat(moreButton.exists()).isFalse(); + + rightControlButton.click(); + UiObject acceptedTitle = getElement(R.string.notificationUI_confirmation_accept_title); + assertThat(acceptedTitle.exists()).isTrue(); + } + + private void startActivity(boolean isEUActivity) { + // Send intent + sIntent.putExtra("isEUDevice", isEUActivity); + sContext.startActivity(sIntent); + + // Wait for the app to appear + sDevice.wait(Until.hasObject(By.pkg(NOTIFICATION_TEST_PACKAGE).depth(0)), LAUNCH_TIMEOUT); } private String getString(int resourceId) { return ApplicationProvider.getApplicationContext().getResources().getString(resourceId); } + + private UiObject getElement(int resId) { + return sDevice.findObject(new UiSelector().text(getString(resId))); + } } -- cgit v1.2.3 From a086c3d1cc7df7be725f9624c3b5eac6b3fc3eba Mon Sep 17 00:00:00 2001 From: Matt Dembski Date: Sun, 23 Oct 2022 21:18:58 +0000 Subject: Logging type initialization fix Bug: 254925672 Test: atest Change-Id: I58bc4b6b465362941e47e8d985eb4bdcf07dc032 --- .../adservices/ui/notifications/ConsentNotificationTriggerTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java index 9d81f09d65..b5b6f45613 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java @@ -27,7 +27,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.app.Notification; import android.app.NotificationManager; import android.content.Context; -import android.content.pm.PackageManager; import androidx.core.app.NotificationManagerCompat; import androidx.test.core.app.ApplicationProvider; @@ -143,7 +142,7 @@ public class ConsentNotificationTriggerTest { Thread.sleep(1000); // wait 1s to make sure that Notification is displayed. verify(mConsentManager).enable(any(Context.class)); - verify(mConsentManager).recordNotificationDisplayed(any(PackageManager.class)); + verify(mConsentManager).recordNotificationDisplayed(); verifyNoMoreInteractions(mConsentManager); assertThat(mNotificationManager.getActiveNotifications()).hasLength(1); final Notification notification = @@ -197,7 +196,7 @@ public class ConsentNotificationTriggerTest { ConsentNotificationTrigger.showConsentNotification(mContext, true); - verify(mConsentManager).recordNotificationDisplayed(any(PackageManager.class)); + verify(mConsentManager).recordNotificationDisplayed(); verifyNoMoreInteractions(mConsentManager); } finally { mStaticMockSession.finishMocking(); -- cgit v1.2.3 From 3a6c054ef333227a5eb250da016ae209d7dbd1ba Mon Sep 17 00:00:00 2001 From: hanlixy Date: Thu, 27 Oct 2022 22:57:41 +0000 Subject: Prefactoring Tests to allow to Mock Flags We're working on ag/20270887 to enable a flag to guard DB schema change. This requires to introduce FlagFactory in DBHelper. It results in many measurement tests to fail due to Device_config access issue to read production flag in test. In order to split the fix from actual logic, I raise this CL to prefactoring affected tests. I fix some of them by changing db to test db, and fix others by mocking the flag directly. Bug: 256028076 Test: atest AdServicesServiceCoreUnitTests AdServicesApkUITests Change-Id: I6d9a62c7e5caba9f705820bdb134aad33a683c48 --- .../ConsentNotificationTriggerTest.java | 3 +++ .../NotificationActivityUiAutomatorTest.java | 3 +++ .../settings/SettingsActivityUiAutomatorTest.java | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 9 deletions(-) (limited to 'adservices/apk/tests') diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java index b5b6f45613..cc9d5ab749 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/ConsentNotificationTriggerTest.java @@ -40,6 +40,7 @@ import androidx.test.uiautomator.UiSelector; import androidx.test.uiautomator.Until; import com.android.adservices.api.R; +import com.android.adservices.service.FlagsFactory; import com.android.adservices.service.consent.ConsentManager; import com.android.dx.mockito.inline.extended.ExtendedMockito; @@ -76,10 +77,12 @@ public class ConsentNotificationTriggerTest { MockitoAnnotations.initMocks(this); mStaticMockSession = ExtendedMockito.mockitoSession() + .spyStatic(FlagsFactory.class) .strictness(Strictness.WARN) .initMocks(this) .startMocking(); try { + ExtendedMockito.doReturn(FlagsFactory.getFlagsForTest()).when(FlagsFactory::getFlags); mNotificationManager = mContext.getSystemService(NotificationManager.class); final String expectedTitle = mContext.getString(R.string.notificationUI_notification_title_eu); diff --git a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java index f7017b1c72..cd072cc619 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/notifications/NotificationActivityUiAutomatorTest.java @@ -36,6 +36,7 @@ import androidx.test.uiautomator.UiSelector; import androidx.test.uiautomator.Until; import com.android.adservices.api.R; +import com.android.adservices.service.FlagsFactory; import com.android.adservices.service.PhFlags; import com.android.adservices.service.common.BackgroundJobsManager; import com.android.dx.mockito.inline.extended.ExtendedMockito; @@ -68,9 +69,11 @@ public class NotificationActivityUiAutomatorTest { ExtendedMockito.mockitoSession() .spyStatic(PhFlags.class) .spyStatic(BackgroundJobsManager.class) + .spyStatic(FlagsFactory.class) .strictness(Strictness.WARN) .initMocks(this) .startMocking(); + ExtendedMockito.doReturn(FlagsFactory.getFlagsForTest()).when(FlagsFactory::getFlags); ExtendedMockito.doNothing() .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); mPhFlags = spy(PhFlags.getInstance()); diff --git a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java index d093295b76..65184b5eb2 100644 --- a/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java +++ b/adservices/apk/tests/src/com/android/adservices/ui/settings/SettingsActivityUiAutomatorTest.java @@ -41,6 +41,7 @@ import androidx.test.uiautomator.Until; import com.android.adservices.api.R; import com.android.adservices.data.topics.Topic; +import com.android.adservices.service.FlagsFactory; import com.android.adservices.service.PhFlags; import com.android.adservices.service.common.BackgroundJobsManager; import com.android.adservices.service.consent.App; @@ -74,6 +75,18 @@ public class SettingsActivityUiAutomatorTest { @Before public void setup() throws UiObjectNotFoundException, IOException { + // Static mocking + mStaticMockSession = + ExtendedMockito.mockitoSession() + .spyStatic(PhFlags.class) + .spyStatic(FlagsFactory.class) + .spyStatic(BackgroundJobsManager.class) + .spyStatic(ConsentManager.class) + .strictness(Strictness.WARN) + .initMocks(this) + .startMocking(); + ExtendedMockito.doReturn(FlagsFactory.getFlagsForTest()).when(FlagsFactory::getFlags); + // prepare objects used by static mocking mConsentManager = spy(ConsentManager.getInstance(ApplicationProvider.getApplicationContext())); @@ -115,15 +128,6 @@ public class SettingsActivityUiAutomatorTest { } doNothing().when(mConsentManager).resetMeasurement(); - // Static mocking - mStaticMockSession = - ExtendedMockito.mockitoSession() - .spyStatic(PhFlags.class) - .spyStatic(BackgroundJobsManager.class) - .spyStatic(ConsentManager.class) - .strictness(Strictness.WARN) - .initMocks(this) - .startMocking(); ExtendedMockito.doNothing() .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); mPhFlags = spy(PhFlags.getInstance()); -- cgit v1.2.3