|
42 | 42 | import static org.junit.Assert.assertEquals; |
43 | 43 | import static org.junit.Assert.assertFalse; |
44 | 44 | import static org.junit.Assert.assertNotNull; |
| 45 | +import static org.junit.Assert.assertNotSame; |
45 | 46 | import static org.junit.Assert.assertNull; |
| 47 | +import static org.junit.Assert.assertSame; |
46 | 48 | import static org.junit.Assert.assertTrue; |
47 | 49 | import static org.junit.Assert.fail; |
48 | 50 | import static org.mockito.Mockito.when; |
49 | 51 |
|
50 | | -import android.content.Context; |
51 | 52 |
|
| 53 | +import androidx.annotation.NonNull; |
52 | 54 | import androidx.test.core.app.ApplicationProvider; |
53 | 55 |
|
54 | | -import com.microsoft.identity.common.components.AndroidPlatformComponentsFactory; |
55 | 56 | import com.microsoft.identity.common.components.MockPlatformComponentsFactory; |
56 | 57 | import com.microsoft.identity.common.internal.platform.AndroidPlatformUtil; |
57 | 58 | import com.microsoft.identity.common.java.cache.BrokerApplicationMetadata; |
|
66 | 67 | import com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCache; |
67 | 68 | import com.microsoft.identity.common.java.cache.AccountDeletionRecord; |
68 | 69 | import com.microsoft.identity.common.java.cache.ICacheRecord; |
| 70 | +import com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCacheWithMemoryCache; |
69 | 71 | import com.microsoft.identity.common.java.dto.AccountRecord; |
70 | 72 | import com.microsoft.identity.common.java.dto.Credential; |
71 | 73 | import com.microsoft.identity.common.java.dto.CredentialType; |
72 | 74 | import com.microsoft.identity.common.java.exception.ClientException; |
| 75 | +import com.microsoft.identity.common.java.flighting.CommonFlight; |
| 76 | +import com.microsoft.identity.common.java.flighting.CommonFlightsManager; |
| 77 | +import com.microsoft.identity.common.java.flighting.IFlightsManager; |
| 78 | +import com.microsoft.identity.common.java.flighting.IFlightsProvider; |
73 | 79 | import com.microsoft.identity.common.java.interfaces.INameValueStorage; |
74 | 80 | import com.microsoft.identity.common.java.interfaces.IPlatformComponents; |
75 | 81 | import com.microsoft.identity.common.java.providers.microsoft.MicrosoftAccount; |
|
79 | 85 | import com.microsoft.identity.common.java.providers.oauth2.OAuth2TokenCache; |
80 | 86 | import com.microsoft.identity.common.shadows.ShadowAndroidSdkStorageEncryptionManager; |
81 | 87 |
|
| 88 | +import org.jetbrains.annotations.NotNull; |
82 | 89 | import org.junit.After; |
83 | 90 | import org.junit.Before; |
84 | 91 | import org.junit.Test; |
85 | 92 | import org.junit.runner.RunWith; |
| 93 | +import org.mockito.Mockito; |
86 | 94 | import org.powermock.api.mockito.PowerMockito; |
87 | 95 | import org.robolectric.RobolectricTestRunner; |
88 | 96 | import org.robolectric.annotation.Config; |
89 | | -import org.robolectric.shadows.ShadowSharedPreferences; |
90 | 97 |
|
91 | 98 | import java.util.ArrayList; |
92 | 99 | import java.util.List; |
@@ -236,6 +243,7 @@ public void tearDown() throws Exception { |
236 | 243 | } |
237 | 244 |
|
238 | 245 | mApplicationMetadataCache.clear(); |
| 246 | + CommonFlightsManager.INSTANCE.resetFlightsManager(); |
239 | 247 | } |
240 | 248 |
|
241 | 249 | private void initOtherCaches(final IPlatformComponents components) { |
@@ -1241,4 +1249,120 @@ public void testClearAll() throws ClientException { |
1241 | 1249 | assertEquals(false, mBrokerOAuth2TokenCache.isClientIdKnownToCache(clientId)); |
1242 | 1250 | } |
1243 | 1251 | } |
| 1252 | + |
| 1253 | + @Test |
| 1254 | + public void testSingleCacheInstancePerStoreName_FlightEnabled() { |
| 1255 | + // Enable the flight |
| 1256 | + updateUseInMemoryCacheFlight(true); |
| 1257 | + |
| 1258 | + final String storeName = "test_store_name"; |
| 1259 | + final IPlatformComponents components1 = mPlatformComponents; |
| 1260 | + final IPlatformComponents components2 = mPlatformComponents; |
| 1261 | + |
| 1262 | + // Call getCacheToBeUsed twice with the same storeName |
| 1263 | + final IAccountCredentialCache cache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(components1, storeName); |
| 1264 | + final IAccountCredentialCache cache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(components2, storeName); |
| 1265 | + |
| 1266 | + // Verify both references point to the same instance |
| 1267 | + assertNotNull(cache1); |
| 1268 | + assertNotNull(cache2); |
| 1269 | + assertSame("Expected same cache instance for same storeName", cache1, cache2); |
| 1270 | + assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache", |
| 1271 | + cache1 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache); |
| 1272 | + } |
| 1273 | + |
| 1274 | + @Test |
| 1275 | + public void testDifferentCacheInstancesPerStoreName_FlightEnabled() { |
| 1276 | + // Enable the flight |
| 1277 | + updateUseInMemoryCacheFlight(true); |
| 1278 | + |
| 1279 | + final String storeName1 = "test_store_name_1"; |
| 1280 | + final String storeName2 = "test_store_name_2"; |
| 1281 | + final IPlatformComponents components = mPlatformComponents; |
| 1282 | + |
| 1283 | + // Call getCacheToBeUsed with different storeNames |
| 1284 | + final IAccountCredentialCache cache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(components, storeName1); |
| 1285 | + final IAccountCredentialCache cache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(components, storeName2); |
| 1286 | + |
| 1287 | + // Verify both are valid but different instances |
| 1288 | + assertNotNull(cache1); |
| 1289 | + assertNotNull(cache2); |
| 1290 | + assertNotSame("Expected different cache instances for different storeNames", cache1, cache2); |
| 1291 | + assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache", |
| 1292 | + cache1 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache); |
| 1293 | + assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache", |
| 1294 | + cache2 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache); |
| 1295 | + } |
| 1296 | + |
| 1297 | + @Test |
| 1298 | + public void testCacheInstanceReusedAcrossMultipleBrokerTokenCaches_FlightEnabled() { |
| 1299 | + // Enable the flight |
| 1300 | + updateUseInMemoryCacheFlight(true); |
| 1301 | + |
| 1302 | + final String storeName = getBrokerUidSequesteredFilename(TEST_APP_UID); |
| 1303 | + |
| 1304 | + // Create multiple BrokerOAuth2TokenCache instances |
| 1305 | + final BrokerOAuth2TokenCache tokenCache1 = new BrokerOAuth2TokenCache |
| 1306 | + (mPlatformComponents, |
| 1307 | + TEST_APP_UID, |
| 1308 | + new NameValueStorageBrokerApplicationMetadataCache(mPlatformComponents)); |
| 1309 | + final BrokerOAuth2TokenCache tokenCache2 = new BrokerOAuth2TokenCache(mPlatformComponents, TEST_APP_UID, |
| 1310 | + new NameValueStorageBrokerApplicationMetadataCache(mPlatformComponents)); |
| 1311 | + |
| 1312 | + // Get the underlying account credential caches |
| 1313 | + final IAccountCredentialCache cache1 = tokenCache1.getCacheToBeUsed(mPlatformComponents, storeName); |
| 1314 | + final IAccountCredentialCache cache2 = tokenCache2.getCacheToBeUsed(mPlatformComponents, storeName); |
| 1315 | + |
| 1316 | + // Verify same instance is reused |
| 1317 | + assertNotNull(cache1); |
| 1318 | + assertNotNull(cache2); |
| 1319 | + assertSame(cache1, cache2); |
| 1320 | + } |
| 1321 | + |
| 1322 | + @Test |
| 1323 | + public void testFociCacheInstanceReused_FlightEnabled() { |
| 1324 | + // Enable the flight |
| 1325 | + updateUseInMemoryCacheFlight(true); |
| 1326 | + |
| 1327 | + final String fociStoreName = BROKER_FOCI_ACCOUNT_CREDENTIAL_SHARED_PREFERENCES; |
| 1328 | + |
| 1329 | + // Call getCacheToBeUsed multiple times for FOCI cache |
| 1330 | + final IAccountCredentialCache fociCache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(mPlatformComponents, fociStoreName); |
| 1331 | + final IAccountCredentialCache fociCache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(mPlatformComponents, fociStoreName); |
| 1332 | + |
| 1333 | + // Verify same FOCI cache instance is reused |
| 1334 | + assertNotNull(fociCache1); |
| 1335 | + assertNotNull(fociCache2); |
| 1336 | + assertSame(fociCache1, fociCache2); |
| 1337 | + } |
| 1338 | + |
| 1339 | + private void updateUseInMemoryCacheFlight(boolean enabled) { |
| 1340 | + final IFlightsProvider mockFlightsProvider = Mockito.mock(IFlightsProvider.class); |
| 1341 | + Mockito.when(mockFlightsProvider.isFlightEnabled(CommonFlight.USE_IN_MEMORY_CACHE_FOR_ACCOUNTS_AND_CREDENTIALS)) |
| 1342 | + .thenReturn(enabled); |
| 1343 | + |
| 1344 | + // Create anonymous IFlightsManager |
| 1345 | + IFlightsManager anonymousFlightsManager = new IFlightsManager() { |
| 1346 | + @Override |
| 1347 | + public @NotNull IFlightsProvider getFlightsProvider(long waitForConfigsWithTimeoutInMs) { |
| 1348 | + return mockFlightsProvider; |
| 1349 | + } |
| 1350 | + @Override |
| 1351 | + public @NotNull IFlightsProvider getFlightsProviderForTenant(@NotNull String tenantId, long waitForConfigsWithTimeoutInMs) { |
| 1352 | + return mockFlightsProvider; |
| 1353 | + } |
| 1354 | + @Override |
| 1355 | + public @NotNull IFlightsProvider getFlightsProviderForTenant(@NotNull String tenantId) { |
| 1356 | + return mockFlightsProvider; |
| 1357 | + } |
| 1358 | + @NonNull |
| 1359 | + @Override |
| 1360 | + public IFlightsProvider getFlightsProvider() { |
| 1361 | + return mockFlightsProvider; |
| 1362 | + } |
| 1363 | + }; |
| 1364 | + |
| 1365 | + // Initialize CommonFlightsManager with the anonymous implementation |
| 1366 | + CommonFlightsManager.INSTANCE.initializeCommonFlightsManager(anonymousFlightsManager); |
| 1367 | + } |
1244 | 1368 | } |
0 commit comments