-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create StorageServiceManagerEndpoint to bind to storage service manag…
…er and perform deletes for foreign hard references. Use it in the integration test to demonstrate how an actual client can perform these deletes e2e. PiperOrigin-RevId: 349617029
- Loading branch information
Showing
5 changed files
with
216 additions
and
8 deletions.
There are no files selected for viewing
This file contains 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
64 changes: 64 additions & 0 deletions
64
java/arcs/sdk/android/storage/service/StorageServiceManagerEndpoint.kt
This file contains 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,64 @@ | ||
package arcs.sdk.android.storage.service | ||
|
||
import arcs.android.storage.service.IHardReferencesRemovalCallback | ||
import arcs.android.storage.service.IStorageServiceManager | ||
import arcs.android.storage.service.StorageServiceManager | ||
import arcs.android.storage.service.suspendForHardReferencesCallback | ||
import arcs.core.data.Schema | ||
import arcs.core.storage.keys.ForeignStorageKey | ||
import kotlinx.coroutines.CoroutineScope | ||
|
||
/** | ||
* A [StorageServiceManagerEndpoint] can be used to bind to an Android [StorageServiceManager] and | ||
* call its callback-style methods. | ||
*/ | ||
class StorageServiceManagerEndpoint( | ||
private val bindHelper: BindHelper, | ||
private val scope: CoroutineScope, | ||
private val storageServiceClass: Class<*> = StorageService::class.java | ||
) { | ||
|
||
/** | ||
* Triggers a hard reference deletions for foreign hard references with the given Schema namespace | ||
* and ID. | ||
*/ | ||
suspend fun triggerForeignHardReferenceDeletion(namespace: Schema, id: String): Long { | ||
return runOnStorageServiceManager { manager, result -> | ||
manager.triggerHardReferenceDeletion(stringForeignStorageKey(namespace), id, result) | ||
} | ||
} | ||
|
||
/** | ||
* Triggers a hard reference reconciliation for foreign hard references with the given Schema | ||
* namespace and ID. | ||
*/ | ||
suspend fun reconcileForeignHardReference(namespace: Schema, idsToRetain: Set<String>): Long { | ||
return runOnStorageServiceManager { manager, result -> | ||
manager.reconcileHardReferences( | ||
stringForeignStorageKey(namespace), | ||
idsToRetain.toList(), | ||
result | ||
) | ||
} | ||
} | ||
|
||
private suspend fun runOnStorageServiceManager( | ||
block: (IStorageServiceManager, IHardReferencesRemovalCallback) -> Unit | ||
): Long { | ||
val intent = StorageServiceIntentHelpers.managerIntent(bindHelper.context, storageServiceClass) | ||
val boundService = bindHelper.bindForIntent( | ||
intent, | ||
scope, | ||
IStorageServiceManager.Stub::asInterface | ||
) | ||
try { | ||
return suspendForHardReferencesCallback { resultCallback -> | ||
block(boundService.service, resultCallback) | ||
} | ||
} finally { | ||
boundService.disconnect() | ||
} | ||
} | ||
|
||
private fun stringForeignStorageKey(namespace: Schema) = ForeignStorageKey(namespace).toString() | ||
} |
This file contains 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 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
137 changes: 137 additions & 0 deletions
137
javatests/arcs/sdk/android/storage/service/StorageServiceManagerEndpointTest.kt
This file contains 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,137 @@ | ||
package arcs.sdk.android.storage.service | ||
|
||
import android.app.Application | ||
import androidx.test.core.app.ApplicationProvider | ||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.work.testing.WorkManagerTestInitHelper | ||
import arcs.core.data.Schema | ||
import arcs.core.data.SchemaFields | ||
import arcs.core.data.SchemaName | ||
import arcs.core.storage.api.DriverAndKeyConfigurator | ||
import arcs.core.storage.keys.ForeignStorageKey | ||
import arcs.jvm.storage.database.testutil.FakeDatabase | ||
import arcs.jvm.storage.database.testutil.FakeDatabaseManager | ||
import arcs.sdk.android.storage.service.testutil.TestBindHelper | ||
import com.google.common.truth.Truth.assertThat | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.runBlocking | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
@OptIn(ExperimentalCoroutinesApi::class) | ||
@RunWith(AndroidJUnit4::class) | ||
class StorageServiceManagerEndpointTest { | ||
|
||
private lateinit var app: Application | ||
private val SCHEMA_NAME = "name" | ||
private val SCHEMA_NAME2 = "name2" | ||
private val schema = Schema( | ||
setOf(SchemaName(SCHEMA_NAME)), | ||
SchemaFields.EMPTY, | ||
"hash" | ||
) | ||
private val schema2 = Schema( | ||
setOf(SchemaName(SCHEMA_NAME2)), | ||
SchemaFields.EMPTY, | ||
"hash" | ||
) | ||
private val dbManager = FakeDatabaseManager() | ||
private lateinit var database: FakeDatabase | ||
|
||
@Before | ||
fun setUp() = runBlocking { | ||
app = ApplicationProvider.getApplicationContext() | ||
WorkManagerTestInitHelper.initializeTestWorkManager(app) | ||
// Install fake dbManager and create one database. | ||
DriverAndKeyConfigurator.configure(dbManager) | ||
database = dbManager.getDatabase("db", true) as FakeDatabase | ||
} | ||
|
||
@Test | ||
fun triggerForeignHardReferenceDeletion_propagatesToDatabase() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
|
||
endpoint.triggerForeignHardReferenceDeletion(schema, "id") | ||
|
||
assertThat(database.hardReferenceDeletes).containsExactly( | ||
ForeignStorageKey(SCHEMA_NAME) to "id" | ||
) | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
|
||
@Test | ||
fun triggerForeignHardReferenceDeletion_sequenceOfCalls() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
assertThat(database.hardReferenceDeletes).isEmpty() | ||
|
||
endpoint.triggerForeignHardReferenceDeletion(schema, "id") | ||
endpoint.triggerForeignHardReferenceDeletion(schema, "id2") | ||
endpoint.triggerForeignHardReferenceDeletion(schema2, "id") | ||
endpoint.triggerForeignHardReferenceDeletion(schema, "id") | ||
|
||
assertThat(database.hardReferenceDeletes).containsExactly( | ||
ForeignStorageKey(SCHEMA_NAME) to "id", | ||
ForeignStorageKey(SCHEMA_NAME) to "id2", | ||
ForeignStorageKey(SCHEMA_NAME2) to "id", | ||
ForeignStorageKey(SCHEMA_NAME) to "id" | ||
) | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
|
||
@Test | ||
fun reconcileForeignHardReference_deletesOne() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
database.allHardReferenceIds.add("id1") | ||
|
||
endpoint.reconcileForeignHardReference(schema, setOf("id2")) | ||
|
||
assertThat(database.hardReferenceDeletes).containsExactly( | ||
ForeignStorageKey(SCHEMA_NAME) to "id1" | ||
) | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
|
||
@Test | ||
fun reconcileForeignHardReference_partialOvelap() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
database.allHardReferenceIds.addAll(listOf("id1", "id2")) | ||
|
||
endpoint.reconcileForeignHardReference(schema, setOf("id2")) | ||
|
||
assertThat(database.hardReferenceDeletes).containsExactly( | ||
ForeignStorageKey(SCHEMA_NAME) to "id1" | ||
) | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
|
||
@Test | ||
fun reconcileForeignHardReference_deletesNone() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
database.allHardReferenceIds.add("id1") | ||
|
||
endpoint.reconcileForeignHardReference(schema, setOf("id1")) | ||
|
||
assertThat(database.hardReferenceDeletes).isEmpty() | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
|
||
@Test | ||
fun reconcileForeignHardReference_emptyValidSet() = runBlocking { | ||
val testBindHelper = TestBindHelper(app) | ||
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking) | ||
database.allHardReferenceIds.add("id1") | ||
|
||
endpoint.reconcileForeignHardReference(schema, emptySet()) | ||
|
||
assertThat(database.hardReferenceDeletes).containsExactly( | ||
ForeignStorageKey(SCHEMA_NAME) to "id1" | ||
) | ||
assertThat(testBindHelper.activeBindings()).isEqualTo(0) | ||
} | ||
} |