diff --git a/engine/src/main/java/com/google/android/fhir/sync/Config.kt b/engine/src/main/java/com/google/android/fhir/sync/Config.kt index 4ff02cd2b3..ba35177c0b 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/Config.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/Config.kt @@ -40,7 +40,6 @@ val defaultRetryConfiguration = object SyncDataParams { const val SORT_KEY = "_sort" const val LAST_UPDATED_KEY = "_lastUpdated" - const val ADDRESS_COUNTRY_KEY = "address-country" const val SUMMARY_KEY = "_summary" const val SUMMARY_COUNT_VALUE = "count" } @@ -60,14 +59,14 @@ class PeriodicSyncConfiguration( val repeat: RepeatInterval, /** Configuration for synchronization retry */ - val retryConfiguration: RetryConfiguration? = defaultRetryConfiguration + val retryConfiguration: RetryConfiguration? = defaultRetryConfiguration, ) data class RepeatInterval( /** The interval at which the sync should be triggered in */ val interval: Long, /** The time unit for the repeat interval */ - val timeUnit: TimeUnit + val timeUnit: TimeUnit, ) fun ParamMap.concatParams(): String { @@ -85,7 +84,7 @@ data class RetryConfiguration( val backoffCriteria: BackoffCriteria, /** Maximum retries for a failing [FhirSyncWorker] */ - val maxRetries: Int + val maxRetries: Int, ) /** @@ -104,5 +103,5 @@ data class BackoffCriteria( val backoffDelay: Long, /** The time unit for [backoffDelay] */ - val timeUnit: TimeUnit + val timeUnit: TimeUnit, ) diff --git a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt index 07c3e644a1..e189daf48a 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/FhirSyncWorker.kt @@ -25,9 +25,7 @@ import com.google.android.fhir.FhirEngine import com.google.android.fhir.FhirEngineProvider import com.google.android.fhir.OffsetDateTimeTypeAdapter import com.google.android.fhir.sync.download.DownloaderImpl -import com.google.android.fhir.sync.upload.SquashedChangesUploadWorkManager -import com.google.android.fhir.sync.upload.UploadWorkManager -import com.google.android.fhir.sync.upload.UploaderImpl +import com.google.android.fhir.sync.upload.Uploader import com.google.gson.ExclusionStrategy import com.google.gson.FieldAttributes import com.google.gson.GsonBuilder @@ -43,10 +41,9 @@ import timber.log.Timber abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameters) : CoroutineWorker(appContext, workerParams) { abstract fun getFhirEngine(): FhirEngine + abstract fun getDownloadWorkManager(): DownloadWorkManager - private fun getUploadWorkManager(): UploadWorkManager { - return SquashedChangesUploadWorkManager() - } + abstract fun getConflictResolver(): ConflictResolver private val gson = @@ -64,9 +61,9 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter ?: return Result.failure( buildWorkData( IllegalStateException( - "FhirEngineConfiguration.ServerConfiguration is not set. Call FhirEngineProvider.init to initialize with appropriate configuration." - ) - ) + "FhirEngineConfiguration.ServerConfiguration is not set. Call FhirEngineProvider.init to initialize with appropriate configuration.", + ), + ), ) val flow = MutableSharedFlow() @@ -88,9 +85,9 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter FhirSynchronizer( applicationContext, getFhirEngine(), - UploaderImpl(dataSource, getUploadWorkManager()), + Uploader(dataSource), DownloaderImpl(dataSource, getDownloadWorkManager()), - getConflictResolver() + getConflictResolver(), ) .apply { subscribe(flow) } .synchronize() @@ -125,7 +122,7 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter return workDataOf( // send serialized state and type so that consumer can convert it back "StateType" to state::class.java.name, - "State" to gson.toJson(state) + "State" to gson.toJson(state), ) } @@ -137,8 +134,9 @@ abstract class FhirSyncWorker(appContext: Context, workerParams: WorkerParameter * Exclusion strategy for [Gson] that handles field exclusions for [SyncJobStatus] returned by * FhirSynchronizer. It should skip serializing the exceptions to avoid exceeding WorkManager * WorkData limit + * * @see https://github.com/google/android-fhir/issues/707 + * href="https://github.com/google/android-fhir/issues/707">https://github.com/google/android-fhir/issues/707 */ internal class StateExclusionStrategy : ExclusionStrategy { override fun shouldSkipField(field: FieldAttributes) = field.name.equals("exceptions") diff --git a/engine/src/main/java/com/google/android/fhir/sync/FhirSynchronizer.kt b/engine/src/main/java/com/google/android/fhir/sync/FhirSynchronizer.kt index 5a4e2aa95d..c58857dfbb 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/FhirSynchronizer.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/FhirSynchronizer.kt @@ -19,6 +19,8 @@ package com.google.android.fhir.sync import android.content.Context import com.google.android.fhir.DatastoreUtil import com.google.android.fhir.FhirEngine +import com.google.android.fhir.sync.download.DownloadState +import com.google.android.fhir.sync.download.Downloader import com.google.android.fhir.sync.upload.UploadState import com.google.android.fhir.sync.upload.Uploader import java.time.OffsetDateTime @@ -28,13 +30,14 @@ import org.hl7.fhir.r4.model.ResourceType enum class SyncOperation { DOWNLOAD, - UPLOAD + UPLOAD, } private sealed class SyncResult { val timestamp: OffsetDateTime = OffsetDateTime.now() class Success : SyncResult() + data class Error(val exceptions: List) : SyncResult() } @@ -46,7 +49,7 @@ internal class FhirSynchronizer( private val fhirEngine: FhirEngine, private val uploader: Uploader, private val downloader: Downloader, - private val conflictResolver: ConflictResolver + private val conflictResolver: ConflictResolver, ) { private var syncState: MutableSharedFlow? = null private val datastoreUtil = DatastoreUtil(context) @@ -135,7 +138,7 @@ internal class FhirSynchronizer( is UploadState.Success -> emit(result.localChangeToken to result.resource).also { setSyncState( - SyncJobStatus.InProgress(SyncOperation.UPLOAD, result.total, result.completed) + SyncJobStatus.InProgress(SyncOperation.UPLOAD, result.total, result.completed), ) } is UploadState.Failure -> exceptions.add(result.syncError) diff --git a/engine/src/main/java/com/google/android/fhir/sync/Downloader.kt b/engine/src/main/java/com/google/android/fhir/sync/download/Downloader.kt similarity index 85% rename from engine/src/main/java/com/google/android/fhir/sync/Downloader.kt rename to engine/src/main/java/com/google/android/fhir/sync/download/Downloader.kt index 9be709402c..4e51e5809b 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/Downloader.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/download/Downloader.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Google LLC + * Copyright 2022-2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,9 @@ * limitations under the License. */ -package com.google.android.fhir.sync +package com.google.android.fhir.sync.download +import com.google.android.fhir.sync.ResourceSyncException import kotlinx.coroutines.flow.Flow import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceType @@ -24,7 +25,7 @@ import org.hl7.fhir.r4.model.ResourceType internal interface Downloader { /** * @return Flow of the [DownloadState] which keeps emitting [Resource]s or Error based on the - * response of each page download request. It also updates progress if [ProgressCallback] exists + * response of each page download request. It also updates progress if [ProgressCallback] exists */ suspend fun download(): Flow } diff --git a/engine/src/main/java/com/google/android/fhir/sync/download/DownloaderImpl.kt b/engine/src/main/java/com/google/android/fhir/sync/download/DownloaderImpl.kt index 9efb3c73cd..72e2461d58 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/download/DownloaderImpl.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/download/DownloaderImpl.kt @@ -19,9 +19,7 @@ package com.google.android.fhir.sync.download import com.google.android.fhir.sync.BundleDownloadRequest import com.google.android.fhir.sync.DataSource import com.google.android.fhir.sync.DownloadRequest -import com.google.android.fhir.sync.DownloadState import com.google.android.fhir.sync.DownloadWorkManager -import com.google.android.fhir.sync.Downloader import com.google.android.fhir.sync.ResourceSyncException import com.google.android.fhir.sync.UrlDownloadRequest import kotlinx.coroutines.flow.Flow @@ -38,7 +36,7 @@ import timber.log.Timber */ internal class DownloaderImpl( private val dataSource: DataSource, - private val downloadWorkManager: DownloadWorkManager + private val downloadWorkManager: DownloadWorkManager, ) : Downloader { private val resourceTypeList = ResourceType.values().map { it.name } diff --git a/engine/src/main/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManager.kt b/engine/src/main/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManager.kt index 94c95c0b23..13efdffdef 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManager.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManager.kt @@ -31,6 +31,7 @@ import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceType typealias ResourceSearchParams = Map + /** * [DownloadWorkManager] implementation based on the provided [ResourceSearchParams] to generate * [Resource] search queries and parse [Bundle.BundleType.SEARCHSET] type [Bundle]. This @@ -39,14 +40,15 @@ typealias ResourceSearchParams = Map */ class ResourceParamsBasedDownloadWorkManager( syncParams: ResourceSearchParams, - val context: TimestampContext + val context: TimestampContext, ) : DownloadWorkManager { private val resourcesToDownloadWithSearchParams = LinkedList(syncParams.entries) private val urlOfTheNextPagesToDownloadForAResource = LinkedList() override suspend fun getNextRequest(): DownloadRequest? { - if (urlOfTheNextPagesToDownloadForAResource.isNotEmpty()) + if (urlOfTheNextPagesToDownloadForAResource.isNotEmpty()) { return urlOfTheNextPagesToDownloadForAResource.poll()?.let { DownloadRequest.of(it) } + } return resourcesToDownloadWithSearchParams.poll()?.let { (resourceType, params) -> val newParams = @@ -74,7 +76,7 @@ class ResourceParamsBasedDownloadWorkManager( private suspend fun getLastUpdatedParam( resourceType: ResourceType, params: ParamMap, - context: TimestampContext + context: TimestampContext, ): MutableMap { val newParams = mutableMapOf() if (!params.containsKey(SyncDataParams.SORT_KEY)) { @@ -108,20 +110,22 @@ class ResourceParamsBasedDownloadWorkManager( response.link .firstOrNull { component -> component.relation == "next" } - ?.url?.let { next -> urlOfTheNextPagesToDownloadForAResource.add(next) } + ?.url + ?.let { next -> urlOfTheNextPagesToDownloadForAResource.add(next) } return response.entry .map { it.resource } .also { resources -> resources .groupBy { it.resourceType } - .entries.map { map -> + .entries + .map { map -> map.value .filter { it.meta.lastUpdated != null } .let { context.saveLastUpdatedTimestamp( map.key, - it.maxOfOrNull { it.meta.lastUpdated }?.toTimeZoneString() + it.maxOfOrNull { it.meta.lastUpdated }?.toTimeZoneString(), ) } } @@ -130,6 +134,7 @@ class ResourceParamsBasedDownloadWorkManager( interface TimestampContext { suspend fun saveLastUpdatedTimestamp(resourceType: ResourceType, timestamp: String?) + suspend fun getLasUpdateTimestamp(resourceType: ResourceType): String? } } diff --git a/engine/src/main/java/com/google/android/fhir/sync/upload/SquashedChangesUploadWorkManager.kt b/engine/src/main/java/com/google/android/fhir/sync/upload/SquashedChangesUploadWorkManager.kt deleted file mode 100644 index 9705c56a85..0000000000 --- a/engine/src/main/java/com/google/android/fhir/sync/upload/SquashedChangesUploadWorkManager.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.fhir.sync.upload - -import com.google.android.fhir.LocalChange -import com.google.android.fhir.sync.UploadRequest -import com.google.android.fhir.sync.upload.patch.Patch -import com.google.android.fhir.sync.upload.patch.PerResourcePatchGenerator -import com.google.android.fhir.sync.upload.request.TransactionBundleGenerator - -/** - * [UploadWorkManager] implementation to squash all the changes at a resource level into one change - * and upload all resource level changes in a [BundleUploadRequest] - */ -class SquashedChangesUploadWorkManager : UploadWorkManager { - - private val bundleUploadRequestGenerator = TransactionBundleGenerator.getDefault() - - /** - * The implementation is to squash all the changes by resource type so that there is at most one - * patch to be uploaded per resource. - */ - override fun generatePatches(localChanges: List): List { - return PerResourcePatchGenerator.generate(localChanges) - } - - /** Use the [TransactionBundleGenerator] to bundle the [Patch]es into [BundleUploadRequest]s. */ - override fun generateRequests(patches: List): List { - return bundleUploadRequestGenerator.generateUploadRequests(patches) - } -} diff --git a/engine/src/main/java/com/google/android/fhir/sync/upload/UploadWorkManager.kt b/engine/src/main/java/com/google/android/fhir/sync/upload/UploadWorkManager.kt deleted file mode 100644 index 88c1994a2f..0000000000 --- a/engine/src/main/java/com/google/android/fhir/sync/upload/UploadWorkManager.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.fhir.sync.upload - -import com.google.android.fhir.LocalChange -import com.google.android.fhir.sync.UploadRequest -import com.google.android.fhir.sync.upload.patch.Patch - -/** - * Manager that pre-processes the local FHIR changes and handles how to upload them to the server. - */ -internal interface UploadWorkManager { - /** - * Transforms the [LocalChange]s to the final set of [Patch]es that need to be uploaded to the - * server. The transformation can be of various types like grouping the [LocalChange]s by resource - * or filtering out certain [LocalChange]s. - */ - fun generatePatches(localChanges: List): List - - /** Generates a list of [UploadRequest]s from the [Patch]es to be uploaded to the server */ - fun generateRequests(patches: List): List -} diff --git a/engine/src/main/java/com/google/android/fhir/sync/upload/Uploader.kt b/engine/src/main/java/com/google/android/fhir/sync/upload/Uploader.kt index 9c76abccfd..0e5653371b 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/upload/Uploader.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/upload/Uploader.kt @@ -18,28 +18,91 @@ package com.google.android.fhir.sync.upload import com.google.android.fhir.LocalChange import com.google.android.fhir.LocalChangeToken +import com.google.android.fhir.sync.DataSource import com.google.android.fhir.sync.ResourceSyncException +import com.google.android.fhir.sync.upload.patch.PerResourcePatchGenerator +import com.google.android.fhir.sync.upload.request.TransactionBundleGenerator import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import org.hl7.fhir.exceptions.FHIRException +import org.hl7.fhir.r4.model.Bundle +import org.hl7.fhir.r4.model.OperationOutcome import org.hl7.fhir.r4.model.Resource +import org.hl7.fhir.r4.model.ResourceType +import timber.log.Timber -/** Module for uploading local changes to a [DataSource]. */ -internal interface Uploader { +/** + * Uploads changes made locally to FHIR resources to server in the following steps: + * 1. fetching local changes from the on-device SQLite database, + * 2. creating patches to be sent to the server using the local changes, + * 3. generating HTTP requests to be sent to the server, + * 4. processing the responses from the server and consolidate any changes (i.e. updates resource + * IDs). + */ +internal class Uploader( + private val dataSource: DataSource, +) { + private val patchGenerator = PerResourcePatchGenerator + private val requestGenerator = TransactionBundleGenerator.getDefault() + + suspend fun upload(localChanges: List): Flow = flow { + val patches = patchGenerator.generate(localChanges) + val requests = requestGenerator.generateUploadRequests(patches) + val token = LocalChangeToken(localChanges.flatMap { it.token.ids }) + val total = requests.size + emit(UploadState.Started(total)) + requests.forEachIndexed { index, uploadRequest -> + try { + val response = dataSource.upload(uploadRequest) + emit( + getUploadResult(uploadRequest.resource.resourceType, response, token, total, index + 1), + ) + } catch (e: Exception) { + Timber.e(e) + emit(UploadState.Failure(ResourceSyncException(ResourceType.Bundle, e))) + } + } + } - /** - * Uploads the local changes to the [DataSource]. Particular implementations should take care of - * transforming the [LocalChange]s to particular network operations. If [ProgressCallback] is - * provided it also reports the intermediate progress - */ - suspend fun upload(localChanges: List): Flow + private fun getUploadResult( + requestResourceType: ResourceType, + response: Resource, + localChangeToken: LocalChangeToken, + total: Int, + completed: Int, + ) = + when { + response is Bundle && response.type == Bundle.BundleType.TRANSACTIONRESPONSE -> { + UploadState.Success(localChangeToken, response, total, completed) + } + response is OperationOutcome && response.issue.isNotEmpty() -> { + UploadState.Failure( + ResourceSyncException( + requestResourceType, + FHIRException(response.issueFirstRep.diagnostics), + ), + ) + } + else -> { + UploadState.Failure( + ResourceSyncException( + requestResourceType, + FHIRException("Unknown response for ${response.resourceType}"), + ), + ) + } + } } internal sealed class UploadState { data class Started(val total: Int) : UploadState() + data class Success( val localChangeToken: LocalChangeToken, val resource: Resource, val total: Int, - val completed: Int + val completed: Int, ) : UploadState() + data class Failure(val syncError: ResourceSyncException) : UploadState() } diff --git a/engine/src/main/java/com/google/android/fhir/sync/upload/UploaderImpl.kt b/engine/src/main/java/com/google/android/fhir/sync/upload/UploaderImpl.kt deleted file mode 100644 index 081fc8b430..0000000000 --- a/engine/src/main/java/com/google/android/fhir/sync/upload/UploaderImpl.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.fhir.sync.upload - -import com.google.android.fhir.LocalChange -import com.google.android.fhir.LocalChangeToken -import com.google.android.fhir.sync.DataSource -import com.google.android.fhir.sync.ResourceSyncException -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import org.hl7.fhir.exceptions.FHIRException -import org.hl7.fhir.r4.model.Bundle -import org.hl7.fhir.r4.model.OperationOutcome -import org.hl7.fhir.r4.model.Resource -import org.hl7.fhir.r4.model.ResourceType -import timber.log.Timber - -/** - * Implementation of the [Uploader]. It orchestrates the pre processing of [LocalChange] and - * constructing appropriate upload requests via [UploadWorkManager] and uploading of requests via - * [DataSource]. [Uploader] clients should call upload and listen to the various states emitted by - * [UploadWorkManager] as [UploadState]. - */ -internal class UploaderImpl( - private val dataSource: DataSource, - private val uploadWorkManager: UploadWorkManager, -) : Uploader { - - override suspend fun upload(localChanges: List): Flow = flow { - val patches = uploadWorkManager.generatePatches(localChanges) - val requests = uploadWorkManager.generateRequests(patches) - val token = LocalChangeToken(localChanges.flatMap { it.token.ids }) - val total = requests.size - emit(UploadState.Started(total)) - requests.forEachIndexed { index, uploadRequest -> - try { - val response = dataSource.upload(uploadRequest) - emit( - getUploadResult(uploadRequest.resource.resourceType, response, token, total, index + 1) - ) - } catch (e: Exception) { - Timber.e(e) - emit(UploadState.Failure(ResourceSyncException(ResourceType.Bundle, e))) - } - } - } - - private fun getUploadResult( - requestResourceType: ResourceType, - response: Resource, - localChangeToken: LocalChangeToken, - total: Int, - completed: Int - ) = - when { - response is Bundle && response.type == Bundle.BundleType.TRANSACTIONRESPONSE -> { - UploadState.Success(localChangeToken, response, total, completed) - } - response is OperationOutcome && response.issue.isNotEmpty() -> { - UploadState.Failure( - ResourceSyncException( - requestResourceType, - FHIRException(response.issueFirstRep.diagnostics) - ) - ) - } - else -> { - UploadState.Failure( - ResourceSyncException( - requestResourceType, - FHIRException("Unknown response for ${response.resourceType}") - ) - ) - } - } -} diff --git a/engine/src/main/java/com/google/android/fhir/sync/upload/request/TransactionBundleGenerator.kt b/engine/src/main/java/com/google/android/fhir/sync/upload/request/TransactionBundleGenerator.kt index b068c4a222..9759481125 100644 --- a/engine/src/main/java/com/google/android/fhir/sync/upload/request/TransactionBundleGenerator.kt +++ b/engine/src/main/java/com/google/android/fhir/sync/upload/request/TransactionBundleGenerator.kt @@ -29,7 +29,7 @@ class TransactionBundleGenerator( private val generatedBundleSize: Int, private val useETagForUpload: Boolean, private val getBundleEntryComponentGeneratorForLocalChangeType: - (type: Patch.Type, useETagForUpload: Boolean) -> BundleEntryComponentGenerator + (type: Patch.Type, useETagForUpload: Boolean) -> BundleEntryComponentGenerator, ) : UploadRequestGenerator { override fun generateUploadRequests(patches: List): List { @@ -43,7 +43,7 @@ class TransactionBundleGenerator( patches.forEach { this.addEntry( getBundleEntryComponentGeneratorForLocalChangeType(it.type, useETagForUpload) - .getEntry(it) + .getEntry(it), ) } } @@ -78,17 +78,16 @@ class TransactionBundleGenerator( generatedBundleSize: Int, useETagForUpload: Boolean, ): TransactionBundleGenerator { - val createFunction = createMapping[httpVerbToUseForCreate] ?: throw IllegalArgumentException( - "Creation using $httpVerbToUseForCreate is not supported." + "Creation using $httpVerbToUseForCreate is not supported.", ) val updateFunction = updateMapping[httpVerbToUseForUpdate] ?: throw IllegalArgumentException( - "Update using $httpVerbToUseForUpdate is not supported." + "Update using $httpVerbToUseForUpdate is not supported.", ) return TransactionBundleGenerator(generatedBundleSize, useETagForUpload) { type, useETag -> @@ -101,11 +100,11 @@ class TransactionBundleGenerator( } private fun putForCreateBasedBundleComponentMapper( - useETagForUpload: Boolean + useETagForUpload: Boolean, ): BundleEntryComponentGenerator = HttpPutForCreateEntryComponentGenerator(useETagForUpload) private fun patchForUpdateBasedBundleComponentMapper( - useETagForUpload: Boolean + useETagForUpload: Boolean, ): BundleEntryComponentGenerator = HttpPatchForUpdateEntryComponentGenerator(useETagForUpload) } } diff --git a/engine/src/test/java/com/google/android/fhir/sync/download/DownloaderImplTest.kt b/engine/src/test/java/com/google/android/fhir/sync/download/DownloaderImplTest.kt index 2a3a7d9a01..19367877a3 100644 --- a/engine/src/test/java/com/google/android/fhir/sync/download/DownloaderImplTest.kt +++ b/engine/src/test/java/com/google/android/fhir/sync/download/DownloaderImplTest.kt @@ -20,7 +20,6 @@ import com.google.android.fhir.logicalId import com.google.android.fhir.sync.BundleDownloadRequest import com.google.android.fhir.sync.DataSource import com.google.android.fhir.sync.DownloadRequest -import com.google.android.fhir.sync.DownloadState import com.google.android.fhir.sync.DownloadWorkManager import com.google.android.fhir.sync.UploadRequest import com.google.android.fhir.sync.UrlDownloadRequest @@ -53,7 +52,7 @@ class DownloaderImplTest { DownloadRequest.of("Patient"), DownloadRequest.of("Encounter"), DownloadRequest.of("Medication/med-123-that-fails"), - DownloadRequest.of(bundleOf("Observation/ob-123", "Condition/con-123")) + DownloadRequest.of(bundleOf("Observation/ob-123", "Condition/con-123")), ) val testDataSource: DataSource = @@ -66,7 +65,7 @@ class DownloaderImplTest { addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "pa-123" } - } + }, ) } "Encounter" -> @@ -79,7 +78,7 @@ class DownloaderImplTest { id = "en-123" subject = Reference("Patient/pa-123") } - } + }, ) } "Medication/med-123-that-fails" -> @@ -88,7 +87,7 @@ class DownloaderImplTest { OperationOutcome.OperationOutcomeIssueComponent().apply { severity = OperationOutcome.IssueSeverity.FATAL diagnostics = "Resource not found." - } + }, ) } else -> OperationOutcome() @@ -105,7 +104,7 @@ class DownloaderImplTest { id = "ob-123" subject = Reference("Patient/pq-123") } - } + }, ) addEntry( Bundle.BundleEntryComponent().apply { @@ -114,7 +113,7 @@ class DownloaderImplTest { id = "con-123" subject = Reference("Patient/pq-123") } - } + }, ) } } @@ -152,7 +151,7 @@ class DownloaderImplTest { DownloadRequest.of("Patient"), DownloadRequest.of("Encounter"), DownloadRequest.of("Medication/med-123-that-fails"), - DownloadRequest.of(bundleOf("Observation/ob-123", "Condition/con-123")) + DownloadRequest.of(bundleOf("Observation/ob-123", "Condition/con-123")), ) val testDataSource: DataSource = @@ -165,7 +164,7 @@ class DownloaderImplTest { addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "pa-123" } - } + }, ) } "Encounter" -> @@ -178,7 +177,7 @@ class DownloaderImplTest { id = "en-123" subject = Reference("Patient/pa-123") } - } + }, ) } "Medication/med-123-that-fails" -> @@ -187,7 +186,7 @@ class DownloaderImplTest { OperationOutcome.OperationOutcomeIssueComponent().apply { severity = OperationOutcome.IssueSeverity.FATAL diagnostics = "Resource not found." - } + }, ) } else -> OperationOutcome() @@ -204,7 +203,7 @@ class DownloaderImplTest { id = "ob-123" subject = Reference("Patient/pq-123") } - } + }, ) addEntry( Bundle.BundleEntryComponent().apply { @@ -213,7 +212,7 @@ class DownloaderImplTest { id = "con-123" subject = Reference("Patient/pq-123") } - } + }, ) } } @@ -239,7 +238,7 @@ class DownloaderImplTest { DownloadState.Success::class.java, DownloadState.Success::class.java, DownloadState.Failure::class.java, - DownloadState.Success::class.java + DownloadState.Success::class.java, ) .inOrder() @@ -261,7 +260,7 @@ class DownloaderImplTest { method = Bundle.HTTPVerb.GET url = it } - } + }, ) } } diff --git a/engine/src/test/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManagerTest.kt b/engine/src/test/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManagerTest.kt index e59cb98ae1..fb76798700 100644 --- a/engine/src/test/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManagerTest.kt +++ b/engine/src/test/java/com/google/android/fhir/sync/download/ResourceParamsBasedDownloadWorkManagerTest.kt @@ -47,7 +47,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { ResourceType.Immunization to emptyMap(), ResourceType.Observation to emptyMap(), ), - TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20") + TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20"), ) val urlsToDownload = mutableListOf() @@ -62,7 +62,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { .containsExactly( "Patient?address-city=NAIROBI&_sort=_lastUpdated&_lastUpdated=gt2022-03-20", "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", - "Immunization?_sort=_lastUpdated&_lastUpdated=gt2022-03-20" + "Immunization?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", ) } @@ -72,7 +72,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( mapOf(ResourceType.Patient to emptyMap(), ResourceType.Observation to emptyMap()), - TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20") + TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20"), ) val urlsToDownload = mutableListOf() @@ -84,7 +84,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { // Call process response so that It can add the next page url to be downloaded next. when (url) { "Patient?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", - "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20" -> { + "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", -> { downloadManager.processResponse( Bundle().apply { type = Bundle.BundleType.SEARCHSET @@ -92,9 +92,9 @@ class ResourceParamsBasedDownloadWorkManagerTest { Bundle.BundleLinkComponent().apply { relation = "next" this.url = "http://url-to-next-page?token=pageToken" - } + }, ) - } + }, ) } } @@ -105,7 +105,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { "Patient?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", "http://url-to-next-page?token=pageToken", "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20", - "http://url-to-next-page?token=pageToken" + "http://url-to-next-page?token=pageToken", ) } @@ -115,7 +115,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( mapOf(ResourceType.Patient to emptyMap()), - TestResourceParamsBasedDownloadWorkManagerContext("2022-06-28") + TestResourceParamsBasedDownloadWorkManagerContext("2022-06-28"), ) val url = downloadManager.getNextRequest()?.let { (it as UrlDownloadRequest).url } assertThat(url).isEqualTo("Patient?_sort=_lastUpdated&_lastUpdated=gt2022-06-28") @@ -130,10 +130,10 @@ class ResourceParamsBasedDownloadWorkManagerTest { ResourceType.Patient to mapOf( SyncDataParams.LAST_UPDATED_KEY to "2022-06-28", - SyncDataParams.SORT_KEY to "status" - ) + SyncDataParams.SORT_KEY to "status", + ), ), - TestResourceParamsBasedDownloadWorkManagerContext("2022-07-07") + TestResourceParamsBasedDownloadWorkManagerContext("2022-07-07"), ) val url = downloadManager.getNextRequest()?.let { (it as UrlDownloadRequest).url } assertThat(url).isEqualTo("Patient?_lastUpdated=2022-06-28&_sort=status") @@ -145,7 +145,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( mapOf(ResourceType.Patient to mapOf(SyncDataParams.LAST_UPDATED_KEY to "gt2022-06-28")), - TestResourceParamsBasedDownloadWorkManagerContext("2022-07-07") + TestResourceParamsBasedDownloadWorkManagerContext("2022-07-07"), ) val url = downloadManager.getNextRequest()?.let { (it as UrlDownloadRequest).url } assertThat(url).isEqualTo("Patient?_lastUpdated=gt2022-06-28&_sort=_lastUpdated") @@ -157,7 +157,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( mapOf(ResourceType.Patient to mapOf(Patient.ADDRESS_CITY.paramName to "NAIROBI")), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val actual = downloadManager.getNextRequest()?.let { (it as UrlDownloadRequest).url } assertThat(actual).isEqualTo("Patient?address-city=NAIROBI&_sort=_lastUpdated") @@ -169,7 +169,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( mapOf(ResourceType.Patient to mapOf(Patient.ADDRESS_CITY.paramName to "NAIROBI")), - TestResourceParamsBasedDownloadWorkManagerContext("") + TestResourceParamsBasedDownloadWorkManagerContext(""), ) val actual = downloadManager.getNextRequest()?.let { (it as UrlDownloadRequest).url } assertThat(actual).isEqualTo("Patient?address-city=NAIROBI&_sort=_lastUpdated") @@ -185,7 +185,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { ResourceType.Immunization to emptyMap(), ResourceType.Observation to emptyMap(), ), - TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20") + TestResourceParamsBasedDownloadWorkManagerContext("2022-03-20"), ) val urls = downloadManager.getSummaryRequestUrls() @@ -196,7 +196,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { .containsExactly( "Patient?address-city=NAIROBI&_sort=_lastUpdated&_lastUpdated=gt2022-03-20&_summary=count", "Immunization?_sort=_lastUpdated&_lastUpdated=gt2022-03-20&_summary=count", - "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20&_summary=count" + "Observation?_sort=_lastUpdated&_lastUpdated=gt2022-03-20&_summary=count", ) } @@ -205,14 +205,14 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = OperationOutcome().apply { addIssue( OperationOutcome.OperationOutcomeIssueComponent().apply { diagnostics = "Server couldn't fulfil the request." - } + }, ) } @@ -230,7 +230,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = Binary().apply { contentType = "application/json" } @@ -243,7 +243,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = Bundle().apply { @@ -251,12 +251,12 @@ class ResourceParamsBasedDownloadWorkManagerTest { addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "Patient-Id-001" } - } + }, ) addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "Patient-Id-002" } - } + }, ) } @@ -269,7 +269,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = Bundle().apply { @@ -277,12 +277,12 @@ class ResourceParamsBasedDownloadWorkManagerTest { addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "Patient-Id-001" } - } + }, ) addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "Patient-Id-002" } - } + }, ) } @@ -296,7 +296,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = Bundle().apply { @@ -306,7 +306,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { Bundle.BundleLinkComponent().apply { relation = "next" url = "next_url" - } + }, ) } @@ -321,7 +321,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { val downloadManager = ResourceParamsBasedDownloadWorkManager( emptyMap(), - NoOpResourceParamsBasedDownloadWorkManagerContext + NoOpResourceParamsBasedDownloadWorkManagerContext, ) val response = Bundle().apply { @@ -329,7 +329,7 @@ class ResourceParamsBasedDownloadWorkManagerTest { addEntry( Bundle.BundleEntryComponent().apply { resource = Patient().apply { id = "Patient-Id-001" } - } + }, ) } @@ -345,6 +345,7 @@ val NoOpResourceParamsBasedDownloadWorkManagerContext = class TestResourceParamsBasedDownloadWorkManagerContext(private val lastUpdatedTimeStamp: String?) : ResourceParamsBasedDownloadWorkManager.TimestampContext { override suspend fun saveLastUpdatedTimestamp(resourceType: ResourceType, timestamp: String?) {} + override suspend fun getLasUpdateTimestamp(resourceType: ResourceType): String? = lastUpdatedTimeStamp } diff --git a/engine/src/test/java/com/google/android/fhir/sync/upload/UploaderImplTest.kt b/engine/src/test/java/com/google/android/fhir/sync/upload/UploaderImplTest.kt index bc2da80244..f991679c6a 100644 --- a/engine/src/test/java/com/google/android/fhir/sync/upload/UploaderImplTest.kt +++ b/engine/src/test/java/com/google/android/fhir/sync/upload/UploaderImplTest.kt @@ -41,10 +41,7 @@ class UploaderImplTest { @Test fun `upload should start`() = runBlocking { - val result = - UploaderImpl(BundleDataSource { Bundle() }, SquashedChangesUploadWorkManager()) - .upload(localChanges) - .toList() + val result = Uploader(BundleDataSource { Bundle() }).upload(localChanges).toList() assertThat(result.first()).isInstanceOf(UploadState.Started::class.java) } @@ -52,9 +49,8 @@ class UploaderImplTest { @Test fun `upload should succeed if response is transaction response`() = runBlocking { val result = - UploaderImpl( + Uploader( BundleDataSource { Bundle().apply { type = Bundle.BundleType.TRANSACTIONRESPONSE } }, - SquashedChangesUploadWorkManager() ) .upload(localChanges) .toList() @@ -71,7 +67,7 @@ class UploaderImplTest { @Test fun `upload should fail if response is operation outcome with issue`() = runBlocking { val result = - UploaderImpl( + Uploader( BundleDataSource { OperationOutcome().apply { addIssue( @@ -79,11 +75,10 @@ class UploaderImplTest { severity = OperationOutcome.IssueSeverity.WARNING code = OperationOutcome.IssueType.CONFLICT diagnostics = "The resource has already been updated." - } + }, ) } }, - SquashedChangesUploadWorkManager() ) .upload(localChanges) .toList() @@ -95,9 +90,8 @@ class UploaderImplTest { @Test fun `upload should fail if response is empty operation outcome`() = runBlocking { val result = - UploaderImpl( + Uploader( BundleDataSource { OperationOutcome() }, - SquashedChangesUploadWorkManager(), ) .upload(localChanges) .toList() @@ -110,9 +104,8 @@ class UploaderImplTest { fun `upload should fail if response is neither transaction response nor operation outcome`() = runBlocking { val result = - UploaderImpl( + Uploader( BundleDataSource { Bundle().apply { type = Bundle.BundleType.SEARCHSET } }, - SquashedChangesUploadWorkManager(), ) .upload(localChanges) .toList() @@ -124,9 +117,8 @@ class UploaderImplTest { @Test fun `upload should fail if there is connection exception`() = runBlocking { val result = - UploaderImpl( + Uploader( BundleDataSource { throw ConnectException("Failed to connect to server.") }, - SquashedChangesUploadWorkManager() ) .upload(localChanges) .toList() @@ -153,14 +145,14 @@ class UploaderImplTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() - .apply { LocalChangeToken(listOf(1)) } + .apply { LocalChangeToken(listOf(1)) }, ) } } diff --git a/engine/src/test/java/com/google/android/fhir/sync/upload/patch/PerResourcePatchGeneratorTest.kt b/engine/src/test/java/com/google/android/fhir/sync/upload/patch/PerResourcePatchGeneratorTest.kt index 54eccc499b..78d365ec02 100644 --- a/engine/src/test/java/com/google/android/fhir/sync/upload/patch/PerResourcePatchGeneratorTest.kt +++ b/engine/src/test/java/com/google/android/fhir/sync/upload/patch/PerResourcePatchGeneratorTest.kt @@ -23,7 +23,6 @@ import com.google.android.fhir.LocalChangeToken import com.google.android.fhir.db.impl.dao.diff import com.google.android.fhir.db.impl.entities.LocalChangeEntity import com.google.android.fhir.logicalId -import com.google.android.fhir.sync.upload.SquashedChangesUploadWorkManager import com.google.android.fhir.testing.assertJsonArrayEqualsIgnoringOrder import com.google.android.fhir.testing.jsonParser import com.google.android.fhir.testing.readFromFile @@ -147,11 +146,11 @@ class PerResourcePatchGeneratorTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(1)) }, @@ -161,10 +160,10 @@ class PerResourcePatchGeneratorTest { resourceId = "Patient-001", type = LocalChangeEntity.Type.DELETE, payload = "", - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() - .apply { LocalChangeToken(listOf(2)) } + .apply { LocalChangeToken(listOf(2)) }, ) val patchToUpload = PerResourcePatchGenerator.generate(changes) @@ -190,11 +189,11 @@ class PerResourcePatchGeneratorTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(1)) }, @@ -212,7 +211,7 @@ class PerResourcePatchGeneratorTest { HumanName().apply { addGiven("Jane") family = "Doe" - } + }, ) }, Patient().apply { @@ -221,12 +220,12 @@ class PerResourcePatchGeneratorTest { HumanName().apply { addGiven("Janet") family = "Doe" - } + }, ) - } + }, ) .toString(), - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(1)) }, @@ -236,12 +235,12 @@ class PerResourcePatchGeneratorTest { resourceId = "Patient-001", type = LocalChangeEntity.Type.DELETE, payload = "", - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(3)) }, ) - val patchToUpload = SquashedChangesUploadWorkManager().generatePatches(changes) + val patchToUpload = PerResourcePatchGenerator.generate(changes) assertThat(patchToUpload).isEmpty() } @@ -293,7 +292,7 @@ class PerResourcePatchGeneratorTest { val patches = PerResourcePatchGenerator.generate( - listOf(updateLocalChange1, updateLocalChange2, deleteLocalChange) + listOf(updateLocalChange1, updateLocalChange2, deleteLocalChange), ) with(patches.single()) { @@ -315,7 +314,7 @@ class PerResourcePatchGeneratorTest { resourceId = "Patient-001", type = LocalChangeEntity.Type.DELETE, payload = "", - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(2)) }, @@ -325,7 +324,7 @@ class PerResourcePatchGeneratorTest { resourceId = "Patient-001", type = LocalChangeEntity.Type.UPDATE, payload = "", - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(3)) }, @@ -350,7 +349,7 @@ class PerResourcePatchGeneratorTest { resourceId = "Patient-001", type = LocalChangeEntity.Type.UPDATE, payload = "", - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(1)) }, @@ -369,11 +368,11 @@ class PerResourcePatchGeneratorTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ) .toLocalChange() .apply { LocalChangeToken(listOf(2)) }, @@ -391,7 +390,7 @@ class PerResourcePatchGeneratorTest { private fun createUpdateLocalChange( oldEntity: Resource, updatedResource: Resource, - currentChangeId: Long + currentChangeId: Long, ): LocalChange { val jsonDiff = diff(jsonParser, oldEntity, updatedResource) return LocalChange( @@ -401,7 +400,7 @@ class PerResourcePatchGeneratorTest { payload = jsonDiff.toString(), versionId = oldEntity.versionId, token = LocalChangeToken(listOf(currentChangeId + 1)), - timestamp = Instant.now() + timestamp = Instant.now(), ) } @@ -413,7 +412,7 @@ class PerResourcePatchGeneratorTest { payload = jsonParser.encodeResourceToString(entity), versionId = entity.versionId, token = LocalChangeToken(listOf(1L)), - timestamp = Instant.now() + timestamp = Instant.now(), ) } @@ -425,7 +424,7 @@ class PerResourcePatchGeneratorTest { payload = "", versionId = entity.versionId, token = LocalChangeToken(listOf(currentChangeId + 1)), - timestamp = Instant.now() + timestamp = Instant.now(), ) } } diff --git a/engine/src/test/java/com/google/android/fhir/sync/upload/request/TransactionBundleGeneratorTest.kt b/engine/src/test/java/com/google/android/fhir/sync/upload/request/TransactionBundleGeneratorTest.kt index 56e41e72f9..d21e30a4c6 100644 --- a/engine/src/test/java/com/google/android/fhir/sync/upload/request/TransactionBundleGeneratorTest.kt +++ b/engine/src/test/java/com/google/android/fhir/sync/upload/request/TransactionBundleGeneratorTest.kt @@ -61,11 +61,11 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ), Patch( resourceType = ResourceType.Patient.name, @@ -80,7 +80,7 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("Jane") family = "Doe" - } + }, ) }, Patient().apply { @@ -89,12 +89,12 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("Janet") family = "Doe" - } + }, ) - } + }, ) .toString(), - timestamp = Instant.now() + timestamp = Instant.now(), ), Patch( resourceType = ResourceType.Patient.name, @@ -108,11 +108,11 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("John") family = "Roe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ), ) val generator = TransactionBundleGenerator.Factory.getDefault() @@ -145,11 +145,11 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("John") family = "Doe" - } + }, ) - } + }, ), - timestamp = Instant.now() + timestamp = Instant.now(), ), Patch( resourceType = ResourceType.Patient.name, @@ -164,7 +164,7 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("Jane") family = "Doe" - } + }, ) }, Patient().apply { @@ -173,13 +173,13 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("Janet") family = "Doe" - } + }, ) - } + }, ) .toString(), versionId = "v-p002-01", - timestamp = Instant.now() + timestamp = Instant.now(), ), Patch( resourceType = ResourceType.Patient.name, @@ -193,12 +193,12 @@ class TransactionBundleGeneratorTest { HumanName().apply { addGiven("John") family = "Roe" - } + }, ) - } + }, ), versionId = "v-p003-01", - timestamp = Instant.now() + timestamp = Instant.now(), ), ) val generator = @@ -206,7 +206,7 @@ class TransactionBundleGeneratorTest { Bundle.HTTPVerb.PUT, Bundle.HTTPVerb.PATCH, 1, - true + true, ) val result = generator.generateUploadRequests(patches) @@ -235,8 +235,8 @@ class TransactionBundleGeneratorTest { type = Patch.Type.UPDATE, payload = "[]", versionId = "patient-002-version-1", - timestamp = Instant.now() - ) + timestamp = Instant.now(), + ), ) val generator = TransactionBundleGenerator.Factory.getDefault(useETagForUpload = false) val result = generator.generateUploadRequests(patches) @@ -255,8 +255,8 @@ class TransactionBundleGeneratorTest { type = Patch.Type.UPDATE, payload = "[]", versionId = "patient-002-version-1", - timestamp = Instant.now() - ) + timestamp = Instant.now(), + ), ) val generator = TransactionBundleGenerator.Factory.getDefault(useETagForUpload = true) val result = generator.generateUploadRequests(patches) @@ -276,7 +276,7 @@ class TransactionBundleGeneratorTest { type = Patch.Type.UPDATE, payload = "[]", versionId = "", - timestamp = Instant.now() + timestamp = Instant.now(), ), Patch( resourceType = ResourceType.Patient.name, @@ -284,7 +284,7 @@ class TransactionBundleGeneratorTest { type = Patch.Type.UPDATE, payload = "[]", versionId = null, - timestamp = Instant.now() + timestamp = Instant.now(), ), ) val generator = TransactionBundleGenerator.Factory.getDefault(useETagForUpload = true)