1 /* 2 * Copyright (C) 2022 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.server.sdksandbox; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.app.sdksandbox.testutils.FakeSdkSandboxManagerLocal; 22 import android.app.sdksandbox.testutils.SdkSandboxStorageManagerUtility; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ProviderInfo; 27 import android.os.FileUtils; 28 import android.os.UserHandle; 29 30 import androidx.test.platform.app.InstrumentationRegistry; 31 32 import com.android.server.pm.PackageManagerLocal; 33 import com.android.server.sdksandbox.SdkSandboxStorageManager.StorageDirInfo; 34 import com.android.server.sdksandbox.SdkSandboxStorageManager.SubDirectories; 35 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.mockito.Mockito; 40 41 import java.io.File; 42 import java.nio.file.Files; 43 import java.nio.file.Path; 44 import java.nio.file.Paths; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Set; 50 import java.util.UUID; 51 52 /** Unit tests for {@link SdkSandboxStorageManager}. */ 53 public class SdkSandboxStorageManagerUnitTest { 54 55 /** Test directory on Android where all storage will be created */ 56 private static final int CLIENT_UID = 11000; 57 58 private static final String CLIENT_PKG_NAME = "client"; 59 private static final String SDK_NAME = "sdk"; 60 private static final String SDK2_NAME = "sdk2"; 61 private static final String STORAGE_UUID = "41217664-9172-527a-b3d5-edabb50a7d69"; 62 private static final int USER_ID = 0; 63 64 // Use the test app's private storage as mount point for sdk storage testing 65 private SdkSandboxStorageManager mSdkSandboxStorageManager; 66 // Separate location where all of the sdk storage directories will be created for testing 67 private String mTestDir; 68 private FakeSdkSandboxManagerLocal mSdkSandboxManagerLocal; 69 private PackageManager mPmMock; 70 private Context mSpyContext; 71 private SdkSandboxStorageManagerUtility mSdkSandboxStorageManagerUtility; 72 73 @Before setup()74 public void setup() throws Exception { 75 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 76 mTestDir = context.getDir("test_dir", Context.MODE_PRIVATE).getPath(); 77 mSpyContext = Mockito.spy(context); 78 79 mPmMock = Mockito.mock(PackageManager.class); 80 Mockito.doReturn(mPmMock).when(mSpyContext).getPackageManager(); 81 Mockito.doReturn(mSpyContext) 82 .when(mSpyContext) 83 .createContextAsUser(Mockito.any(UserHandle.class), Mockito.anyInt()); 84 85 PackageManagerLocal packageManagerLocal = Mockito.mock(PackageManagerLocal.class); 86 87 mSdkSandboxManagerLocal = new FakeSdkSandboxManagerLocal(); 88 mSdkSandboxStorageManager = 89 new SdkSandboxStorageManager( 90 mSpyContext, mSdkSandboxManagerLocal, packageManagerLocal, mTestDir); 91 mSdkSandboxStorageManagerUtility = 92 new SdkSandboxStorageManagerUtility(mSdkSandboxStorageManager); 93 } 94 95 @After tearDown()96 public void tearDown() throws Exception { 97 FileUtils.deleteContents(new File(mTestDir)); 98 } 99 100 @Test test_GetSdkDataPackageDirectory()101 public void test_GetSdkDataPackageDirectory() throws Exception { 102 assertThat(mSdkSandboxStorageManager.getSdkDataPackageDirectory(null, USER_ID, "foo", true)) 103 .isEqualTo(mTestDir + "/data/misc_ce/0/sdksandbox/foo"); 104 // Build DE path 105 assertThat( 106 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 107 null, USER_ID, "foo", false)) 108 .isEqualTo(mTestDir + "/data/misc_de/0/sdksandbox/foo"); 109 // Build with different package name 110 assertThat(mSdkSandboxStorageManager.getSdkDataPackageDirectory(null, USER_ID, "bar", true)) 111 .isEqualTo(mTestDir + "/data/misc_ce/0/sdksandbox/bar"); 112 // Build with different user 113 assertThat(mSdkSandboxStorageManager.getSdkDataPackageDirectory(null, 10, "foo", true)) 114 .isEqualTo(mTestDir + "/data/misc_ce/10/sdksandbox/foo"); 115 // Build with different volume 116 assertThat( 117 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 118 "hello", USER_ID, "foo", true)) 119 .isEqualTo(mTestDir + "/mnt/expand/hello/misc_ce/0/sdksandbox/foo"); 120 } 121 122 @Test test_StorageDirInfo_GetterApis()123 public void test_StorageDirInfo_GetterApis() throws Exception { 124 final StorageDirInfo sdkInfo = new StorageDirInfo("foo", "bar"); 125 assertThat(sdkInfo.getCeDataDir()).isEqualTo("foo"); 126 assertThat(sdkInfo.getDeDataDir()).isEqualTo("bar"); 127 } 128 129 @Test test_getSdkStorageDirInfo_nonExistingStorage()130 public void test_getSdkStorageDirInfo_nonExistingStorage() throws Exception { 131 // Call getSdkStorageDirInfo on SdkStorageManager 132 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 133 final StorageDirInfo sdkInfo = 134 mSdkSandboxStorageManager.getSdkStorageDirInfo(callingInfo, SDK_NAME); 135 136 assertThat(sdkInfo.getCeDataDir()).isNull(); 137 assertThat(sdkInfo.getDeDataDir()).isNull(); 138 } 139 140 @Test test_getSdkStorageDirInfo_storageExists()141 public void test_getSdkStorageDirInfo_storageExists() throws Exception { 142 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 143 USER_ID, CLIENT_PKG_NAME, Arrays.asList(SDK_NAME), Collections.emptyList()); 144 145 final ApplicationInfo info = new ApplicationInfo(); 146 info.storageUuid = UUID.fromString(STORAGE_UUID); 147 Mockito.doReturn(info) 148 .when(mPmMock) 149 .getApplicationInfo(Mockito.any(String.class), Mockito.anyInt()); 150 151 // Call getSdkStorageDirInfo on SdkStorageManager 152 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 153 final StorageDirInfo sdkInfo = 154 mSdkSandboxStorageManager.getSdkStorageDirInfo(callingInfo, SDK_NAME); 155 156 assertThat(sdkInfo.getCeDataDir()) 157 .isEqualTo(mTestDir + "/data/misc_ce/0/sdksandbox/client/sdk@sdk"); 158 assertThat(sdkInfo.getDeDataDir()) 159 .isEqualTo(mTestDir + "/data/misc_de/0/sdksandbox/client/sdk@sdk"); 160 } 161 162 @Test test_getInernalStorageDirInfo_nonExistingStorage()163 public void test_getInernalStorageDirInfo_nonExistingStorage() throws Exception { 164 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 165 final StorageDirInfo dirInfo = 166 mSdkSandboxStorageManager.getInternalStorageDirInfo(callingInfo, SDK_NAME); 167 168 assertThat(dirInfo.getCeDataDir()).isNull(); 169 assertThat(dirInfo.getDeDataDir()).isNull(); 170 } 171 172 @Test test_getInternalStorageDirInfo_storageExists()173 public void test_getInternalStorageDirInfo_storageExists() throws Exception { 174 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 175 USER_ID, 176 CLIENT_PKG_NAME, 177 Collections.emptyList(), 178 Arrays.asList(SubDirectories.SANDBOX_DIR)); 179 180 final ApplicationInfo info = new ApplicationInfo(); 181 info.storageUuid = UUID.fromString(STORAGE_UUID); 182 Mockito.doReturn(info) 183 .when(mPmMock) 184 .getApplicationInfo(Mockito.any(String.class), Mockito.anyInt()); 185 186 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 187 final StorageDirInfo internalSubDirInfo = 188 mSdkSandboxStorageManager.getInternalStorageDirInfo( 189 callingInfo, SubDirectories.SANDBOX_DIR); 190 191 assertThat(internalSubDirInfo.getCeDataDir()) 192 .isEqualTo(mTestDir + "/data/misc_ce/0/sdksandbox/client/sandbox#sandbox"); 193 assertThat(internalSubDirInfo.getDeDataDir()) 194 .isEqualTo(mTestDir + "/data/misc_de/0/sdksandbox/client/sandbox#sandbox"); 195 } 196 197 @Test test_getMountedVolumes_newVolumeExists()198 public void test_getMountedVolumes_newVolumeExists() throws Exception { 199 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 200 /*volumeUuid=*/ null, 201 USER_ID, 202 CLIENT_PKG_NAME, 203 Arrays.asList(SDK_NAME), 204 Collections.emptyList()); 205 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 206 "newVolume", 207 /*userId=*/ 0, 208 CLIENT_PKG_NAME, 209 Arrays.asList(SDK_NAME), 210 Collections.emptyList()); 211 212 final List<String> mountedVolumes = mSdkSandboxStorageManager.getMountedVolumes(); 213 214 assertThat(mountedVolumes).containsExactly(null, "newVolume"); 215 } 216 217 @Test test_GetMountedVolumes_NewVolumeDoesNotExist()218 public void test_GetMountedVolumes_NewVolumeDoesNotExist() throws Exception { 219 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 220 /*volumeUuid=*/ null, 221 USER_ID, 222 CLIENT_PKG_NAME, 223 Arrays.asList(SDK_NAME), 224 Collections.emptyList()); 225 226 final List<String> mountedVolumes = mSdkSandboxStorageManager.getMountedVolumes(); 227 228 assertThat(mountedVolumes).containsExactly((String) null); 229 } 230 231 @Test test_onUserUnlocking_Instrumentation_NoSdk_PackageDirNotRemoved()232 public void test_onUserUnlocking_Instrumentation_NoSdk_PackageDirNotRemoved() throws Exception { 233 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 234 /*volumeUuid=*/ null, 235 USER_ID, 236 CLIENT_PKG_NAME, 237 Collections.emptyList(), 238 Collections.emptyList()); 239 240 // Set instrumentation started, so that isInstrumentationRunning will return true 241 mSdkSandboxManagerLocal.notifyInstrumentationStarted(CLIENT_PKG_NAME, CLIENT_UID); 242 243 mSdkSandboxStorageManager.onUserUnlocking(0); 244 245 final Path ceDataPackageDirectory = 246 Paths.get( 247 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 248 null, USER_ID, CLIENT_PKG_NAME, true)); 249 250 final Path deDataPackageDirectory = 251 Paths.get( 252 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 253 null, USER_ID, CLIENT_PKG_NAME, false)); 254 255 assertThat(Files.exists(ceDataPackageDirectory)).isTrue(); 256 assertThat(Files.exists(deDataPackageDirectory)).isTrue(); 257 } 258 259 @Test test_onUserUnlocking_NoInstrumentation_NoSdk_PackageDirRemoved()260 public void test_onUserUnlocking_NoInstrumentation_NoSdk_PackageDirRemoved() throws Exception { 261 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 262 /*volumeUuid=*/ null, 263 USER_ID, 264 CLIENT_PKG_NAME, 265 Collections.emptyList(), 266 Collections.emptyList()); 267 268 mSdkSandboxStorageManager.onUserUnlocking(USER_ID); 269 270 final Path ceDataPackageDirectory = 271 Paths.get( 272 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 273 null, USER_ID, CLIENT_PKG_NAME, true)); 274 275 final Path deDataPackageDirectory = 276 Paths.get( 277 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 278 null, USER_ID, CLIENT_PKG_NAME, false)); 279 280 assertThat(Files.exists(ceDataPackageDirectory)).isFalse(); 281 assertThat(Files.exists(deDataPackageDirectory)).isFalse(); 282 } 283 284 @Test test_SdkSubDirectories_NonExistingParentPath()285 public void test_SdkSubDirectories_NonExistingParentPath() throws Exception { 286 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 287 USER_ID, CLIENT_PKG_NAME, Arrays.asList(SDK_NAME), Collections.emptyList()); 288 289 final SubDirectories subDirs = new SubDirectories("/does/not/exist"); 290 291 assertThat(subDirs.getSdkSubDir("does.not.exist")).isNull(); 292 assertThat(subDirs.getSdkSubDir(SDK_NAME)).isNull(); 293 } 294 295 @Test test_SdkSubDirectories_GetSdkSubDir()296 public void test_SdkSubDirectories_GetSdkSubDir() throws Exception { 297 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 298 USER_ID, CLIENT_PKG_NAME, Arrays.asList(SDK_NAME), Collections.emptyList()); 299 300 final String packageDir = 301 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 302 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 303 304 final SubDirectories subDirs = new SubDirectories(packageDir); 305 306 assertThat(subDirs.getSdkSubDir("does.not.exist")).isNull(); 307 assertThat(subDirs.getSdkSubDir("does.not.exist", /*fullPath=*/ true)).isNull(); 308 309 final String expectedSubDirName = SDK_NAME + "@" + SDK_NAME; 310 assertThat(subDirs.getSdkSubDir(SDK_NAME)).isEqualTo(expectedSubDirName); 311 final String expectedFullPath = Paths.get(packageDir, expectedSubDirName).toString(); 312 assertThat(subDirs.getSdkSubDir(SDK_NAME, /*fullPath=*/ true)).isEqualTo(expectedFullPath); 313 } 314 315 @Test test_SdkSubDirectories_IsValid()316 public void test_SdkSubDirectories_IsValid() throws Exception { 317 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 318 USER_ID, 319 CLIENT_PKG_NAME, 320 Arrays.asList(SDK_NAME, SDK2_NAME), 321 Arrays.asList(SubDirectories.SHARED_DIR, SubDirectories.SANDBOX_DIR)); 322 323 final String packageDir = 324 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 325 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 326 327 final SubDirectories subDirs = new SubDirectories(packageDir); 328 329 assertThat(subDirs.isValid(Collections.emptySet())).isFalse(); 330 assertThat(subDirs.isValid(Set.of(SDK_NAME))).isFalse(); 331 assertThat(subDirs.isValid(Set.of(SDK_NAME, SDK2_NAME))).isTrue(); 332 } 333 334 @Test test_SdkSubDirectories_IsValid_MissingNonSdkStorage()335 public void test_SdkSubDirectories_IsValid_MissingNonSdkStorage() throws Exception { 336 // Avoid creating "shared" storage 337 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 338 USER_ID, CLIENT_PKG_NAME, Arrays.asList(SDK_NAME), Collections.emptyList()); 339 340 final String packageDir = 341 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 342 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 343 344 final SubDirectories subDirs = new SubDirectories(packageDir); 345 346 assertThat(subDirs.isValid(Set.of(SDK_NAME))).isFalse(); 347 } 348 349 @Test test_SdkSubDirectories_IsValid_HasUnknownSubDir()350 public void test_SdkSubDirectories_IsValid_HasUnknownSubDir() throws Exception { 351 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 352 USER_ID, 353 CLIENT_PKG_NAME, 354 Arrays.asList(SDK_NAME), 355 Arrays.asList(SubDirectories.SHARED_DIR)); 356 357 // Create a random subdir not following our format 358 final String packageDir = 359 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 360 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 361 Path invalidSubDir = Paths.get(packageDir, "invalid"); 362 Files.createDirectories(invalidSubDir); 363 364 final SubDirectories subDirs = new SubDirectories(packageDir); 365 366 assertThat(subDirs.isValid(Set.of(SDK_NAME))).isFalse(); 367 } 368 369 @Test test_SdkSubDirectories_GenerateSubDirNames_InternalOnly_NonExisting()370 public void test_SdkSubDirectories_GenerateSubDirNames_InternalOnly_NonExisting() 371 throws Exception { 372 final SubDirectories subDirs = new SubDirectories("does.not.exist"); 373 374 final List<String> internalSubDirs = subDirs.generateSubDirNames(Collections.emptyList()); 375 assertThat(internalSubDirs).hasSize(SubDirectories.INTERNAL_SUBDIRS.size()); 376 assertThat(internalSubDirs).contains(SubDirectories.SHARED_DIR); 377 for (String subDir : internalSubDirs) { 378 if (subDir.equals(SubDirectories.SHARED_DIR)) continue; 379 final String[] tokens = subDir.split("#"); 380 assertThat(tokens).asList().hasSize(2); 381 assertThat(SubDirectories.INTERNAL_SUBDIRS).contains(tokens[0]); 382 } 383 } 384 385 @Test test_SdkSubDirectories_GenerateSubDirNames_InternalOnly_Existing()386 public void test_SdkSubDirectories_GenerateSubDirNames_InternalOnly_Existing() 387 throws Exception { 388 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 389 USER_ID, 390 CLIENT_PKG_NAME, 391 Collections.emptyList(), 392 Arrays.asList(SubDirectories.SHARED_DIR, SubDirectories.SANDBOX_DIR)); 393 394 final String packageDir = 395 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 396 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 397 final SubDirectories subDirs = new SubDirectories(packageDir); 398 399 final List<String> internalSubDirs = subDirs.generateSubDirNames(Collections.emptyList()); 400 final String expectedSandboxDirName = 401 SubDirectories.SANDBOX_DIR + "#" + SubDirectories.SANDBOX_DIR; 402 assertThat(internalSubDirs).containsExactly("shared", expectedSandboxDirName); 403 } 404 405 @Test test_SdkSubDirectories_GenerateSubDirNames_WithSdkNames()406 public void test_SdkSubDirectories_GenerateSubDirNames_WithSdkNames() throws Exception { 407 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 408 USER_ID, 409 CLIENT_PKG_NAME, 410 Arrays.asList(SDK_NAME), 411 Arrays.asList(SubDirectories.SHARED_DIR, SubDirectories.SANDBOX_DIR)); 412 413 final String packageDir = 414 mSdkSandboxStorageManager.getSdkDataPackageDirectory( 415 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, /*isCeData=*/ true); 416 final SubDirectories subDirs = new SubDirectories(packageDir); 417 418 final List<String> allSubDirNames = 419 subDirs.generateSubDirNames(Arrays.asList(SDK_NAME, "foo")); 420 assertThat(allSubDirNames).hasSize(2 + SubDirectories.INTERNAL_SUBDIRS.size()); 421 422 // Assert internal directories 423 final String expectedSandboxDirName = 424 SubDirectories.SANDBOX_DIR + "#" + SubDirectories.SANDBOX_DIR; 425 assertThat(allSubDirNames).containsAtLeast("shared", expectedSandboxDirName); 426 427 // Assert per-sdk directories 428 assertThat(allSubDirNames).contains(SDK_NAME + "@" + SDK_NAME); 429 boolean foundFoo = 430 allSubDirNames.stream() 431 .anyMatch(s -> s.contains("@") && s.split("@")[0].equals("foo")); 432 assertThat(foundFoo).isTrue(); 433 } 434 435 @Test test_getSdkStorageDirInfo()436 public void test_getSdkStorageDirInfo() throws Exception { 437 final List<String> sdkNames = Arrays.asList(SDK_NAME); 438 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 439 USER_ID, CLIENT_PKG_NAME, sdkNames, new ArrayList<>()); 440 441 final ApplicationInfo info = new ApplicationInfo(); 442 info.storageUuid = UUID.fromString(STORAGE_UUID); 443 Mockito.doReturn(info) 444 .when(mPmMock) 445 .getApplicationInfo(Mockito.any(String.class), Mockito.anyInt()); 446 447 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 448 449 List<StorageDirInfo> sdkStorageDirInfo = 450 mSdkSandboxStorageManager.getSdkStorageDirInfo(callingInfo); 451 List<StorageDirInfo> expectedSdkStorageDirInfo = 452 mSdkSandboxStorageManagerUtility.getSdkStorageDirInfoForTest( 453 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, sdkNames); 454 455 assertThat(sdkStorageDirInfo).containsExactlyElementsIn(expectedSdkStorageDirInfo); 456 } 457 458 @Test test_getInternalStorageDirInfo()459 public void test_getInternalStorageDirInfo() throws Exception { 460 final List<String> nonSdkDirectories = 461 Arrays.asList(SubDirectories.SHARED_DIR, SubDirectories.SANDBOX_DIR); 462 mSdkSandboxStorageManagerUtility.createSdkStorageForTest( 463 USER_ID, CLIENT_PKG_NAME, new ArrayList<>(), nonSdkDirectories); 464 465 final ApplicationInfo info = new ApplicationInfo(); 466 info.storageUuid = UUID.fromString(STORAGE_UUID); 467 Mockito.doReturn(info) 468 .when(mPmMock) 469 .getApplicationInfo(Mockito.any(String.class), Mockito.anyInt()); 470 471 final CallingInfo callingInfo = new CallingInfo(CLIENT_UID, CLIENT_PKG_NAME); 472 473 List<StorageDirInfo> internalStorageDirInfo = 474 mSdkSandboxStorageManager.getInternalStorageDirInfo(callingInfo); 475 List<StorageDirInfo> expectedInternalStorageDirInfo = 476 mSdkSandboxStorageManagerUtility.getInternalStorageDirInfoForTest( 477 /*volumeUuid=*/ null, USER_ID, CLIENT_PKG_NAME, nonSdkDirectories); 478 479 assertThat(internalStorageDirInfo) 480 .containsExactlyElementsIn(expectedInternalStorageDirInfo); 481 } 482 } 483