Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
- 'infra/auth-store/**'
- 'infra/auth-logic/**'
- 'infra/matching/**'
- 'infra/backend-api/**'
feature1:
- 'feature/orchestrator/**'
- 'feature/client-api/**'
Expand Down Expand Up @@ -149,6 +150,7 @@ jobs:
infra:auth-store
infra:auth-logic
infra:matching
infra:backend-api
reportsId: infra2

feature-unit-tests1:
Expand Down
4 changes: 4 additions & 0 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ gradlePlugin {
id = "simprints.library.kotlinSerialization"
implementationClass = "LibraryKotlinSerializationConventionPlugin"
}
register("libraryBackendApi") {
id = "simprints.library.backendApi"
implementationClass = "LibraryBackendConventionPlugin"
}

// Testing setup plugins
register("testingUnit") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import common.getLibs
import common.implementation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class LibraryBackendConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
val libs = getLibs()
dependencies {
implementation(libs, "retrofit.core")

add("implementation", project(":infra:backend-api"))
}
}
}
}
3 changes: 1 addition & 2 deletions fingerprint/infra/scanner/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id("simprints.infra")
id("simprints.library.kotlinSerialization")
id("simprints.library.backendApi")
}

android {
Expand All @@ -11,8 +12,6 @@ dependencies {
// Kotlin
implementation(libs.kotlin.reflect)

implementation(libs.retrofit.core)

implementation(project(":infra:config-store"))
implementation(project(":infra:auth-store"))
implementation(project(":infra:recent-user-activity"))
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.simprints.fingerprint.infra.scanner.data.remote.network

import com.simprints.core.DispatcherIO
import com.simprints.infra.authstore.AuthStore
import com.simprints.infra.backendapi.BackendApiClient
import com.simprints.infra.logging.Simber
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
Expand All @@ -13,7 +14,7 @@ import javax.inject.Inject
* This class is responsible for downloading the firmware updates.
*/
internal class FingerprintFileDownloader @Inject constructor(
private val fingerprintApiClientFactory: FingerprintApiClientFactory,
private val backendApiClient: BackendApiClient,
private val authStore: AuthStore,
@param:DispatcherIO private val dispatcher: CoroutineDispatcher,
) {
Expand All @@ -36,11 +37,8 @@ internal class FingerprintFileDownloader @Inject constructor(
URL(url).readBytes()
}

suspend fun getFileUrl(fileId: String): String {
val fileUrlRemoteApi = getFileUrlRemoteApi().api
return fileUrlRemoteApi.getFileUrl(projectId, fileId).url
}

private suspend fun getFileUrlRemoteApi(): FingerprintApiClient<FileUrlRemoteInterface> =
fingerprintApiClientFactory.buildClient(FileUrlRemoteInterface::class)
suspend fun getFileUrl(fileId: String): String = backendApiClient
.executeCall(FileUrlRemoteInterface::class) { api ->
api.getFileUrl(projectId, fileId).url
}.getOrThrow()
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.simprints.fingerprint.infra.scanner.data.remote.network

import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.*
import com.simprints.fingerprint.infra.scanner.data.FirmwareTestData
import com.simprints.infra.authstore.AuthStore
import com.simprints.infra.backendapi.ApiResult
import com.simprints.infra.backendapi.BackendApiClient
import com.simprints.testtools.common.coroutines.TestCoroutineRule
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.*
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
Expand All @@ -19,11 +17,14 @@ internal class FingerprintFileDownloaderTest {
private lateinit var fingerprintFileDownloader: FingerprintFileDownloader

@MockK
lateinit var fingerprintApiClientFactory: FingerprintApiClientFactory
lateinit var backendApiClient: BackendApiClient

@MockK
lateinit var authStore: AuthStore

@MockK
lateinit var api: FileUrlRemoteInterface

@get:Rule
val testCoroutineRule = TestCoroutineRule()

Expand All @@ -32,20 +33,24 @@ internal class FingerprintFileDownloaderTest {
MockKAnnotations.init(this)
fingerprintFileDownloader =
FingerprintFileDownloader(
fingerprintApiClientFactory,
backendApiClient,
authStore,
testCoroutineRule.testCoroutineDispatcher,
)
}

@Test
fun getFileUrl() = runTest(UnconfinedTestDispatcher()) {
fun getFileUrl() = runTest {
// Given
val apiClient: FingerprintApiClient<FileUrlRemoteInterface> = mockk()
val api: FileUrlRemoteInterface = mockk()
coEvery { fingerprintApiClientFactory.buildClient<FileUrlRemoteInterface>(any()) } returns apiClient
every { apiClient.api } returns api
coEvery { api.getFileUrl(any(), any()) } returns FileUrl(FirmwareTestData.SOME_URL)
coEvery { backendApiClient.executeCall<FileUrlRemoteInterface, Any>(any(), any()) } coAnswers {
try {
ApiResult.Success(secondArg<suspend (FileUrlRemoteInterface) -> Any>()(api))
} catch (e: Exception) {
ApiResult.Failure(e)
}
}

every { authStore.signedInProjectId } returns "projectId"
// When
val result = fingerprintFileDownloader.getFileUrl("Any fileId")
Expand Down
2 changes: 1 addition & 1 deletion infra/auth-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id("simprints.infra")
id("simprints.config.cloud")
id("simprints.library.kotlinSerialization")
id("simprints.library.backendApi")
}

android {
Expand All @@ -21,7 +22,6 @@ dependencies {

implementation(project(":fingerprint:infra:scanner"))

implementation(libs.retrofit.core)
implementation(libs.playServices.integrity)
implementation(libs.workManager.work)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import com.simprints.infra.authstore.domain.models.AuthRequest
import com.simprints.infra.authstore.domain.models.AuthenticationData
import com.simprints.infra.authstore.domain.models.Token
import com.simprints.infra.authstore.exceptions.AuthRequestInvalidCredentialsException
import com.simprints.infra.network.SimNetwork
import com.simprints.infra.backendapi.BackendApiClient
import com.simprints.infra.network.exceptions.SyncCloudIntegrationException
import javax.inject.Inject

internal class AuthenticationRemoteDataSource @Inject constructor(
private val apiClientFactory: UnauthenticatedClientFactory,
private val backendApiClient: BackendApiClient,
) {
suspend fun requestAuthenticationData(
projectId: String,
deviceId: String,
): AuthenticationData = try {
getApiClient()
.executeCall {
it.requestAuthenticationData(projectId, deviceId)
}.toDomain()
backendApiClient
.executeUnauthenticatedCall(AuthenticationRemoteInterface::class) { api -> api.requestAuthenticationData(projectId, deviceId) }
.getOrThrow()
.toDomain()
} catch (e: Exception) {
if (e is SyncCloudIntegrationException && e.httpStatusCode() == NOT_FOUND_STATUS_CODE) {
throw AuthRequestInvalidCredentialsException()
Expand All @@ -33,14 +33,15 @@ internal class AuthenticationRemoteDataSource @Inject constructor(
deviceId: String,
credentials: AuthRequest,
): Token = try {
getApiClient()
.executeCall {
it.requestCustomTokens(
backendApiClient
.executeUnauthenticatedCall(AuthenticationRemoteInterface::class) { api ->
api.requestCustomTokens(
projectId,
deviceId,
ApiAuthRequestBody.fromDomain(credentials),
)
}.toDomain()
}.getOrThrow()
.toDomain()
} catch (e: Exception) {
if (e is SyncCloudIntegrationException && e.httpStatusCode() == UNAUTHORIZED_STATUS_CODE) {
throw AuthRequestInvalidCredentialsException()
Expand All @@ -49,9 +50,6 @@ internal class AuthenticationRemoteDataSource @Inject constructor(
}
}

private fun getApiClient(): SimNetwork.SimApiClient<AuthenticationRemoteInterface> =
apiClientFactory.build(AuthenticationRemoteInterface::class)

companion object {
private const val UNAUTHORIZED_STATUS_CODE = 401
private const val NOT_FOUND_STATUS_CODE = 404
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package com.simprints.infra.authlogic.authenticator.remote

import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.*
import com.simprints.infra.authlogic.authenticator.remote.models.ApiAuthRequestBody
import com.simprints.infra.authlogic.authenticator.remote.models.ApiAuthenticationData
import com.simprints.infra.authlogic.authenticator.remote.models.ApiToken
import com.simprints.infra.authstore.domain.models.AuthRequest
import com.simprints.infra.authstore.domain.models.AuthenticationData
import com.simprints.infra.authstore.domain.models.Token
import com.simprints.infra.authstore.exceptions.AuthRequestInvalidCredentialsException
import com.simprints.infra.network.SimNetwork
import com.simprints.infra.backendapi.ApiResult
import com.simprints.infra.backendapi.BackendApiClient
import com.simprints.infra.network.exceptions.BackendMaintenanceException
import com.simprints.infra.network.exceptions.SyncCloudIntegrationException
import com.simprints.testtools.common.alias.InterfaceInvocation
import com.simprints.testtools.common.syntax.assertThrows
import io.mockk.coEvery
import io.mockk.mockk
import io.mockk.*
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest
import okhttp3.ResponseBody.Companion.toResponseBody
Expand All @@ -33,20 +32,18 @@ class AuthenticationRemoteDataSourceTest {
}

private val remoteInterface = mockk<AuthenticationRemoteInterface>()
private val simApiClient = mockk<SimNetwork.SimApiClient<AuthenticationRemoteInterface>>()
private val simApiClientFactory = mockk<UnauthenticatedClientFactory>()
private val authenticationRemoteDataSource = AuthenticationRemoteDataSource(simApiClientFactory)
private val backendApiClient = mockk<BackendApiClient>()
private val authenticationRemoteDataSource = AuthenticationRemoteDataSource(backendApiClient)

@Before
fun setUp() {
coEvery { simApiClient.executeCall<ApiAuthenticationData>(any()) } coAnswers {
val args = this.args
@Suppress("UNCHECKED_CAST")
(args[0] as InterfaceInvocation<AuthenticationRemoteInterface, ApiAuthenticationData>).invoke(
remoteInterface,
)
coEvery { backendApiClient.executeUnauthenticatedCall<AuthenticationRemoteInterface, Any>(any(), any()) } coAnswers {
try {
ApiResult.Success(secondArg<suspend (AuthenticationRemoteInterface) -> Any>()(remoteInterface))
} catch (e: Exception) {
ApiResult.Failure(e)
}
}
coEvery { simApiClientFactory.build(AuthenticationRemoteInterface::class) } returns simApiClient
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ package com.simprints.infra.authstore
import com.google.firebase.FirebaseApp
import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.infra.authstore.domain.models.Token
import com.simprints.infra.network.SimNetwork
import com.simprints.infra.network.SimRemoteInterface
import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass

interface AuthStore {
var signedInUserId: TokenizableString?
Expand All @@ -20,6 +17,8 @@ interface AuthStore {

suspend fun storeFirebaseToken(token: Token)

suspend fun getFirebaseToken(): String

fun clearFirebaseToken()

fun isFirebaseSignedIn(projectId: String): Boolean
Expand All @@ -32,6 +31,4 @@ interface AuthStore {
* @throws IllegalStateException if not initialized
*/
fun getCoreApp(): FirebaseApp

suspend fun <T : SimRemoteInterface> buildClient(remoteInterface: KClass<T>): SimNetwork.SimApiClient<T>
}
Loading