1 /*
2  * Copyright (C) 2022 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.adservices.cts;
18 
19 import static com.android.adservices.AdServicesCommon.BINDER_TIMEOUT_SYSTEM_PROPERTY_NAME;
20 import static com.android.adservices.service.FlagsConstants.KEY_ENABLE_ENROLLMENT_TEST_SEED;
21 import static com.android.adservices.service.FlagsConstants.KEY_ENFORCE_ISOLATE_MAX_HEAP_SIZE;
22 import static com.android.adservices.service.FlagsConstants.KEY_ISOLATE_MAX_HEAP_SIZE_BYTES;
23 
24 import static com.google.common.truth.Truth.assertThat;
25 
26 import static org.junit.Assert.assertThrows;
27 
28 import android.Manifest;
29 import android.adservices.adselection.AdSelectionConfig;
30 import android.adservices.adselection.AdSelectionConfigFixture;
31 import android.adservices.adselection.AdSelectionFromOutcomesConfig;
32 import android.adservices.adselection.AdSelectionFromOutcomesConfigFixture;
33 import android.adservices.adselection.AdSelectionOutcome;
34 import android.adservices.adselection.AddAdSelectionFromOutcomesOverrideRequest;
35 import android.adservices.adselection.AddAdSelectionOverrideRequest;
36 import android.adservices.adselection.RemoveAdSelectionFromOutcomesOverrideRequest;
37 import android.adservices.adselection.RemoveAdSelectionOverrideRequest;
38 import android.adservices.adselection.ReportImpressionRequest;
39 import android.adservices.clients.adselection.AdSelectionClient;
40 import android.adservices.clients.adselection.TestAdSelectionClient;
41 import android.adservices.common.AdSelectionSignals;
42 import android.adservices.common.AdTechIdentifier;
43 import android.adservices.utils.CtsWebViewSupportUtil;
44 import android.net.Uri;
45 import android.os.Process;
46 
47 import androidx.test.platform.app.InstrumentationRegistry;
48 
49 import com.android.adservices.LoggerFactory;
50 import com.android.adservices.common.AdServicesFlagsSetterRule;
51 import com.android.adservices.common.AdservicesTestHelper;
52 import com.android.adservices.service.devapi.DevContext;
53 import com.android.adservices.service.devapi.DevContextFilter;
54 import com.android.adservices.shared.testing.annotations.RequiresSdkLevelAtLeastS;
55 import com.android.adservices.shared.testing.annotations.SetFlagDisabled;
56 import com.android.adservices.shared.testing.annotations.SetFlagEnabled;
57 import com.android.adservices.shared.testing.annotations.SetLongDebugFlag;
58 
59 import com.google.common.util.concurrent.ListenableFuture;
60 
61 import org.junit.Assume;
62 import org.junit.Before;
63 import org.junit.Test;
64 
65 import java.util.ArrayList;
66 import java.util.concurrent.ExecutionException;
67 import java.util.concurrent.Executor;
68 import java.util.concurrent.Executors;
69 import java.util.concurrent.TimeUnit;
70 
71 @RequiresSdkLevelAtLeastS // TODO(b/291488819) - Remove SDK Level check if Fledge is enabled on R.
72 @SetFlagEnabled(KEY_ENABLE_ENROLLMENT_TEST_SEED)
73 @SetFlagDisabled(KEY_ENFORCE_ISOLATE_MAX_HEAP_SIZE)
74 @SetFlagDisabled(KEY_ISOLATE_MAX_HEAP_SIZE_BYTES)
75 // TODO (b/330324133): Short-term solution to allow test to extend binder timeout to
76 // resolve the test flakiness.
77 @SetLongDebugFlag(name = BINDER_TIMEOUT_SYSTEM_PROPERTY_NAME, value = 10_000)
78 public final class TestAdSelectionManagerTest extends ForegroundCtsTestCase {
79 
80     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
81     private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
82 
83     private static final String DECISION_LOGIC_JS = "function test() { return \"hello world\"; }";
84     private static final long AD_SELECTION_ID = 1;
85     private static final AdTechIdentifier SELLER = AdTechIdentifier.fromString("test.com");
86     private static final Uri DECISION_LOGIC_URI =
87             Uri.parse("https://test.com/test/decisions_logic_uris");
88     private static final Uri TRUSTED_SCORING_SIGNALS_URI =
89             Uri.parse("https://test.com/test/decisions_logic_uris");
90     private static final AdSelectionSignals TRUSTED_SCORING_SIGNALS =
91             AdSelectionSignals.fromString(
92                     "{\n"
93                             + "\t\"render_uri_1\": \"signals_for_1\",\n"
94                             + "\t\"render_uri_2\": \"signals_for_2\"\n"
95                             + "}");
96     private static final AdSelectionConfig AD_SELECTION_CONFIG =
97             AdSelectionConfigFixture.anAdSelectionConfigBuilder()
98                     .setSeller(SELLER)
99                     .setDecisionLogicUri(DECISION_LOGIC_URI)
100                     .setTrustedScoringSignalsUri(TRUSTED_SCORING_SIGNALS_URI)
101                     .build();
102 
103     private static final AdSelectionSignals SELECTION_SIGNALS = AdSelectionSignals.EMPTY;
104 
105     private static final AdSelectionFromOutcomesConfig AD_SELECTION_FROM_OUTCOMES_CONFIG =
106             AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(
107                     SELLER, DECISION_LOGIC_URI);
108 
109     private TestAdSelectionClient mTestAdSelectionClient;
110     private boolean mIsDebugMode;
111 
112     @Override
getAdServicesFlagsSetterRule()113     protected AdServicesFlagsSetterRule getAdServicesFlagsSetterRule() {
114         return AdServicesFlagsSetterRule.forAllApisEnabledTests()
115                 .setCompatModeFlags()
116                 .setPpapiAppAllowList(mPackageName);
117     }
118 
119     @Before
setup()120     public void setup() {
121 
122         if (sdkLevel.isAtLeastT()) {
123             assertForegroundActivityStarted();
124         }
125 
126         mTestAdSelectionClient =
127                 new TestAdSelectionClient.Builder()
128                         .setContext(sContext)
129                         .setExecutor(CALLBACK_EXECUTOR)
130                         .build();
131         DevContext devContext = DevContextFilter.create(sContext).createDevContext(Process.myUid());
132         mIsDebugMode = devContext.getDevOptionsEnabled();
133 
134         InstrumentationRegistry.getInstrumentation()
135                 .getUiAutomation()
136                 .adoptShellPermissionIdentity(Manifest.permission.WRITE_DEVICE_CONFIG);
137 
138         // Kill AdServices process
139         AdservicesTestHelper.killAdservicesProcess(sContext);
140     }
141 
142     @Test
testFailsWithInvalidAdSelectionId()143     public void testFailsWithInvalidAdSelectionId() {
144         Assume.assumeTrue(CtsWebViewSupportUtil.isJSSandboxAvailable(sContext));
145         sLogger.i("Calling Report Impression");
146 
147         AdSelectionClient adSelectionClient =
148                 new AdSelectionClient.Builder()
149                         .setContext(sContext)
150                         .setExecutor(CALLBACK_EXECUTOR)
151                         .build();
152         assertInvalidAdSelectionIdFailsImpressionReporting(adSelectionClient);
153     }
154 
155     @Test
testFailsWithInvalidAdSelectionId_usingGetMethodToCreateManager()156     public void testFailsWithInvalidAdSelectionId_usingGetMethodToCreateManager() {
157         Assume.assumeTrue(CtsWebViewSupportUtil.isJSSandboxAvailable(sContext));
158         sLogger.i("Calling Report Impression");
159 
160         AdSelectionClient adSelectionClient =
161                 new AdSelectionClient.Builder()
162                         .setContext(sContext)
163                         .setExecutor(CALLBACK_EXECUTOR)
164                         .setUseGetMethodToCreateManagerInstance(true)
165                         .build();
166         assertInvalidAdSelectionIdFailsImpressionReporting(adSelectionClient);
167     }
168 
assertInvalidAdSelectionIdFailsImpressionReporting( AdSelectionClient adSelectionClient)169     private void assertInvalidAdSelectionIdFailsImpressionReporting(
170             AdSelectionClient adSelectionClient) {
171         ReportImpressionRequest input =
172                 new ReportImpressionRequest(AD_SELECTION_ID, AD_SELECTION_CONFIG);
173 
174         ListenableFuture<Void> result = adSelectionClient.reportImpression(input);
175 
176         Exception exception =
177                 assertThrows(
178                         ExecutionException.class,
179                         () -> {
180                             result.get(10, TimeUnit.SECONDS);
181                         });
182         assertThat(exception.getCause()).isInstanceOf(IllegalArgumentException.class);
183     }
184 
185     @Test
testAddOverrideFailsWithDebugModeDisabled()186     public void testAddOverrideFailsWithDebugModeDisabled() {
187         Assume.assumeFalse(mIsDebugMode);
188 
189         AddAdSelectionOverrideRequest request =
190                 new AddAdSelectionOverrideRequest(
191                         AD_SELECTION_CONFIG, DECISION_LOGIC_JS, TRUSTED_SCORING_SIGNALS);
192 
193         ListenableFuture<Void> result =
194                 mTestAdSelectionClient.overrideAdSelectionConfigRemoteInfo(request);
195 
196         Exception exception =
197                 assertThrows(
198                         ExecutionException.class,
199                         () -> {
200                             result.get(10, TimeUnit.SECONDS);
201                         });
202         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
203     }
204 
205     @Test
testAddOverrideFailsWithDebugModeDisabled_usingGetMethodToCreateManager()206     public void testAddOverrideFailsWithDebugModeDisabled_usingGetMethodToCreateManager()
207             throws Exception {
208         Assume.assumeFalse(mIsDebugMode);
209         overrideAdSelectionClient();
210         testAddOverrideFailsWithDebugModeDisabled();
211     }
212 
213     @Test
testRemoveOverrideFailsWithDebugModeDisabled()214     public void testRemoveOverrideFailsWithDebugModeDisabled() {
215         Assume.assumeFalse(mIsDebugMode);
216 
217         RemoveAdSelectionOverrideRequest request =
218                 new RemoveAdSelectionOverrideRequest(AD_SELECTION_CONFIG);
219 
220         ListenableFuture<Void> result =
221                 mTestAdSelectionClient.removeAdSelectionConfigRemoteInfoOverride(request);
222 
223         Exception exception =
224                 assertThrows(
225                         ExecutionException.class,
226                         () -> {
227                             result.get(10, TimeUnit.SECONDS);
228                         });
229         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
230     }
231 
232     @Test
testRemoveOverrideFailsWithDebugModeDisabled_usingGetMethodToCreateManager()233     public void testRemoveOverrideFailsWithDebugModeDisabled_usingGetMethodToCreateManager()
234             throws Exception {
235         Assume.assumeFalse(mIsDebugMode);
236         overrideAdSelectionClient();
237         testRemoveOverrideFailsWithDebugModeDisabled();
238     }
239 
240     @Test
testResetAllOverridesFailsWithDebugModeDisabled()241     public void testResetAllOverridesFailsWithDebugModeDisabled() {
242         Assume.assumeFalse(mIsDebugMode);
243 
244         TestAdSelectionClient testAdSelectionClient =
245                 new TestAdSelectionClient.Builder()
246                         .setContext(sContext)
247                         .setExecutor(CALLBACK_EXECUTOR)
248                         .build();
249         assertResetAllOverridesFailsWithDebugModeDisabled(testAdSelectionClient);
250     }
251 
252     @Test
testResetAllOverridesFailsWithDebugModeDisabled_usingGetMethodToCreateManager()253     public void testResetAllOverridesFailsWithDebugModeDisabled_usingGetMethodToCreateManager() {
254         Assume.assumeFalse(mIsDebugMode);
255 
256         TestAdSelectionClient testAdSelectionClient =
257                 new TestAdSelectionClient.Builder()
258                         .setContext(sContext)
259                         .setExecutor(CALLBACK_EXECUTOR)
260                         .setUseGetMethodToCreateManagerInstance(true)
261                         .build();
262         assertResetAllOverridesFailsWithDebugModeDisabled(testAdSelectionClient);
263     }
264 
assertResetAllOverridesFailsWithDebugModeDisabled( TestAdSelectionClient testAdSelectionClient)265     private void assertResetAllOverridesFailsWithDebugModeDisabled(
266             TestAdSelectionClient testAdSelectionClient) {
267         ListenableFuture<Void> result =
268                 testAdSelectionClient.resetAllAdSelectionConfigRemoteOverrides();
269 
270         Exception exception =
271                 assertThrows(
272                         ExecutionException.class,
273                         () -> {
274                             result.get(10, TimeUnit.SECONDS);
275                         });
276         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
277     }
278 
279     @Test
testFailsWithInvalidAdSelectionConfigNoBuyers()280     public void testFailsWithInvalidAdSelectionConfigNoBuyers() {
281         Assume.assumeTrue(CtsWebViewSupportUtil.isJSSandboxAvailable(sContext));
282         AdSelectionClient adSelectionClient =
283                 new AdSelectionClient.Builder()
284                         .setContext(sContext)
285                         .setExecutor(CALLBACK_EXECUTOR)
286                         .build();
287         assertNoBuyersConfigFailsAdSelection(adSelectionClient);
288     }
289 
290     @Test
testFailsWithInvalidAdSelectionConfigNoBuyers_usingGetMethodToCreateManager()291     public void testFailsWithInvalidAdSelectionConfigNoBuyers_usingGetMethodToCreateManager() {
292         Assume.assumeTrue(CtsWebViewSupportUtil.isJSSandboxAvailable(sContext));
293         AdSelectionClient adSelectionClient =
294                 new AdSelectionClient.Builder()
295                         .setContext(sContext)
296                         .setExecutor(CALLBACK_EXECUTOR)
297                         .setUseGetMethodToCreateManagerInstance(true)
298                         .build();
299         assertNoBuyersConfigFailsAdSelection(adSelectionClient);
300     }
301 
assertNoBuyersConfigFailsAdSelection(AdSelectionClient adSelectionClient)302     private void assertNoBuyersConfigFailsAdSelection(AdSelectionClient adSelectionClient) {
303         sLogger.i("Calling Ad Selection");
304         AdSelectionConfig adSelectionConfigNoBuyers =
305                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
306                         .setSeller(SELLER)
307                         .setDecisionLogicUri(DECISION_LOGIC_URI)
308                         .setCustomAudienceBuyers(new ArrayList<>())
309                         .setTrustedScoringSignalsUri(TRUSTED_SCORING_SIGNALS_URI)
310                         .build();
311 
312         ListenableFuture<AdSelectionOutcome> result =
313                 adSelectionClient.selectAds(adSelectionConfigNoBuyers);
314 
315         Exception exception =
316                 assertThrows(
317                         ExecutionException.class,
318                         () -> {
319                             result.get(10, TimeUnit.SECONDS);
320                         });
321         assertThat(exception.getCause()).isInstanceOf(IllegalArgumentException.class);
322     }
323 
overrideAdSelectionClient()324     private void overrideAdSelectionClient() {
325         mTestAdSelectionClient =
326                 new TestAdSelectionClient.Builder()
327                         .setContext(sContext)
328                         .setExecutor(CALLBACK_EXECUTOR)
329                         .setUseGetMethodToCreateManagerInstance(true)
330                         .build();
331     }
332 
333     @Test
testAddFromOutcomesOverrideFailsWithDebugModeDisabled()334     public void testAddFromOutcomesOverrideFailsWithDebugModeDisabled() throws Exception {
335         Assume.assumeFalse(mIsDebugMode);
336 
337         AddAdSelectionFromOutcomesOverrideRequest request =
338                 new AddAdSelectionFromOutcomesOverrideRequest(
339                         AD_SELECTION_FROM_OUTCOMES_CONFIG, DECISION_LOGIC_JS, SELECTION_SIGNALS);
340 
341         ListenableFuture<Void> result =
342                 mTestAdSelectionClient.overrideAdSelectionFromOutcomesConfigRemoteInfo(request);
343 
344         Exception exception =
345                 assertThrows(
346                         ExecutionException.class,
347                         () -> {
348                             result.get(10, TimeUnit.SECONDS);
349                         });
350         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
351     }
352 
353     @Test
testRemoveFromOutcomesOverrideFailsWithDebugModeDisabled()354     public void testRemoveFromOutcomesOverrideFailsWithDebugModeDisabled() throws Exception {
355         Assume.assumeFalse(mIsDebugMode);
356 
357         RemoveAdSelectionFromOutcomesOverrideRequest request =
358                 new RemoveAdSelectionFromOutcomesOverrideRequest(AD_SELECTION_FROM_OUTCOMES_CONFIG);
359 
360         ListenableFuture<Void> result =
361                 mTestAdSelectionClient.removeAdSelectionFromOutcomesConfigRemoteInfoOverride(
362                         request);
363 
364         Exception exception =
365                 assertThrows(
366                         ExecutionException.class,
367                         () -> {
368                             result.get(10, TimeUnit.SECONDS);
369                         });
370         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
371     }
372 
373     @Test
testResetAllFromOutcomesOverridesFailsWithDebugModeDisabled()374     public void testResetAllFromOutcomesOverridesFailsWithDebugModeDisabled() throws Exception {
375         Assume.assumeFalse(mIsDebugMode);
376 
377         ListenableFuture<Void> result =
378                 mTestAdSelectionClient.resetAllAdSelectionFromOutcomesConfigRemoteOverrides();
379 
380         Exception exception =
381                 assertThrows(
382                         ExecutionException.class,
383                         () -> {
384                             result.get(10, TimeUnit.SECONDS);
385                         });
386         assertThat(exception.getCause()).isInstanceOf(SecurityException.class);
387     }
388 
389     // TODO(b/221876775): Add override CTS tests for frequency cap API review
390 }
391