Create linter to detect demoting test without attaching a bug id.

Test: `atest SystemUILintCheckerTest`
Bug: 270628073
Change-Id: Id5b64293b6d49391e644bfe5cc47a4a94644737c
This commit is contained in:
Jeff Chen
2023-02-23 16:53:28 -08:00
parent 49f323d997
commit dfb7ec50fc
3 changed files with 230 additions and 1 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.systemui.lint
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.SourceCodeScanner
import org.jetbrains.uast.UAnnotation
import org.jetbrains.uast.UElement
class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(UAnnotation::class.java)
}
override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitAnnotation(node: UAnnotation) {
if (node.qualifiedName !in DEMOTING_ANNOTATION) {
return
}
val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int
if (bugId <= 0) {
val location = context.getLocation(node)
val message = "Please attach a bug id to track demoted test"
context.report(ISSUE, node, location, message)
}
}
}
}
companion object {
val DEMOTING_ANNOTATION =
listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest")
@JvmField
val ISSUE: Issue =
Issue.create(
id = "DemotingTestWithoutBug",
briefDescription = "Demoting a test without attaching a bug.",
explanation =
"""
Annotations (`@FlakyTest`) demote tests to an unmonitored \
test suite. Please set the `bugId` field in such annotations to track \
the test status.
""",
category = Category.TESTING,
priority = 8,
severity = Severity.WARNING,
implementation =
Implementation(
DemotingTestWithoutBugDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}

View File

@@ -39,7 +39,8 @@ class SystemUIIssueRegistry : IssueRegistry() {
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
StaticSettingsProviderDetector.ISSUE
StaticSettingsProviderDetector.ISSUE,
DemotingTestWithoutBugDetector.ISSUE
)
override val api: Int

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = DemotingTestWithoutBugDetector()
override fun getIssues(): List<Issue> = listOf(DemotingTestWithoutBugDetector.ISSUE)
@Test
fun testMarkFlaky_withBugId() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import androidx.test.filters.FlakyTest;
@FlakyTest(bugId = 123)
public class TestClass {
public void testCase() {}
}
"""
)
.indented(),
*stubs
)
.issues(DemotingTestWithoutBugDetector.ISSUE)
.run()
.expectClean()
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.platform.test.annotations.FlakyTest;
@FlakyTest(bugId = 123)
public class TestClass {
public void testCase() {}
}
"""
)
.indented(),
*stubs
)
.issues(DemotingTestWithoutBugDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testMarkFlaky_withoutBugId() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import androidx.test.filters.FlakyTest;
@FlakyTest
public class TestClass {
public void testCase() {}
}
"""
)
.indented(),
*stubs
)
.issues(DemotingTestWithoutBugDetector.ISSUE)
.run()
.expect(
"""
src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
@FlakyTest
~~~~~~~~~~
0 errors, 1 warnings
"""
)
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.platform.test.annotations.FlakyTest;
@FlakyTest
public class TestClass {
public void testCase() {}
}
"""
)
.indented(),
*stubs
)
.issues(DemotingTestWithoutBugDetector.ISSUE)
.run()
.expect(
"""
src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
@FlakyTest
~~~~~~~~~~
0 errors, 1 warnings
"""
)
}
private val filtersFlakyTestStub: TestFile =
java(
"""
package androidx.test.filters;
public @interface FlakyTest {
int bugId() default -1;
}
"""
)
private val annotationsFlakyTestStub: TestFile =
java(
"""
package android.platform.test.annotations;
public @interface FlakyTest {
int bugId() default -1;
}
"""
)
private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub)
}