Skip to content

Commit 71fb91f

Browse files
committed
Update existing test classes.
1 parent 4662ecd commit 71fb91f

6 files changed

Lines changed: 324 additions & 139 deletions

File tree

.github/workflows/reusable-lib-workflow.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ jobs:
184184
fi
185185
done
186186
- name: Test Report
187-
uses: mikepenz/action-junit-report@v5
187+
uses: mikepenz/action-junit-report
188188
if: success() || failure()
189189
with:
190190
check_name: ${{ inputs.lib }} Test Results

.github/workflows/reusable-ui-workflow.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ jobs:
127127
fi
128128
done
129129
- name: Test Report
130-
uses: mikepenz/action-junit-report@v5
130+
uses: mikepenz/action-junit-report
131131
if: success() || failure()
132132
with:
133133
check_name: ${{ inputs.lib }} Test Results

libs/SalesforceSDK/src/com/salesforce/androidsdk/ui/LoginViewModel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,8 @@ open class LoginViewModel(val bootConfig: BootConfig) : ViewModel() {
489489
}.toString()
490490
}
491491

492-
private suspend fun doCodeExchange(
492+
@VisibleForTesting
493+
internal suspend fun doCodeExchange(
493494
code: String?,
494495
onAuthFlowError: (error: String, errorDesc: String?, e: Throwable?) -> Unit,
495496
onAuthFlowSuccess: (userAccount: UserAccount) -> Unit,

libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/AuthenticationUtilitiesTest.kt

Lines changed: 162 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ class AuthenticationUtilitiesTest {
6868
private val handleScreenLockPolicy: (OAuth2.IdServiceResponse?, UserAccount) -> Unit = mockk()
6969
private val handleBiometricAuthPolicy: (OAuth2.IdServiceResponse?, UserAccount) -> Unit = mockk()
7070
private val handleDuplicateUserAccount: (UserAccountManager, UserAccount, OAuth2.IdServiceResponse?) -> Unit = mockk()
71-
private var blockIntegrationUser: Boolean = false
72-
private var nativeLogin: Boolean = false
7371

7472
@Before
7573
fun setUp() {
@@ -97,16 +95,13 @@ class AuthenticationUtilitiesTest {
9795
every { mockUserAccountManager.createAccount(any()) } returns mockk<android.os.Bundle>()
9896
every { mockUserAccountManager.switchToUser(any()) } returns Unit
9997
every { mockUserAccountManager.sendUserSwitchIntent(any(), any()) } returns Unit
100-
10198
}
10299

103100
@Test
104101
fun testOnAuthFlowComplete_blockIntegrationUser_shouldCallError() = runTest {
105-
// Given
106-
blockIntegrationUser = true
107102

108103
// When
109-
callOnAuthFlowComplete()
104+
callOnAuthFlowComplete(blockIntegrationUser = true)
110105

111106
// Then
112107
verify { onAuthFlowError.invoke("Error", "Authentication error. Please try again.", null) }
@@ -151,7 +146,7 @@ class AuthenticationUtilitiesTest {
151146
.accountName(buildAccountName(userIdentity.username, tokenResponse.instanceUrl))
152147
.loginServer("https://login.salesforce.com")
153148
.clientId("test_consumer_key")
154-
.nativeLogin(nativeLogin)
149+
.nativeLogin(false)
155150
.build()
156151

157152
// When
@@ -177,7 +172,7 @@ class AuthenticationUtilitiesTest {
177172
val tokenResponseWithoutIdScope = createTokenEndpointResponse(
178173
scope = "refresh_token" // Missing id scope
179174
)
180-
175+
181176
// Mock fetchUserIdentity to return null (simulating no id scope)
182177
coEvery { fetchUserIdentity.invoke(any()) } returns null
183178

@@ -188,7 +183,7 @@ class AuthenticationUtilitiesTest {
188183
.accountName(buildAccountName(null, tokenResponseWithoutIdScope.instanceUrl))
189184
.loginServer("https://login.salesforce.com")
190185
.clientId("test_consumer_key")
191-
.nativeLogin(nativeLogin)
186+
.nativeLogin(false)
192187
.build()
193188

194189
// When
@@ -206,12 +201,167 @@ class AuthenticationUtilitiesTest {
206201
verify { startMainActivity.invoke() }
207202
verify { handleScreenLockPolicy.invoke(null, expectedAccount) }
208203
verify { handleBiometricAuthPolicy.invoke(null, expectedAccount) }
209-
204+
210205
// Verify that fetchUserIdentity was called but returned null
211206
coVerify(exactly = 1) { fetchUserIdentity.invoke(tokenResponseWithoutIdScope) }
212207
}
208+
@Test
209+
fun testOnAuthFlowComplete_withNativeLogin_shouldCallSuccess() = runTest {
210+
// Given
211+
val tokenResponseWithoutIdScope = createTokenEndpointResponse(
212+
scope = "refresh_token" // Missing id scope
213+
)
214+
215+
// Mock fetchUserIdentity to return null (simulating no id scope)
216+
coEvery { fetchUserIdentity.invoke(any()) } returns null
217+
218+
// Create the expected UserAccount object without IdServiceResponse population
219+
val expectedAccount = UserAccountBuilder.getInstance()
220+
.populateFromTokenEndpointResponse(tokenResponseWithoutIdScope)
221+
.populateFromIdServiceResponse(null) // No identity service response
222+
.accountName(buildAccountName(null, tokenResponseWithoutIdScope.instanceUrl))
223+
.loginServer("https://login.salesforce.com")
224+
.clientId("test_consumer_key")
225+
.nativeLogin(true) // Expect true
226+
.build()
227+
228+
// When
229+
callOnAuthFlowComplete(
230+
customTokenResponse = tokenResponseWithoutIdScope,
231+
nativeLogin = true,
232+
)
233+
234+
// Then
235+
verify(exactly = 0) { onAuthFlowError.invoke(any(), any(), any()) }
236+
verify { onAuthFlowSuccess.invoke(expectedAccount) }
237+
verify { mockUserAccountManager.createAccount(expectedAccount) }
238+
verify { mockUserAccountManager.switchToUser(expectedAccount) }
239+
verify { setAdministratorPreferences.invoke(null, expectedAccount) }
240+
verify { handleDuplicateUserAccount.invoke(mockUserAccountManager, expectedAccount, null) }
241+
verify { addAccount.invoke(expectedAccount) }
242+
verify { updateLoggingPrefs.invoke(expectedAccount) }
243+
verify { startMainActivity.invoke() }
244+
verify { handleScreenLockPolicy.invoke(null, expectedAccount) }
245+
verify { handleBiometricAuthPolicy.invoke(null, expectedAccount) }
246+
247+
// Verify that fetchUserIdentity was called but returned null
248+
coVerify(exactly = 1) { fetchUserIdentity.invoke(tokenResponseWithoutIdScope) }
249+
}
250+
251+
252+
// region Token Migration Tests
253+
254+
@Test
255+
fun testOnAuthFlowComplete_tokenMigration_shouldNotCallStartMainActivity() = runTest {
256+
// Given
257+
val userIdentity = createIdServiceResponse()
258+
coEvery { fetchUserIdentity.invoke(any()) } returns userIdentity
259+
260+
// When - tokenMigration is true
261+
callOnAuthFlowComplete(tokenMigration = true)
262+
263+
// Then - startMainActivity should NOT be called during token migration
264+
verify(exactly = 0) { startMainActivity.invoke() }
265+
// But onAuthFlowSuccess should still be called
266+
verify(exactly = 1) { onAuthFlowSuccess.invoke(any()) }
267+
}
268+
269+
@Test
270+
fun testOnAuthFlowComplete_tokenMigration_shouldCallSuccess() = runTest {
271+
// Given
272+
val tokenResponse = createTokenEndpointResponse()
273+
val userIdentity = createIdServiceResponse()
274+
coEvery { fetchUserIdentity.invoke(any()) } returns userIdentity
275+
276+
// Create the expected UserAccount object
277+
val expectedAccount = UserAccountBuilder.getInstance()
278+
.populateFromTokenEndpointResponse(tokenResponse)
279+
.populateFromIdServiceResponse(userIdentity)
280+
.accountName(buildAccountName(userIdentity.username, tokenResponse.instanceUrl))
281+
.loginServer("https://login.salesforce.com")
282+
.clientId("test_consumer_key")
283+
.nativeLogin(false)
284+
.build()
285+
286+
// When - tokenMigration is true
287+
callOnAuthFlowComplete(tokenMigration = true)
288+
289+
// Then - onAuthFlowSuccess should be called with the account
290+
verify(exactly = 1) { onAuthFlowSuccess.invoke(expectedAccount) }
291+
verify(exactly = 0) { onAuthFlowError.invoke(any(), any(), any()) }
292+
}
293+
294+
@Test
295+
fun testOnAuthFlowComplete_tokenMigration_shouldCreateAccount() = runTest {
296+
// Given
297+
val userIdentity = createIdServiceResponse()
298+
coEvery { fetchUserIdentity.invoke(any()) } returns userIdentity
299+
300+
// When - tokenMigration is true
301+
callOnAuthFlowComplete(tokenMigration = true)
302+
303+
// Then - account creation and user switch should still happen
304+
verify(exactly = 1) { mockUserAccountManager.createAccount(any()) }
305+
verify(exactly = 1) { mockUserAccountManager.switchToUser(any()) }
306+
verify(exactly = 1) { addAccount.invoke(any()) }
307+
}
308+
309+
@Test
310+
fun testOnAuthFlowComplete_tokenMigration_shouldHandleLockPolicies() = runTest {
311+
// Given
312+
val userIdentity = createIdServiceResponse()
313+
coEvery { fetchUserIdentity.invoke(any()) } returns userIdentity
314+
315+
// When - tokenMigration is true
316+
callOnAuthFlowComplete(tokenMigration = true)
317+
318+
// Then - policies should still be handled
319+
verify(exactly = 1) { handleScreenLockPolicy.invoke(any(), any()) }
320+
verify(exactly = 1) { handleBiometricAuthPolicy.invoke(any(), any()) }
321+
}
322+
323+
@Test
324+
fun testOnAuthFlowComplete_tokenMigration_withBlockedIntegrationUser_shouldCallError() = runTest {
325+
// When - tokenMigration is true but user is blocked
326+
callOnAuthFlowComplete(
327+
blockIntegrationUser = true,
328+
tokenMigration = true,
329+
)
330+
331+
// Then - error should still be called for blocked users
332+
verify { onAuthFlowError.invoke("Error", "Authentication error. Please try again.", null) }
333+
verify(exactly = 0) { onAuthFlowSuccess.invoke(any()) }
334+
verify(exactly = 0) { startMainActivity.invoke() }
335+
}
336+
337+
@Test
338+
fun testOnAuthFlowComplete_tokenMigration_withManagedAppRequirement_shouldCallError() = runTest {
339+
// Given
340+
val userIdentityWithManagedAppRequirement = createIdServiceResponse(
341+
customPermissions = JSONObject().apply {
342+
put("must_be_managed_app", true)
343+
}
344+
)
345+
coEvery { fetchUserIdentity.invoke(any()) } returns userIdentityWithManagedAppRequirement
346+
every { mockRuntimeConfig.isManagedApp } returns false
347+
348+
// When - tokenMigration is true but managed app required
349+
callOnAuthFlowComplete(tokenMigration = true)
350+
351+
// Then - error should still be called
352+
verify { onAuthFlowError.invoke("Error", "Authentication only allowed from managed device.", null) }
353+
verify(exactly = 0) { onAuthFlowSuccess.invoke(any()) }
354+
verify(exactly = 0) { startMainActivity.invoke() }
355+
}
356+
357+
// endregion
213358

214-
private suspend fun callOnAuthFlowComplete(customTokenResponse: OAuth2.TokenEndpointResponse? = null) {
359+
private suspend fun callOnAuthFlowComplete(
360+
customTokenResponse: OAuth2.TokenEndpointResponse? = null,
361+
nativeLogin: Boolean = false,
362+
tokenMigration: Boolean = false,
363+
blockIntegrationUser: Boolean = false,
364+
) {
215365
onAuthFlowComplete(
216366
tokenResponse = customTokenResponse ?: createTokenEndpointResponse(),
217367
loginServer = "https://login.salesforce.com",
@@ -220,6 +370,7 @@ class AuthenticationUtilitiesTest {
220370
onAuthFlowSuccess = onAuthFlowSuccess,
221371
buildAccountName = buildAccountName,
222372
nativeLogin = nativeLogin,
373+
tokenMigration = tokenMigration,
223374
context = testContext,
224375
userAccountManager = mockUserAccountManager,
225376
blockIntegrationUser = blockIntegrationUser,

0 commit comments

Comments
 (0)