diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt index b33fa710367e3862882a3c9996551f5da374c2db..c7f8960056aa00d84f1b9f8631136a0ab23ba381 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt @@ -27,6 +27,9 @@ import de.rki.coronawarnapp.exception.ApplicationConfigurationInvalidException import de.rki.coronawarnapp.http.requests.RegistrationTokenRequest import de.rki.coronawarnapp.http.requests.ReqistrationRequest import de.rki.coronawarnapp.http.requests.TanRequestBody +import de.rki.coronawarnapp.http.service.DistributionService +import de.rki.coronawarnapp.http.service.SubmissionService +import de.rki.coronawarnapp.http.service.VerificationService import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants import de.rki.coronawarnapp.service.submission.SubmissionConstants @@ -41,19 +44,36 @@ import java.io.File import java.util.Date import java.util.UUID -object WebRequestBuilder { - private val TAG: String? = WebRequestBuilder::class.simpleName - - private const val EXPORT_BINARY_FILE_NAME = "export.bin" - private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" - - private val serviceFactory = ServiceFactory() - - private val distributionService by lazy { serviceFactory.distributionService() } - private val verificationService by lazy { serviceFactory.verificationService() } - private val submissionService by lazy { serviceFactory.submissionService() } +class WebRequestBuilder( + private val distributionService: DistributionService, + private val verificationService: VerificationService, + private val submissionService: SubmissionService, + private val verificationKeys: VerificationKeys +) { + companion object { + private val TAG: String? = WebRequestBuilder::class.simpleName + private const val EXPORT_BINARY_FILE_NAME = "export.bin" + private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" + + @Volatile + private var instance: WebRequestBuilder? = null + + fun getInstance(): WebRequestBuilder { + return instance ?: synchronized(this) { + instance ?: buildWebRequestBuilder().also { instance = it } + } + } - private val verificationKeys = VerificationKeys() + private fun buildWebRequestBuilder(): WebRequestBuilder { + val serviceFactory = ServiceFactory() + return WebRequestBuilder( + serviceFactory.distributionService(), + serviceFactory.verificationService(), + serviceFactory.submissionService(), + VerificationKeys() + ) + } + } suspend fun asyncGetDateIndex(): List<String> = withContext(Dispatchers.IO) { return@withContext distributionService diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt index 596ba0925338015533e0c50a5fd8e82cd3e1365a..137dc448bf064e38c726e9db5766356aa3b58265 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt @@ -6,8 +6,7 @@ import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass object ApplicationConfigurationService { suspend fun asyncRetrieveApplicationConfiguration(): ApplicationConfigurationOuterClass.ApplicationConfiguration { - return WebRequestBuilder - .asyncGetApplicationConfigurationFromServer() + return WebRequestBuilder.getInstance().asyncGetApplicationConfigurationFromServer() } suspend fun asyncRetrieveExposureConfiguration(): ExposureConfiguration = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt index fc4cc03daa3f1b55fb7581869329283a6973a5bf..bf03586ffb9c53deec91b86317f40047bf3a4471 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt @@ -48,7 +48,7 @@ object DiagnosisKeyService { */ suspend fun asyncSubmitKeys(authCode: String, keysToReport: List<KeyExportFormat.TemporaryExposureKey>) { Log.d(TAG, "Diagnosis Keys will be submitted.") - WebRequestBuilder.asyncSubmitKeysToServer( + WebRequestBuilder.getInstance().asyncSubmitKeysToServer( authCode, false, keysToReport diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt index 6cdd39fee0dc016c5cc81b382fc8a3da92d809f8..1f8f64b59edf6dbf3a5b9ed94a8d24de4a8bd004 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt @@ -24,7 +24,7 @@ object SubmissionService { private suspend fun asyncRegisterDeviceViaGUID(guid: String) { val registrationToken = - WebRequestBuilder.asyncGetRegistrationToken( + WebRequestBuilder.getInstance().asyncGetRegistrationToken( guid, QR_CODE_KEY_TYPE ) @@ -35,7 +35,7 @@ object SubmissionService { private suspend fun asyncRegisterDeviceViaTAN(tan: String) { val registrationToken = - WebRequestBuilder.asyncGetRegistrationToken( + WebRequestBuilder.getInstance().asyncGetRegistrationToken( tan, TELE_TAN_KEY_TYPE ) @@ -45,7 +45,7 @@ object SubmissionService { } suspend fun asyncRequestAuthCode(registrationToken: String): String { - return WebRequestBuilder.asyncGetTan(registrationToken) + return WebRequestBuilder.getInstance().asyncGetTan(registrationToken) } suspend fun asyncSubmitExposureKeys() { @@ -58,7 +58,7 @@ object SubmissionService { val registrationToken = LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() return TestResult.fromInt( - WebRequestBuilder.asyncGetTestResult(registrationToken) + WebRequestBuilder.getInstance().asyncGetTestResult(registrationToken) ) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt index 9fe260c58c70dbc7a58117c63594756fba8d38ef..64b71b742bb75f97ab49e500079c237bd73b8c49 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt @@ -76,7 +76,7 @@ object CachedKeyFileHolder { return@withContext getLast3Hours(currentDate) .map { getURLForHour(currentDate.toServerFormat(), it) } .map { url -> async { - return@async WebRequestBuilder.asyncGetKeyFilesFromServer(url) + return@async WebRequestBuilder.getInstance().asyncGetKeyFilesFromServer(url) } }.awaitAll() } else { throw IllegalStateException( @@ -152,7 +152,7 @@ object CachedKeyFileHolder { */ private suspend fun String.createDayEntryForUrl() = keyCache.createEntry( this.generateCacheKeyFromString(), - WebRequestBuilder.asyncGetKeyFilesFromServer(this).toURI(), + WebRequestBuilder.getInstance().asyncGetKeyFilesFromServer(this).toURI(), DAY ) @@ -183,13 +183,13 @@ object CachedKeyFileHolder { * Get all dates from server based as formatted dates */ private suspend fun getDatesFromServer() = - WebRequestBuilder.asyncGetDateIndex() + WebRequestBuilder.getInstance().asyncGetDateIndex() /** * Get all hours from server based as formatted dates */ private suspend fun getHoursFromServer(day: Date) = - WebRequestBuilder.asyncGetHourIndex(day) + WebRequestBuilder.getInstance().asyncGetHourIndex(day) /** * TODO remove before release diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..305daf8a9ee5ecf9aa965165964ee2591a01a067 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt @@ -0,0 +1,78 @@ +package de.rki.coronawarnapp.http + +import de.rki.coronawarnapp.http.service.DistributionService +import de.rki.coronawarnapp.http.service.SubmissionService +import de.rki.coronawarnapp.http.service.VerificationService +import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toServerFormat +import de.rki.coronawarnapp.util.security.VerificationKeys +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockkObject +import io.mockk.unmockkAll +import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.util.Date + +class WebRequestBuilderTest { + @MockK private lateinit var verificationService: VerificationService + @MockK private lateinit var distributionService: DistributionService + @MockK private lateinit var submissionService: SubmissionService + @MockK private lateinit var verificationKeys: VerificationKeys + + private lateinit var webRequestBuilder: WebRequestBuilder + + @Before + fun setUp() = run { + MockKAnnotations.init(this) + webRequestBuilder = WebRequestBuilder( + distributionService, + verificationService, + submissionService, + verificationKeys + ) + } + + @After + fun tearDown() = unmockkAll() + + @Test + fun retrievingDateIndexIsSuccessful() { + val urlString = DiagnosisKeyConstants.AVAILABLE_DATES_URL + coEvery { distributionService.getDateIndex(urlString) } + .returns(listOf("1900-01-01", "2000-01-01")) + + runBlocking { + val expectedResult = listOf("1900-01-01", "2000-01-01") + Assert.assertEquals(webRequestBuilder.asyncGetDateIndex(), expectedResult) + coVerify { + distributionService.getDateIndex(urlString) + } + } + } + + @Test + fun asyncGetHourIndex() { + val day = Date() + val urlString = DiagnosisKeyConstants.AVAILABLE_DATES_URL + + "/${day.toServerFormat()}/${DiagnosisKeyConstants.HOUR}" + + coEvery { distributionService.getHourIndex(urlString) } + .returns(listOf("1", "2")) + + runBlocking { + val expectedResult = listOf("1", "2") + Assert.assertEquals(webRequestBuilder.asyncGetHourIndex(day), expectedResult) + coVerify { + distributionService.getHourIndex(urlString) + } + } + } +} \ No newline at end of file