1
package com.avito.instrumentation
3
import com.avito.android.build_verdict.BuildVerdictTask
4
import com.avito.android.build_verdict.span.SpannedString
5
import com.avito.android.build_verdict.span.SpannedString.Companion.link
6
import com.avito.android.build_verdict.span.SpannedString.Companion.multiline
7
import com.avito.android.getApk
8
import com.avito.android.getApkOrThrow
9
import com.avito.android.stats.StatsDConfig
10
import com.avito.gradle.worker.inMemoryWork
11
import com.avito.instrumentation.configuration.Experiments
12
import com.avito.instrumentation.internal.RunnerInputDumper
13
import com.avito.logger.GradleLoggerPlugin
14
import com.avito.runner.config.InstrumentationConfigurationCacheableData
15
import com.avito.runner.config.InstrumentationConfigurationDataFactory
16
import com.avito.runner.config.RunnerInputParams
17
import com.avito.runner.config.RunnerReportConfig
18
import com.avito.runner.finalizer.verdict.InstrumentationTestsTaskVerdict
19
import com.avito.runner.model.InstrumentationParameters
20
import com.avito.runner.scheduler.runner.model.ExecutionParameters
21
import com.avito.runner.scheduler.runner.scheduler.TestSchedulerFactoryProvider
22
import com.avito.runner.scheduler.runner.scheduler.TestSchedulerResult
23
import com.avito.runner.scheduler.suite.filter.ImpactAnalysisResult
24
import com.avito.test.model.DeviceName
25
import com.avito.utils.BuildFailer
26
import com.avito.utils.gradle.KubernetesCredentials
27
import com.google.gson.Gson
28
import com.google.gson.GsonBuilder
29
import org.gradle.api.DefaultTask
30
import org.gradle.api.file.DirectoryProperty
31
import org.gradle.api.file.RegularFileProperty
32
import org.gradle.api.model.ObjectFactory
33
import org.gradle.api.provider.MapProperty
34
import org.gradle.api.provider.Property
35
import org.gradle.api.provider.SetProperty
36
import org.gradle.api.tasks.CacheableTask
37
import org.gradle.api.tasks.Input
38
import org.gradle.api.tasks.InputDirectory
39
import org.gradle.api.tasks.InputFile
40
import org.gradle.api.tasks.Internal
41
import org.gradle.api.tasks.Optional
42
import org.gradle.api.tasks.OutputDirectory
43
import org.gradle.api.tasks.PathSensitive
44
import org.gradle.api.tasks.PathSensitivity
45
import org.gradle.api.tasks.TaskAction
46
import org.gradle.workers.WorkerExecutor
47
import java.time.Duration
48
import javax.inject.Inject
51
public abstract class InstrumentationTestsTask @Inject constructor(
52
objects: ObjectFactory,
53
private val workerExecutor: WorkerExecutor
54
) : DefaultTask(), BuildVerdictTask {
58
@get:PathSensitive(PathSensitivity.RELATIVE)
59
public abstract val application: DirectoryProperty
63
public abstract val applicationPackageName: Property<String>
66
@get:PathSensitive(PathSensitivity.RELATIVE)
67
public abstract val testApplication: DirectoryProperty
70
public abstract val testApplicationPackageName: Property<String>
74
public abstract val testArtifactsDirectoryPackageName: Property<String>
77
public abstract val runOnlyChangedTests: Property<Boolean>
81
@get:PathSensitive(PathSensitivity.RELATIVE)
82
public abstract val changedTests: RegularFileProperty
86
@get:PathSensitive(PathSensitivity.RELATIVE)
87
public abstract val applicationProguardMapping: RegularFileProperty
91
@get:PathSensitive(PathSensitivity.RELATIVE)
92
public abstract val testProguardMapping: RegularFileProperty
95
public abstract val buildId: Property<String>
98
public abstract val buildType: Property<String>
101
public abstract val gitCommit: Property<String>
104
public abstract val gitBranch: Property<String>
107
public abstract val experiments: Property<Experiments>
110
public abstract val suppressFailure: Property<Boolean>
113
public abstract val suppressFlaky: Property<Boolean>
116
public abstract val instrumentationConfiguration: Property<InstrumentationConfigurationCacheableData>
119
public abstract val mergedInstrumentationParams: MapProperty<String, String>
122
public abstract val reportConfig: Property<RunnerReportConfig>
125
public abstract val targetInstrumentationParams: MapProperty<DeviceName, InstrumentationParameters>
128
public abstract val instrumentationRunner: Property<String>
131
public abstract val logcatTags: SetProperty<String>
134
public abstract val enableDeviceDebug: Property<Boolean>
137
public abstract val gradleTestKitRun: Property<Boolean>
140
public abstract val projectName: Property<String>
143
public abstract val kubernetesCredentials: Property<KubernetesCredentials>
146
public abstract val kubernetesHttpTries: Property<Int>
149
public abstract val buildFailer: Property<BuildFailer>
152
public abstract val statsDConfig: Property<StatsDConfig>
155
public abstract val adbPullTimeout: Property<Duration>
158
public abstract val output: DirectoryProperty
162
public abstract val macrobenchmarkOutputDirectory: DirectoryProperty
164
private val verdictFile = objects.fileProperty().convention(output.file("verdict.json"))
167
override val verdict: SpannedString
169
val verdictFile = verdictFile.asFile.get()
170
return if (verdictFile.exists()) {
171
val gson: Gson = GsonBuilder().setPrettyPrinting().create()
172
val verdictRaw = verdictFile.reader()
173
val verdict = gson.fromJson(verdictRaw, InstrumentationTestsTaskVerdict::class.java)
175
lines = listOf(link(verdict.reportUrl, verdict.title)) +
176
verdict.problemTests.map { test ->
177
link(test.testUrl, test.title)
181
SpannedString("Can't find verdict file $verdictFile")
186
public fun doWork() {
187
val configuration = instrumentationConfiguration.get()
188
val experiments = experiments.get()
189
val output = output.get().asFile
191
val testRunParams = RunnerInputParams(
192
mainApk = requireNotNull(application.orNull?.getApk()) {
193
"Unable to create valid RunnerInputParams - mainApk cannot be null."
195
testApk = testApplication.get().getApkOrThrow(),
196
instrumentationConfiguration = InstrumentationConfigurationDataFactory(
197
instrumentationConfigurationCacheableData = configuration,
198
mergedInstrumentationParams = InstrumentationParameters(mergedInstrumentationParams.get()),
199
reportConfig = reportConfig.get(),
200
targetInstrumentationParams = targetInstrumentationParams.get(),
202
executionParameters = ExecutionParameters(
203
applicationPackageName.get(),
204
testApplicationPackageName.get(),
205
testArtifactsDirectoryPackageName.getOrElse(applicationPackageName.get()),
206
instrumentationRunner.get(),
209
buildId = buildId.get(),
210
buildType = buildType.get(),
211
kubernetesCredentials = requireNotNull(kubernetesCredentials.orNull) {
212
"you need to provide kubernetesCredentials"
214
kubernetesHttpTries = kubernetesHttpTries.get(),
215
deviceDebug = enableDeviceDebug.get(),
216
projectName = projectName.get(),
217
suppressFailure = suppressFailure.get(),
218
suppressFlaky = suppressFlaky.get(),
219
impactAnalysisResult = ImpactAnalysisResult.create(
220
runOnlyChangedTests = runOnlyChangedTests.get(),
221
changedTestsFile = changedTests.asFile.orNull
224
verdictFile = verdictFile.get().asFile,
225
statsDConfig = statsDConfig.get(),
226
proguardMappings = listOf(
227
applicationProguardMapping,
229
).mapNotNull { it.orNull?.asFile },
230
saveTestArtifactsToOutputs = experiments.saveTestArtifactsToOutputs,
231
useLegacyExtensionsV1Beta = experiments.useLegacyExtensionsV1Beta,
232
adbPullTimeout = adbPullTimeout.get(),
233
macrobenchmarkOutputDir = macrobenchmarkOutputDirectory.orNull?.asFile,
236
val isGradleTestKitRun = gradleTestKitRun.get()
238
RunnerInputDumper(output).dumpInput(
239
input = testRunParams,
240
isGradleTestKitRun = isGradleTestKitRun
243
if (!isGradleTestKitRun) {
244
val loggerFactory = GradleLoggerPlugin.provideLoggerFactory(this).get()
245
workerExecutor.inMemoryWork {
247
val result = TestSchedulerFactoryProvider(loggerFactory)
248
.provide(testRunParams)
252
TestSchedulerResult.Ok -> {
256
is TestSchedulerResult.Failure -> buildFailer.get().failBuild(result.message)