1 /* 2 * Copyright (C) 2018 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 android.net; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Mockito.any; 24 import static org.mockito.Mockito.doAnswer; 25 import static org.mockito.Mockito.doNothing; 26 import static org.mockito.Mockito.doThrow; 27 import static org.mockito.Mockito.eq; 28 import static org.mockito.Mockito.inOrder; 29 import static org.mockito.Mockito.times; 30 import static org.mockito.Mockito.verify; 31 32 import android.content.Context; 33 import android.net.ipmemorystore.Blob; 34 import android.net.ipmemorystore.IOnStatusListener; 35 import android.net.ipmemorystore.NetworkAttributes; 36 import android.net.ipmemorystore.NetworkAttributesParcelable; 37 import android.net.ipmemorystore.Status; 38 import android.net.networkstack.ModuleNetworkStackClient; 39 import android.os.Build; 40 import android.os.RemoteException; 41 42 import androidx.test.filters.SmallTest; 43 44 import com.android.testutils.DevSdkIgnoreRule; 45 import com.android.testutils.DevSdkIgnoreRunner; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.mockito.ArgumentCaptor; 51 import org.mockito.Captor; 52 import org.mockito.InOrder; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 56 import java.net.UnknownHostException; 57 import java.util.Arrays; 58 59 @RunWith(DevSdkIgnoreRunner.class) 60 @SmallTest 61 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 62 public class IpMemoryStoreTest { 63 private static final String TAG = IpMemoryStoreTest.class.getSimpleName(); 64 private static final String TEST_CLIENT_ID = "testClientId"; 65 private static final String TEST_DATA_NAME = "testData"; 66 private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other"; 67 private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12, 68 -128, 0, 89, 112, 91, -34 }; 69 private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes( 70 "hint", 219); 71 72 @Mock 73 Context mMockContext; 74 @Mock 75 ModuleNetworkStackClient mModuleNetworkStackClient; 76 @Mock 77 IIpMemoryStore mMockService; 78 @Mock 79 IOnStatusListener mIOnStatusListener; 80 IpMemoryStore mStore; 81 82 @Captor 83 ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor; 84 @Captor 85 ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor; 86 87 @Before setUp()88 public void setUp() { 89 MockitoAnnotations.initMocks(this); 90 } 91 startIpMemoryStore(boolean supplyService)92 private void startIpMemoryStore(boolean supplyService) { 93 if (supplyService) { 94 doAnswer(invocation -> { 95 ((IIpMemoryStoreCallbacks) invocation.getArgument(0)) 96 .onIpMemoryStoreFetched(mMockService); 97 return null; 98 }).when(mModuleNetworkStackClient).fetchIpMemoryStore(any()); 99 } else { 100 doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture()); 101 } 102 mStore = new IpMemoryStore(mMockContext) { 103 @Override 104 protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) { 105 return mModuleNetworkStackClient; 106 } 107 }; 108 } 109 buildTestNetworkAttributes(String hint, int mtu)110 private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) { 111 return new NetworkAttributes.Builder() 112 .setCluster(hint) 113 .setMtu(mtu) 114 .build(); 115 } 116 117 @Test testNetworkAttributes()118 public void testNetworkAttributes() throws Exception { 119 startIpMemoryStore(true /* supplyService */); 120 final String l2Key = "fakeKey"; 121 122 mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, 123 status -> assertTrue("Store not successful : " + status.resultCode, 124 status.isSuccess())); 125 verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key), 126 mNapCaptor.capture(), any()); 127 assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); 128 129 mStore.retrieveNetworkAttributes(l2Key, 130 (status, key, attr) -> { 131 assertTrue("Retrieve network attributes not successful : " 132 + status.resultCode, status.isSuccess()); 133 assertEquals(l2Key, key); 134 assertEquals(TEST_NETWORK_ATTRIBUTES, attr); 135 }); 136 137 verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any()); 138 } 139 140 @Test testPrivateData()141 public void testPrivateData() throws RemoteException { 142 startIpMemoryStore(true /* supplyService */); 143 final Blob b = new Blob(); 144 b.data = TEST_BLOB_DATA; 145 final String l2Key = "fakeKey"; 146 147 mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, 148 status -> { 149 assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); 150 }); 151 verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), 152 eq(b), any()); 153 154 mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, 155 (status, key, name, data) -> { 156 assertTrue("Retrieve blob status not successful : " + status.resultCode, 157 status.isSuccess()); 158 assertEquals(l2Key, key); 159 assertEquals(name, TEST_DATA_NAME); 160 assertTrue(Arrays.equals(b.data, data.data)); 161 }); 162 verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), 163 eq(TEST_OTHER_DATA_NAME), any()); 164 } 165 166 @Test testFindL2Key()167 public void testFindL2Key() 168 throws UnknownHostException, RemoteException, Exception { 169 startIpMemoryStore(true /* supplyService */); 170 final String l2Key = "fakeKey"; 171 172 mStore.findL2Key(TEST_NETWORK_ATTRIBUTES, 173 (status, key) -> { 174 assertTrue("Retrieve network sameness not successful : " + status.resultCode, 175 status.isSuccess()); 176 assertEquals(l2Key, key); 177 }); 178 verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any()); 179 assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); 180 } 181 182 @Test testIsSameNetwork()183 public void testIsSameNetwork() throws UnknownHostException, RemoteException { 184 startIpMemoryStore(true /* supplyService */); 185 final String l2Key1 = "fakeKey1"; 186 final String l2Key2 = "fakeKey2"; 187 188 mStore.isSameNetwork(l2Key1, l2Key2, 189 (status, answer) -> { 190 assertFalse("Retrieve network sameness suspiciously successful : " 191 + status.resultCode, status.isSuccess()); 192 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode); 193 assertNull(answer); 194 }); 195 verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any()); 196 } 197 198 @Test testEnqueuedIpMsRequests()199 public void testEnqueuedIpMsRequests() throws Exception { 200 startIpMemoryStore(false /* supplyService */); 201 202 final Blob b = new Blob(); 203 b.data = TEST_BLOB_DATA; 204 final String l2Key = "fakeKey"; 205 206 // enqueue multiple ipms requests 207 mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, 208 status -> assertTrue("Store not successful : " + status.resultCode, 209 status.isSuccess())); 210 mStore.retrieveNetworkAttributes(l2Key, 211 (status, key, attr) -> { 212 assertTrue("Retrieve network attributes not successful : " 213 + status.resultCode, status.isSuccess()); 214 assertEquals(l2Key, key); 215 assertEquals(TEST_NETWORK_ATTRIBUTES, attr); 216 }); 217 mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, 218 status -> assertTrue("Store not successful : " + status.resultCode, 219 status.isSuccess())); 220 mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, 221 (status, key, name, data) -> { 222 assertTrue("Retrieve blob status not successful : " + status.resultCode, 223 status.isSuccess()); 224 assertEquals(l2Key, key); 225 assertEquals(name, TEST_DATA_NAME); 226 assertTrue(Arrays.equals(b.data, data.data)); 227 }); 228 229 // get ipms service ready 230 mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService); 231 232 InOrder inOrder = inOrder(mMockService); 233 234 inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); 235 inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any()); 236 inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), 237 eq(b), any()); 238 inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), 239 eq(TEST_OTHER_DATA_NAME), any()); 240 assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); 241 } 242 243 @Test testEnqueuedIpMsRequestsWithException()244 public void testEnqueuedIpMsRequestsWithException() throws Exception { 245 startIpMemoryStore(true /* supplyService */); 246 doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any()); 247 248 final Blob b = new Blob(); 249 b.data = TEST_BLOB_DATA; 250 final String l2Key = "fakeKey"; 251 252 // enqueue multiple ipms requests 253 mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, 254 status -> assertTrue("Store not successful : " + status.resultCode, 255 status.isSuccess())); 256 mStore.retrieveNetworkAttributes(l2Key, 257 (status, key, attr) -> { 258 assertTrue("Retrieve network attributes not successful : " 259 + status.resultCode, status.isSuccess()); 260 assertEquals(l2Key, key); 261 assertEquals(TEST_NETWORK_ATTRIBUTES, attr); 262 }); 263 mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, 264 status -> assertTrue("Store not successful : " + status.resultCode, 265 status.isSuccess())); 266 mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, 267 (status, key, name, data) -> { 268 assertTrue("Retrieve blob status not successful : " + status.resultCode, 269 status.isSuccess()); 270 assertEquals(l2Key, key); 271 assertEquals(name, TEST_DATA_NAME); 272 assertTrue(Arrays.equals(b.data, data.data)); 273 }); 274 275 // verify the rest of the queue is still processed in order even if the remote exception 276 // occurs when calling one or more requests 277 InOrder inOrder = inOrder(mMockService); 278 279 inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); 280 inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), 281 eq(b), any()); 282 inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), 283 eq(TEST_OTHER_DATA_NAME), any()); 284 assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); 285 } 286 287 @Test testEnqueuedIpMsRequestsCallbackFunctionWithException()288 public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception { 289 startIpMemoryStore(true /* supplyService */); 290 291 final Blob b = new Blob(); 292 b.data = TEST_BLOB_DATA; 293 final String l2Key = "fakeKey"; 294 295 // enqueue multiple ipms requests 296 mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, 297 status -> assertTrue("Store not successful : " + status.resultCode, 298 status.isSuccess())); 299 mStore.retrieveNetworkAttributes(l2Key, 300 (status, key, attr) -> { 301 throw new RuntimeException("retrieveNetworkAttributes test"); 302 }); 303 mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, 304 status -> { 305 throw new RuntimeException("storeBlob test"); 306 }); 307 mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, 308 (status, key, name, data) -> { 309 assertTrue("Retrieve blob status not successful : " + status.resultCode, 310 status.isSuccess()); 311 assertEquals(l2Key, key); 312 assertEquals(name, TEST_DATA_NAME); 313 assertTrue(Arrays.equals(b.data, data.data)); 314 }); 315 316 // verify the rest of the queue is still processed in order even if when one or more 317 // callback throw the remote exception 318 InOrder inOrder = inOrder(mMockService); 319 320 inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), 321 any()); 322 inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any()); 323 inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), 324 eq(b), any()); 325 inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), 326 eq(TEST_OTHER_DATA_NAME), any()); 327 assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); 328 } 329 330 @Test testFactoryReset()331 public void testFactoryReset() throws RemoteException { 332 startIpMemoryStore(true /* supplyService */); 333 mStore.factoryReset(); 334 verify(mMockService, times(1)).factoryReset(); 335 } 336 } 337