Skip to content

Commit

Permalink
create StorageServiceManagerEndpoint to bind to storage service manag…
Browse files Browse the repository at this point in the history
…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
galganif authored and arcs-c3po committed Dec 31, 2020
1 parent ae7ba2b commit ab7f43c
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 8 deletions.
3 changes: 3 additions & 0 deletions java/arcs/sdk/android/storage/service/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ arcs_kt_android_library(
"//java/arcs/android/storage",
"//java/arcs/android/storage/database",
"//java/arcs/android/storage/service",
"//java/arcs/android/storage/service:aidl",
"//java/arcs/android/storage/ttl",
"//java/arcs/android/util",
"//java/arcs/core/crdt",
"//java/arcs/core/data",
"//java/arcs/core/storage",
"//java/arcs/core/storage/database",
"//java/arcs/core/storage/driver:driver_providers",
"//java/arcs/core/storage/keys",
"//java/arcs/core/util",
"//java/arcs/core/util/performance",
"//java/arcs/core/util/statistics",
Expand Down
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()
}
17 changes: 9 additions & 8 deletions javatests/arcs/android/integration/IntegrationEnvironment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ import arcs.core.host.SchedulerProvider
import arcs.core.host.SimpleSchedulerProvider
import arcs.core.storage.StorageEndpointManager
import arcs.core.storage.api.DriverAndKeyConfigurator
import arcs.core.storage.database.HardReferenceManager
import arcs.core.storage.driver.RamDisk
import arcs.core.storage.keys.ForeignStorageKey
import arcs.core.util.TaggedLog
import arcs.jvm.host.ExplicitHostRegistry
import arcs.jvm.util.JvmTime
import arcs.sdk.Particle
import arcs.sdk.android.storage.AndroidStorageServiceEndpointManager
import arcs.sdk.android.storage.service.StorageServiceManagerEndpoint
import arcs.sdk.android.storage.service.testutil.TestBindHelper
import kotlin.coroutines.CoroutineContext
import kotlin.time.Duration
Expand Down Expand Up @@ -306,15 +305,17 @@ class IntegrationEnvironment(
}

suspend fun triggerHardReferenceDelete(namespace: Schema, id: String): Long {
// TODO(b/175513193): once this method is part of the StorageServiceManager interface, we should
// switch this method to use that.
return HardReferenceManager(dbManager).triggerDatabaseDeletion(ForeignStorageKey(namespace), id)
return StorageServiceManagerEndpoint(
TestBindHelper(ApplicationProvider.getApplicationContext()),
testScope
).triggerForeignHardReferenceDeletion(namespace, id)
}

suspend fun reconcileHardReference(namespace: Schema, fullSet: Set<String>): Long {
// TODO(b/175513193): once this method is part of the StorageServiceManager interface, we should
// switch this method to use that.
return HardReferenceManager(dbManager).reconcile(ForeignStorageKey(namespace), fullSet)
return StorageServiceManagerEndpoint(
TestBindHelper(ApplicationProvider.getApplicationContext()),
testScope
).reconcileForeignHardReference(namespace, fullSet)
}

suspend fun waitForIdle(arc: Arc) {
Expand Down
3 changes: 3 additions & 0 deletions javatests/arcs/sdk/android/storage/service/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ arcs_kt_android_test_suite(
"//java/arcs/android/storage/ttl",
"//java/arcs/core/crdt",
"//java/arcs/core/data",
"//java/arcs/core/data:schema_fields",
"//java/arcs/core/storage",
"//java/arcs/core/storage/api",
"//java/arcs/core/storage/keys",
"//java/arcs/core/testutil",
"//java/arcs/jvm/storage/database/testutil",
"//java/arcs/sdk/android/storage",
"//java/arcs/sdk/android/storage/service",
"//java/arcs/sdk/android/storage/service/testutil",
"//third_party/android/androidx_test/core",
"//third_party/android/androidx_test/ext/junit",
"//third_party/java/androidx/work:testing",
Expand Down
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)
}
}

0 comments on commit ab7f43c

Please sign in to comment.