1 /* 2 * Copyright (C) 2019 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 org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNotSame; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.mockito.Mockito.doThrow; 25 import static org.mockito.Mockito.reset; 26 import static org.mockito.Mockito.times; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.verifyNoMoreInteractions; 29 import static org.mockito.Mockito.when; 30 31 import android.car.Car; 32 import android.car.vms.IVmsPublisherClient; 33 import android.car.vms.IVmsPublisherService; 34 import android.car.vms.IVmsSubscriberClient; 35 import android.car.vms.VmsLayer; 36 import android.car.vms.VmsLayersOffering; 37 import android.car.vms.VmsSubscriptionState; 38 import android.content.Context; 39 import android.content.pm.PackageManager; 40 import android.os.Binder; 41 import android.os.IBinder; 42 import android.os.RemoteException; 43 44 import androidx.test.filters.SmallTest; 45 46 import com.android.car.stats.CarStatsService; 47 import com.android.car.stats.VmsClientLogger; 48 import com.android.car.vms.VmsBrokerService; 49 import com.android.car.vms.VmsClientManager; 50 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.mockito.ArgumentCaptor; 56 import org.mockito.Captor; 57 import org.mockito.Mock; 58 import org.mockito.junit.MockitoJUnit; 59 import org.mockito.junit.MockitoRule; 60 61 import java.util.Arrays; 62 import java.util.Collections; 63 import java.util.HashSet; 64 65 @SmallTest 66 public class VmsPublisherServiceTest { 67 private static final VmsSubscriptionState SUBSCRIPTION_STATE = new VmsSubscriptionState(12345, 68 Collections.emptySet(), Collections.emptySet()); 69 private static final VmsLayersOffering OFFERING = new VmsLayersOffering(Collections.emptySet(), 70 54321); 71 private static final VmsLayer LAYER = new VmsLayer(1, 2, 3); 72 73 private static final int PUBLISHER_ID = 54321; 74 private static final byte[] PAYLOAD = new byte[]{1, 2, 3, 4}; 75 76 private static final int PUBLISHER_UID = 10100; 77 private static final int SUBSCRIBER_UID = 10101; 78 private static final int SUBSCRIBER_UID2 = 10102; 79 private static final int NO_SUBSCRIBERS_UID = -1; 80 81 @Rule 82 public MockitoRule mMockitoRule = MockitoJUnit.rule(); 83 @Mock 84 private Context mContext; 85 @Mock 86 private CarStatsService mStatsService; 87 @Mock 88 private VmsBrokerService mBrokerService; 89 @Captor 90 private ArgumentCaptor<VmsBrokerService.PublisherListener> mProxyCaptor; 91 @Mock 92 private VmsClientManager mClientManager; 93 94 @Mock 95 private VmsClientLogger mPublisherLog; 96 @Mock 97 private VmsClientLogger mSubscriberLog; 98 @Mock 99 private VmsClientLogger mSubscriberLog2; 100 @Mock 101 private VmsClientLogger mNoSubscribersLog; 102 103 @Mock 104 private IVmsSubscriberClient mSubscriberClient; 105 @Mock 106 private IVmsSubscriberClient mSubscriberClient2; 107 108 private VmsPublisherService mPublisherService; 109 private MockPublisherClient mPublisherClient; 110 private MockPublisherClient mPublisherClient2; 111 112 @Before setUp()113 public void setUp() { 114 mPublisherService = new VmsPublisherService(mContext, mStatsService, mBrokerService, 115 mClientManager, () -> PUBLISHER_UID); 116 verify(mClientManager).setPublisherService(mPublisherService); 117 118 when(mClientManager.getSubscriberUid(mSubscriberClient)).thenReturn(SUBSCRIBER_UID); 119 when(mClientManager.getSubscriberUid(mSubscriberClient2)).thenReturn(SUBSCRIBER_UID2); 120 121 when(mStatsService.getVmsClientLogger(PUBLISHER_UID)).thenReturn(mPublisherLog); 122 when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID)).thenReturn(mSubscriberLog); 123 when(mStatsService.getVmsClientLogger(SUBSCRIBER_UID2)).thenReturn(mSubscriberLog2); 124 when(mStatsService.getVmsClientLogger(NO_SUBSCRIBERS_UID)).thenReturn(mNoSubscribersLog); 125 126 mPublisherClient = new MockPublisherClient(); 127 mPublisherClient2 = new MockPublisherClient(); 128 when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID)) 129 .thenReturn(new HashSet<>(Arrays.asList(mSubscriberClient, mSubscriberClient2))); 130 } 131 132 @After tearDown()133 public void tearDown() { 134 verifyNoMoreInteractions(mPublisherLog, mSubscriberLog, mSubscriberLog2, mNoSubscribersLog); 135 } 136 137 @Test testInit()138 public void testInit() { 139 mPublisherService.init(); 140 } 141 142 @Test testOnClientConnected()143 public void testOnClientConnected() { 144 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 145 mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2); 146 verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture()); 147 148 assertNotNull(mPublisherClient.mPublisherService); 149 assertSame(mPublisherClient.mPublisherService, mProxyCaptor.getAllValues().get(0)); 150 151 assertNotNull(mPublisherClient2.mPublisherService); 152 assertSame(mPublisherClient2.mPublisherService, mProxyCaptor.getAllValues().get(1)); 153 assertNotSame(mPublisherClient2.mPublisherService, mPublisherClient.mPublisherService); 154 } 155 156 @Test testOnClientDisconnected()157 public void testOnClientDisconnected() { 158 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 159 mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2); 160 verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture()); 161 162 reset(mClientManager, mBrokerService); 163 mPublisherService.onClientDisconnected("SomeClient"); 164 165 verify(mBrokerService).removeDeadPublisher(mPublisherClient.mToken); 166 verify(mBrokerService).removePublisherListener(mProxyCaptor.getAllValues().get(0)); 167 verifyNoMoreInteractions(mBrokerService); 168 } 169 170 @Test testSetLayersOffering()171 public void testSetLayersOffering() throws Exception { 172 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 173 174 mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING); 175 verify(mBrokerService).setPublisherLayersOffering(mPublisherClient.mToken, OFFERING); 176 } 177 178 @Test(expected = SecurityException.class) testSetLayersOffering_InvalidToken()179 public void testSetLayersOffering_InvalidToken() throws Exception { 180 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 181 182 mPublisherClient.mPublisherService.setLayersOffering(new Binder(), OFFERING); 183 } 184 185 @Test(expected = SecurityException.class) testSetLayersOffering_Disconnected()186 public void testSetLayersOffering_Disconnected() throws Exception { 187 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 188 mPublisherService.onClientDisconnected("SomeClient"); 189 190 mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING); 191 } 192 193 @Test(expected = SecurityException.class) testSetLayersOffering_PermissionDenied()194 public void testSetLayersOffering_PermissionDenied() throws Exception { 195 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 196 when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn( 197 PackageManager.PERMISSION_DENIED); 198 199 mPublisherClient.mPublisherService.setLayersOffering(mPublisherClient.mToken, OFFERING); 200 } 201 202 @Test testPublish()203 public void testPublish() throws Exception { 204 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 205 206 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID, 207 PAYLOAD); 208 verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD); 209 verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD); 210 211 verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length); 212 verify(mSubscriberLog).logPacketReceived(LAYER, PAYLOAD.length); 213 verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length); 214 } 215 216 @Test testPublishNullLayerAndNullPayload()217 public void testPublishNullLayerAndNullPayload() throws Exception { 218 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 219 220 // We just want to ensure that no exceptions are thrown here. 221 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, null, PUBLISHER_ID, 222 null); 223 } 224 225 @Test testPublish_NoSubscribers()226 public void testPublish_NoSubscribers() throws Exception { 227 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 228 when(mBrokerService.getSubscribersForLayerFromPublisher(LAYER, PUBLISHER_ID)) 229 .thenReturn(Collections.emptySet()); 230 231 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID, 232 PAYLOAD); 233 234 verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length); 235 verify(mNoSubscribersLog).logPacketDropped(LAYER, PAYLOAD.length); 236 } 237 238 @Test testPublish_ClientError()239 public void testPublish_ClientError() throws Exception { 240 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 241 doThrow(new RemoteException()).when(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD); 242 243 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID, 244 PAYLOAD); 245 verify(mSubscriberClient).onVmsMessageReceived(LAYER, PAYLOAD); 246 verify(mSubscriberClient2).onVmsMessageReceived(LAYER, PAYLOAD); 247 248 verify(mPublisherLog).logPacketSent(LAYER, PAYLOAD.length); 249 verify(mSubscriberLog).logPacketDropped(LAYER, PAYLOAD.length); 250 verify(mSubscriberLog2).logPacketReceived(LAYER, PAYLOAD.length); 251 } 252 253 @Test(expected = SecurityException.class) testPublish_InvalidToken()254 public void testPublish_InvalidToken() throws Exception { 255 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 256 257 mPublisherClient.mPublisherService.publish(new Binder(), LAYER, PUBLISHER_ID, PAYLOAD); 258 } 259 260 @Test(expected = SecurityException.class) testPublish_Disconnected()261 public void testPublish_Disconnected() throws Exception { 262 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 263 mPublisherService.onClientDisconnected("SomeClient"); 264 265 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID, 266 PAYLOAD); 267 } 268 269 @Test(expected = SecurityException.class) testPublish_PermissionDenied()270 public void testPublish_PermissionDenied() throws Exception { 271 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 272 when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn( 273 PackageManager.PERMISSION_DENIED); 274 275 mPublisherClient.mPublisherService.publish(mPublisherClient.mToken, LAYER, PUBLISHER_ID, 276 PAYLOAD); 277 } 278 279 @Test testGetSubscriptions()280 public void testGetSubscriptions() throws Exception { 281 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 282 when(mBrokerService.getSubscriptionState()).thenReturn(SUBSCRIPTION_STATE); 283 284 assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mPublisherService.getSubscriptions()); 285 } 286 287 @Test(expected = SecurityException.class) testGetSubscriptions_Disconnected()288 public void testGetSubscriptions_Disconnected() throws Exception { 289 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 290 mPublisherService.onClientDisconnected("SomeClient"); 291 292 mPublisherClient.mPublisherService.getSubscriptions(); 293 } 294 295 @Test(expected = SecurityException.class) testGetSubscriptions_PermissionDenied()296 public void testGetSubscriptions_PermissionDenied() throws Exception { 297 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 298 when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn( 299 PackageManager.PERMISSION_DENIED); 300 301 mPublisherClient.mPublisherService.getSubscriptions(); 302 } 303 304 @Test testGetPublisherId()305 public void testGetPublisherId() throws Exception { 306 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 307 when(mBrokerService.getPublisherId(PAYLOAD)).thenReturn(PUBLISHER_ID); 308 309 assertEquals(PUBLISHER_ID, mPublisherClient.mPublisherService.getPublisherId(PAYLOAD)); 310 } 311 312 @Test(expected = SecurityException.class) testGetPublisherId_Disconnected()313 public void testGetPublisherId_Disconnected() throws Exception { 314 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 315 mPublisherService.onClientDisconnected("SomeClient"); 316 317 mPublisherClient.mPublisherService.getPublisherId(PAYLOAD); 318 } 319 320 @Test(expected = SecurityException.class) testGetPublisherId_PermissionDenied()321 public void testGetPublisherId_PermissionDenied() throws Exception { 322 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 323 when(mContext.checkCallingOrSelfPermission(Car.PERMISSION_VMS_PUBLISHER)).thenReturn( 324 PackageManager.PERMISSION_DENIED); 325 326 mPublisherClient.mPublisherService.getPublisherId(PAYLOAD); 327 } 328 329 @Test testOnSubscriptionChange()330 public void testOnSubscriptionChange() { 331 mPublisherService.onClientConnected("SomeClient", mPublisherClient); 332 mPublisherService.onClientConnected("SomeOtherClient", mPublisherClient2); 333 verify(mBrokerService, times(2)).addPublisherListener(mProxyCaptor.capture()); 334 335 mProxyCaptor.getAllValues().get(0).onSubscriptionChange(SUBSCRIPTION_STATE); 336 337 assertEquals(SUBSCRIPTION_STATE, mPublisherClient.mSubscriptionState); 338 assertNull(mPublisherClient2.mSubscriptionState); 339 } 340 341 @Test testRelease()342 public void testRelease() { 343 mPublisherService.release(); 344 } 345 346 private class MockPublisherClient extends IVmsPublisherClient.Stub { 347 private IBinder mToken; 348 private IVmsPublisherService mPublisherService; 349 private VmsSubscriptionState mSubscriptionState; 350 351 @Override setVmsPublisherService(IBinder token, IVmsPublisherService service)352 public void setVmsPublisherService(IBinder token, IVmsPublisherService service) { 353 assertNotNull(token); 354 assertNotNull(service); 355 if (mToken != null) { 356 throw new IllegalArgumentException("Publisher service set multiple times"); 357 } 358 this.mToken = token; 359 this.mPublisherService = service; 360 } 361 362 @Override onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)363 public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) { 364 assertNotNull(subscriptionState); 365 this.mSubscriptionState = subscriptionState; 366 } 367 } 368 } 369