From 11fa37ebb49e4ec4a975d111bf3512139b905062 Mon Sep 17 00:00:00 2001
From: Matthew Fritze
Date: Tue, 17 Jul 2018 13:47:39 -0700
Subject: [PATCH] Add Settings Search Regression test
Take a snapshot of the currently available search results, and
verify that search results aren't accidentally removed.
We use 4 items to identify a search result:
- Title
- Data Key
- Slice Uri
We use Title & Key to identify the search result, since they should not change.
The Slice Uri is used to make sure we don't regress on Slice Availability.
Test: runtest --path packages/apps/Settings/tests/unit/src/com/android/settings/search/SettingsSearchResultRegressionTest.java
Change-Id: I22498229bbcd1e90c9e0a026af9df4367a98190a
---
tests/uitests/AndroidManifest.xml | 1 +
tests/uitests/assets/search_results_list | 623 ++++++++++++++++++
.../android/settings/search/SearchData.java | 81 +++
.../SettingsSearchResultRegressionTest.java | 210 ++++++
4 files changed, 915 insertions(+)
create mode 100644 tests/uitests/assets/search_results_list
create mode 100644 tests/uitests/src/com/android/settings/search/SearchData.java
create mode 100644 tests/uitests/src/com/android/settings/search/SettingsSearchResultRegressionTest.java
diff --git a/tests/uitests/AndroidManifest.xml b/tests/uitests/AndroidManifest.xml
index 91e15b8b43d..49a2fd110aa 100644
--- a/tests/uitests/AndroidManifest.xml
+++ b/tests/uitests/AndroidManifest.xml
@@ -28,6 +28,7 @@
+
+ * The data set used here (/tests/unit/assets/search_results_list) needs to be updated
+ * every once in a while so that we can check newly added results.
+ *
+ */
+ @Test
+ @Presubmit
+ public void searchResultsDoNotRegress() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ final Uri uri = getTestProviderUri();
+ final Cursor cursor = resolver.query(uri, null, null, null, null);
+
+ if (cursor == null) {
+ // Assume Settings Intelligence is wrong.
+ return;
+ }
+
+ final Set availableSearchResults = getSearchDataFromCursor(cursor);
+ final Set registeredSearchResults = getRegisteredResults();
+
+ // Seed with results that we expect
+ final Set missingSearchResults = new HashSet<>(registeredSearchResults);
+ // Seed with results that are available
+ final Set newSearchResults = new HashSet<>(availableSearchResults);
+
+ // Remove all available results, leaving results that have been removed.
+ missingSearchResults.removeAll(availableSearchResults);
+ // Remove all results we expect, leaving results that have not yet been registered.
+ newSearchResults.removeAll(registeredSearchResults);
+
+ assertWithMessage(ERROR_RESULTS_MISSING + ERROR_RERUN_TEST)
+ .that(missingSearchResults).isEmpty();
+ assertWithMessage(ERROR_NEW_RESULTS + ERROR_RERUN_TEST).that(newSearchResults).isEmpty();
+ }
+
+ // TODO (b/113907111) add a test to catch duplicate title search results.
+
+ /**
+ * Test to generate a new list of search results. Uncomment the Test annotation and run the
+ * test to generate the list.
+ */
+ @Ignore
+ @Test
+ public void generate_search_result_list() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ final Uri uri = getTestProviderUri();
+ final Cursor cursor = resolver.query(uri, null, null, null, null);
+ final List availableSearchResults =
+ new ArrayList<>(getSearchDataFromCursor(cursor));
+
+ Collections.sort(availableSearchResults, Comparator.comparing(SearchData::getTitle)
+ .thenComparing(SearchData::getKey));
+
+ assertThat(generateListFromSearchData(availableSearchResults)).isNull();
+ }
+
+ private Set getSearchDataFromCursor(Cursor cursor) {
+ final Set searchData = new HashSet<>();
+
+ final int titleIndex = cursor.getColumnIndex(
+ IndexColumns.DATA_TITLE);
+ final int keyIndex = cursor.getColumnIndex(
+ IndexColumns.DATA_KEY_REF);
+
+ while (cursor.moveToNext()) {
+ String title = cursor.getString(titleIndex);
+ String key = cursor.getString(keyIndex);
+
+ if (TextUtils.isEmpty(title)) {
+ title = "";
+ }
+
+ if (TextUtils.isEmpty(key)) {
+ key = "";
+ }
+
+ searchData.add(new SearchData.Builder()
+ .setTitle(title)
+ .setKey(key)
+ .build());
+ }
+
+ return searchData;
+ }
+
+ /**
+ * Utility method to generate the list of search results that this class uses to validate
+ * results.
+ */
+ private String generateListFromSearchData(List searchData) {
+ StringBuilder builder = new StringBuilder();
+ for (SearchData searchResult : searchData) {
+ builder.append(searchResult.title)
+ .append(
+ SearchData.DELIM)
+ .append(searchResult.key)
+ .append("\n");
+ }
+ return builder.toString();
+ }
+
+ private Uri getTestProviderUri() {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority("com.google.android.settings.intelligence.modules.search.regression")
+ .build();
+ }
+
+ private Set getRegisteredResults() {
+ final String filename = "search_results_list";
+ final Set registeredResults = new HashSet<>();
+
+ try {
+ final InputStream in = mContext.getAssets().open(filename);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ registeredResults.add(
+ SearchData.from(line));
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Error initializing registered result list "
+ + filename, e);
+ }
+
+ return registeredResults;
+ }
+}
\ No newline at end of file