Skip to content

Commit 293a21d

Browse files
authored
Add APIs to decide whether client wants to re-use test matrices or not (#65)
* WIP provide APIs to skip cached test matrices * use suspend function for cached test matrix filter * fix ktlint * add filter to the pair method for consistency
1 parent 4c9ab1c commit 293a21d

File tree

9 files changed

+68
-17
lines changed

9 files changed

+68
-17
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.androidx.ci.testRunner
2+
3+
import dev.androidx.ci.generated.ftl.TestMatrix
4+
5+
/**
6+
* Filter interface that is used to decide whether a TestMatrix result can be re-used.
7+
*
8+
* Return `true` if the cached TestMatrix can be re-used, false otherwise
9+
*/
10+
typealias CachedTestMatrixFilter = suspend (TestMatrix) -> Boolean

AndroidXCI/lib/src/main/kotlin/dev/androidx/ci/testRunner/FirebaseTestLabController.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ internal class FirebaseTestLabController(
108108
sharding: ShardingOption?,
109109
deviceSetup: DeviceSetup?,
110110
devicePicker: DevicePicker? = null,
111-
pullScreenshots: Boolean = false
111+
pullScreenshots: Boolean = false,
112+
cachedTestMatrixFilter: CachedTestMatrixFilter,
112113
): List<TestMatrix> {
113114
val devices = (devicePicker ?: defaultDevicePicker).pickDevices()
114115
logger.info {
@@ -123,7 +124,8 @@ internal class FirebaseTestLabController(
123124
clientInfo = clientInfo,
124125
sharding = sharding,
125126
deviceSetup = deviceSetup,
126-
pullScreenshots = pullScreenshots
127+
pullScreenshots = pullScreenshots,
128+
cachedTestMatrixFilter = cachedTestMatrixFilter
127129
)
128130
}
129131
}
@@ -208,7 +210,8 @@ internal class FirebaseTestLabController(
208210
suspend fun pairAndStartTests(
209211
apks: List<UploadedApk>,
210212
placeholderApk: UploadedApk,
211-
devicePicker: DevicePicker? = null
213+
devicePicker: DevicePicker? = null,
214+
cachedTestMatrixFilter: CachedTestMatrixFilter,
212215
): List<TestMatrix> {
213216
val pairs = apks.mapNotNull { uploadedApk ->
214217
val isTestApkWithLegacySuffix = uploadedApk.apkInfo.filePath.endsWith(TEST_APK_SUFFIX_LEGACY)
@@ -239,7 +242,8 @@ internal class FirebaseTestLabController(
239242
testApk = it.second,
240243
sharding = null,
241244
deviceSetup = null,
242-
devicePicker = devicePicker
245+
devicePicker = devicePicker,
246+
cachedTestMatrixFilter = cachedTestMatrixFilter,
243247
)
244248
}
245249
}

AndroidXCI/lib/src/main/kotlin/dev/androidx/ci/testRunner/TestMatrixStore.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ internal class TestMatrixStore(
6767
clientInfo: ClientInfo?,
6868
sharding: ShardingOption?,
6969
deviceSetup: DeviceSetup?,
70-
pullScreenshots: Boolean = false
70+
pullScreenshots: Boolean = false,
71+
cachedTestMatrixFilter: CachedTestMatrixFilter = { true },
7172
): TestMatrix {
7273

7374
val testRunId = TestRun.createId(
@@ -91,12 +92,16 @@ internal class TestMatrixStore(
9192
logger.warn {
9293
"Skipping cache for ${it.testMatrixId} because its state is $state"
9394
}
95+
} else if (!cachedTestMatrixFilter(it)) {
96+
logger.info {
97+
"Not re-using cached matrix due to filter"
98+
}
9499
} else {
95100
return it
96101
}
97102
}
98103
logger.trace {
99-
"No test run history for $testRunId, creating a new one."
104+
"No test run history for $testRunId or cached TestMatrix is rejected, creating a new one."
100105
}
101106
val newTestMatrix = firebaseTestLabApi.createTestMatrix(
102107
projectId = firebaseProjectId,

AndroidXCI/lib/src/main/kotlin/dev/androidx/ci/testRunner/TestRunnerService.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ interface TestRunnerService {
7878
sharding: ShardingOption?,
7979
deviceSetup: DeviceSetup?,
8080
devicePicker: (TestEnvironmentCatalog) -> List<AndroidDevice>,
81-
pullScreenshots: Boolean = false
81+
pullScreenshots: Boolean = false,
82+
cachedTestMatrixFilter: CachedTestMatrixFilter = { true },
8283
): ScheduleTestsResponse
8384

8485
/**

AndroidXCI/lib/src/main/kotlin/dev/androidx/ci/testRunner/TestRunnerServiceImpl.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ internal class TestRunnerServiceImpl internal constructor(
9898
sharding: ShardingOption?,
9999
deviceSetup: DeviceSetup?,
100100
devicePicker: (TestEnvironmentCatalog) -> List<AndroidDevice>,
101-
pullScreenshots: Boolean
101+
pullScreenshots: Boolean,
102+
cachedTestMatrixFilter: CachedTestMatrixFilter,
102103
): TestRunnerService.ScheduleTestsResponse {
103104
val testMatrices = testLabController.submitTests(
104105
appApk = appApk ?: apkStore.getPlaceholderApk(),
@@ -107,7 +108,8 @@ internal class TestRunnerServiceImpl internal constructor(
107108
sharding = sharding,
108109
deviceSetup = deviceSetup,
109110
devicePicker = devicePicker,
110-
pullScreenshots = pullScreenshots
111+
pullScreenshots = pullScreenshots,
112+
cachedTestMatrixFilter = cachedTestMatrixFilter
111113
)
112114
return TestRunnerService.ScheduleTestsResponse.create(
113115
testMatrices

AndroidXCI/lib/src/main/kotlin/dev/androidx/ci/testRunner/TestScheduler.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ internal sealed interface TestScheduler {
5151
private val githubApi: GithubApi,
5252
private val firebaseTestLabController: FirebaseTestLabController,
5353
private val apkStore: ApkStore,
54-
private val devicePicker: DevicePicker?
54+
private val devicePicker: DevicePicker?,
5555
) : TestScheduler {
5656
override suspend fun enqueueTests(
5757
artifact: ArtifactsResponse.Artifact
@@ -61,7 +61,8 @@ internal sealed interface TestScheduler {
6161
return firebaseTestLabController.pairAndStartTests(
6262
apks = apks,
6363
placeholderApk = apkStore.getPlaceholderApk(),
64-
devicePicker = devicePicker
64+
devicePicker = devicePicker,
65+
cachedTestMatrixFilter = { true }
6566
)
6667
}
6768

@@ -98,13 +99,13 @@ internal sealed interface TestScheduler {
9899
githubApi: GithubApi,
99100
firebaseTestLabController: FirebaseTestLabController,
100101
apkStore: ApkStore,
101-
devicePicker: DevicePicker?
102+
devicePicker: DevicePicker?,
102103
): TestScheduler {
103104
return PairAndRunAllApks(
104105
githubApi = githubApi,
105106
firebaseTestLabController = firebaseTestLabController,
106107
apkStore = apkStore,
107-
devicePicker = devicePicker
108+
devicePicker = devicePicker,
108109
)
109110
}
110111
}
@@ -223,7 +224,8 @@ internal sealed interface TestScheduler {
223224
instrumentationArguments = instrumentationArguments
224225
),
225226
devicePicker = devicePicker,
226-
pullScreenshots = false
227+
pullScreenshots = false,
228+
cachedTestMatrixFilter = { true }
227229
)
228230
}
229231

@@ -324,7 +326,7 @@ internal sealed interface TestScheduler {
324326
githubApi: GithubApi,
325327
firebaseTestLabController: FirebaseTestLabController,
326328
apkStore: ApkStore,
327-
devicePicker: DevicePicker?
329+
devicePicker: DevicePicker?,
328330
): TestScheduler
329331
}
330332
companion object {

AndroidXCI/lib/src/test/kotlin/dev/androidx/ci/testRunner/FirebaseTestLabControllerTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ internal class FirebaseTestLabControllerTest {
6464
)
6565
val testMatrices = firebaseTestLabApi.pairAndStartTests(
6666
apks = apks,
67-
placeholderApk = placeholderApk
67+
placeholderApk = placeholderApk,
68+
cachedTestMatrixFilter = { true }
6869
)
6970
assertThat(testMatrices).hasSize(4)
7071
val appApkPaths = testMatrices.mapNotNull {

AndroidXCI/lib/src/test/kotlin/dev/androidx/ci/testRunner/TestMatrixStoreTest.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ internal class TestMatrixStoreTest {
105105
environmentMatrix = envMatrix1,
106106
clientInfo = clientInfo,
107107
deviceSetup = deviceSetup,
108-
sharding = sharding
108+
sharding = sharding,
109+
cachedTestMatrixFilter = { true },
109110
)
110111

111112
assertThat(firebaseTestLabApi.getTestMatrices()).hasSize(1)
@@ -219,6 +220,17 @@ internal class TestMatrixStoreTest {
219220
sharding = sharding
220221
)
221222
assertThat(reUploadedAfterDeletion.testMatrixId).isNotEqualTo(testMatrix.testMatrixId)
223+
val dontReuse = store.getOrCreateTestMatrix(
224+
appApk = appApk,
225+
testApk = testApk,
226+
environmentMatrix = envMatrix1,
227+
clientInfo = clientInfo,
228+
deviceSetup = deviceSetup,
229+
sharding = sharding,
230+
cachedTestMatrixFilter = { false }
231+
)
232+
assertThat(dontReuse.testMatrixId)
233+
.isNotIn(listOf(testMatrix.testMatrixId, reUploadedAfterDeletion.testMatrixId))
222234
}
223235

224236
@Test

AndroidXCI/lib/src/test/kotlin/dev/androidx/ci/testRunner/TestRunnerServiceImplTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ class TestRunnerServiceImplTest {
140140
assertThat(
141141
sameRequest.testMatrices
142142
).containsExactlyElementsIn(result.testMatrices)
143+
// reject apk, should be a new one
144+
val noReuse = subject.scheduleTests(
145+
testApk = upload1,
146+
appApk = null,
147+
clientInfo = null,
148+
sharding = null,
149+
deviceSetup = null,
150+
devicePicker = devicePicker,
151+
cachedTestMatrixFilter = { false }
152+
)
153+
assertThat(
154+
noReuse.testMatrices
155+
).containsNoneIn(result.testMatrices)
156+
143157
// change client info, it should result in new test matrices
144158
val clientInfo = ClientInfo(
145159
name = "test",

0 commit comments

Comments
 (0)