blob: 2bd09df11912bd1c668b85c3f6ccda05c000ca34 [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.car;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.car.Car;
import android.car.vms.IVmsPublisherClient;
import android.car.vms.IVmsPublisherService;
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.VmsLayer;
import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsSubscriptionState;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import com.android.car.stats.CarStatsService;
import com.android.car.stats.VmsClientLogger;
import com.android.car.vms.VmsBrokerService;
import com.android.car.vms.VmsClientManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@SmallTest
public class VmsPublisherServiceTest {
private static final VmsSubscriptionState SUBSCRIPTION_STATE = new VmsSubscriptionState(12345,
Collections.emptySet(), Collections.emptySet());
private static final VmsLayersOffering OFFERING = new VmsLayersOffering(Collections.emptySet(),
54321);
private static final VmsLayer LAYER = new VmsLayer(1, 2, 3);
private static final int PUBLISHER_ID = 54321;
private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4};
private static final int PUBLISHER_UID = 10100;
private static final int SUBSCRIBER_UID = 10101;
private static final int SUBSCRIBER_UID2 = 10102;
private static final int NO_SUBSCRIBERS_UID = -1;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private Context mContext;
@Mock
private CarStatsService mStatsService;
@Mock
private VmsBrokerService mBrokerService;
@Captor
private ArgumentCaptor<VmsBrokerService.PublisherListener> mProxyCaptor;
@Mock
private VmsClientManager mClientManager;
@Mock
private VmsClientLogger mPublisherLog;
@Mock
private VmsClientLogger mSubscriberLog;
@Mock
private VmsClientLogger mSubscriberLog2;
@Mock
private VmsClientLogger mNoSubscribersLog;
@Mock
private IVmsSubscriberClient mSubscriberClient;
@Mock
private IVmsSubscriberClient mSubscriberClient2;
private VmsPublisherService mPublisherService;
private MockPublisherClient mPublisherClient;
private MockPublisherClient mPublisherClient2;
@Before
public void setUp() {
mPublisherService = new VmsPublisherService(mContext, mStatsService, mBrokerService,
mClientManager, () -> PUBLISHER_UID);
verify(mClientManager).setPublisherService(mPublisherService);
when(mClientManager.getSubscriberUid(mSubscriberClient)).thenReturn(SUBSCRIBER_UID);
when(mClientManager.getSubscriberUid(mSubscriberClient2)).thenReturn(SUBSCRIBER_UID2);
when(mStatsService.getVmsClientLogger(PUBLISHER_UID)).thenReturn(mPublisherLog);
when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID)).thenReturn(mSubscriberLog);
when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID2)).thenReturn(mSubscriberLog2);
when(mStatsService.getVmsClientLogger(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog);
mPublisherClient = new MockPublisherClient();
mPublisherClient2 = new MockPublisherClient();
when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID))
.thenReturn(new HashSet<>(Arrays.asList(mSubscriberClient, mSubscriberClient2)));
}
@After
public void tearDown() {
verifyNoMoreInteractions(mPublisherLog, mSubscriberLog, mSubscriberLog2, mNoSubscribersLog);
}
@Test
public void testInit() {
mPublisherService.init();
}
@Test
public void testOnClientConnected() {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
assertNotNull(mPublisherClient.mPublisherService);
assertSame(mPublisherClient.mPublisherService, mProxyCaptor.getAllValues().get(0));
assertNotNull(mPublisherClient2.mPublisherService);
assertSame(mPublisherClient2.mPublisherService, mProxyCaptor.getAllValues().get(1));
assertNotSame(mPublisherClient2.mPublisherService, mPublisherClient.mPublisherService);
}
@Test
public void testOnClientDisconnected() {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
reset(mClientManager, mBrokerService);
mPublisherService.onClientDisconnected("SomeClient");
verify(mBrokerService).removeDeadPublisher(mPublisherClient.mToken);
verify(mBrokerService).removePublisherListener(mProxyCaptor.getAllValues().get(0));
verifyNoMoreInteractions(mBrokerService);
}
@Test
public void testSetLayersOffering() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
verify(mBrokerService).setPublisherLayersOffering(mPublisherClient.mToken, OFFERING);
}
@Test(expected = SecurityException.class)
public void testSetLayersOffering_InvalidToken() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherClient.mPublisherService.setLayersOffering(new Binder(), OFFERING);
}
@Test(expected = SecurityException.class)
public void testSetLayersOffering_Disconnected() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientDisconnected("SomeClient");
mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
}
@Test(expected = SecurityException.class)
public void testSetLayersOffering_PermissionDenied() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
PackageManager.PERMISSION_DENIED);
mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING);
}
@Test
public void testPublish() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
PAYLOAD);
verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD);
verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
verify(mSubscriberLog).logPacketReceived(LAYER, PAYLOAD.length);
verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length);
}
@Test
public void testPublishNullLayerAndNullPayload() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
// We just want to ensure that no exceptions are thrown here.
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, null, PUBLISHER_ID,
null);
}
@Test
public void testPublish_NoSubscribers() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID))
.thenReturn(Collections.emptySet());
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
PAYLOAD);
verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
verify(mNoSubscribersLog).logPacketDropped(LAYER, PAYLOAD.length);
}
@Test
public void testPublish_ClientError() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
doThrow(new RemoteException()).when(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
PAYLOAD);
verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD);
verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD);
verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length);
verify(mSubscriberLog).logPacketDropped(LAYER, PAYLOAD.length);
verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length);
}
@Test(expected = SecurityException.class)
public void testPublish_InvalidToken() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherClient.mPublisherService.publish(new Binder(), LAYER, PUBLISHER_ID, PAYLOAD);
}
@Test(expected = SecurityException.class)
public void testPublish_Disconnected() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientDisconnected("SomeClient");
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
PAYLOAD);
}
@Test(expected = SecurityException.class)
public void testPublish_PermissionDenied() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
PackageManager.PERMISSION_DENIED);
mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID,
PAYLOAD);
}
@Test
public void testGetSubscriptions() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mBrokerService.getSubscriptionState()).thenReturn(SUBSCRIPTION_STATE);
assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mPublisherService.getSubscriptions());
}
@Test(expected = SecurityException.class)
public void testGetSubscriptions_Disconnected() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientDisconnected("SomeClient");
mPublisherClient.mPublisherService.getSubscriptions();
}
@Test(expected = SecurityException.class)
public void testGetSubscriptions_PermissionDenied() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
PackageManager.PERMISSION_DENIED);
mPublisherClient.mPublisherService.getSubscriptions();
}
@Test
public void testGetPublisherId() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mBrokerService.getPublisherId(PAYLOAD)).thenReturn(PUBLISHER_ID);
assertEquals(PUBLISHER_ID, mPublisherClient.mPublisherService.getPublisherId(PAYLOAD));
}
@Test(expected = SecurityException.class)
public void testGetPublisherId_Disconnected() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientDisconnected("SomeClient");
mPublisherClient.mPublisherService.getPublisherId(PAYLOAD);
}
@Test(expected = SecurityException.class)
public void testGetPublisherId_PermissionDenied() throws Exception {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn(
PackageManager.PERMISSION_DENIED);
mPublisherClient.mPublisherService.getPublisherId(PAYLOAD);
}
@Test
public void testOnSubscriptionChange() {
mPublisherService.onClientConnected("SomeClient", mPublisherClient);
mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2);
verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture());
mProxyCaptor.getAllValues().get(0).onSubscriptionChange(SUBSCRIPTION_STATE);
assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mSubscriptionState);
assertNull(mPublisherClient2.mSubscriptionState);
}
@Test
public void testRelease() {
mPublisherService.release();
}
private class MockPublisherClient extends IVmsPublisherClient.Stub {
private IBinder mToken;
private IVmsPublisherService mPublisherService;
private VmsSubscriptionState mSubscriptionState;
@Override
public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
assertNotNull(token);
assertNotNull(service);
if (mToken != null) {
throw new IllegalArgumentException("Publisher service set multiple times");
}
this.mToken = token;
this.mPublisherService = service;
}
@Override
public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
assertNotNull(subscriptionState);
this.mSubscriptionState = subscriptionState;
}
}
}