1 /*
2  * Copyright 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.ondevicepersonalization;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertThrows;
21 
22 import android.adservices.ondevicepersonalization.aidl.IDataAccessService;
23 import android.adservices.ondevicepersonalization.aidl.IDataAccessServiceCallback;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.PersistableBundle;
27 import android.os.RemoteException;
28 
29 import androidx.test.ext.junit.runners.AndroidJUnit4;
30 import androidx.test.filters.SmallTest;
31 
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 
35 import java.nio.charset.StandardCharsets;
36 
37 @SmallTest
38 @RunWith(AndroidJUnit4.class)
39 public class EventUrlProviderTest {
40     static final int EVENT_TYPE_ERROR = 10;
41     private final EventUrlProvider mEventUrlProvider =
42             new EventUrlProvider(new TestDataService());
43     private static final byte[] RESPONSE_BYTES = {'A', 'B'};
44 
testGetEventUrlWithEmptyResponse()45     @Test public void testGetEventUrlWithEmptyResponse() throws Exception {
46         PersistableBundle params = new PersistableBundle();
47         params.putInt("type", 5);
48         params.putString("id", "abc");
49         assertEquals(
50                 "odp://5-abc-null-null-null",
51                 mEventUrlProvider.createEventTrackingUrlWithResponse(
52                         params, null, null).toString());
53     }
54 
testGetEventUrlReturnsResponseFromService()55     @Test public void testGetEventUrlReturnsResponseFromService() throws Exception {
56         PersistableBundle params = new PersistableBundle();
57         params.putInt("type", 5);
58         params.putString("id", "abc");
59         assertEquals(
60                 "odp://5-abc-AB-image/gif-null",
61                 mEventUrlProvider.createEventTrackingUrlWithResponse(
62                         params, RESPONSE_BYTES, "image/gif").toString());
63     }
64 
testGetEventUrlWithRedirectReturnsResponseFromService()65     @Test public void testGetEventUrlWithRedirectReturnsResponseFromService() throws Exception {
66         PersistableBundle params = new PersistableBundle();
67         params.putInt("type", 5);
68         params.putString("id", "abc");
69         assertEquals(
70                 "odp://5-abc-null-null-http://def",
71                 mEventUrlProvider.createEventTrackingUrlWithRedirect(
72                         params, Uri.parse("http://def"))
73                 .toString());
74     }
75 
testGetEventUrlThrowsOnError()76     @Test public void testGetEventUrlThrowsOnError() throws Exception {
77         // EventType 10 triggers error in the mock service.
78         PersistableBundle params = new PersistableBundle();
79         params.putInt("type", EVENT_TYPE_ERROR);
80         params.putString("id", "abc");
81         assertThrows(
82                 IllegalStateException.class,
83                 () -> mEventUrlProvider.createEventTrackingUrlWithResponse(
84                         params, null, null));
85     }
86 
87     class TestDataService extends IDataAccessService.Stub {
88         @Override
onRequest( int operation, Bundle params, IDataAccessServiceCallback callback)89         public void onRequest(
90                 int operation,
91                 Bundle params,
92                 IDataAccessServiceCallback callback) {
93             if (operation == Constants.DATA_ACCESS_OP_GET_EVENT_URL) {
94                 PersistableBundle eventParams = params.getParcelable(
95                         Constants.EXTRA_EVENT_PARAMS, PersistableBundle.class);
96                 int eventType = eventParams.getInt("type");
97                 String id = eventParams.getString("id");
98                 byte[] responseDataBytes = params.getByteArray(Constants.EXTRA_RESPONSE_DATA);
99                 String responseData = (responseDataBytes != null)
100                         ? new String(responseDataBytes, StandardCharsets.UTF_8) : "null";
101                 String mimeType = params.getString(Constants.EXTRA_MIME_TYPE);
102                 String destinationUrl = params.getString(Constants.EXTRA_DESTINATION_URL);
103                 if (eventType == EVENT_TYPE_ERROR) {
104                     try {
105                         callback.onError(Constants.STATUS_INTERNAL_ERROR);
106                     } catch (RemoteException e) {
107                         // Ignored.
108                     }
109                 } else {
110                     String url = String.format(
111                             "odp://%d-%s-%s-%s-%s", eventType, id, responseData, mimeType,
112                             destinationUrl);
113                     Bundle result = new Bundle();
114                     result.putParcelable(Constants.EXTRA_RESULT, Uri.parse(url));
115                     try {
116                         callback.onSuccess(result);
117                     } catch (RemoteException e) {
118                         // Ignored.
119                     }
120                 }
121             } else {
122                 throw new IllegalStateException("Unexpected test input");
123             }
124         }
125         @Override
logApiCallStats(int apiName, long latencyMillis, int responseCode)126         public void logApiCallStats(int apiName, long latencyMillis, int responseCode) {}
127     }
128 }
129