-
-
Notifications
You must be signed in to change notification settings - Fork 45
Token and Work History Parsing tests + some validation changes #3440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
24558a9
Stricter validations and tests for connect access token parser
shubham1g5 aad128b
Tests on work history parser
shubham1g5 a03df29
no op refactor to improve code style
shubham1g5 1eeb39a
convert to second to be consistent
shubham1g5 c601abf
dry code better
shubham1g5 a88e7fa
ktlint format
shubham1g5 547d16c
ktlint format
shubham1g5 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
...tests/src/org/commcare/connect/network/connectId/parser/ConnectTokenResponseParserTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| package org.commcare.connect.network.connectId.parser | ||
|
|
||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
| import org.commcare.CommCareTestApplication | ||
| import org.commcare.android.database.connect.models.ConnectUserRecord | ||
| import org.commcare.connect.ConnectConstants | ||
| import org.commcare.core.network.AuthInfo | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Assert.assertTrue | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import org.robolectric.annotation.Config | ||
| import java.io.ByteArrayInputStream | ||
| import java.util.Date | ||
| import kotlin.math.abs | ||
|
|
||
| @Config(application = CommCareTestApplication::class) | ||
| @RunWith(AndroidJUnit4::class) | ||
| class ConnectTokenResponseParserTest { | ||
| private data class TokenTestData( | ||
| val token: String, | ||
| val expiresInSeconds: Int? = null, | ||
| val expectedTimeDeltaSeconds: Long? = null, | ||
| ) | ||
|
|
||
| private fun createTokenJson( | ||
| token: String, | ||
| expiresValue: Any? = null, | ||
| ): String = | ||
| if (expiresValue != null) { | ||
| """ | ||
| { | ||
| "${ConnectConstants.CONNECT_KEY_TOKEN}": "$token", | ||
| "${ConnectConstants.CONNECT_KEY_EXPIRES}": $expiresValue | ||
| } | ||
| """.trimIndent() | ||
| } else { | ||
| """ | ||
| { | ||
| "${ConnectConstants.CONNECT_KEY_TOKEN}": "$token" | ||
| } | ||
| """.trimIndent() | ||
| } | ||
|
|
||
| private fun createTokenJson(testData: TokenTestData): String = createTokenJson(testData.token, testData.expiresInSeconds) | ||
|
|
||
| private fun parseTokenAndAssertBasics( | ||
| jsonResponse: String, | ||
| expectedToken: String, | ||
| userRecord: ConnectUserRecord = ConnectUserRecord(), | ||
| ): Pair<AuthInfo.TokenAuth, ConnectUserRecord> { | ||
| val parser = ConnectTokenResponseParser<AuthInfo.TokenAuth>() | ||
| val inputStream = ByteArrayInputStream(jsonResponse.toByteArray()) | ||
| val result = parser.parse(200, inputStream, userRecord) | ||
|
|
||
| assertEquals(expectedToken, result.bearerToken) | ||
| assertEquals(expectedToken, userRecord.connectToken) | ||
|
|
||
| return Pair(result, userRecord) | ||
| } | ||
|
|
||
| private fun assertExpirationTime( | ||
| userRecord: ConnectUserRecord, | ||
| currentTime: Date, | ||
| expectedDeltaSeconds: Long, | ||
| tolerance: Long = 5000L, | ||
| ) { | ||
| val expectedExpirationTime = currentTime.time + (expectedDeltaSeconds * 1000L) | ||
| val actualExpirationTime = userRecord.connectTokenExpiration.time | ||
| val timeDifference = abs(actualExpirationTime - expectedExpirationTime) | ||
| assertTrue("Expiration time should be within ${tolerance}ms of expected", timeDifference < tolerance) | ||
| } | ||
|
|
||
| private fun testTokenWithExpiration(testData: TokenTestData) { | ||
| // Arrange | ||
| val currentTime = Date() | ||
| val jsonResponse = createTokenJson(testData) | ||
|
|
||
| // Act & Basic Assert | ||
| val (_, userRecord) = parseTokenAndAssertBasics(jsonResponse, testData.token) | ||
|
|
||
| // Assert Expiration | ||
| if (testData.expectedTimeDeltaSeconds != null) { | ||
| assertExpirationTime(userRecord, currentTime, testData.expectedTimeDeltaSeconds) | ||
| } | ||
| } | ||
|
|
||
| // Helper method for exception testing | ||
| private fun parseTokenExpectingException(jsonResponse: String) { | ||
| val parser = ConnectTokenResponseParser<AuthInfo.TokenAuth>() | ||
| val userRecord = ConnectUserRecord() | ||
| val inputStream = ByteArrayInputStream(jsonResponse.toByteArray()) | ||
| parser.parse(200, inputStream, userRecord) | ||
| } | ||
|
|
||
| @Test | ||
| fun testParseValidResponseWithExpiresIn() { | ||
| testTokenWithExpiration( | ||
| TokenTestData( | ||
| token = "test_token_123", | ||
| expiresInSeconds = 3600, | ||
| expectedTimeDeltaSeconds = 3600L, | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testParseValidResponseWithoutExpiresIn() { | ||
| testTokenWithExpiration( | ||
| TokenTestData( | ||
| token = "another_test_token", | ||
| expiresInSeconds = null, | ||
| expectedTimeDeltaSeconds = 0L, | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testParseValidResponseWithZeroExpiresIn() { | ||
| testTokenWithExpiration( | ||
| TokenTestData( | ||
| token = "zero_expiry_token", | ||
| expiresInSeconds = 0, | ||
| expectedTimeDeltaSeconds = 0L, | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| @Test(expected = IllegalStateException::class) | ||
| fun testParseEmptyToken() { | ||
| testTokenWithExpiration( | ||
| TokenTestData( | ||
| token = "", | ||
| expiresInSeconds = 0, | ||
| expectedTimeDeltaSeconds = 0L, | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| @Test(expected = RuntimeException::class) | ||
| fun testParseInvalidJsonThrowsRuntimeException() { | ||
| // Arrange & Act & Assert | ||
| parseTokenExpectingException("{ invalid json }") | ||
| } | ||
|
|
||
| @Test(expected = RuntimeException::class) | ||
| fun testParseMissingTokenFieldThrowsRuntimeException() { | ||
| // Arrange | ||
| val jsonResponse = | ||
| """ | ||
| { | ||
| "${ConnectConstants.CONNECT_KEY_EXPIRES}": 3600 | ||
| } | ||
| """.trimIndent() | ||
|
|
||
| // Act & Assert | ||
| parseTokenExpectingException(jsonResponse) | ||
| } | ||
|
|
||
| @Test(expected = IllegalStateException::class) | ||
| fun testParseNullTokenField() { | ||
| // Arrange | ||
| val jsonResponse = createTokenJson("null", 3600) | ||
|
|
||
| // Act & Assert | ||
| parseTokenExpectingException(jsonResponse) | ||
| } | ||
|
|
||
| @Test | ||
| fun testParseWithInvalidExpiresInType() { | ||
| // Arrange | ||
| val jsonResponse = createTokenJson("test_token", "\"not_a_number\"") | ||
|
|
||
| // Act & Assert | ||
| // optInt returns 0 for invalid strings, so this should work without throwing exception | ||
| val (_, userRecord) = parseTokenAndAssertBasics(jsonResponse, "test_token") | ||
| } | ||
|
|
||
| @Test(expected = IllegalStateException::class) | ||
| fun testParseWithNegativeExpiresIn() { | ||
| // Arrange | ||
| val jsonResponse = createTokenJson("test_token", -3600) | ||
|
|
||
| // Act & Assert | ||
| parseTokenExpectingException(jsonResponse) | ||
| } | ||
|
|
||
| @Test(expected = RuntimeException::class) | ||
| fun testParseEmptyResponseThrowsRuntimeException() { | ||
| // Arrange & Act & Assert | ||
| parseTokenExpectingException("") | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.