Skip to content

Commit 5c6310d

Browse files
authored
Simplify service test pattern (#4817)
* Make a simple test lifecycle registry, instead of creating empty testactivity * Remove use of `runBlockingTest`: according to Kotlin/kotlinx.coroutines#1222, if the test results in coroutines being finished on other threads, it's possible to receive "This job has not yet completed" exceptions, even though the jobs were properly terminated. Since we don't need the delay-skipping properties of `runBlockingTest`, I think it's OK to use `runBlocking`.
1 parent b5578ea commit 5c6310d

File tree

5 files changed

+48
-97
lines changed

5 files changed

+48
-97
lines changed

javatests/arcs/android/host/BUILD

+11-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ licenses(["notice"])
99

1010
package(default_visibility = ["//visibility:public"])
1111

12+
kt_android_library(
13+
name = "test_app",
14+
testonly = 1,
15+
srcs = ["TestActivity.kt"],
16+
manifest = ":AndroidManifest.xml",
17+
deps = [
18+
"//third_party/java/androidx/appcompat",
19+
],
20+
)
21+
1222
arcs_kt_android_test_suite(
1323
name = "host",
1424
srcs = glob(["*Test.kt"]),
@@ -17,6 +27,7 @@ arcs_kt_android_test_suite(
1727
deps = [
1828
":schemas",
1929
":services",
30+
":test_app",
2031
"//java/arcs/android/crdt",
2132
"//java/arcs/android/host",
2233
"//java/arcs/android/sdk/host",
@@ -42,7 +53,6 @@ arcs_kt_android_test_suite(
4253
"//java/arcs/sdk/android/storage",
4354
"//java/arcs/sdk/android/storage/service",
4455
"//java/arcs/sdk/android/storage/service/testutil",
45-
"//javatests/arcs/android/storage/handle:test_app",
4656
"//javatests/arcs/core/allocator:allocator-test-util",
4757
"//third_party/android/androidx_test/core",
4858
"//third_party/android/androidx_test/ext/junit",

javatests/arcs/android/storage/handle/AndroidHandleManagerTest.kt

+37-71
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package arcs.android.storage.handle
22

33
import android.app.Application
44
import androidx.lifecycle.Lifecycle
5+
import androidx.lifecycle.LifecycleOwner
6+
import androidx.lifecycle.LifecycleRegistry
57
import androidx.test.core.app.ActivityScenario
68
import androidx.test.core.app.ApplicationProvider
79
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -27,10 +29,7 @@ import arcs.sdk.android.storage.service.DefaultConnectionFactory
2729
import arcs.sdk.android.storage.service.testutil.TestBindingDelegate
2830
import com.google.common.truth.Truth.assertThat
2931
import com.nhaarman.mockitokotlin2.mock
30-
import kotlinx.coroutines.launch
3132
import kotlinx.coroutines.runBlocking
32-
import kotlinx.coroutines.test.TestCoroutineScope
33-
import kotlinx.coroutines.test.runBlockingTest
3433
import org.junit.Before
3534
import org.junit.Test
3635
import org.junit.runner.RunWith
@@ -39,11 +38,16 @@ import org.mockito.Mockito.verify
3938

4039
@Suppress("EXPERIMENTAL_API_USAGE")
4140
@RunWith(AndroidJUnit4::class)
42-
class AndroidHandleManagerTest {
41+
class AndroidHandleManagerTest : LifecycleOwner {
42+
private lateinit var lifecycle: LifecycleRegistry
43+
override fun getLifecycle() = lifecycle
44+
4345
private lateinit var app: Application
4446

4547
private val backingKey = RamDiskStorageKey("entities")
4648

49+
private lateinit var handleManager: HandleManager
50+
4751
val entity1 = RawEntity(
4852
"entity1",
4953
singletons = mapOf(
@@ -93,61 +97,35 @@ class AndroidHandleManagerTest {
9397
@Before
9498
fun setUp() {
9599
RamDisk.clear()
100+
lifecycle = LifecycleRegistry(this).apply {
101+
setCurrentState(Lifecycle.State.CREATED)
102+
setCurrentState(Lifecycle.State.STARTED)
103+
setCurrentState(Lifecycle.State.RESUMED)
104+
}
96105
app = ApplicationProvider.getApplicationContext()
97-
app.setTheme(R.style.Theme_AppCompat);
98106

99107
// Initialize WorkManager for instrumentation tests.
100108
WorkManagerTestInitHelper.initializeTestWorkManager(app)
101-
}
102-
103-
fun handleManagerTest(
104-
block: suspend TestCoroutineScope.(HandleManager) -> Unit
105-
) = runBlockingTest {
106-
val scenario = ActivityScenario.launch(TestActivity::class.java)
107-
108-
scenario.moveToState(Lifecycle.State.STARTED)
109-
110-
val activityJob = launch {
111-
scenario.onActivity { activity ->
112-
val hf = AndroidHandleManager(
113-
lifecycle = activity.lifecycle,
114-
context = activity,
115-
connectionFactory = DefaultConnectionFactory(activity, TestBindingDelegate(app)),
116-
coroutineContext = coroutineContext
117-
)
118-
runBlocking {
119-
this@runBlockingTest.block(hf)
120-
}
121-
scenario.close()
122-
}
123-
}
124-
125-
activityJob.join()
126-
}
127109

128-
@Test
129-
fun testCreateSingletonHandle() = handleManagerTest { hm ->
130-
val singletonHandle = hm.singletonHandle(singletonKey, schema)
131-
singletonHandle.store(entity1)
132-
133-
// Now read back from a different handle
134-
val readbackHandle = hm.singletonHandle(singletonKey, schema)
135-
val readBack = readbackHandle.fetch()
136-
assertThat(readBack).isEqualTo(entity1)
110+
handleManager = AndroidHandleManager(
111+
lifecycle = lifecycle,
112+
context = app,
113+
connectionFactory = DefaultConnectionFactory(app, TestBindingDelegate(app))
114+
)
137115
}
138116

139117
@Test
140-
fun testDereferencingFromSingletonEntity() = handleManagerTest { hm ->
141-
val singleton1Handle = hm.singletonHandle(singletonKey, schema)
142-
val singleton1Handle2 = hm.singletonHandle(singletonKey, schema)
118+
fun singleton_dereferenceEntity() = runBlocking {
119+
val singleton1Handle = handleManager.singletonHandle(singletonKey, schema)
120+
val singleton1Handle2 = handleManager.singletonHandle(singletonKey, schema)
143121
singleton1Handle.store(entity1)
144122

145123
// Create a second handle for the second entity, so we can store it.
146-
val singleton2Handle = hm.singletonHandle(
124+
val singleton2Handle = handleManager.singletonHandle(
147125
ReferenceModeStorageKey(backingKey, RamDiskStorageKey("entity2")),
148126
schema
149127
)
150-
val singleton2Handle2 = hm.singletonHandle(
128+
val singleton2Handle2 = handleManager.singletonHandle(
151129
ReferenceModeStorageKey(backingKey, RamDiskStorageKey("entity2")),
152130
schema
153131
)
@@ -171,40 +149,28 @@ class AndroidHandleManagerTest {
171149
}
172150

173151
@Test
174-
fun testCreateSetHandle() = handleManagerTest { hm ->
175-
val setHandle = hm.setHandle(setKey, schema)
176-
setHandle.store(entity1)
177-
setHandle.store(entity2)
178-
179-
// Now read back from a different handle
180-
val secondHandle = hm.setHandle(setKey, schema)
181-
val readBack = secondHandle.fetchAll()
182-
assertThat(readBack).containsExactly(entity1, entity2)
183-
}
184-
185-
@Test
186-
fun testDereferencingFromSetHandleEntity() = handleManagerTest { hm ->
187-
val setHandle = hm.setHandle(setKey, schema)
152+
fun set_dereferenceEntity () = runBlocking {
153+
val setHandle = handleManager.setHandle(setKey, schema)
188154
setHandle.store(entity1)
189155
setHandle.store(entity2)
190156

191-
val secondHandle = hm.setHandle(setKey, schema)
157+
val secondHandle = handleManager.setHandle(setKey, schema)
192158
secondHandle.fetchAll().also { assertThat(it).hasSize(2) }.forEach { entity ->
193159
val expectedBestFriend = if (entity.id == "entity1") entity2 else entity1
194160
val actualBestFriend = (entity.singletons["best_friend"] as Reference)
195-
.dereference()
161+
.dereference(coroutineContext)
196162
assertThat(actualBestFriend).isEqualTo(expectedBestFriend)
197163
}
198164
}
199165

200166
private fun testMapForKey(key: StorageKey) = VersionMap(key.toKeyString() to 1)
201167

202168
@Test
203-
fun testSetHandleOnUpdate() = handleManagerTest { hm ->
169+
fun set_onHandleUpdate() = runBlocking<Unit> {
204170
val testCallback1 = mock<SetCallbacks<RawEntity>>()
205171
val testCallback2 = mock<SetCallbacks<RawEntity>>()
206-
val firstHandle = hm.setHandle(setKey, schema, testCallback1)
207-
val secondHandle = hm.setHandle(setKey, schema, testCallback2)
172+
val firstHandle = handleManager.setHandle(setKey, schema, testCallback1)
173+
val secondHandle = handleManager.setHandle(setKey, schema, testCallback2)
208174

209175
val expectedAdd = CrdtSet.Operation.Add(
210176
setKey.toKeyString(),
@@ -226,11 +192,11 @@ class AndroidHandleManagerTest {
226192
}
227193

228194
@Test
229-
fun testSingletonHandleOnUpdate() = handleManagerTest { hm ->
195+
fun singleton_OnHandleUpdate() = runBlocking<Unit> {
230196
val testCallback1 = mock<SingletonCallbacks<RawEntity>>()
231197
val testCallback2 = mock<SingletonCallbacks<RawEntity>>()
232-
val firstHandle = hm.singletonHandle(singletonKey, schema, testCallback1)
233-
val secondHandle = hm.singletonHandle(singletonKey, schema, testCallback2)
198+
val firstHandle = handleManager.singletonHandle(singletonKey, schema, testCallback1)
199+
val secondHandle = handleManager.singletonHandle(singletonKey, schema, testCallback2)
234200
secondHandle.store(entity1)
235201
val expectedAdd = CrdtSingleton.Operation.Update(
236202
singletonKey.toKeyString(),
@@ -250,18 +216,18 @@ class AndroidHandleManagerTest {
250216
}
251217

252218
@Test
253-
fun testSetSyncOnRegister() = handleManagerTest { hm ->
219+
fun set_syncOnRegister() = runBlocking<Unit> {
254220
val testCallback = mock<SetCallbacks<RawEntity>>()
255-
val firstHandle = hm.setHandle(setKey, schema, testCallback)
221+
val firstHandle = handleManager.setHandle(setKey, schema, testCallback)
256222
verify(testCallback, times(1)).onSync(firstHandle)
257223
firstHandle.fetchAll()
258224
verify(testCallback, times(1)).onSync(firstHandle)
259225
}
260226

261227
@Test
262-
fun testSingletonSyncOnRegister() = handleManagerTest { hm ->
228+
fun singleton_syncOnRegister() = runBlocking<Unit> {
263229
val testCallback = mock<SingletonCallbacks<RawEntity>>()
264-
val firstHandle = hm.singletonHandle(setKey, schema, testCallback)
230+
val firstHandle = handleManager.singletonHandle(setKey, schema, testCallback)
265231
verify(testCallback, times(1)).onSync(firstHandle)
266232
firstHandle.fetch()
267233
verify(testCallback, times(1)).onSync(firstHandle)

javatests/arcs/android/storage/handle/AndroidManifest.xml

-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@
1616

1717
<application>
1818
<service android:name="arcs.sdk.android.service.StorageService" android:exported="false"/>
19-
<activity android:name="arcs.android.storage.handle.TestActivity" >
20-
<intent-filter>
21-
<action android:name="android.intent.action.MAIN"/>
22-
<category android:name="android.intent.category.LAUNCHER"/>
23-
</intent-filter>
24-
</activity>
2519
</application>
2620

2721
</manifest>

javatests/arcs/android/storage/handle/BUILD

-14
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,18 @@ load(
22
"//third_party/java/arcs/build_defs:build_defs.bzl",
33
"arcs_kt_android_test_suite",
44
)
5-
load("//tools/build_defs/kotlin:rules.bzl", "kt_android_library")
65

76
licenses(["notice"])
87

98
package(default_visibility = ["//visibility:public"])
109

11-
kt_android_library(
12-
name = "test_app",
13-
testonly = 1,
14-
srcs = ["TestActivity.kt"],
15-
manifest = ":AndroidManifest.xml",
16-
deps = [
17-
"//third_party/java/androidx/appcompat",
18-
],
19-
)
20-
2110
arcs_kt_android_test_suite(
2211
name = "handle",
2312
size = "medium",
2413
srcs = glob(["*Test.kt"]),
2514
manifest = "AndroidManifest.xml",
2615
package = "arcs.android.storage.handle",
2716
deps = [
28-
":test_app",
2917
"//java/arcs/android/crdt",
3018
"//java/arcs/android/storage",
3119
"//java/arcs/android/storage/handle",
@@ -45,14 +33,12 @@ arcs_kt_android_test_suite(
4533
"//java/arcs/sdk/android/storage/service/testutil",
4634
"//third_party/android/androidx_test/core",
4735
"//third_party/android/androidx_test/ext/junit",
48-
"//third_party/java/androidx/appcompat",
4936
"//third_party/java/androidx/work:testing",
5037
"//third_party/java/junit:junit-android",
5138
"//third_party/java/mockito:mockito-android",
5239
"//third_party/java/robolectric",
5340
"//third_party/java/truth:truth-android",
5441
"//third_party/kotlin/kotlinx_coroutines",
55-
"//third_party/kotlin/kotlinx_coroutines:kotlinx_coroutines_test",
5642
"//third_party/kotlin/mockito_kotlin:mockito_kotlin-android",
5743
],
5844
)

javatests/arcs/android/storage/handle/TestActivity.kt

-5
This file was deleted.

0 commit comments

Comments
 (0)