Bug 1433322 - 3. Run GeckoView unit tests with 'mach android test'; r?nalexander
Run unit tests under geckoview/ when running 'mach android test'. This
also lets us run those tests on Taskcluster.
The test report parser for 'mach android test' had a bug where the input
directory was wrong. As a result, we weren't producing test output at
all. This patch fixes the input directory, and outputs an error if no
reports are found at all to avoid this bug in the future.
MozReview-Commit-ID: IiswQaSPCr0
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -143,16 +143,20 @@ android {
}
}
}
}
dependencies {
implementation "com.android.support:support-v4:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
implementation "com.android.support:palette-v7:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
+
+ testImplementation 'junit:junit:4.12'
+ testImplementation 'org.robolectric:robolectric:3.5.1'
+ testImplementation 'org.mockito:mockito-core:1.10.19'
}
apply from: "${topsrcdir}/mobile/android/gradle/with_gecko_binaries.gradle"
android.libraryVariants.all { variant ->
// See the notes in mobile/android/app/build.gradle for details on including
// Gecko binaries and the Omnijar.
if ((variant.productFlavors*.name).contains('withGeckoBinaries')) {
--- a/mobile/android/gradle.configure
+++ b/mobile/android/gradle.configure
@@ -63,27 +63,32 @@ def gradle_android_build_config():
),
geckoview_example=namespace(
variant=variant(('official', 'withGeckoBinaries', 'noMinApi'), 'debug'),
),
)
@depends(gradle_android_build_config)
-def gradle_android_app_variant_name(build_config):
+def gradle_android_variant_name(build_config):
'''Like "officialPhotonDebug".'''
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
- return uncapitalize(build_config.app.variant.name)
+ return namespace(
+ app=uncapitalize(build_config.app.variant.name),
+ geckoview=uncapitalize(build_config.geckoview.variant.name),
+ )
-set_config('GRADLE_ANDROID_APP_VARIANT_NAME', gradle_android_app_variant_name)
+set_config('GRADLE_ANDROID_APP_VARIANT_NAME', gradle_android_variant_name.app)
+
+set_config('GRADLE_ANDROID_GECKOVIEW_VARIANT_NAME', gradle_android_variant_name.geckoview)
@depends(gradle_android_build_config)
def gradle_android_app_tasks(build_config):
'''Gradle tasks run by |mach android assemble-app|.'''
return [
'geckoview:generateJNIWrappersForGenerated{geckoview.variant.name}'.format(geckoview=build_config.geckoview),
'app:generateJNIWrappersForFennec{app.variant.name}'.format(app=build_config.app),
@@ -133,16 +138,18 @@ set_config('GRADLE_ANDROID_APP_APK', gra
set_config('GRADLE_ANDROID_APP_ANDROIDTEST_APK', gradle_android_app_apks.app_androidTest_apk)
@depends(gradle_android_build_config)
def gradle_android_test_tasks(build_config):
'''Gradle tasks run by |mach android test|.'''
return [
'app:test{app.variant.name}UnitTest'.format(app=build_config.app),
+ 'geckoview:test{geckoview.variant.name}UnitTest'.format(
+ geckoview=build_config.geckoview),
]
set_config('GRADLE_ANDROID_TEST_TASKS', gradle_android_test_tasks)
@depends(gradle_android_build_config)
def gradle_android_lint_tasks(build_config):
'''Gradle tasks run by |mach android lint|.'''
--- a/mobile/android/mach_commands.py
+++ b/mobile/android/mach_commands.py
@@ -66,34 +66,51 @@ class MachCommands(MachCommandBase):
@SubCommand('android', 'test',
"""Run Android local unit tests.
See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-test""")
@CommandArgument('args', nargs=argparse.REMAINDER)
def android_test(self, args):
ret = self.gradle(self.substs['GRADLE_ANDROID_TEST_TASKS'] + ["--continue"] + args, verbose=True)
- # Findbug produces both HTML and XML reports. Visit the
+ ret |= self._parse_android_test_results('public/app/unittest', 'gradle/build/mobile/android/app',
+ (self.substs['GRADLE_ANDROID_APP_VARIANT_NAME'],))
+
+ ret |= self._parse_android_test_results('public/geckoview/unittest', 'gradle/build/mobile/android/geckoview',
+ (self.substs['GRADLE_ANDROID_GECKOVIEW_VARIANT_NAME'],))
+
+ return ret
+
+ def _parse_android_test_results(self, artifactdir, gradledir, variants):
+ # Unit tests produce both HTML and XML reports. Visit the
# XML report(s) to report errors and link to the HTML
# report(s) for human consumption.
import itertools
import xml.etree.ElementTree as ET
from mozpack.files import (
FileFinder,
)
+ ret = 0
+ found_reports = False
+
root_url = self._root_url(
- artifactdir='public/android/unittest',
- objdir='gradle/build/mobile/android/app/reports/tests')
+ artifactdir=artifactdir,
+ objdir=gradledir + '/reports/tests')
- reports = (self.substs['GRADLE_ANDROID_APP_VARIANT_NAME'],)
- for report in reports:
- finder = FileFinder(os.path.join(self.topobjdir, 'gradle/build/mobile/android/app/test-results/', report))
+ def capitalize(s):
+ # Can't use str.capitalize because it lower cases trailing letters.
+ return (s[0].upper() + s[1:]) if s else ''
+
+ for variant in variants:
+ report = 'test{}UnitTest'.format(capitalize(variant))
+ finder = FileFinder(os.path.join(self.topobjdir, gradledir + '/test-results/', report))
for p, _ in finder.find('TEST-*.xml'):
+ found_reports = True
f = open(os.path.join(finder.base, p), 'rt')
tree = ET.parse(f)
root = tree.getroot()
# Log reports for Tree Herder "Job Details".
print('TinderboxPrint: report<br/><a href="{}/{}/index.html">HTML {} report</a>, visit "Inspect Task" link for details'.format(root_url, report, report))
# And make the report display as soon as possible.
@@ -127,16 +144,20 @@ class MachCommands(MachCommandBase):
for line in ET.tostring(skipped).strip().splitlines():
print('TEST-INFO | {} | {}'.format(name, line))
if not error_count:
print('TEST-PASS | {}'.format(name))
print('SUITE-END | android-test | {} {}'.format(report, root.get('name')))
+ if not found_reports:
+ print('TEST-UNEXPECTED-FAIL | android-test | No reports found under {}'.format(gradledir))
+ return 1
+
return ret
@SubCommand('android', 'lint',
"""Run Android lint.
See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-lint""")
@CommandArgument('args', nargs=argparse.REMAINDER)
def android_lint(self, args):
--- a/taskcluster/ci/build/android-stuff.yml
+++ b/taskcluster/ci/build/android-stuff.yml
@@ -10,19 +10,22 @@ android-test/opt:
symbol: A(test)
worker-type: aws-provisioner-v1/gecko-{level}-b-android
worker:
docker-image: {in-tree: android-build}
env:
GRADLE_USER_HOME: "/builds/worker/workspace/build/src/mobile/android/gradle/dotgradle-offline"
PERFHERDER_EXTRA_OPTIONS: android-test
artifacts:
- - name: public/android/unittest
+ - name: public/app/unittest
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/reports/tests
type: directory
+ - name: public/geckoview/unittest
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/reports/tests
+ type: directory
- name: public/build
path: /builds/worker/artifacts/
type: directory
max-run-time: 36000
run:
using: mozharness
actions: [get-secrets build]
config: