• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 com.android.car.telemetry;
18 
19 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS;
20 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_PARSE_FAILED;
21 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED;
22 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD;
23 import static android.car.telemetry.CarTelemetryManager.STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.junit.Assert.assertThrows;
28 import static org.junit.Assume.assumeTrue;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.ArgumentMatchers.isNull;
33 import static org.mockito.Mockito.doAnswer;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.verify;
36 
37 import android.annotation.NonNull;
38 import android.car.Car;
39 import android.car.telemetry.CarTelemetryManager;
40 import android.car.telemetry.TelemetryProto;
41 import android.util.ArrayMap;
42 
43 import androidx.test.ext.junit.runners.AndroidJUnit4;
44 import androidx.test.filters.MediumTest;
45 
46 import com.android.car.MockedCarTestBase;
47 
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 
51 import java.util.Map;
52 import java.util.concurrent.Executor;
53 import java.util.concurrent.Executors;
54 import java.util.concurrent.Semaphore;
55 
56 /**
57  * Tests the public entry points for the CarTelemetryManager. It uses a real instance of
58  * CarTelemetryService, however the service cannot find ScriptExecutor package so this class
59  * cannot test script execution and report retrieval.
60  * Tests that use a real CarTelemetryService should be in CarTelemetryManagerTest.
61  * Tests that use a spied CarTelemetryService should be in CarTelemetryManagerSpyServiceTest.
62  */
63 @RunWith(AndroidJUnit4.class)
64 @MediumTest
65 public class CarTelemetryManagerTest extends MockedCarTestBase {
66     private static final byte[] INVALID_METRICS_CONFIG = "bad config".getBytes();
67     private static final Executor CALLBACK_EXECUTOR = Executors.newSingleThreadExecutor();
68     private static final String CONFIG_NAME = "my_metrics_config";
69     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V1 =
70             TelemetryProto.MetricsConfig.newBuilder()
71                     .setName(CONFIG_NAME).setVersion(1).setScript("no-op").build();
72     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V2 =
73             METRICS_CONFIG_V1.toBuilder().setVersion(2).build();
74 
75     private final AddMetricsConfigCallbackImpl mAddMetricsConfigCallback =
76             new AddMetricsConfigCallbackImpl();
77 
78     private CarTelemetryManager mCarTelemetryManager;
79 
80     @Override
setUp()81     public void setUp() throws Exception {
82         super.setUp();
83         assumeTrue(getCar().isFeatureEnabled(Car.CAR_TELEMETRY_SERVICE));
84 
85         mCarTelemetryManager = (CarTelemetryManager) getCar().getCarManager(
86                 Car.CAR_TELEMETRY_SERVICE);
87     }
88 
89     @Override
createCarTelemetryService()90     protected CarTelemetryService createCarTelemetryService() {
91         // Forces the base class implementation to instantiate real instance of
92         // CarTelemetryService in ICarImpl.
93         return null;
94     }
95 
96     @Test
testAddMetricsConfig()97     public void testAddMetricsConfig() throws Exception {
98         // invalid config, should fail
99         mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, INVALID_METRICS_CONFIG,
100                 CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
101         mAddMetricsConfigCallback.mSemaphore.acquire();
102         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
103                 STATUS_ADD_METRICS_CONFIG_PARSE_FAILED);
104 
105         // new valid config, should succeed
106         mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
107                 CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
108         mAddMetricsConfigCallback.mSemaphore.acquire();
109         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
110                 STATUS_ADD_METRICS_CONFIG_SUCCEEDED);
111 
112         // duplicate config, should fail
113         mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
114                 CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
115         mAddMetricsConfigCallback.mSemaphore.acquire();
116         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
117                 STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS);
118 
119         // newer version of the config should replace older version
120         mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V2.toByteArray(),
121                 CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
122         mAddMetricsConfigCallback.mSemaphore.acquire();
123         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
124                 STATUS_ADD_METRICS_CONFIG_SUCCEEDED);
125 
126         // older version of the config should not be accepted
127         mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
128                 CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
129         mAddMetricsConfigCallback.mSemaphore.acquire();
130         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
131                 STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD);
132     }
133 
134     @Test
testAddMetricsConfig_invalidFieldInConfig_shouldFail()135     public void testAddMetricsConfig_invalidFieldInConfig_shouldFail() throws Exception {
136         // configure a bad publisher, read interval is not allowed to be less than 1
137         TelemetryProto.Publisher.Builder badPublisher =
138                 TelemetryProto.Publisher.newBuilder().setMemory(
139                         TelemetryProto.MemoryPublisher.newBuilder().setReadIntervalSec(-1));
140         TelemetryProto.Subscriber.Builder badSubscriber =
141                 TelemetryProto.Subscriber.newBuilder()
142                         .setHandler("handler_fn_1")
143                         .setPublisher(badPublisher);
144         TelemetryProto.MetricsConfig config =
145                 METRICS_CONFIG_V1.toBuilder().addSubscribers(badSubscriber).build();
146 
147         mCarTelemetryManager.addMetricsConfig(
148                 CONFIG_NAME, config.toByteArray(), CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
149 
150         mAddMetricsConfigCallback.mSemaphore.acquire();
151         assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
152                 STATUS_ADD_METRICS_CONFIG_PARSE_FAILED);
153     }
154 
155     @Test
testSetClearListener()156     public void testSetClearListener() {
157         CarTelemetryManager.ReportReadyListener listener = metricsConfigName -> { };
158 
159         // test clearReportReadyListener, should not error
160         mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener);
161 
162         // setListener multiple times should fail
163         assertThrows(IllegalStateException.class,
164                 () -> mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener));
165 
166         // test clearReportReadyListener, should not error
167         mCarTelemetryManager.clearReportReadyListener();
168         mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener);
169     }
170 
171     @Test
testGetFinishedReport_noSuchConfig()172     public void testGetFinishedReport_noSuchConfig() throws Exception {
173         Semaphore semaphore = new Semaphore(0);
174         CarTelemetryManager.MetricsReportCallback callback = mock(
175                 CarTelemetryManager.MetricsReportCallback.class);
176         doAnswer((invocation) -> {
177             semaphore.release();
178             return null;
179         }).when(callback).onResult(any(), any(), any(), anyInt());
180 
181         mCarTelemetryManager.getFinishedReport(CONFIG_NAME, CALLBACK_EXECUTOR, callback);
182 
183         semaphore.acquire();
184         verify(callback).onResult(
185                 eq(CONFIG_NAME),
186                 isNull(),
187                 isNull(),
188                 eq(STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST));
189     }
190 
191     private static final class AddMetricsConfigCallbackImpl
192             implements CarTelemetryManager.AddMetricsConfigCallback {
193 
194         private Semaphore mSemaphore = new Semaphore(0);
195         private Map<String, Integer> mAddConfigStatusMap = new ArrayMap<>();
196 
197         @Override
onAddMetricsConfigStatus(@onNull String metricsConfigName, int statusCode)198         public void onAddMetricsConfigStatus(@NonNull String metricsConfigName, int statusCode) {
199             mAddConfigStatusMap.put(metricsConfigName, statusCode);
200             mSemaphore.release();
201         }
202     }
203 }
204