refactor: store API keys in app preferences
This commit is contained in:
@@ -17,6 +17,7 @@ import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import space.hackenslacker.kanbn4droid.app.auth.AuthFailureReason
|
||||
import space.hackenslacker.kanbn4droid.app.auth.ApiKeyStore
|
||||
import space.hackenslacker.kanbn4droid.app.auth.AuthResult
|
||||
import space.hackenslacker.kanbn4droid.app.auth.KanbnApiClient
|
||||
@@ -65,16 +66,70 @@ class LoginFlowTest {
|
||||
@Test
|
||||
fun invalidStoredSessionFallsBackToLoginAndKeepsUrl() {
|
||||
val sessionStore = InMemorySessionStore("https://kan.bn/")
|
||||
val keyStore = InMemoryApiKeyStore("bad-key")
|
||||
MainActivity.dependencies.sessionStoreFactory = { sessionStore }
|
||||
MainActivity.dependencies.apiKeyStoreFactory = { InMemoryApiKeyStore("bad-key") }
|
||||
MainActivity.dependencies.apiKeyStoreFactory = { keyStore }
|
||||
MainActivity.dependencies.apiClientFactory = {
|
||||
FakeApiClient(AuthResult.Failure("Authentication failed. Check your API key."))
|
||||
FakeApiClient(
|
||||
AuthResult.Failure(
|
||||
message = "Authentication failed. Check your API key.",
|
||||
reason = AuthFailureReason.Authentication,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
onView(withId(R.id.baseUrlInput)).check(matches(withText("https://kan.bn/")))
|
||||
onView(withId(R.id.signInButton)).check(matches(isDisplayed()))
|
||||
assertEquals(1, keyStore.invalidationCount)
|
||||
assertEquals(null, keyStore.currentKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectivityFailureDuringAutoLoginFallsBackWithoutInvalidatingKey() {
|
||||
val sessionStore = InMemorySessionStore("https://kan.bn/")
|
||||
val keyStore = InMemoryApiKeyStore("bad-key")
|
||||
MainActivity.dependencies.sessionStoreFactory = { sessionStore }
|
||||
MainActivity.dependencies.apiKeyStoreFactory = { keyStore }
|
||||
MainActivity.dependencies.apiClientFactory = {
|
||||
FakeApiClient(
|
||||
AuthResult.Failure(
|
||||
message = "Cannot reach server. Check your connection and URL.",
|
||||
reason = AuthFailureReason.Connectivity,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
onView(withId(R.id.baseUrlInput)).check(matches(withText("https://kan.bn/")))
|
||||
onView(withId(R.id.signInButton)).check(matches(isDisplayed()))
|
||||
assertEquals(0, keyStore.invalidationCount)
|
||||
assertEquals("bad-key", keyStore.currentKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serverFailureDuringAutoLoginFallsBackWithoutInvalidatingKey() {
|
||||
val sessionStore = InMemorySessionStore("https://kan.bn/")
|
||||
val keyStore = InMemoryApiKeyStore("bad-key")
|
||||
MainActivity.dependencies.sessionStoreFactory = { sessionStore }
|
||||
MainActivity.dependencies.apiKeyStoreFactory = { keyStore }
|
||||
MainActivity.dependencies.apiClientFactory = {
|
||||
FakeApiClient(
|
||||
AuthResult.Failure(
|
||||
message = "Server error: 500",
|
||||
reason = AuthFailureReason.Server,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
onView(withId(R.id.baseUrlInput)).check(matches(withText("https://kan.bn/")))
|
||||
onView(withId(R.id.signInButton)).check(matches(isDisplayed()))
|
||||
assertEquals(0, keyStore.invalidationCount)
|
||||
assertEquals("bad-key", keyStore.currentKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,6 +169,9 @@ class LoginFlowTest {
|
||||
private var key: String?,
|
||||
) : ApiKeyStore {
|
||||
var savedKey: String? = null
|
||||
var invalidationCount: Int = 0
|
||||
val currentKey: String?
|
||||
get() = key
|
||||
|
||||
override suspend fun saveApiKey(baseUrl: String, apiKey: String): Result<Unit> {
|
||||
key = apiKey
|
||||
@@ -124,6 +182,7 @@ class LoginFlowTest {
|
||||
override suspend fun getApiKey(baseUrl: String): Result<String?> = Result.success(key)
|
||||
|
||||
override suspend fun invalidateApiKey(baseUrl: String): Result<Unit> {
|
||||
invalidationCount += 1
|
||||
key = null
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package space.hackenslacker.kanbn4droid.app.auth
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PreferencesApiKeyStoreTest {
|
||||
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
private val store = PreferencesApiKeyStore(context)
|
||||
|
||||
@Before
|
||||
fun clearStore() = runBlocking {
|
||||
store.invalidateApiKey("setup").getOrThrow()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveThenGetReturnsKey() = runBlocking {
|
||||
val saveResult = store.saveApiKey("https://kan.bn/", "kan_key")
|
||||
val getResult = store.getApiKey("https://kan.bn/")
|
||||
|
||||
assertEquals(true, saveResult.isSuccess)
|
||||
assertEquals("kan_key", getResult.getOrNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidateClearsKey() = runBlocking {
|
||||
store.saveApiKey("https://kan.bn/", "kan_key").getOrThrow()
|
||||
|
||||
val invalidateResult = store.invalidateApiKey("https://kan.bn/")
|
||||
val getResult = store.getApiKey("https://kan.bn/")
|
||||
|
||||
assertEquals(true, invalidateResult.isSuccess)
|
||||
assertNull(getResult.getOrNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getReturnsNullWhenAbsent() = runBlocking {
|
||||
val getResult = store.getApiKey("https://kan.bn/")
|
||||
|
||||
assertNull(getResult.getOrNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun blankAndMalformedBaseUrlStillWork() = runBlocking {
|
||||
val saveBlankResult = store.saveApiKey("", "kan_key")
|
||||
val getMalformedResult = store.getApiKey("not a url")
|
||||
val invalidateMalformedResult = store.invalidateApiKey("::://")
|
||||
val getAfterInvalidateResult = store.getApiKey(" ")
|
||||
|
||||
assertEquals(true, saveBlankResult.isSuccess)
|
||||
assertEquals("kan_key", getMalformedResult.getOrNull())
|
||||
assertEquals(true, invalidateMalformedResult.isSuccess)
|
||||
assertNull(getAfterInvalidateResult.getOrNull())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user