blob: ff347c22c789a2536e1ad280672b6053af3c5461 [file] [log] [blame]
/*
* 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.tests.cts.topics;
import static com.google.common.truth.Truth.assertThat;
import android.adservices.clients.topics.AdvertisingTopicsClient;
import android.adservices.topics.GetTopicsRequest;
import android.adservices.topics.GetTopicsResponse;
import android.adservices.topics.Topic;
import android.content.Context;
import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import com.android.adservices.common.AdservicesCtsHelper;
import com.android.compatibility.common.util.ShellUtils;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@RunWith(JUnit4.class)
public class PreviewApiTest {
private static final String TAG = "PreviewApiTest";
// The JobId of the Epoch Computation.
private static final int EPOCH_JOB_ID = 2;
// Override the Epoch Job Period to this value to speed up the epoch computation.
private static final long TEST_EPOCH_JOB_PERIOD_MS = 3_000;
// Default Epoch Period.
private static final long TOPICS_EPOCH_JOB_PERIOD_MS = 7 * 86_400_000; // 7 days.
// Use 0 percent for random topic in the test so that we can verify the returned topic.
private static final int TEST_TOPICS_PERCENTAGE_FOR_RANDOM_TOPIC = 0;
private static final int TOPICS_PERCENTAGE_FOR_RANDOM_TOPIC = 5;
protected static final Context sContext = ApplicationProvider.getApplicationContext();
private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private static final String ADSERVICES_PACKAGE_NAME =
AdservicesCtsHelper.getAdServicesPackageName(sContext, TAG);
@Before
public void setup() throws Exception {
// Skip the test if it runs on unsupported platforms.
Assume.assumeTrue(AdservicesCtsHelper.isDeviceSupported());
// We need to skip 3 epochs so that if there is any usage from other test runs, it will
// not be used for epoch retrieval.
Thread.sleep(3 * TEST_EPOCH_JOB_PERIOD_MS);
overrideEpochPeriod(TEST_EPOCH_JOB_PERIOD_MS);
// We need to turn off random topic so that we can verify the returned topic.
overridePercentageForRandomTopic(TEST_TOPICS_PERCENTAGE_FOR_RANDOM_TOPIC);
// TODO(b/263297331): Handle rollback support for R and S.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
overrideConsentSourceOfTruth(/* PPAPI_ONLY */ 1);
}
}
@After
public void teardown() {
overrideEpochPeriod(TOPICS_EPOCH_JOB_PERIOD_MS);
overridePercentageForRandomTopic(TOPICS_PERCENTAGE_FOR_RANDOM_TOPIC);
overrideConsentSourceOfTruth(null);
}
@Test
public void testRecordObservation() throws ExecutionException, InterruptedException {
// The Test app has 2 SDKs: sdk1 calls the Topics API. This will record the usage for Sdk1
// by default, recordObservation is true.
AdvertisingTopicsClient advertisingTopicsClient1 =
new AdvertisingTopicsClient.Builder()
.setContext(sContext)
.setSdkName("sdk1")
.setExecutor(CALLBACK_EXECUTOR)
.build();
// Sdk2 calls the Topics API and set the Record Observation to false. This will not record
// the usage for sdk2.
AdvertisingTopicsClient advertisingTopicsClient2 =
new AdvertisingTopicsClient.Builder()
.setContext(sContext)
.setSdkName("sdk2")
.setShouldRecordObservation(false)
.setExecutor(CALLBACK_EXECUTOR)
.build();
// At beginning, Sdk1 receives no topic.
GetTopicsResponse sdk1Result = advertisingTopicsClient1.getTopics().get();
assertThat(sdk1Result.getTopics()).isEmpty();
// At beginning, Sdk2 receives no topic.
GetTopicsResponse sdk2Result = advertisingTopicsClient2.getTopics().get();
assertThat(sdk2Result.getTopics()).isEmpty();
// Now force the Epoch Computation Job. This should be done in the same epoch for
// callersCanLearnMap to have the entry for processing.
forceEpochComputationJob();
// Wait to the next epoch. We will not need to do this after we implement the fix in
// go/rb-topics-epoch-scheduling
Thread.sleep(TEST_EPOCH_JOB_PERIOD_MS);
// Since the sdk1 called the Topics API in the previous Epoch, it should receive some topic.
sdk1Result = advertisingTopicsClient1.getTopics().get();
assertThat(sdk1Result.getTopics()).isNotEmpty();
// We only have 1 test app which has 5 classification topics: 10147,10253,10175,10254,10333
// in the precomputed list.
// These 5 classification topics will become top 5 topics of the epoch since there is
// no other apps calling Topics API.
// The app will be assigned one random topic from one of these 5 topics.
assertThat(sdk1Result.getTopics()).hasSize(1);
Topic topic = sdk1Result.getTopics().get(0);
// topic is one of the 5 classification topics of the Test App.
assertThat(topic.getTopicId()).isIn(Arrays.asList(10147, 10253, 10175, 10254, 10333));
assertThat(topic.getModelVersion()).isAtLeast(1L);
assertThat(topic.getTaxonomyVersion()).isAtLeast(1L);
// Sdk2 can not get any topics in this epoch because sdk2 sets not to record
// observation in previous epoch.
sdk2Result = advertisingTopicsClient2.getTopics().get();
assertThat(sdk2Result.getTopics()).isEmpty();
}
// This test is to add test/line coverage for Topics API. There is no specific logic to test.
@Test
public void testForTopicsAPITestCoverage() {
String sdkName = "sdk1";
boolean shouldRecordObservation = false; // default value is true
GetTopicsRequest.Builder builder = new GetTopicsRequest.Builder();
builder.setAdsSdkName(sdkName);
builder.setShouldRecordObservation(shouldRecordObservation);
GetTopicsRequest request = builder.build();
assertThat(request.getAdsSdkName()).isEqualTo(sdkName);
assertThat(request.shouldRecordObservation()).isEqualTo(shouldRecordObservation);
// Below are for test coverage purpose. There is no assertion against them.
Topic mockedTopic =
new Topic(/* taxonomyVersion */ 1L, /* modelVersion*/ 1L, /* topicId */ 1);
GetTopicsResponse.Builder mockedBuilder =
new GetTopicsResponse.Builder(List.of(mockedTopic));
mockedBuilder.build();
}
// Override the Epoch Period to shorten the Epoch Length in the test.
private void overrideEpochPeriod(long overrideEpochPeriod) {
ShellUtils.runShellCommand(
"setprop debug.adservices.topics_epoch_job_period_ms " + overrideEpochPeriod);
}
// Override the Percentage For Random Topic in the test.
private void overridePercentageForRandomTopic(long overridePercentage) {
ShellUtils.runShellCommand(
"setprop debug.adservices.topics_percentage_for_random_topics "
+ overridePercentage);
}
/** Forces JobScheduler to run the Epoch Computation job */
private void forceEpochComputationJob() {
ShellUtils.runShellCommand(
"cmd jobscheduler run -f" + " " + ADSERVICES_PACKAGE_NAME + " " + EPOCH_JOB_ID);
}
private void overrideConsentSourceOfTruth(Integer value) {
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth " + value);
}
}