1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.baselineprofile.gradle.producer
18 
19 import androidx.baselineprofile.gradle.utils.BaselineProfileProjectSetupRule
20 import androidx.baselineprofile.gradle.utils.TestAgpVersion
21 import androidx.baselineprofile.gradle.utils.TestAgpVersion.TEST_AGP_VERSION_8_1_1
22 import androidx.baselineprofile.gradle.utils.TestAgpVersion.TEST_AGP_VERSION_8_2_0
23 import androidx.baselineprofile.gradle.utils.TestAgpVersion.TEST_AGP_VERSION_8_3_1
24 import androidx.baselineprofile.gradle.utils.TestAgpVersion.TEST_AGP_VERSION_8_4_2
25 import androidx.baselineprofile.gradle.utils.VariantProfile
26 import androidx.baselineprofile.gradle.utils.build
27 import androidx.baselineprofile.gradle.utils.buildAndAssertThatOutput
28 import androidx.baselineprofile.gradle.utils.buildAndFailAndAssertThatOutput
29 import androidx.baselineprofile.gradle.utils.require
30 import com.google.common.truth.StringSubject
31 import com.google.common.truth.Truth.assertThat
32 import org.junit.Rule
33 import org.junit.Test
34 import org.junit.runner.RunWith
35 import org.junit.runners.Parameterized
36 
37 private val GRADLE_PRINT_ARGS_TASK =
38     """
39 abstract class PrintArgsTask extends DefaultTask {
40     @Input abstract MapProperty<String, String> getProperties()
41     @TaskAction void exec() {
42         for (Map.Entry<String, String> e : getProperties().get().entrySet()) {
43             println(e.key + "=" + e.value)
44         }
45     }
46 }
47 androidComponents {
48     onVariants(selector()) { variant ->
49         tasks.register(variant.name + "Arguments", PrintArgsTask) { t ->
50             t.properties.set(variant.instrumentationRunnerArguments)
51         }
52     }
53 }
54 """
55         .trimIndent()
56 
57 @RunWith(Parameterized::class)
58 class BaselineProfileProducerPluginTest(agpVersion: TestAgpVersion) {
59 
60     companion object {
61         @Parameterized.Parameters(name = "agpVersion={0}")
62         @JvmStatic
parametersnull63         fun parameters() = TestAgpVersion.values()
64     }
65 
66     @get:Rule
67     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
68 
69     private val emptyReleaseVariantProfile =
70         VariantProfile(flavor = null, buildType = "release", profileFileLines = mapOf())
71 
72     @Test
73     fun verifyTasksWithAndroidTestPlugin() {
74         projectSetup.appTarget.setup()
75         projectSetup.producer.setup(
76             variantProfiles = listOf(emptyReleaseVariantProfile),
77             targetProject = projectSetup.appTarget
78         )
79 
80         projectSetup.producer.gradleRunner.build("tasks") {
81             val notFound =
82                 it.lines()
83                     .require(
84                         "connectedNonMinifiedReleaseAndroidTest - ",
85                         "collectNonMinifiedReleaseBaselineProfile - "
86                     )
87             assertThat(notFound).isEmpty()
88         }
89     }
90 
91     @Test
nonExistingManagedDeviceShouldThrowErrornull92     fun nonExistingManagedDeviceShouldThrowError() {
93         projectSetup.appTarget.setup()
94         projectSetup.producer.setup(
95             variantProfiles = listOf(emptyReleaseVariantProfile),
96             targetProject = projectSetup.appTarget,
97             managedDevices = listOf(),
98             baselineProfileBlock =
99                 """
100                 managedDevices = ["nonExisting"]
101             """
102                     .trimIndent()
103         )
104 
105         projectSetup.producer.gradleRunner.buildAndFailAndAssertThatOutput("tasks") {
106             contains("No managed device named `nonExisting` was found.")
107         }
108     }
109 
110     @Test
existingManagedDeviceShouldCreateCollectTaskDependingOnManagedDeviceTasknull111     fun existingManagedDeviceShouldCreateCollectTaskDependingOnManagedDeviceTask() {
112         projectSetup.appTarget.setup()
113         projectSetup.producer.setup(
114             variantProfiles = listOf(emptyReleaseVariantProfile),
115             targetProject = projectSetup.appTarget,
116             managedDevices = listOf("somePixelDevice"),
117             baselineProfileBlock =
118                 """
119                 managedDevices = ["somePixelDevice"]
120             """
121                     .trimIndent()
122         )
123 
124         projectSetup.producer.gradleRunner.build(
125             "collectNonMinifiedReleaseBaselineProfile",
126             "--dry-run"
127         ) {
128             val appTargetName = projectSetup.appTarget.name
129             val producerName = projectSetup.producer.name
130             val notFound =
131                 it.lines()
132                     .require(
133                         ":$appTargetName:packageNonMinifiedRelease",
134                         ":$producerName:somePixelDeviceNonMinifiedReleaseAndroidTest",
135                         ":$producerName:connectedNonMinifiedReleaseAndroidTest",
136                         ":$producerName:collectNonMinifiedReleaseBaselineProfile"
137                     )
138             assertThat(notFound).isEmpty()
139         }
140     }
141 
142     @Test
skipGenerationPropertyShouldDisableTestTasksnull143     fun skipGenerationPropertyShouldDisableTestTasks() {
144         projectSetup.appTarget.setup()
145         projectSetup.producer.setup(
146             variantProfiles = listOf(emptyReleaseVariantProfile),
147             targetProject = projectSetup.appTarget,
148             managedDevices = listOf("somePixelDevice"),
149             baselineProfileBlock =
150                 """
151                 managedDevices = ["somePixelDevice"]
152             """
153                     .trimIndent(),
154             additionalGradleCodeBlock =
155                 """
156                 afterEvaluate {
157                     for (String taskName : [
158                             "somePixelDeviceNonMinifiedReleaseAndroidTest",
159                             "collectNonMinifiedReleaseBaselineProfile"]) {
160                         def task = tasks.getByName(taskName)
161                         println(taskName + "=" + task.enabled)
162                     }
163                 }
164             """
165                     .trimIndent()
166         )
167 
168         // Execute any task and check the expected output.
169         // Note that executing `somePixelDeviceSetup` will fail for `LicenseNotAcceptedException`.
170         projectSetup.producer.gradleRunner.build(
171             "tasks",
172             "-Pandroidx.baselineprofile.skipgeneration"
173         ) {
174             val notFound =
175                 it.lines()
176                     .require(
177                         "somePixelDeviceNonMinifiedReleaseAndroidTest=false",
178                         "collectNonMinifiedReleaseBaselineProfile=false"
179                     )
180             assertThat(notFound).isEmpty()
181         }
182     }
183 
184     @Test
whenUseOnlyConnectedDevicesShouldOverrideDslnull185     fun whenUseOnlyConnectedDevicesShouldOverrideDsl() {
186         projectSetup.appTarget.setup()
187         projectSetup.producer.setup(
188             variantProfiles = listOf(emptyReleaseVariantProfile),
189             targetProject = projectSetup.appTarget,
190             managedDevices = listOf("somePixelDevice"),
191             baselineProfileBlock =
192                 """
193                 managedDevices = ["somePixelDevice"]
194                 useConnectedDevices = false
195             """
196                     .trimIndent()
197         )
198 
199         // Execute any task and check the expected output.
200         // Note that executing `somePixelDeviceSetup` will fail for `LicenseNotAcceptedException`.
201         projectSetup.producer.gradleRunner.buildAndAssertThatOutput(
202             "collectNonMinifiedReleaseBaselineProfile",
203             "--dry-run",
204             "-Pandroidx.baselineprofile.forceonlyconnecteddevices"
205         ) {
206             contains("connectedNonMinifiedReleaseAndroidTest")
207             doesNotContain("somePixelDeviceNonMinifiedReleaseAndroidTest")
208         }
209     }
210 
211     @Test
whenNotUseOnlyConnectedDevicesShouldOverrideDslnull212     fun whenNotUseOnlyConnectedDevicesShouldOverrideDsl() {
213         projectSetup.appTarget.setup()
214         projectSetup.producer.setup(
215             variantProfiles = listOf(emptyReleaseVariantProfile),
216             targetProject = projectSetup.appTarget,
217             managedDevices = listOf("somePixelDevice"),
218             baselineProfileBlock =
219                 """
220                 managedDevices = ["somePixelDevice"]
221                 useConnectedDevices = false
222             """
223                     .trimIndent()
224         )
225 
226         // Execute any task and check the expected output.
227         // Note that executing `somePixelDeviceSetup` will fail for `LicenseNotAcceptedException`.
228         projectSetup.producer.gradleRunner.buildAndAssertThatOutput(
229             "collectNonMinifiedReleaseBaselineProfile",
230             "--dry-run",
231         ) {
232             doesNotContain("connectedNonMinifiedReleaseAndroidTest")
233             contains("somePixelDeviceNonMinifiedReleaseAndroidTest")
234         }
235     }
236 }
237 
238 @RunWith(Parameterized::class)
239 class BaselineProfileProducerPluginTestWithAgp81AndAbove(agpVersion: TestAgpVersion) {
240 
241     companion object {
242         @Parameterized.Parameters(name = "agpVersion={0}")
243         @JvmStatic
parametersnull244         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_1_1)
245     }
246 
247     @get:Rule
248     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
249 
250     private val emptyReleaseVariantProfile =
251         VariantProfile(flavor = null, buildType = "release", profileFileLines = mapOf())
252 
253     @Test
254     fun verifyTasksWithAndroidTestPlugin() {
255         projectSetup.appTarget.setup()
256         projectSetup.producer.setup(
257             variantProfiles = listOf(emptyReleaseVariantProfile),
258             targetProject = projectSetup.appTarget
259         )
260 
261         projectSetup.producer.gradleRunner.build("tasks") {
262             val notFound =
263                 it.lines()
264                     .require(
265                         "connectedNonMinifiedReleaseAndroidTest - ",
266                         "connectedBenchmarkReleaseAndroidTest - ",
267                         "collectNonMinifiedReleaseBaselineProfile - "
268                     )
269             assertThat(notFound).isEmpty()
270         }
271     }
272 }
273 
274 @RunWith(Parameterized::class)
275 class BaselineProfileProducerPluginTestWithAgp82AndAbove(agpVersion: TestAgpVersion) {
276 
277     companion object {
278         @Parameterized.Parameters(name = "agpVersion={0}")
279         @JvmStatic
parametersnull280         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_2_0)
281     }
282 
283     @get:Rule
284     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
285 
286     private val emptyReleaseVariantProfile =
287         VariantProfile(flavor = null, buildType = "release", profileFileLines = mapOf())
288 
289     @Test
290     fun verifyInstrumentationRunnerArgumentsAreSet() {
291         projectSetup.appTarget.setup()
292         projectSetup.producer.setup(
293             variantProfiles = listOf(emptyReleaseVariantProfile),
294             targetProject = projectSetup.appTarget,
295             additionalGradleCodeBlock = GRADLE_PRINT_ARGS_TASK
296         )
297 
298         data class AssertData(
299             val taskName: String,
300             val applyProp: Boolean,
301             val assertBlock: StringSubject.() -> (Unit)
302         )
303 
304         arrayOf(
305                 AssertData("benchmarkReleaseArguments", false) {
306                     contains("androidx.benchmark.enabledRules=macrobenchmark")
307                     contains("androidx.benchmark.skipOnEmulator=true")
308                 },
309                 AssertData("nonMinifiedReleaseArguments", false) {
310                     contains("androidx.benchmark.enabledRules=baselineprofile")
311                 },
312                 AssertData("benchmarkReleaseArguments", true) {
313                     doesNotContain("androidx.benchmark.enabledRules=macrobenchmark")
314                     contains("androidx.benchmark.skipOnEmulator=true")
315                 },
316                 AssertData("nonMinifiedReleaseArguments", true) {
317                     doesNotContain("androidx.benchmark.enabledRules=baselineprofile")
318                 },
319             )
320             .forEach {
321                 projectSetup.producer.gradleRunner.buildAndAssertThatOutput(
322                     arguments =
323                         listOfNotNull(
324                                 it.taskName,
325                                 if (it.applyProp) "-Pandroidx.baselineprofile.dontdisablerules"
326                                 else null
327                             )
328                             .toTypedArray(),
329                     assertBlock = it.assertBlock
330                 )
331             }
332     }
333 
334     @Test
runWhenInstrumentationRunnerArgumentsAreSetManuallynull335     fun runWhenInstrumentationRunnerArgumentsAreSetManually() {
336         projectSetup.appTarget.setup()
337         projectSetup.producer.setup(
338             variantProfiles = listOf(emptyReleaseVariantProfile),
339             targetProject = projectSetup.appTarget
340         )
341 
342         val enabledRuleProp =
343             "-Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules"
344         projectSetup.producer.gradleRunner.build(
345             "connectedBenchmarkReleaseAndroidTest",
346             "$enabledRuleProp=Macrobenchmark"
347         ) {
348             // This should not fail.
349         }
350 
351         projectSetup.producer.gradleRunner.build(
352             "connectedNonMinifiedReleaseAndroidTest",
353             "$enabledRuleProp=BaselineProfile"
354         ) {
355             // This should not fail.
356         }
357     }
358 }
359 
360 @RunWith(Parameterized::class)
361 class BaselineProfileProducerPluginTestWithAgp83AndAbove(agpVersion: TestAgpVersion) {
362 
363     companion object {
364         @Parameterized.Parameters(name = "agpVersion={0}")
365         @JvmStatic
parametersnull366         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_3_1)
367     }
368 
369     @get:Rule
370     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
371 
372     private val emptyReleaseVariantProfile =
373         VariantProfile(flavor = null, buildType = "release", profileFileLines = mapOf())
374 
375     @Test
376     fun verifyTargetPackageNamePassedAsInstrumentationRunnerArgumentWithOverride() {
377         projectSetup.appTarget.setup()
378         projectSetup.producer.setup(
379             variantProfiles = listOf(emptyReleaseVariantProfile),
380             targetProject = projectSetup.appTarget,
381             additionalGradleCodeBlock = GRADLE_PRINT_ARGS_TASK
382         )
383 
384         val prop =
385             "-Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.targetPackageName"
386         arrayOf(
387                 arrayOf(
388                     "benchmarkReleaseArguments",
389                     "$prop=com.someotherpackage1",
390                     "androidx.benchmark.targetPackageName=com.someotherpackage1"
391                 ),
392                 arrayOf(
393                     "nonMinifiedReleaseArguments",
394                     "$prop=com.someotherpackage2",
395                     "androidx.benchmark.targetPackageName=com.someotherpackage2"
396                 ),
397             )
398             .forEach {
399                 projectSetup.producer.gradleRunner.buildAndAssertThatOutput(it[0], it[1]) {
400                     // Note that if the targetPackageName argument is overridden from CLI
401                     // then it shouldn't be in the runner arguments map at this stage, as it's
402                     // added later by the test plugin.
403                     doesNotContain(it[2])
404                 }
405             }
406     }
407 }
408 
409 @RunWith(Parameterized::class)
410 class BaselineProfileProducerPluginTestWithAgp84AndAbove(agpVersion: TestAgpVersion) {
411 
412     companion object {
413         @Parameterized.Parameters(name = "agpVersion={0}")
414         @JvmStatic
parametersnull415         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_4_2)
416     }
417 
418     @get:Rule
419     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
420 
421     private val emptyReleaseVariantProfile =
422         VariantProfile(flavor = null, buildType = "release", profileFileLines = mapOf())
423 
424     @Test
425     fun verifyTargetPackageNamePassedAsInstrumentationRunnerArgument() {
426         projectSetup.appTarget.setup()
427         projectSetup.producer.setup(
428             variantProfiles = listOf(emptyReleaseVariantProfile),
429             targetProject = projectSetup.appTarget,
430             additionalGradleCodeBlock = GRADLE_PRINT_ARGS_TASK
431         )
432         arrayOf(
433                 Pair(
434                     "benchmarkReleaseArguments",
435                     "androidx.benchmark.targetPackageName=com.example.namespace"
436                 ),
437                 Pair(
438                     "nonMinifiedReleaseArguments",
439                     "androidx.benchmark.targetPackageName=com.example.namespace"
440                 ),
441             )
442             .forEach {
443                 projectSetup.producer.gradleRunner.buildAndAssertThatOutput(it.first) {
444                     contains(it.second)
445                 }
446             }
447     }
448 }
449