blob: d4f61a910905f44da3221bf2a874574f93a07b09 [file] [log] [blame]
Rui Qiu337cb242021-06-03 11:26:16 -07001/*
2 * Copyright (C) 2021 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
17package com.android.car.telemetry.databroker;
18
19import static com.google.common.truth.Truth.assertThat;
Rui Qiu033041e2021-06-21 14:59:11 -070020import static com.google.common.truth.Truth.assertWithMessage;
Rui Qiu337cb242021-06-03 11:26:16 -070021
Rui Qiua86ab602021-07-02 10:40:36 -070022import static org.mockito.ArgumentMatchers.any;
23import static org.mockito.ArgumentMatchers.anyInt;
24import static org.mockito.ArgumentMatchers.anyString;
Rui Qiuaba02082021-08-16 16:24:00 -070025import static org.mockito.ArgumentMatchers.eq;
Rui Qiua86ab602021-07-02 10:40:36 -070026import static org.mockito.Mockito.verify;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070027import static org.mockito.Mockito.when;
Rui Qiu337cb242021-06-03 11:26:16 -070028
Rui Qiua86ab602021-07-02 10:40:36 -070029import android.annotation.Nullable;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070030import android.car.hardware.CarPropertyConfig;
Rui Qiua86ab602021-07-02 10:40:36 -070031import android.content.Context;
32import android.content.ServiceConnection;
Rui Qiu033041e2021-06-21 14:59:11 -070033import android.os.Handler;
Rui Qiua86ab602021-07-02 10:40:36 -070034import android.os.IBinder;
Max Dashouk6987e9c2021-09-20 13:19:30 -070035import android.os.ParcelFileDescriptor;
Rui Qiuaba02082021-08-16 16:24:00 -070036import android.os.PersistableBundle;
Rui Qiua86ab602021-07-02 10:40:36 -070037import android.os.RemoteException;
Rui Qiu033041e2021-06-21 14:59:11 -070038import android.os.SystemClock;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070039
40import com.android.car.CarPropertyService;
Rui Qiuaba02082021-08-16 16:24:00 -070041import com.android.car.telemetry.ResultStore;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070042import com.android.car.telemetry.TelemetryProto;
43import com.android.car.telemetry.publisher.PublisherFactory;
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -070044import com.android.car.telemetry.publisher.StatsManagerProxy;
Max Dashouk9912ac32021-08-13 17:54:51 +000045import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
46import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070047
48import org.junit.Before;
Rui Qiu337cb242021-06-03 11:26:16 -070049import org.junit.Test;
50import org.junit.runner.RunWith;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070051import org.mockito.Mock;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070052import org.mockito.Mockito;
Rui Qiu337cb242021-06-03 11:26:16 -070053import org.mockito.junit.MockitoJUnitRunner;
54
Rui Qiuda9f0ba2021-09-14 12:15:37 -070055import java.nio.file.Files;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070056import java.util.Collections;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070057import java.util.concurrent.CountDownLatch;
Rui Qiu033041e2021-06-21 14:59:11 -070058import java.util.concurrent.PriorityBlockingQueue;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070059import java.util.concurrent.TimeUnit;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070060
Rui Qiu337cb242021-06-03 11:26:16 -070061@RunWith(MockitoJUnitRunner.class)
Rui Qiuac8b5ba2021-08-25 16:04:17 -070062public class DataBrokerTest {
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070063 private static final int PROP_ID = 100;
64 private static final int PROP_AREA = 200;
Rui Qiu033041e2021-06-21 14:59:11 -070065 private static final int PRIORITY_HIGH = 1;
Rui Qiud95f95d2021-08-17 12:29:33 -070066 private static final int PRIORITY_LOW = 100;
Rui Qiu033041e2021-06-21 14:59:11 -070067 private static final long TIMEOUT_MS = 5_000L;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070068 private static final CarPropertyConfig<Integer> PROP_CONFIG =
69 CarPropertyConfig.newBuilder(Integer.class, PROP_ID, PROP_AREA).setAccess(
70 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
Rui Qiu337cb242021-06-03 11:26:16 -070071 private static final TelemetryProto.VehiclePropertyPublisher
72 VEHICLE_PROPERTY_PUBLISHER_CONFIGURATION =
73 TelemetryProto.VehiclePropertyPublisher.newBuilder().setReadRate(
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070074 1).setVehiclePropertyId(PROP_ID).build();
Rui Qiu337cb242021-06-03 11:26:16 -070075 private static final TelemetryProto.Publisher PUBLISHER_CONFIGURATION =
76 TelemetryProto.Publisher.newBuilder().setVehicleProperty(
77 VEHICLE_PROPERTY_PUBLISHER_CONFIGURATION).build();
78 private static final TelemetryProto.Subscriber SUBSCRIBER_FOO =
79 TelemetryProto.Subscriber.newBuilder().setHandler("function_name_foo").setPublisher(
Rui Qiud95f95d2021-08-17 12:29:33 -070080 PUBLISHER_CONFIGURATION).setPriority(PRIORITY_HIGH).build();
Rui Qiu337cb242021-06-03 11:26:16 -070081 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_FOO =
82 TelemetryProto.MetricsConfig.newBuilder().setName("Foo").setVersion(
83 1).addSubscribers(SUBSCRIBER_FOO).build();
84 private static final TelemetryProto.Subscriber SUBSCRIBER_BAR =
85 TelemetryProto.Subscriber.newBuilder().setHandler("function_name_bar").setPublisher(
Rui Qiud95f95d2021-08-17 12:29:33 -070086 PUBLISHER_CONFIGURATION).setPriority(PRIORITY_LOW).build();
Rui Qiu337cb242021-06-03 11:26:16 -070087 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_BAR =
88 TelemetryProto.MetricsConfig.newBuilder().setName("Bar").setVersion(
89 1).addSubscribers(SUBSCRIBER_BAR).build();
90
Rui Qiuea6a4942021-09-07 15:05:34 -070091
92 // when count reaches 0, all handler messages are scheduled to be dispatched after current time
Rui Qiuac8b5ba2021-08-25 16:04:17 -070093 private CountDownLatch mIdleHandlerLatch = new CountDownLatch(1);
Rui Qiuea6a4942021-09-07 15:05:34 -070094 private PersistableBundle mData = new PersistableBundle();
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070095 private DataBrokerImpl mDataBroker;
Rui Qiua86ab602021-07-02 10:40:36 -070096 private FakeScriptExecutor mFakeScriptExecutor;
Rui Qiu033041e2021-06-21 14:59:11 -070097 private ScriptExecutionTask mHighPriorityTask;
98 private ScriptExecutionTask mLowPriorityTask;
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -070099
Rui Qiua86ab602021-07-02 10:40:36 -0700100 @Mock
101 private Context mMockContext;
102 @Mock
103 private CarPropertyService mMockCarPropertyService;
104 @Mock
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700105 private Handler mMockHandler;
106 @Mock
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700107 private StatsManagerProxy mMockStatsManager;
108 @Mock
Rui Qiua86ab602021-07-02 10:40:36 -0700109 private IBinder mMockScriptExecutorBinder;
Rui Qiuaba02082021-08-16 16:24:00 -0700110 @Mock
111 private ResultStore mMockResultStore;
Rui Qiua86ab602021-07-02 10:40:36 -0700112
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -0700113 @Before
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700114 public void setUp() throws Exception {
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -0700115 when(mMockCarPropertyService.getPropertyList())
116 .thenReturn(Collections.singletonList(PROP_CONFIG));
Rui Qiua86ab602021-07-02 10:40:36 -0700117 // bind service should return true, otherwise broker is disabled
118 when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
Zhomart Mukhamejanovcdcb4e12021-08-23 18:24:40 -0700119 PublisherFactory factory = new PublisherFactory(
Rui Qiuda9f0ba2021-09-14 12:15:37 -0700120 mMockCarPropertyService, mMockHandler, mMockStatsManager,
121 Files.createTempDirectory("telemetry_test").toFile());
Rui Qiuaba02082021-08-16 16:24:00 -0700122 mDataBroker = new DataBrokerImpl(mMockContext, factory, mMockResultStore);
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700123 // add IdleHandler to get notified when all messages and posts are handled
124 mDataBroker.getTelemetryHandler().getLooper().getQueue().addIdleHandler(() -> {
125 mIdleHandlerLatch.countDown();
126 return true;
127 });
Rui Qiua86ab602021-07-02 10:40:36 -0700128
129 mFakeScriptExecutor = new FakeScriptExecutor();
130 when(mMockScriptExecutorBinder.queryLocalInterface(anyString()))
131 .thenReturn(mFakeScriptExecutor);
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700132 when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(i -> {
133 ServiceConnection conn = i.getArgument(1);
134 conn.onServiceConnected(null, mMockScriptExecutorBinder);
135 return true;
136 });
Rui Qiua86ab602021-07-02 10:40:36 -0700137
Rui Qiu033041e2021-06-21 14:59:11 -0700138 mHighPriorityTask = new ScriptExecutionTask(
Rui Qiud95f95d2021-08-17 12:29:33 -0700139 new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO),
Rui Qiuea6a4942021-09-07 15:05:34 -0700140 mData,
Rui Qiu033041e2021-06-21 14:59:11 -0700141 SystemClock.elapsedRealtime());
142 mLowPriorityTask = new ScriptExecutionTask(
Rui Qiud95f95d2021-08-17 12:29:33 -0700143 new DataSubscriber(mDataBroker, METRICS_CONFIG_BAR, SUBSCRIBER_BAR),
Rui Qiuea6a4942021-09-07 15:05:34 -0700144 mData,
Rui Qiu033041e2021-06-21 14:59:11 -0700145 SystemClock.elapsedRealtime());
146 }
147
148 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700149 public void testSetTaskExecutionPriority_whenNoTask_shouldNotInvokeScriptExecutor()
150 throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700151 mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
152
Rui Qiua86ab602021-07-02 10:40:36 -0700153 waitForHandlerThreadToFinish();
154 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(0);
Rui Qiu033041e2021-06-21 14:59:11 -0700155 }
156
157 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700158 public void testSetTaskExecutionPriority_whenNextTaskPriorityLow_shouldNotRunTask()
159 throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700160 mDataBroker.getTaskQueue().add(mLowPriorityTask);
161
162 mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
163
164 waitForHandlerThreadToFinish();
165 // task is not polled
166 assertThat(mDataBroker.getTaskQueue().peek()).isEqualTo(mLowPriorityTask);
Rui Qiua86ab602021-07-02 10:40:36 -0700167 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(0);
Rui Qiu033041e2021-06-21 14:59:11 -0700168 }
169
170 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700171 public void testSetTaskExecutionPriority_whenNextTaskPriorityHigh_shouldInvokeScriptExecutor()
172 throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700173 mDataBroker.getTaskQueue().add(mHighPriorityTask);
174
175 mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
176
177 waitForHandlerThreadToFinish();
178 // task is polled and run
179 assertThat(mDataBroker.getTaskQueue().peek()).isNull();
Rui Qiua86ab602021-07-02 10:40:36 -0700180 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
Rui Qiu033041e2021-06-21 14:59:11 -0700181 }
182
183 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700184 public void testScheduleNextTask_whenNoTask_shouldNotInvokeScriptExecutor() throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700185 mDataBroker.scheduleNextTask();
186
Rui Qiua86ab602021-07-02 10:40:36 -0700187 waitForHandlerThreadToFinish();
188 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(0);
Rui Qiu033041e2021-06-21 14:59:11 -0700189 }
190
191 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700192 public void testScheduleNextTask_whenTaskInProgress_shouldNotInvokeScriptExecutorAgain()
193 throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700194 PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
195 taskQueue.add(mHighPriorityTask);
196 mDataBroker.scheduleNextTask(); // start a task
197 waitForHandlerThreadToFinish();
198 assertThat(taskQueue.peek()).isNull(); // assert that task is polled and running
199 taskQueue.add(mHighPriorityTask); // add another task into the queue
200
201 mDataBroker.scheduleNextTask(); // schedule next task while the last task is in progress
202
Rui Qiuea6a4942021-09-07 15:05:34 -0700203 waitForHandlerThreadToFinish();
Rui Qiua86ab602021-07-02 10:40:36 -0700204 // verify task is not polled
205 assertThat(taskQueue.peek()).isEqualTo(mHighPriorityTask);
206 // expect one invocation for the task that is running
207 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
208 }
209
210 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700211 public void testScheduleNextTask_whenTaskCompletes_shouldAutomaticallyScheduleNextTask()
212 throws Exception {
Rui Qiua86ab602021-07-02 10:40:36 -0700213 PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
214 // add two tasks into the queue for execution
215 taskQueue.add(mHighPriorityTask);
216 taskQueue.add(mHighPriorityTask);
217
218 mDataBroker.scheduleNextTask(); // start a task
219 waitForHandlerThreadToFinish();
220 // end a task, should automatically schedule the next task
Rui Qiuea6a4942021-09-07 15:05:34 -0700221 mFakeScriptExecutor.notifyScriptSuccess(mData); // posts to telemetry handler
Rui Qiua86ab602021-07-02 10:40:36 -0700222
223 waitForHandlerThreadToFinish();
224 // verify queue is empty, both tasks are polled and executed
225 assertThat(taskQueue.peek()).isNull();
226 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(2);
227 }
228
229 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700230 public void testScheduleNextTask_onScriptSuccess_shouldStoreInterimResult() throws Exception {
Rui Qiuea6a4942021-09-07 15:05:34 -0700231 mData.putBoolean("script is finished", false);
232 mData.putDouble("value of euler's number", 2.71828);
Rui Qiuaba02082021-08-16 16:24:00 -0700233 mDataBroker.getTaskQueue().add(mHighPriorityTask);
Rui Qiuaba02082021-08-16 16:24:00 -0700234
235 mDataBroker.scheduleNextTask();
236 waitForHandlerThreadToFinish();
Rui Qiuea6a4942021-09-07 15:05:34 -0700237 mFakeScriptExecutor.notifyScriptSuccess(mData); // posts to telemetry handler
Rui Qiuaba02082021-08-16 16:24:00 -0700238
Rui Qiuea6a4942021-09-07 15:05:34 -0700239 waitForHandlerThreadToFinish();
Rui Qiuaba02082021-08-16 16:24:00 -0700240 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
Rui Qiuea6a4942021-09-07 15:05:34 -0700241 verify(mMockResultStore).putInterimResult(
242 eq(mHighPriorityTask.getMetricsConfig().getName()), eq(mData));
243 }
244
245 @Test
Rui Qiu862d6ea2021-08-17 15:00:09 -0700246 public void testScheduleNextTask_onScriptError_shouldStoreErrorObject() throws Exception {
247 mDataBroker.getTaskQueue().add(mHighPriorityTask);
248 TelemetryProto.TelemetryError.ErrorType errorType =
249 TelemetryProto.TelemetryError.ErrorType.LUA_RUNTIME_ERROR;
250 String errorMessage = "test onError";
251 TelemetryProto.TelemetryError expectedError = TelemetryProto.TelemetryError.newBuilder()
252 .setErrorType(errorType)
253 .setMessage(errorMessage)
254 .build();
255
256 mDataBroker.scheduleNextTask();
257 waitForHandlerThreadToFinish();
258 mFakeScriptExecutor.notifyScriptError(errorType.getNumber(), errorMessage);
259
260 waitForHandlerThreadToFinish();
261 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
262 verify(mMockResultStore).putError(eq(METRICS_CONFIG_FOO.getName()), eq(expectedError));
263 }
264
265 @Test
Rui Qiuea6a4942021-09-07 15:05:34 -0700266 public void testScheduleNextTask_whenScriptFinishes_shouldStoreFinalResult()
267 throws Exception {
268 mData.putBoolean("script is finished", true);
269 mData.putDouble("value of pi", 3.14159265359);
270 mDataBroker.getTaskQueue().add(mHighPriorityTask);
271
272 mDataBroker.scheduleNextTask();
273 waitForHandlerThreadToFinish();
274 mFakeScriptExecutor.notifyScriptFinish(mData); // posts to telemetry handler
275
276 waitForHandlerThreadToFinish();
277 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
278 verify(mMockResultStore).putFinalResult(
279 eq(mHighPriorityTask.getMetricsConfig().getName()), eq(mData));
280 }
281
282 @Test
283 public void testScheduleNextTask_whenInterimDataExists_shouldPassToScriptExecutor()
284 throws Exception {
285 mData.putDouble("value of golden ratio", 1.618033);
286 mDataBroker.getTaskQueue().add(mHighPriorityTask);
287 when(mMockResultStore.getInterimResult(mHighPriorityTask.getMetricsConfig().getName()))
288 .thenReturn(mData);
289
290 mDataBroker.scheduleNextTask();
291
292 waitForHandlerThreadToFinish();
293 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
294 assertThat(mFakeScriptExecutor.getSavedState()).isEqualTo(mData);
Rui Qiuaba02082021-08-16 16:24:00 -0700295 }
296
297 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700298 public void testScheduleNextTask_whenBindScriptExecutorFailed_shouldDisableBroker()
299 throws Exception {
300 // fail all future attempts to bind to it
301 Mockito.reset(mMockContext);
302 when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(false);
Rui Qiua86ab602021-07-02 10:40:36 -0700303 mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
304 PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
305 taskQueue.add(mHighPriorityTask);
Rui Qiua86ab602021-07-02 10:40:36 -0700306
307 // will rebind to ScriptExecutor if it is null
308 mDataBroker.scheduleNextTask();
309
310 waitForHandlerThreadToFinish();
311 // all subscribers should have been removed
312 assertThat(mDataBroker.getSubscriptionMap()).hasSize(0);
313 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(0);
314 }
315
316 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700317 public void testScheduleNextTask_whenScriptExecutorThrowsException_shouldRequeueTask()
318 throws Exception {
Rui Qiua86ab602021-07-02 10:40:36 -0700319 PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
320 taskQueue.add(mHighPriorityTask);
321 mFakeScriptExecutor.failNextApiCalls(1); // fail the next invokeScript() call
322
323 mDataBroker.scheduleNextTask();
324
325 waitForHandlerThreadToFinish();
326 // expect invokeScript() to be called and failed, causing the same task to be re-queued
327 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
Rui Qiu033041e2021-06-21 14:59:11 -0700328 assertThat(taskQueue.peek()).isEqualTo(mHighPriorityTask);
329 }
330
331 @Test
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700332 public void testAddTaskToQueue_shouldInvokeScriptExecutor() throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700333 mDataBroker.addTaskToQueue(mHighPriorityTask);
334
Rui Qiua86ab602021-07-02 10:40:36 -0700335 waitForHandlerThreadToFinish();
336 assertThat(mFakeScriptExecutor.getApiInvocationCount()).isEqualTo(1);
Zhomart Mukhamejanov44570cb2021-06-07 10:23:13 -0700337 }
338
Rui Qiu337cb242021-06-03 11:26:16 -0700339 @Test
340 public void testAddMetricsConfiguration_newMetricsConfig() {
Rui Qiuf14c6a22021-07-14 10:39:16 -0700341 mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
342
Rui Qiuf14c6a22021-07-14 10:39:16 -0700343 assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
344 assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_BAR.getName());
345 // there should be one data subscriber in the subscription list of METRICS_CONFIG_BAR
346 assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_BAR.getName())).hasSize(1);
347 }
348
349
350 @Test
351 public void testAddMetricsConfiguration_duplicateMetricsConfig_shouldDoNothing() {
352 // this metrics config has already been added in setUp()
Rui Qiu337cb242021-06-03 11:26:16 -0700353 mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
354
Rui Qiuf14c6a22021-07-14 10:39:16 -0700355 assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
Rui Qiu337cb242021-06-03 11:26:16 -0700356 assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_FOO.getName());
Rui Qiu337cb242021-06-03 11:26:16 -0700357 assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_FOO.getName())).hasSize(1);
358 }
359
360 @Test
Rui Qiuf14c6a22021-07-14 10:39:16 -0700361 public void testRemoveMetricsConfiguration_shouldRemoveAllAssociatedTasks() {
Rui Qiu337cb242021-06-03 11:26:16 -0700362 mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
363 mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
Rui Qiud95f95d2021-08-17 12:29:33 -0700364 ScriptExecutionTask taskWithMetricsConfigFoo = new ScriptExecutionTask(
365 new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO),
Rui Qiuea6a4942021-09-07 15:05:34 -0700366 mData,
Rui Qiuf14c6a22021-07-14 10:39:16 -0700367 SystemClock.elapsedRealtime());
368 PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
369 taskQueue.add(mHighPriorityTask); // associated with METRICS_CONFIG_FOO
Rui Qiud95f95d2021-08-17 12:29:33 -0700370 taskQueue.add(mLowPriorityTask); // associated with METRICS_CONFIG_BAR
371 taskQueue.add(taskWithMetricsConfigFoo); // associated with METRICS_CONFIG_FOO
Rui Qiuf14c6a22021-07-14 10:39:16 -0700372 assertThat(taskQueue).hasSize(3);
373
374 mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_FOO);
Rui Qiu337cb242021-06-03 11:26:16 -0700375
Rui Qiuf14c6a22021-07-14 10:39:16 -0700376 assertThat(taskQueue).hasSize(1);
Rui Qiud95f95d2021-08-17 12:29:33 -0700377 assertThat(taskQueue.poll()).isEqualTo(mLowPriorityTask);
Rui Qiuf14c6a22021-07-14 10:39:16 -0700378 }
379
380 @Test
381 public void testRemoveMetricsConfiguration_whenMetricsConfigNonExistent_shouldDoNothing() {
382 mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_BAR);
383
Rui Qiuf14c6a22021-07-14 10:39:16 -0700384 assertThat(mDataBroker.getSubscriptionMap()).hasSize(0);
Rui Qiu337cb242021-06-03 11:26:16 -0700385 }
386
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700387 private void waitForHandlerThreadToFinish() throws Exception {
Rui Qiu033041e2021-06-21 14:59:11 -0700388 assertWithMessage("handler not idle in %sms", TIMEOUT_MS)
Rui Qiua4a8fd02021-09-02 19:08:40 -0700389 .that(mIdleHandlerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
Rui Qiuea6a4942021-09-07 15:05:34 -0700390 mIdleHandlerLatch = new CountDownLatch(1); // reset idle handler condition
Rui Qiu337cb242021-06-03 11:26:16 -0700391 }
Rui Qiua86ab602021-07-02 10:40:36 -0700392
393 private static class FakeScriptExecutor implements IScriptExecutor {
394 private IScriptExecutorListener mListener;
395 private int mApiInvocationCount = 0;
396 private int mFailApi = 0;
Rui Qiuea6a4942021-09-07 15:05:34 -0700397 private PersistableBundle mSavedState = null;
Rui Qiua86ab602021-07-02 10:40:36 -0700398
399 @Override
Max Dashoukdafdd222021-08-20 10:42:25 -0700400 public void invokeScript(String scriptBody, String functionName,
401 PersistableBundle publishedData, @Nullable PersistableBundle savedState,
402 IScriptExecutorListener listener)
Rui Qiua86ab602021-07-02 10:40:36 -0700403 throws RemoteException {
404 mApiInvocationCount++;
Rui Qiuea6a4942021-09-07 15:05:34 -0700405 mSavedState = savedState;
Rui Qiua86ab602021-07-02 10:40:36 -0700406 mListener = listener;
407 if (mFailApi > 0) {
408 mFailApi--;
409 throw new RemoteException("Simulated failure");
410 }
411 }
412
413 @Override
Max Dashouk6987e9c2021-09-20 13:19:30 -0700414 public void invokeScriptForLargeInput(String scriptBody, String functionName,
415 ParcelFileDescriptor publishedDataFileDescriptor,
416 @Nullable PersistableBundle savedState,
417 IScriptExecutorListener listener) throws RemoteException {
418 mApiInvocationCount++;
419 mSavedState = savedState;
420 mListener = listener;
421 if (mFailApi > 0) {
422 mFailApi--;
423 throw new RemoteException("Simulated failure");
424 }
425 }
426
427 @Override
Rui Qiua86ab602021-07-02 10:40:36 -0700428 public IBinder asBinder() {
429 return null;
430 }
431
Rui Qiuaba02082021-08-16 16:24:00 -0700432 /** Mocks script temporary completion. */
Max Dashoukdafdd222021-08-20 10:42:25 -0700433 public void notifyScriptSuccess(PersistableBundle bundle) {
Rui Qiua86ab602021-07-02 10:40:36 -0700434 try {
Rui Qiuaba02082021-08-16 16:24:00 -0700435 mListener.onSuccess(bundle);
Rui Qiua86ab602021-07-02 10:40:36 -0700436 } catch (RemoteException e) {
437 // nothing to do
438 }
439 }
440
Rui Qiuea6a4942021-09-07 15:05:34 -0700441 /** Mocks script producing final result. */
442 public void notifyScriptFinish(PersistableBundle bundle) {
443 try {
444 mListener.onScriptFinished(bundle);
445 } catch (RemoteException e) {
446 // nothing to do
447 }
448 }
449
Rui Qiu862d6ea2021-08-17 15:00:09 -0700450 /** Mocks script finished with error. */
451 public void notifyScriptError(int errorType, String errorMessage) {
452 try {
453 mListener.onError(errorType, errorMessage, null);
454 } catch (RemoteException e) {
455 // nothing to do
456 }
457 }
458
Rui Qiua86ab602021-07-02 10:40:36 -0700459 /** Fails the next N invokeScript() call. */
460 public void failNextApiCalls(int n) {
461 mFailApi = n;
462 }
463
464 /** Returns number of times the ScriptExecutor API was invoked. */
465 public int getApiInvocationCount() {
466 return mApiInvocationCount;
467 }
Rui Qiuea6a4942021-09-07 15:05:34 -0700468
469 /** Returns the interim data passed in invokeScript(). */
470 public PersistableBundle getSavedState() {
471 return mSavedState;
472 }
Rui Qiua86ab602021-07-02 10:40:36 -0700473 }
Rui Qiu337cb242021-06-03 11:26:16 -0700474}