1 /* 2 * Copyright (C) 2023 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 junit.framework.Assert.assertEquals; 20 21 import static org.junit.Assert.assertThrows; 22 23 import android.adservices.ondevicepersonalization.aidl.IDataAccessService; 24 import android.adservices.ondevicepersonalization.aidl.IDataAccessServiceCallback; 25 import android.content.ContentValues; 26 import android.os.Bundle; 27 import android.os.RemoteException; 28 29 import androidx.test.ext.junit.runners.AndroidJUnit4; 30 import androidx.test.filters.SmallTest; 31 32 import com.android.ondevicepersonalization.internal.util.OdpParceledListSlice; 33 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.time.Instant; 39 import java.util.ArrayList; 40 import java.util.List; 41 42 /** 43 * Unit Tests of LogReader API. 44 */ 45 @SmallTest 46 @RunWith(AndroidJUnit4.class) 47 public class LogReaderTest { 48 49 LogReader mLogReader; 50 51 @Before setup()52 public void setup() { 53 mLogReader = new LogReader( 54 IDataAccessService.Stub.asInterface( 55 new LogReaderTest.LocalDataService())); 56 } 57 58 @Test testGetRequestsSuccess()59 public void testGetRequestsSuccess() { 60 List<RequestLogRecord> result = mLogReader.getRequests( 61 Instant.ofEpochMilli(10), Instant.ofEpochMilli(100)); 62 assertEquals(2, result.size()); 63 assertEquals(1, result.get(0).getRows().size()); 64 assertEquals((int) (result.get(0).getRows().get(0).getAsInteger("a")), 1); 65 assertEquals((int) (result.get(0).getRows().get(0).getAsInteger("b")), 1); 66 assertEquals(1, result.get(1).getRows().size()); 67 assertEquals((int) (result.get(1).getRows().get(0).getAsInteger("a")), 1); 68 assertEquals((int) (result.get(1).getRows().get(0).getAsInteger("b")), 1); 69 } 70 71 @Test testGetRequestsNullTimeError()72 public void testGetRequestsNullTimeError() { 73 assertThrows(NullPointerException.class, () -> mLogReader.getRequests( 74 null, Instant.ofEpochMilli(100))); 75 assertThrows(NullPointerException.class, () -> mLogReader.getRequests( 76 Instant.ofEpochMilli(100), null)); 77 } 78 79 @Test testGetRequestsError()80 public void testGetRequestsError() { 81 // Triggers an expected error in the mock service. 82 assertThrows(IllegalStateException.class, () -> mLogReader.getRequests( 83 Instant.ofEpochMilli(7), Instant.ofEpochMilli(100))); 84 } 85 86 @Test testGetRequestsNegativeTimeError()87 public void testGetRequestsNegativeTimeError() { 88 assertThrows(IllegalArgumentException.class, () -> mLogReader.getRequests( 89 Instant.ofEpochMilli(-1), Instant.ofEpochMilli(100))); 90 } 91 92 @Test testGetRequestsBadTimeRangeError()93 public void testGetRequestsBadTimeRangeError() { 94 assertThrows(IllegalArgumentException.class, () -> mLogReader.getRequests( 95 Instant.ofEpochMilli(100), Instant.ofEpochMilli(100))); 96 assertThrows(IllegalArgumentException.class, () -> mLogReader.getRequests( 97 Instant.ofEpochMilli(1000), Instant.ofEpochMilli(100))); 98 } 99 100 @Test testGetJoinedEventsSuccess()101 public void testGetJoinedEventsSuccess() { 102 List<EventLogRecord> result = mLogReader.getJoinedEvents( 103 Instant.ofEpochMilli(10), Instant.ofEpochMilli(100)); 104 assertEquals(2, result.size()); 105 assertEquals(result.get(0).getTimeMillis(), 30); 106 assertEquals(result.get(0).getRequestLogRecord().getTimeMillis(), 20); 107 assertEquals(result.get(0).getType(), 1); 108 assertEquals((int) (result.get(0).getData().getAsInteger("a")), 1); 109 assertEquals((int) (result.get(0).getData().getAsInteger("b")), 1); 110 assertEquals(result.get(1).getTimeMillis(), 40); 111 assertEquals(result.get(1).getRequestLogRecord().getTimeMillis(), 30); 112 assertEquals(result.get(1).getType(), 2); 113 assertEquals((int) (result.get(1).getData().getAsInteger("a")), 1); 114 assertEquals((int) (result.get(1).getData().getAsInteger("b")), 1); 115 } 116 117 @Test testGetJoinedEventsError()118 public void testGetJoinedEventsError() { 119 // Triggers an expected error in the mock service. 120 assertThrows(IllegalStateException.class, () -> mLogReader.getJoinedEvents( 121 Instant.ofEpochMilli(7), Instant.ofEpochMilli(100))); 122 } 123 124 @Test testGetJoinedEventsNullTimeError()125 public void testGetJoinedEventsNullTimeError() { 126 assertThrows(NullPointerException.class, () -> mLogReader.getJoinedEvents( 127 null, Instant.ofEpochMilli(100))); 128 assertThrows(NullPointerException.class, () -> mLogReader.getJoinedEvents( 129 Instant.ofEpochMilli(100), null)); 130 } 131 132 @Test testGetJoinedEventsNegativeTimeError()133 public void testGetJoinedEventsNegativeTimeError() { 134 assertThrows(IllegalArgumentException.class, () -> mLogReader.getJoinedEvents( 135 Instant.ofEpochMilli(-1), Instant.ofEpochMilli(100))); 136 } 137 138 @Test testGetJoinedEventsInputError()139 public void testGetJoinedEventsInputError() { 140 assertThrows(IllegalArgumentException.class, () -> mLogReader.getJoinedEvents( 141 Instant.ofEpochMilli(100), Instant.ofEpochMilli(100))); 142 assertThrows(IllegalArgumentException.class, () -> mLogReader.getJoinedEvents( 143 Instant.ofEpochMilli(1000), Instant.ofEpochMilli(100))); 144 } 145 146 public static class LocalDataService extends IDataAccessService.Stub { 147 LocalDataService()148 public LocalDataService() { 149 } 150 151 @Override onRequest( int operation, Bundle params, IDataAccessServiceCallback callback)152 public void onRequest( 153 int operation, 154 Bundle params, 155 IDataAccessServiceCallback callback) { 156 if (operation == Constants.DATA_ACCESS_OP_GET_REQUESTS 157 || operation == Constants.DATA_ACCESS_OP_GET_JOINED_EVENTS) { 158 long[] timestamps = params.getLongArray(Constants.EXTRA_LOOKUP_KEYS); 159 if (timestamps[0] == 7) { 160 // Raise expected error. 161 try { 162 callback.onError(Constants.STATUS_INTERNAL_ERROR); 163 } catch (RemoteException e) { 164 // Ignored. 165 } 166 return; 167 } 168 169 Bundle result = new Bundle(); 170 ContentValues values = new ContentValues(); 171 values.put("a", 1); 172 values.put("b", 1); 173 if (operation == Constants.DATA_ACCESS_OP_GET_REQUESTS) { 174 List<RequestLogRecord> records = new ArrayList<>(); 175 records.add(new RequestLogRecord.Builder() 176 .setRequestId(1) 177 .addRow(values) 178 .build()); 179 records.add(new RequestLogRecord.Builder() 180 .setRequestId(2) 181 .addRow(values) 182 .build()); 183 result.putParcelable(Constants.EXTRA_RESULT, 184 new OdpParceledListSlice<RequestLogRecord>(records)); 185 } else if (operation == Constants.DATA_ACCESS_OP_GET_JOINED_EVENTS) { 186 List<EventLogRecord> records = new ArrayList<>(); 187 records.add(new EventLogRecord.Builder() 188 .setType(1) 189 .setTimeMillis(30) 190 .setData(values) 191 .setRequestLogRecord(new RequestLogRecord.Builder() 192 .setRequestId(0) 193 .addRow(values) 194 .setTimeMillis(20) 195 .build()) 196 .build()); 197 records.add(new EventLogRecord.Builder() 198 .setType(2) 199 .setTimeMillis(40) 200 .setData(values) 201 .setRequestLogRecord(new RequestLogRecord.Builder() 202 .setRequestId(0) 203 .addRow(values) 204 .setTimeMillis(30) 205 .build()) 206 .build()); 207 result.putParcelable(Constants.EXTRA_RESULT, 208 new OdpParceledListSlice<EventLogRecord>(records)); 209 } 210 try { 211 callback.onSuccess(result); 212 } catch (RemoteException e) { 213 // Ignored. 214 } 215 } 216 } 217 218 @Override logApiCallStats(int apiName, long latencyMillis, int responseCode)219 public void logApiCallStats(int apiName, long latencyMillis, int responseCode) {} 220 } 221 } 222