Add the remaining CarTelemetryManager API
This change adds the remaining APIs to CarTelemetryManager
(go/st-communication-api), which allows the client (cloud app) to send
manifest as well as receive script outputs
CarTelemetryService is enabled with
> adb shell cmd car_service enable-feature car_telemetry_service
Bug: 184087869
Test: m CarService
Test: atest CarTelemetryManagerTest
Change-Id: Ic2fd311c884bc52773a9c8fe000618a971fcbc7d
Merged-In: Ic2fd311c884bc52773a9c8fe000618a971fcbc7d
(cherry picked from commit 16d571374d60bc2920f5c0f8ccdb7e6a5eb386c8)
diff --git a/car-lib/src/android/car/telemetry/CarTelemetryManager.java b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
index 24d787b..91df1dd 100644
--- a/car-lib/src/android/car/telemetry/CarTelemetryManager.java
+++ b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
@@ -17,6 +17,7 @@
package android.car.telemetry;
import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.car.Car;
@@ -28,6 +29,8 @@
import com.android.internal.annotations.GuardedBy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;
@@ -41,6 +44,7 @@
private static final boolean DEBUG = false;
private static final String TAG = CarTelemetryManager.class.getSimpleName();
+ private static final int MANIFEST_MAX_SIZE_BYTES = 10 * 1024; // 10 kb
private final CarTelemetryServiceListener mCarTelemetryServiceListener =
new CarTelemetryServiceListener(this);
@@ -53,6 +57,51 @@
private Executor mExecutor;
/**
+ * Status to indicate that manifest was added successfully.
+ */
+ public static final int ERROR_NONE = 0;
+
+ /**
+ * Status to indicate that add manifest failed because the same manifest based on the
+ * ManifestKey already exists.
+ */
+ public static final int ERROR_SAME_MANIFEST_EXISTS = 1;
+
+ /**
+ * Status to indicate that add manifest failed because a newer version of the manifest exists.
+ */
+ public static final int ERROR_NEWER_MANIFEST_EXISTS = 2;
+
+ /**
+ * Status to indicate that add manifest failed because CarTelemetryService is unable to parse
+ * the given byte array into a Manifest.
+ */
+ public static final int ERROR_PARSE_MANIFEST_FAILED = 3;
+
+ /**
+ * Status to indicate that add manifest failed because of failure to verify the signature of
+ * the manifest.
+ */
+ public static final int ERROR_SIGNATURE_VERIFICATION_FAILED = 4;
+
+ /**
+ * Status to indicate that add manifest failed because of a general error in cars.
+ */
+ public static final int ERROR_UNKNOWN = 5;
+
+ /** @hide */
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_NONE,
+ ERROR_SAME_MANIFEST_EXISTS,
+ ERROR_NEWER_MANIFEST_EXISTS,
+ ERROR_PARSE_MANIFEST_FAILED,
+ ERROR_SIGNATURE_VERIFICATION_FAILED,
+ ERROR_UNKNOWN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AddManifestError {}
+
+ /**
* Application registers {@link CarTelemetryResultsListener} object to receive data from
* {@link com.android.car.telemetry.CarTelemetryService}.
*
@@ -169,4 +218,115 @@
handleRemoteExceptionFromCarService(e);
}
}
+
+ /**
+ * Called by client to send telemetry manifest. The size of the manifest cannot exceed a
+ * predefined size. Otherwise an exception is thrown.
+ * The {@link ManifestKey} is used to uniquely identify a manifest. If a manifest of the same
+ * name already exists in {@link com.android.car.telemetry.CarTelemetryService}, then the
+ * version will be compared. If the version is strictly higher, the existing manifest will be
+ * replaced by the new one.
+ * TODO(b/185420981): Update javadoc after CarTelemetryService has concrete implementation.
+ *
+ * @param key the unique key to identify the manifest.
+ * @param manifest the serialized bytes of a Manifest object.
+ * @return {@link #AddManifestError} to tell the result of the request.
+ * @throws IllegalArgumentException if the manifest size exceeds limit.
+ *
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] manifest) {
+ if (manifest.length > MANIFEST_MAX_SIZE_BYTES) {
+ throw new IllegalArgumentException("Manifest size exceeds limit.");
+ }
+ try {
+ return mService.addManifest(key, manifest);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ return ERROR_UNKNOWN;
+ }
+
+ /**
+ * Removes a manifest from {@link com.android.car.telemetry.CarTelemetryService}. If the
+ * manifest does not exist, nothing will be removed but the status will be indicated in the
+ * return value.
+ *
+ * @param key the unique key to identify the manifest. Name and version must be exact.
+ * @return true for success, false otherwise.
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public boolean removeManifest(@NonNull ManifestKey key) {
+ try {
+ return mService.removeManifest(key);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ return false;
+ }
+
+ /**
+ * Removes all manifests from {@link com.android.car.telemetry.CarTelemetryService}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public void removeAllManifests() {
+ try {
+ mService.removeAllManifests();
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
+
+ /**
+ * An asynchronous API for the client to get script execution results of a specific manifest
+ * from the {@link com.android.car.telemetry.CarTelemetryService} through the listener.
+ * This call is destructive. The returned results will be deleted from CarTelemetryService.
+ *
+ * @param key the unique key to identify the manifest.
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public void sendFinishedReports(@NonNull ManifestKey key) {
+ try {
+ mService.sendFinishedReports(key);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
+
+ /**
+ * An asynchronous API for the client to get all script execution results
+ * from the {@link com.android.car.telemetry.CarTelemetryService} through the listener.
+ * This call is destructive. The returned results will be deleted from CarTelemetryService.
+ *
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public void sendAllFinishedReports() {
+ try {
+ mService.sendAllFinishedReports();
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
+
+ /**
+ * An asynchronous API for the client to get all script execution errors
+ * from the {@link com.android.car.telemetry.CarTelemetryService} through the listener.
+ * This call is destructive. The returned results will be deleted from CarTelemetryService.
+ *
+ * @hide
+ */
+ @RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
+ public void sendScriptExecutionErrors() {
+ try {
+ mService.sendScriptExecutionErrors();
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
}
diff --git a/car-lib/src/android/car/telemetry/ICarTelemetryService.aidl b/car-lib/src/android/car/telemetry/ICarTelemetryService.aidl
index e2eb3e9..09743d8 100644
--- a/car-lib/src/android/car/telemetry/ICarTelemetryService.aidl
+++ b/car-lib/src/android/car/telemetry/ICarTelemetryService.aidl
@@ -1,6 +1,7 @@
package android.car.telemetry;
import android.car.telemetry.ICarTelemetryServiceListener;
+import android.car.telemetry.ManifestKey;
/**
* Internal binder interface for {@code CarTelemetryService}, used by {@code CarTelemetryManager}.
@@ -18,4 +19,35 @@
* Clears the listener registered with CarTelemetryService.
*/
void clearListener();
+
+ /**
+ * Sends telemetry manifests to CarTelemetryService.
+ */
+ int addManifest(in ManifestKey key, in byte[] manifest);
+
+ /**
+ * Removes a manifest based on the key.
+ */
+ boolean removeManifest(in ManifestKey key);
+
+ /**
+ * Removes all manifests.
+ */
+ void removeAllManifests();
+
+ /**
+ * Sends script results associated with the given key using the
+ * {@code ICarTelemetryServiceListener}.
+ */
+ void sendFinishedReports(in ManifestKey key);
+
+ /**
+ * Sends all script results associated using the {@code ICarTelemetryServiceListener}.
+ */
+ void sendAllFinishedReports();
+
+ /**
+ * Sends all errors using the {@code ICarTelemetryServiceListener}.
+ */
+ void sendScriptExecutionErrors();
}
\ No newline at end of file
diff --git a/car-lib/src/android/car/telemetry/ManifestKey.aidl b/car-lib/src/android/car/telemetry/ManifestKey.aidl
new file mode 100644
index 0000000..25097df
--- /dev/null
+++ b/car-lib/src/android/car/telemetry/ManifestKey.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.telemetry;
+
+/**
+ * @hide
+ */
+parcelable ManifestKey;
\ No newline at end of file
diff --git a/car-lib/src/android/car/telemetry/ManifestKey.java b/car-lib/src/android/car/telemetry/ManifestKey.java
new file mode 100644
index 0000000..b0a69c2
--- /dev/null
+++ b/car-lib/src/android/car/telemetry/ManifestKey.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.telemetry;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable that wraps around the Manifest name and version.
+ *
+ * @hide
+ */
+public final class ManifestKey implements Parcelable {
+
+ @NonNull
+ private String mName;
+ private int mVersion;
+
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ public int getVersion() {
+ return mVersion;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeInt(mVersion);
+ }
+
+ private ManifestKey(Parcel in) {
+ mName = in.readString();
+ mVersion = in.readInt();
+ }
+
+ public ManifestKey(@NonNull String name, int version) {
+ mName = name;
+ mVersion = version;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<ManifestKey> CREATOR =
+ new Parcelable.Creator<ManifestKey>() {
+ @Override
+ public ManifestKey createFromParcel(Parcel in) {
+ return new ManifestKey(in);
+ }
+
+ @Override
+ public ManifestKey[] newArray(int size) {
+ return new ManifestKey[size];
+ }
+ };
+}
diff --git a/car-test-lib/src/android/car/testapi/CarTelemetryController.java b/car-test-lib/src/android/car/testapi/CarTelemetryController.java
index 1f57497..e4df3f3 100644
--- a/car-test-lib/src/android/car/testapi/CarTelemetryController.java
+++ b/car-test-lib/src/android/car/testapi/CarTelemetryController.java
@@ -16,6 +16,8 @@
package android.car.testapi;
+import android.car.telemetry.ManifestKey;
+
/**
* Controller to manipulate and verify {@link android.car.telemetry.CarTelemetryManager} in
* unit tests.
@@ -27,4 +29,20 @@
* registered with the manager, otherwise returns {@code false}.
*/
boolean isListenerSet();
+
+ /**
+ * Returns the number of valid manifests registered with the manager.
+ */
+ int getValidManifestsCount();
+
+ /**
+ * Associate a blob of data with the given key, used for testing the flush reports APIs.
+ */
+ void addDataForKey(ManifestKey key, byte[] data);
+
+ /**
+ * Configure the blob of data to be flushed with the
+ * {@code FakeCarTelemetryService#flushScriptExecutionErrors()} API.
+ */
+ void setErrorData(byte[] error);
}
diff --git a/car-test-lib/src/android/car/testapi/FakeCarTelemetryService.java b/car-test-lib/src/android/car/testapi/FakeCarTelemetryService.java
index af8a2b4..407d29f 100644
--- a/car-test-lib/src/android/car/testapi/FakeCarTelemetryService.java
+++ b/car-test-lib/src/android/car/testapi/FakeCarTelemetryService.java
@@ -16,8 +16,18 @@
package android.car.testapi;
+import static android.car.telemetry.CarTelemetryManager.ERROR_NEWER_MANIFEST_EXISTS;
+import static android.car.telemetry.CarTelemetryManager.ERROR_NONE;
+import static android.car.telemetry.CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS;
+
+import android.car.telemetry.CarTelemetryManager.AddManifestError;
import android.car.telemetry.ICarTelemetryService;
import android.car.telemetry.ICarTelemetryServiceListener;
+import android.car.telemetry.ManifestKey;
+import android.os.RemoteException;
+
+import java.util.HashMap;
+import java.util.Map;
/**
* A fake implementation of {@link ICarTelemetryService.Stub} to facilitate the use of
@@ -28,8 +38,13 @@
public class FakeCarTelemetryService extends ICarTelemetryService.Stub implements
CarTelemetryController {
+ private byte[] mErrorBytes;
private ICarTelemetryServiceListener mListener;
+ private final Map<String, Integer> mNameVersionMap = new HashMap<>();
+ private final Map<ManifestKey, byte[]> mManifestMap = new HashMap<>();
+ private final Map<ManifestKey, byte[]> mScriptResultMap = new HashMap<>();
+
@Override
public void setListener(ICarTelemetryServiceListener listener) {
mListener = listener;
@@ -40,9 +55,74 @@
mListener = null;
}
+ @Override
+ public @AddManifestError int addManifest(ManifestKey key, byte[] manifest) {
+ if (mNameVersionMap.getOrDefault(key.getName(), 0) > key.getVersion()) {
+ return ERROR_NEWER_MANIFEST_EXISTS;
+ } else if (mNameVersionMap.getOrDefault(key.getName(), 0) == key.getVersion()) {
+ return ERROR_SAME_MANIFEST_EXISTS;
+ }
+ mNameVersionMap.put(key.getName(), key.getVersion());
+ mManifestMap.put(key, manifest);
+ return ERROR_NONE;
+ }
+
+ @Override
+ public boolean removeManifest(ManifestKey key) {
+ if (!mManifestMap.containsKey(key)) {
+ return false;
+ }
+ mNameVersionMap.remove(key.getName());
+ mManifestMap.remove(key);
+ return true;
+ }
+
+ @Override
+ public void removeAllManifests() {
+ mNameVersionMap.clear();
+ mManifestMap.clear();
+ }
+
+ @Override
+ public void sendFinishedReports(ManifestKey key) throws RemoteException {
+ if (!mScriptResultMap.containsKey(key)) {
+ return;
+ }
+ mListener.onDataReceived(mScriptResultMap.get(key));
+ mScriptResultMap.remove(key);
+ }
+
+ @Override
+ public void sendAllFinishedReports() throws RemoteException {
+ for (byte[] data : mScriptResultMap.values()) {
+ mListener.onDataReceived(data);
+ }
+ mScriptResultMap.clear();
+ }
+
+ @Override
+ public void sendScriptExecutionErrors() throws RemoteException {
+ mListener.onDataReceived(mErrorBytes);
+ }
+
/**************************** CarTelemetryController impl ********************************/
@Override
public boolean isListenerSet() {
return mListener != null;
}
+
+ @Override
+ public int getValidManifestsCount() {
+ return mManifestMap.size();
+ }
+
+ @Override
+ public void addDataForKey(ManifestKey key, byte[] data) {
+ mScriptResultMap.put(key, data);
+ }
+
+ @Override
+ public void setErrorData(byte[] error) {
+ mErrorBytes = error;
+ }
}
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index b68e020..74f4509 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -15,10 +15,14 @@
*/
package com.android.car.telemetry;
+import static android.car.telemetry.CarTelemetryManager.ERROR_NONE;
+
import android.annotation.NonNull;
import android.car.Car;
+import android.car.telemetry.CarTelemetryManager.AddManifestError;
import android.car.telemetry.ICarTelemetryService;
import android.car.telemetry.ICarTelemetryServiceListener;
+import android.car.telemetry.ManifestKey;
import android.content.Context;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -62,7 +66,7 @@
*/
@Override
public void setListener(@NonNull ICarTelemetryServiceListener listener) {
- // TODO(b/150978930): verify that only a hardcoded app can set the listener
+ // TODO(b/184890506): verify that only a hardcoded app can set the listener
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
if (DEBUG) {
@@ -83,4 +87,89 @@
}
mListener = null;
}
+
+ /**
+ * Allows client to send telemetry manifests.
+ *
+ * @param key the unique key to identify the manifest.
+ * @param manifest the serialized bytes of a Manifest object.
+ * @return {@link AddManifestError} the error code.
+ */
+ @Override
+ public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] manifest) {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Adding manifest to car telemetry service");
+ }
+ return ERROR_NONE;
+ }
+
+ /**
+ * Removes a manifest based on the key.
+ */
+ @Override
+ public boolean removeManifest(@NonNull ManifestKey key) {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Removing manifest from car telemetry service");
+ }
+ return true;
+ }
+
+ /**
+ * Removes all manifests.
+ */
+ @Override
+ public void removeAllManifests() {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Removing all manifest from car telemetry service");
+ }
+ }
+
+ /**
+ * Sends script results associated with the given key using the
+ * {@link ICarTelemetryServiceListener}.
+ */
+ @Override
+ public void sendFinishedReports(@NonNull ManifestKey key) {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Flushing reports for a manifest");
+ }
+ }
+
+ /**
+ * Sends all script results associated using the {@link ICarTelemetryServiceListener}.
+ */
+ @Override
+ public void sendAllFinishedReports() {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Flushing all reports");
+ }
+ }
+
+ /**
+ * Sends all errors using the {@link ICarTelemetryServiceListener}.
+ */
+ @Override
+ public void sendScriptExecutionErrors() {
+ // TODO(b/184087869): Implement
+ mContext.enforceCallingOrSelfPermission(
+ Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
+ if (DEBUG) {
+ Slog.d(TAG, "Flushing script execution errors");
+ }
+ }
}
diff --git a/tests/CarLibTests/src/android/car/CarTelemetryManagerTest.java b/tests/CarLibTests/src/android/car/CarTelemetryManagerTest.java
index 90b5f7a..eb037af 100644
--- a/tests/CarLibTests/src/android/car/CarTelemetryManagerTest.java
+++ b/tests/CarLibTests/src/android/car/CarTelemetryManagerTest.java
@@ -16,10 +16,17 @@
package android.car;
+import static android.car.telemetry.CarTelemetryManager.ERROR_NONE;
+import static android.car.telemetry.CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.app.Application;
import android.car.telemetry.CarTelemetryManager;
+import android.car.telemetry.ManifestKey;
import android.car.testapi.CarTelemetryController;
import android.car.testapi.FakeCar;
@@ -43,10 +50,16 @@
@Rule
public MockitoRule rule = MockitoJUnit.rule();
+ private static final byte[] ERROR_BYTES = "ERROR".getBytes();
+ private static final byte[] MANIFEST_BYTES = "MANIFEST".getBytes();
+ private static final byte[] SCRIPT_RESULT_BYTES = "SCRIPT RESULT".getBytes();
+ private static final ManifestKey DEFAULT_MANIFEST_KEY =
+ new ManifestKey("NAME", 1);
private static final Executor DIRECT_EXECUTOR = Runnable::run;
private CarTelemetryController mCarTelemetryController;
private CarTelemetryManager mCarTelemetryManager;
+
@Mock
private CarTelemetryManager.CarTelemetryResultsListener mListener;
@@ -77,4 +90,85 @@
assertThat(mCarTelemetryController.isListenerSet()).isFalse();
}
+
+ @Test
+ public void addManifest_whenNew_shouldSucceed() {
+ int result = mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+
+ assertThat(result).isEqualTo(ERROR_NONE);
+ assertThat(mCarTelemetryController.getValidManifestsCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void addManifest_whenDuplicate_shouldIgnore() {
+ int firstResult =
+ mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+ int secondResult =
+ mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+
+ assertThat(firstResult).isEqualTo(ERROR_NONE);
+ assertThat(secondResult).isEqualTo(ERROR_SAME_MANIFEST_EXISTS);
+ assertThat(mCarTelemetryController.getValidManifestsCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void removeManifest_whenValid_shouldSucceed() {
+ mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+
+ boolean result = mCarTelemetryManager.removeManifest(DEFAULT_MANIFEST_KEY);
+
+ assertThat(result).isTrue();
+ assertThat(mCarTelemetryController.getValidManifestsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void removeManifest_whenInvalid_shouldIgnore() {
+ mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+
+ boolean result = mCarTelemetryManager.removeManifest(new ManifestKey("NAME", 100));
+
+ assertThat(result).isFalse();
+ assertThat(mCarTelemetryController.getValidManifestsCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void removeAllManifests_shouldSucceed() {
+ mCarTelemetryManager.addManifest(DEFAULT_MANIFEST_KEY, MANIFEST_BYTES);
+ mCarTelemetryManager.addManifest(new ManifestKey("NAME", 100), MANIFEST_BYTES);
+
+ mCarTelemetryManager.removeAllManifests();
+
+ assertThat(mCarTelemetryController.getValidManifestsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void sendFinishedReports_shouldSucceed() {
+ mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener);
+ mCarTelemetryController.addDataForKey(DEFAULT_MANIFEST_KEY, SCRIPT_RESULT_BYTES);
+
+ mCarTelemetryManager.sendFinishedReports(DEFAULT_MANIFEST_KEY);
+
+ verify(mListener).onDataReceived(SCRIPT_RESULT_BYTES);
+ }
+
+ @Test
+ public void sendAllFinishedReports_shouldSucceed() {
+ mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener);
+ mCarTelemetryController.addDataForKey(DEFAULT_MANIFEST_KEY, SCRIPT_RESULT_BYTES);
+ mCarTelemetryController.addDataForKey(new ManifestKey("key name", 1), SCRIPT_RESULT_BYTES);
+
+ mCarTelemetryManager.sendAllFinishedReports();
+
+ verify(mListener, times(2)).onDataReceived(SCRIPT_RESULT_BYTES);
+ }
+
+ @Test
+ public void sendScriptExecutionErrors_shouldSucceed() {
+ mCarTelemetryManager.setListener(DIRECT_EXECUTOR, mListener);
+ mCarTelemetryController.setErrorData(ERROR_BYTES);
+
+ mCarTelemetryManager.sendScriptExecutionErrors();
+
+ verify(mListener).onDataReceived(ERROR_BYTES);
+ }
}