blob: b177655c18c6576856418c74ba28a751e9adba2e [file] [log] [blame]
Rui Qiu8c415de2021-05-03 15:52: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;
18
Rui Qiuf721b132021-09-10 12:41:09 -070019import static com.google.common.truth.Truth.assertThat;
Rui Qiu9b9341c2021-08-25 10:39:04 -070020import static com.google.common.truth.Truth.assertWithMessage;
Rui Qiu8c415de2021-05-03 15:52:16 -070021
Rui Qiud5b4b0b2021-09-14 15:51:50 -070022import static org.mockito.ArgumentMatchers.any;
Rui Qiu9b9341c2021-08-25 10:39:04 -070023import static org.mockito.ArgumentMatchers.eq;
Rui Qiud5b4b0b2021-09-14 15:51:50 -070024import static org.mockito.Mockito.never;
Rui Qiu9b9341c2021-08-25 10:39:04 -070025import static org.mockito.Mockito.verify;
Rui Qiua3418982021-08-20 11:21:12 -070026import static org.mockito.Mockito.when;
27
Rui Qiu8c415de2021-05-03 15:52:16 -070028import android.car.telemetry.CarTelemetryManager;
Rui Qiu9b9341c2021-08-25 10:39:04 -070029import android.car.telemetry.ICarTelemetryServiceListener;
30import android.car.telemetry.MetricsConfigKey;
Rui Qiu8c415de2021-05-03 15:52:16 -070031import android.content.Context;
Rui Qiu9b9341c2021-08-25 10:39:04 -070032import android.os.Handler;
Rui Qiuf721b132021-09-10 12:41:09 -070033import android.os.PersistableBundle;
Rui Qiu8c415de2021-05-03 15:52:16 -070034
35import androidx.test.filters.SmallTest;
36
Rui Qiua3418982021-08-20 11:21:12 -070037import com.android.car.CarLocalServices;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070038import com.android.car.CarPropertyService;
Rui Qiua3418982021-08-20 11:21:12 -070039import com.android.car.systeminterface.SystemInterface;
Rui Qiu3d3806b2021-09-22 11:42:45 -070040import com.android.car.systeminterface.SystemStateInterface;
Rui Qiua3418982021-08-20 11:21:12 -070041
Rui Qiu8c415de2021-05-03 15:52:16 -070042import org.junit.Before;
43import org.junit.Rule;
44import org.junit.Test;
Rui Qiua3418982021-08-20 11:21:12 -070045import org.junit.runner.RunWith;
Rui Qiu8c415de2021-05-03 15:52:16 -070046import org.mockito.Mock;
47import org.mockito.junit.MockitoJUnit;
Rui Qiua3418982021-08-20 11:21:12 -070048import org.mockito.junit.MockitoJUnitRunner;
Rui Qiu8c415de2021-05-03 15:52:16 -070049import org.mockito.junit.MockitoRule;
50
Rui Qiud5b4b0b2021-09-14 15:51:50 -070051import java.io.ByteArrayOutputStream;
Rui Qiua3418982021-08-20 11:21:12 -070052import java.io.File;
53import java.nio.file.Files;
Rui Qiu9b9341c2021-08-25 10:39:04 -070054import java.util.concurrent.CountDownLatch;
55import java.util.concurrent.TimeUnit;
Rui Qiua3418982021-08-20 11:21:12 -070056
57@RunWith(MockitoJUnitRunner.class)
Rui Qiu8c415de2021-05-03 15:52:16 -070058@SmallTest
59public class CarTelemetryServiceTest {
Rui Qiu9b9341c2021-08-25 10:39:04 -070060 private static final long TIMEOUT_MS = 5_000L;
61 private static final String METRICS_CONFIG_NAME = "my_metrics_config";
62 private static final MetricsConfigKey KEY_V1 = new MetricsConfigKey(METRICS_CONFIG_NAME, 1);
63 private static final MetricsConfigKey KEY_V2 = new MetricsConfigKey(METRICS_CONFIG_NAME, 2);
64 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V1 =
65 TelemetryProto.MetricsConfig.newBuilder()
66 .setName(METRICS_CONFIG_NAME).setVersion(1).setScript("no-op").build();
67 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V2 =
68 TelemetryProto.MetricsConfig.newBuilder()
69 .setName(METRICS_CONFIG_NAME).setVersion(2).setScript("no-op").build();
Rui Qiu8c415de2021-05-03 15:52:16 -070070
Rui Qiu9b9341c2021-08-25 10:39:04 -070071 private CountDownLatch mIdleHandlerLatch = new CountDownLatch(1);
Rui Qiu8c415de2021-05-03 15:52:16 -070072 private CarTelemetryService mService;
Rui Qiua3418982021-08-20 11:21:12 -070073 private File mTempSystemCarDir;
Rui Qiu9b9341c2021-08-25 10:39:04 -070074 private Handler mTelemetryHandler;
Rui Qiuf721b132021-09-10 12:41:09 -070075 private MetricsConfigStore mMetricsConfigStore;
76 private ResultStore mResultStore;
Rui Qiua3418982021-08-20 11:21:12 -070077
78 @Rule
79 public MockitoRule mMockitoRule = MockitoJUnit.rule();
80 @Mock
Rui Qiuac8b5ba2021-08-25 16:04:17 -070081 private CarPropertyService mMockCarPropertyService;
82 @Mock
Rui Qiua3418982021-08-20 11:21:12 -070083 private Context mContext;
84 @Mock
Rui Qiu9b9341c2021-08-25 10:39:04 -070085 private ICarTelemetryServiceListener mMockListener;
86 @Mock
Rui Qiua3418982021-08-20 11:21:12 -070087 private SystemInterface mMockSystemInterface;
Rui Qiu3d3806b2021-09-22 11:42:45 -070088 @Mock
89 private SystemStateInterface mMockSystemStateInterface;
Rui Qiu8c415de2021-05-03 15:52:16 -070090
91 @Before
Rui Qiua3418982021-08-20 11:21:12 -070092 public void setUp() throws Exception {
93 CarLocalServices.removeServiceForTest(SystemInterface.class);
94 CarLocalServices.addService(SystemInterface.class, mMockSystemInterface);
95
96 mTempSystemCarDir = Files.createTempDirectory("telemetry_test").toFile();
97 when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempSystemCarDir);
Rui Qiu3d3806b2021-09-22 11:42:45 -070098 when(mMockSystemInterface.getSystemStateInterface()).thenReturn(mMockSystemStateInterface);
Rui Qiua3418982021-08-20 11:21:12 -070099
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700100 mService = new CarTelemetryService(mContext, mMockCarPropertyService);
Rui Qiu9b9341c2021-08-25 10:39:04 -0700101 mService.init();
102 mService.setListener(mMockListener);
103
104 mTelemetryHandler = mService.getTelemetryHandler();
105 mTelemetryHandler.getLooper().getQueue().addIdleHandler(() -> {
106 mIdleHandlerLatch.countDown();
107 return true;
108 });
109 waitForHandlerThreadToFinish();
Rui Qiuf721b132021-09-10 12:41:09 -0700110
111 mMetricsConfigStore = mService.getMetricsConfigStore();
112 mResultStore = mService.getResultStore();
Rui Qiu8c415de2021-05-03 15:52:16 -0700113 }
114
115 @Test
Rui Qiu9b9341c2021-08-25 10:39:04 -0700116 public void testAddMetricsConfig_newMetricsConfig_shouldSucceed() throws Exception {
117 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
Rui Qiu8c415de2021-05-03 15:52:16 -0700118
Rui Qiu9b9341c2021-08-25 10:39:04 -0700119 waitForHandlerThreadToFinish();
120 verify(mMockListener).onAddMetricsConfigStatus(
121 eq(KEY_V1), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_NONE));
Rui Qiu8c415de2021-05-03 15:52:16 -0700122 }
123
124 @Test
Rui Qiu9b9341c2021-08-25 10:39:04 -0700125 public void testAddMetricsConfig_duplicateMetricsConfig_shouldFail() throws Exception {
126 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
127 waitForHandlerThreadToFinish();
128 verify(mMockListener).onAddMetricsConfigStatus(
129 eq(KEY_V1), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_NONE));
Rui Qiu8c415de2021-05-03 15:52:16 -0700130
Rui Qiu9b9341c2021-08-25 10:39:04 -0700131 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
Rui Qiu8c415de2021-05-03 15:52:16 -0700132
Rui Qiu9b9341c2021-08-25 10:39:04 -0700133 waitForHandlerThreadToFinish();
134 verify(mMockListener).onAddMetricsConfigStatus(
135 eq(KEY_V1), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_ALREADY_EXISTS));
Rui Qiu8c415de2021-05-03 15:52:16 -0700136 }
137
138 @Test
Rui Qiu9b9341c2021-08-25 10:39:04 -0700139 public void testAddMetricsConfig_invalidMetricsConfig_shouldFail() throws Exception {
Rui Qiuf721b132021-09-10 12:41:09 -0700140 mService.addMetricsConfig(KEY_V1, "bad config".getBytes());
Rui Qiu8c415de2021-05-03 15:52:16 -0700141
Rui Qiu9b9341c2021-08-25 10:39:04 -0700142 waitForHandlerThreadToFinish();
143 verify(mMockListener).onAddMetricsConfigStatus(
144 eq(KEY_V1), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_PARSE_FAILED));
Rui Qiu8c415de2021-05-03 15:52:16 -0700145 }
146
147 @Test
Rui Qiu9b9341c2021-08-25 10:39:04 -0700148 public void testAddMetricsConfig_olderMetricsConfig_shouldFail() throws Exception {
149 mService.addMetricsConfig(KEY_V2, METRICS_CONFIG_V2.toByteArray());
150 waitForHandlerThreadToFinish();
151 verify(mMockListener).onAddMetricsConfigStatus(
152 eq(KEY_V2), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_NONE));
Rui Qiu8c415de2021-05-03 15:52:16 -0700153
Rui Qiu9b9341c2021-08-25 10:39:04 -0700154 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
Rui Qiu8c415de2021-05-03 15:52:16 -0700155
Rui Qiu9b9341c2021-08-25 10:39:04 -0700156 waitForHandlerThreadToFinish();
157 verify(mMockListener).onAddMetricsConfigStatus(
158 eq(KEY_V1), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_VERSION_TOO_OLD));
Rui Qiu8c415de2021-05-03 15:52:16 -0700159 }
160
161 @Test
Rui Qiuf721b132021-09-10 12:41:09 -0700162 public void testAddMetricsConfig_newerMetricsConfig_shouldReplaceAndDeleteOldResult()
163 throws Exception {
Rui Qiu9b9341c2021-08-25 10:39:04 -0700164 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
Rui Qiuf721b132021-09-10 12:41:09 -0700165 mResultStore.putInterimResult(KEY_V1.getName(), new PersistableBundle());
Rui Qiu8c415de2021-05-03 15:52:16 -0700166
Rui Qiu9b9341c2021-08-25 10:39:04 -0700167 mService.addMetricsConfig(KEY_V2, METRICS_CONFIG_V2.toByteArray());
Rui Qiu8c415de2021-05-03 15:52:16 -0700168
Rui Qiu9b9341c2021-08-25 10:39:04 -0700169 waitForHandlerThreadToFinish();
170 verify(mMockListener).onAddMetricsConfigStatus(
171 eq(KEY_V2), eq(CarTelemetryManager.ERROR_METRICS_CONFIG_NONE));
Rui Qiuf721b132021-09-10 12:41:09 -0700172 assertThat(mMetricsConfigStore.getActiveMetricsConfigs())
173 .containsExactly(METRICS_CONFIG_V2);
174 assertThat(mResultStore.getInterimResult(KEY_V1.getName())).isNull();
Rui Qiu8c415de2021-05-03 15:52:16 -0700175 }
176
177 @Test
Rui Qiu9f80c7c2021-09-28 15:15:36 -0700178 public void testRemoveMetricsConfig_shouldDeleteConfigAndResult() throws Exception {
Rui Qiu9b9341c2021-08-25 10:39:04 -0700179 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
Rui Qiuf721b132021-09-10 12:41:09 -0700180 mResultStore.putInterimResult(KEY_V1.getName(), new PersistableBundle());
Rui Qiu8c415de2021-05-03 15:52:16 -0700181
Rui Qiu9b9341c2021-08-25 10:39:04 -0700182 mService.removeMetricsConfig(KEY_V1);
Rui Qiu8c415de2021-05-03 15:52:16 -0700183
Rui Qiu9b9341c2021-08-25 10:39:04 -0700184 waitForHandlerThreadToFinish();
Rui Qiuf721b132021-09-10 12:41:09 -0700185 assertThat(mMetricsConfigStore.getActiveMetricsConfigs()).isEmpty();
186 assertThat(mResultStore.getInterimResult(KEY_V1.getName())).isNull();
Rui Qiu8c415de2021-05-03 15:52:16 -0700187 }
188
189 @Test
Rui Qiuf721b132021-09-10 12:41:09 -0700190 public void testRemoveAllMetricsConfigs_shouldRemoveConfigsAndResults() throws Exception {
191 MetricsConfigKey key = new MetricsConfigKey("test config", 2);
192 TelemetryProto.MetricsConfig config =
193 TelemetryProto.MetricsConfig.newBuilder().setName(key.getName()).build();
194 mService.addMetricsConfig(key, config.toByteArray());
195 mService.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray());
196 mResultStore.putInterimResult(KEY_V1.getName(), new PersistableBundle());
197 mResultStore.putFinalResult(key.getName(), new PersistableBundle());
198
199 mService.removeAllMetricsConfigs();
200
201 waitForHandlerThreadToFinish();
202 assertThat(mMetricsConfigStore.getActiveMetricsConfigs()).isEmpty();
203 assertThat(mResultStore.getInterimResult(KEY_V1.getName())).isNull();
204 assertThat(mResultStore.getFinalResult(key.getName(), /* deleteResult = */ false)).isNull();
205 }
206
Rui Qiud5b4b0b2021-09-14 15:51:50 -0700207 @Test
208 public void testSendFinishedReports_whenNoReport_shouldNotReceiveResponse() throws Exception {
209 mService.sendFinishedReports(KEY_V1);
210
211 waitForHandlerThreadToFinish();
212 verify(mMockListener, never()).onResult(any(), any());
213 verify(mMockListener, never()).onError(any(), any());
214 }
215
216 @Test
217 public void testSendFinishedReports_whenFinalResult_shouldReceiveResult() throws Exception {
218 PersistableBundle finalResult = new PersistableBundle();
219 finalResult.putBoolean("finished", true);
220 mResultStore.putFinalResult(KEY_V1.getName(), finalResult);
221
222 mService.sendFinishedReports(KEY_V1);
223
224 waitForHandlerThreadToFinish();
225 ByteArrayOutputStream bos = new ByteArrayOutputStream();
226 finalResult.writeToStream(bos);
227 verify(mMockListener).onResult(eq(KEY_V1), eq(bos.toByteArray()));
228 // result should have been deleted
229 assertThat(mResultStore.getFinalResult(KEY_V1.getName(), false)).isNull();
230 }
231
232 @Test
233 public void testSendFinishedReports_whenError_shouldReceiveError() throws Exception {
234 TelemetryProto.TelemetryError error = TelemetryProto.TelemetryError.newBuilder()
235 .setErrorType(TelemetryProto.TelemetryError.ErrorType.LUA_RUNTIME_ERROR)
236 .setMessage("test error")
237 .build();
238 mResultStore.putError(KEY_V1.getName(), error);
239
240 mService.sendFinishedReports(KEY_V1);
241
242 waitForHandlerThreadToFinish();
243 verify(mMockListener).onError(eq(KEY_V1), eq(error.toByteArray()));
244 // error should have been deleted
245 assertThat(mResultStore.getError(KEY_V1.getName(), false)).isNull();
246 }
247
248 @Test
249 public void testSendFinishedReports_whenListenerNotSet_shouldDoNothing() throws Exception {
250 PersistableBundle finalResult = new PersistableBundle();
251 finalResult.putBoolean("finished", true);
252 mResultStore.putFinalResult(KEY_V1.getName(), finalResult);
253 mService.clearListener(); // no listener = no way to send back results
254
255 mService.sendFinishedReports(KEY_V1);
256
257 waitForHandlerThreadToFinish();
258 // if listener is null, nothing should be done, result should still be in result store
259 assertThat(mResultStore.getFinalResult(KEY_V1.getName(), false).toString())
260 .isEqualTo(finalResult.toString());
261 }
262
Rui Qiu9b9341c2021-08-25 10:39:04 -0700263 private void waitForHandlerThreadToFinish() throws Exception {
264 assertWithMessage("handler not idle in %sms", TIMEOUT_MS)
265 .that(mIdleHandlerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
266 mIdleHandlerLatch = new CountDownLatch(1); // reset idle handler condition
267 mTelemetryHandler.runWithScissors(() -> { }, TIMEOUT_MS);
Rui Qiu8c415de2021-05-03 15:52:16 -0700268 }
269}