1 /* 2 * Copyright (C) 2017 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; 18 19 import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_ALREADY_EXISTS; 20 import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_NONE; 21 import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_PARSE_FAILED; 22 import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_VERSION_TOO_OLD; 23 24 import static com.google.common.truth.Truth.assertThat; 25 import static com.google.common.truth.Truth.assertWithMessage; 26 27 import static org.junit.Assert.assertThrows; 28 import static org.junit.Assume.assumeTrue; 29 30 import android.annotation.NonNull; 31 import android.car.Car; 32 import android.car.telemetry.CarTelemetryManager; 33 import android.car.telemetry.MetricsConfigKey; 34 import android.os.Handler; 35 import android.os.HandlerThread; 36 import android.util.ArrayMap; 37 import android.util.Log; 38 39 import androidx.test.ext.junit.runners.AndroidJUnit4; 40 import androidx.test.filters.MediumTest; 41 42 import com.android.car.telemetry.CarTelemetryService; 43 import com.android.car.telemetry.TelemetryProto; 44 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 import java.util.Map; 49 import java.util.concurrent.CountDownLatch; 50 import java.util.concurrent.Executor; 51 import java.util.concurrent.TimeUnit; 52 53 /** Test the public entry points for the CarTelemetryManager. */ 54 @RunWith(AndroidJUnit4.class) 55 @MediumTest 56 public class CarTelemetryManagerTest extends MockedCarTestBase { 57 private static final long TIMEOUT_MS = 5_000L; 58 private static final String TAG = CarTelemetryManagerTest.class.getSimpleName(); 59 private static final byte[] INVALID_METRICS_CONFIG = "bad config".getBytes(); 60 private static final Executor DIRECT_EXECUTOR = Runnable::run; 61 private static final MetricsConfigKey KEY_V1 = new MetricsConfigKey("my_metrics_config", 1); 62 private static final MetricsConfigKey KEY_V2 = new MetricsConfigKey("my_metrics_config", 2); 63 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V1 = 64 TelemetryProto.MetricsConfig.newBuilder() 65 .setName("my_metrics_config").setVersion(1).setScript("no-op").build(); 66 private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V2 = 67 METRICS_CONFIG_V1.toBuilder().setVersion(2).build(); 68 69 private final FakeCarTelemetryResultsListener mListener = new FakeCarTelemetryResultsListener(); 70 private final HandlerThread mTelemetryThread = 71 CarServiceUtils.getHandlerThread(CarTelemetryService.class.getSimpleName()); 72 private final Handler mHandler = new Handler(mTelemetryThread.getLooper()); 73 74 private CarTelemetryManager mCarTelemetryManager; 75 private CountDownLatch mIdleHandlerLatch = new CountDownLatch(1); 76 77 @Override setUp()78 public void setUp() throws Exception { 79 super.setUp(); 80 assumeTrue(getCar().isFeatureEnabled(Car.CAR_TELEMETRY_SERVICE)); 81 82 mTelemetryThread.getLooper().getQueue().addIdleHandler(() -> { 83 mIdleHandlerLatch.countDown(); 84 return true; 85 }); 86 87 Log.i(TAG, "attempting to get CAR_TELEMETRY_SERVICE"); 88 mCarTelemetryManager = (CarTelemetryManager) getCar().getCarManager( 89 Car.CAR_TELEMETRY_SERVICE); 90 mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener); 91 } 92 93 @Test testSetClearListener()94 public void testSetClearListener() { 95 mCarTelemetryManager.clearListener(); 96 mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener); 97 98 // setListener multiple times should fail 99 assertThrows(IllegalStateException.class, 100 () -> mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener)); 101 } 102 103 @Test testApiInvocationWithoutSettingListener()104 public void testApiInvocationWithoutSettingListener() { 105 mCarTelemetryManager.clearListener(); 106 107 assertThrows(IllegalStateException.class, 108 () -> mCarTelemetryManager.addMetricsConfig( 109 KEY_V1, METRICS_CONFIG_V1.toByteArray())); 110 assertThrows(IllegalStateException.class, 111 () -> mCarTelemetryManager.removeMetricsConfig(KEY_V1)); 112 assertThrows(IllegalStateException.class, 113 () -> mCarTelemetryManager.removeAllMetricsConfigs()); 114 assertThrows(IllegalStateException.class, 115 () -> mCarTelemetryManager.sendFinishedReports(KEY_V1)); 116 assertThrows(IllegalStateException.class, 117 () -> mCarTelemetryManager.sendAllFinishedReports()); 118 } 119 120 @Test testAddMetricsConfig()121 public void testAddMetricsConfig() throws Exception { 122 // invalid config, should fail 123 mCarTelemetryManager.addMetricsConfig(KEY_V1, INVALID_METRICS_CONFIG); 124 waitForHandlerThreadToFinish(); 125 assertThat(mListener.getAddConfigStatus(KEY_V1)).isEqualTo( 126 ERROR_METRICS_CONFIG_PARSE_FAILED); 127 128 // new valid config, should succeed 129 mCarTelemetryManager.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray()); 130 waitForHandlerThreadToFinish(); 131 assertThat(mListener.getAddConfigStatus(KEY_V1)).isEqualTo(ERROR_METRICS_CONFIG_NONE); 132 133 // duplicate config, should fail 134 mCarTelemetryManager.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray()); 135 waitForHandlerThreadToFinish(); 136 assertThat(mListener.getAddConfigStatus(KEY_V1)).isEqualTo( 137 ERROR_METRICS_CONFIG_ALREADY_EXISTS); 138 139 // newer version of the config should replace older version 140 mCarTelemetryManager.addMetricsConfig(KEY_V2, METRICS_CONFIG_V2.toByteArray()); 141 waitForHandlerThreadToFinish(); 142 assertThat(mListener.getAddConfigStatus(KEY_V2)).isEqualTo(ERROR_METRICS_CONFIG_NONE); 143 144 // older version of the config should not be accepted 145 mCarTelemetryManager.addMetricsConfig(KEY_V1, METRICS_CONFIG_V1.toByteArray()); 146 waitForHandlerThreadToFinish(); 147 assertThat(mListener.getAddConfigStatus(KEY_V1)).isEqualTo( 148 ERROR_METRICS_CONFIG_VERSION_TOO_OLD); 149 } 150 waitForHandlerThreadToFinish()151 private void waitForHandlerThreadToFinish() throws Exception { 152 assertWithMessage("handler not idle in %sms", TIMEOUT_MS) 153 .that(mIdleHandlerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue(); 154 mIdleHandlerLatch = new CountDownLatch(1); // reset idle handler condition 155 mHandler.runWithScissors(() -> { 156 }, TIMEOUT_MS); 157 } 158 159 160 private static final class FakeCarTelemetryResultsListener 161 implements CarTelemetryManager.CarTelemetryResultsListener { 162 163 private Map<MetricsConfigKey, Integer> mAddConfigStatusMap = new ArrayMap<>(); 164 165 @Override onResult(@onNull MetricsConfigKey key, @NonNull byte[] result)166 public void onResult(@NonNull MetricsConfigKey key, @NonNull byte[] result) { 167 } 168 169 @Override onError(@onNull MetricsConfigKey key, @NonNull byte[] error)170 public void onError(@NonNull MetricsConfigKey key, @NonNull byte[] error) { 171 } 172 173 @Override onAddMetricsConfigStatus(@onNull MetricsConfigKey key, int statusCode)174 public void onAddMetricsConfigStatus(@NonNull MetricsConfigKey key, int statusCode) { 175 mAddConfigStatusMap.put(key, statusCode); 176 } 177 getAddConfigStatus(MetricsConfigKey key)178 public int getAddConfigStatus(MetricsConfigKey key) { 179 return mAddConfigStatusMap.getOrDefault(key, -100); 180 } 181 } 182 } 183