1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.appsearch.testutil;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.annotation.NonNull;
23 import android.app.appsearch.AppSearchBatchResult;
24 import android.app.appsearch.AppSearchSessionShim;
25 import android.app.appsearch.GenericDocument;
26 import android.app.appsearch.GetByDocumentIdRequest;
27 import android.app.appsearch.SearchResult;
28 import android.app.appsearch.SearchResultsShim;
29 
30 import com.android.server.appsearch.external.localstorage.visibilitystore.CallerAccess;
31 import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityChecker;
32 import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Set;
37 import java.util.concurrent.Future;
38 
39 /**
40  * Class with helper functions for testing for AppSearch.
41  *
42  * @hide
43  */
44 public class AppSearchTestUtils {
AppSearchTestUtils()45     private AppSearchTestUtils() {}
46 
47     /** Checks batch result. */
48     @NonNull
checkIsBatchResultSuccess( @onNull Future<AppSearchBatchResult<K, V>> future)49     public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
50             @NonNull Future<AppSearchBatchResult<K, V>> future) throws Exception {
51         AppSearchBatchResult<K, V> result = future.get();
52         assertWithMessage("AppSearchBatchResult not successful: " + result)
53                 .that(result.isSuccess())
54                 .isTrue();
55         return result;
56     }
57 
58     /** Gets documents from ids. */
59     @NonNull
doGet( @onNull AppSearchSessionShim session, @NonNull String namespace, @NonNull String... ids)60     public static List<GenericDocument> doGet(
61             @NonNull AppSearchSessionShim session,
62             @NonNull String namespace,
63             @NonNull String... ids)
64             throws Exception {
65         AppSearchBatchResult<String, GenericDocument> result =
66                 checkIsBatchResultSuccess(
67                         session.getByDocumentIdAsync(
68                                 new GetByDocumentIdRequest.Builder(namespace).addIds(ids).build()));
69         assertThat(result.getSuccesses()).hasSize(ids.length);
70         assertThat(result.getFailures()).isEmpty();
71         List<GenericDocument> list = new ArrayList<>(ids.length);
72         for (String id : ids) {
73             list.add(result.getSuccesses().get(id));
74         }
75         return list;
76     }
77 
78     /** Gets documents from {@link GetByDocumentIdRequest}. */
79     @NonNull
doGet( @onNull AppSearchSessionShim session, @NonNull GetByDocumentIdRequest request)80     public static List<GenericDocument> doGet(
81             @NonNull AppSearchSessionShim session, @NonNull GetByDocumentIdRequest request)
82             throws Exception {
83         AppSearchBatchResult<String, GenericDocument> result =
84                 checkIsBatchResultSuccess(session.getByDocumentIdAsync(request));
85         Set<String> ids = request.getIds();
86         assertThat(result.getSuccesses()).hasSize(ids.size());
87         assertThat(result.getFailures()).isEmpty();
88         List<GenericDocument> list = new ArrayList<>(ids.size());
89         for (String id : ids) {
90             list.add(result.getSuccesses().get(id));
91         }
92         return list;
93     }
94 
95     /** Extracts documents from {@link SearchResultsShim}. */
96     @NonNull
convertSearchResultsToDocuments( @onNull SearchResultsShim searchResults)97     public static List<GenericDocument> convertSearchResultsToDocuments(
98             @NonNull SearchResultsShim searchResults) throws Exception {
99         List<SearchResult> results = retrieveAllSearchResults(searchResults);
100         List<GenericDocument> documents = new ArrayList<>(results.size());
101         for (SearchResult result : results) {
102             documents.add(result.getGenericDocument());
103         }
104         return documents;
105     }
106 
107     /** Extracts all {@link SearchResult} from {@link SearchResultsShim}. */
108     @NonNull
retrieveAllSearchResults( @onNull SearchResultsShim searchResults)109     public static List<SearchResult> retrieveAllSearchResults(
110             @NonNull SearchResultsShim searchResults) throws Exception {
111         List<SearchResult> page = searchResults.getNextPageAsync().get();
112         List<SearchResult> results = new ArrayList<>();
113         while (!page.isEmpty()) {
114             results.addAll(page);
115             page = searchResults.getNextPageAsync().get();
116         }
117         return results;
118     }
119 
120     /**
121      * Creates a mock {@link VisibilityChecker} where schema is searchable if prefixedSchema is one
122      * of the provided set of visiblePrefixedSchemas and caller does not have system access.
123      *
124      * @param visiblePrefixedSchemas Schema types that are accessible to any caller.
125      * @return Mocked {@link VisibilityChecker} instance.
126      */
127     @NonNull
createMockVisibilityChecker( @onNull Set<String> visiblePrefixedSchemas)128     public static VisibilityChecker createMockVisibilityChecker(
129             @NonNull Set<String> visiblePrefixedSchemas) {
130         return new VisibilityChecker() {
131             @Override
132             public boolean isSchemaSearchableByCaller(
133                     @NonNull CallerAccess callerAccess,
134                     @NonNull String packageName,
135                     @NonNull String prefixedSchema,
136                     @NonNull VisibilityStore visibilityStore) {
137                 return visiblePrefixedSchemas.contains(prefixedSchema);
138             }
139 
140             @Override
141             public boolean doesCallerHaveSystemAccess(@NonNull String s) {
142                 return false;
143             }
144         };
145     }
146 
147     /**
148      * Creates a mock {@link VisibilityChecker}, where it can be configured if schema is searchable
149      * by caller and caller does not have system access.
150      *
151      * @param isSchemaSearchableByCaller Schema visibility for caller.
152      * @return Mocked {@link VisibilityChecker} instance.
153      */
154     @NonNull
155     public static VisibilityChecker createMockVisibilityChecker(
156             boolean isSchemaSearchableByCaller) {
157         return new VisibilityChecker() {
158             @Override
159             public boolean isSchemaSearchableByCaller(
160                     @NonNull CallerAccess callerAccess,
161                     @NonNull String packageName,
162                     @NonNull String prefixedSchema,
163                     @NonNull VisibilityStore visibilityStore) {
164                 return isSchemaSearchableByCaller;
165             }
166 
167             @Override
168             public boolean doesCallerHaveSystemAccess(@NonNull String s) {
169                 return false;
170             }
171         };
172     }
173 }
174