From 8262a44875c2d82033e1f9e16639d7efbca58e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 19 Mar 2019 13:32:06 +0100 Subject: [android] unit and instrumentation tests code coverage report --- Makefile | 11 ++++++++ circle.yml | 11 +++++++- platform/android/MapboxGLAndroidSDK/build.gradle | 11 ++++---- platform/android/build.gradle | 1 + platform/android/gradle/dependencies.gradle | 4 ++- platform/android/gradle/jacoco-report.gradle | 33 ++++++++++++++++++++++++ platform/android/scripts/parse-jacoco-report.py | 31 ++++++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 platform/android/gradle/jacoco-report.gradle create mode 100755 platform/android/scripts/parse-jacoco-report.py diff --git a/Makefile b/Makefile index ecc4273cff..a6aa414068 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ export BUILDTYPE ?= Debug +export IS_LOCAL_DEVELOPMENT ?= true export WITH_CXX11ABI ?= $(shell scripts/check-cxx11abi.sh) ifeq ($(BUILDTYPE), Release) @@ -691,6 +692,16 @@ run-android-unit-test: platform/android/gradle/configuration.gradle run-android-unit-test-%: platform/android/gradle/configuration.gradle cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest --info --tests "$*" +# Run unit test and build a coverage report from .exec file generated by unit tests and .ec file generated by instrumentation tests +.PHONY: android-create-jacoco-report +android-create-jacoco-report: platform/android/gradle/configuration.gradle + cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:jacocoTestReport + +# Parse merged jacoco report and send it to S3 +.PHONY: android-parse-and-send-jacoco-report +android-parse-and-send-jacoco-report: + python platform/android/scripts/parse-jacoco-report.py + # Builds a release package of the Android SDK .PHONY: apackage apackage: platform/android/gradle/configuration.gradle diff --git a/circle.yml b/circle.yml index 6883cd6f5a..87de7109ac 100644 --- a/circle.yml +++ b/circle.yml @@ -571,7 +571,16 @@ jobs: gcloud firebase test android run --type instrumentation \ --app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/debug/MapboxGLAndroidSDKTestApp-debug.apk \ --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/androidTest/debug/MapboxGLAndroidSDKTestApp-debug-androidTest.apk \ - --device-ids << parameters.firebase_device_id >> --os-version-ids << parameters.firebase_device_os >> --locales en --orientations portrait --timeout 20m + --device-ids << parameters.firebase_device_id >> --os-version-ids << parameters.firebase_device_os >> --locales en --orientations portrait --timeout 20m \ + --environment-variables coverage=true,coverageFile="/sdcard/coverage.ec" --directories-to-pull /sdcard --results-dir mapbox-android-sdk-${CIRCLE_BUILD_NUM} + coverageFile=`gsutil ls gs://test-lab-186672a0qp5bq-ycr70axads3nc/mapbox-android-sdk-${CIRCLE_BUILD_NUM}/**/*.ec | tail -1` + gsutil cp $coverageFile $PWD/platform/android/MapboxGLAndroidSDK/build/jacoco | true + fi + - run: + name: Parse and send Jacoco reports + command: | + if [[ $CIRCLE_BRANCH == master ]]; then + make android-create-jacoco-report && make android-parse-and-send-jacoco-report fi - store_artifacts: path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/debug diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 89937448e9..927317996b 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -23,10 +23,6 @@ dependencies { android { compileSdkVersion androidVersions.compileSdkVersion - // Roboelectric 4.0 required config - // http://robolectric.org/migrating/#migrating-to-40 - testOptions.unitTests.includeAndroidResources = true - defaultConfig { minSdkVersion androidVersions.minSdkVersion targetSdkVersion androidVersions.targetSdkVersion @@ -134,12 +130,16 @@ android { testOptions { unitTests { returnDefaultValues true + + // Roboelectric 4.0 required config + // http://robolectric.org/migrating/#migrating-to-40 includeAndroidResources = true } } buildTypes { debug { + testCoverageEnabled true jniDebuggable true } } @@ -169,4 +169,5 @@ apply from: "${rootDir}/gradle/gradle-checkstyle.gradle" apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle" apply from: "${rootDir}/gradle/gradle-update-vendor-modules.gradle" apply from: "${rootDir}/gradle/android-nitpick.gradle" -apply from: "${rootDir}/gradle/gradle-bintray.gradle" \ No newline at end of file +apply from: "${rootDir}/gradle/gradle-bintray.gradle" +apply from: "${rootDir}/gradle/jacoco-report.gradle" \ No newline at end of file diff --git a/platform/android/build.gradle b/platform/android/build.gradle index 5334c93ce9..97f3037afb 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath dependenciesList.bintrayPlugin classpath dependenciesList.artifactoryPlugin classpath dependenciesList.androidPublishPlugin + classpath dependenciesList.jacocoPlugin } } diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index bc8184b5cd..1d17e7f83d 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -29,7 +29,8 @@ ext { androidPublish : '3.6.2', lint : '26.1.4', gms : '16.0.0', - reLinker : '1.3.1' + reLinker : '1.3.1', + jacoco : '0.8.3' ] dependenciesList = [ @@ -72,6 +73,7 @@ ext { bintrayPlugin : "com.jfrog.bintray.gradle:gradle-bintray-plugin:${versions.bintray}", artifactoryPlugin : "org.jfrog.buildinfo:build-info-extractor-gradle:${versions.artifactory}", androidPublishPlugin : "digital.wup:android-maven-publish:${versions.androidPublish}", + jacocoPlugin : "org.jacoco:org.jacoco.core:${versions.jacoco}", lint : "com.android.tools.lint:lint:${versions.lint}", lintApi : "com.android.tools.lint:lint-api:${versions.lint}", diff --git a/platform/android/gradle/jacoco-report.gradle b/platform/android/gradle/jacoco-report.gradle new file mode 100644 index 0000000000..e50facb683 --- /dev/null +++ b/platform/android/gradle/jacoco-report.gradle @@ -0,0 +1,33 @@ +apply plugin: 'jacoco' +apply from: "${rootDir}/gradle/dependencies.gradle" + +jacoco { + toolVersion = versions.jacoco +} + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { + group = "Reporting" + description = "Combine code coverage to unified report." + + reports { + xml.enabled = true + html.enabled = true + } + + def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes) + def mainSrc = "${project.projectDir}/src/main/java" + println(mainSrc) + def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec") + def execSrc = fileTree(dir: "$project.buildDir", include: "**/*.exec") + + doFirst { + def files = files([ecSrc, execSrc]).files + println "Creating Jacoco Report for ${files.size()} coverage files" + files.each { file -> println file } + } + + sourceDirectories = files([mainSrc]) + classDirectories = files([debugTree]) + executionData = files([ecSrc, execSrc]) +} \ No newline at end of file diff --git a/platform/android/scripts/parse-jacoco-report.py b/platform/android/scripts/parse-jacoco-report.py new file mode 100755 index 0000000000..4d06fda6cc --- /dev/null +++ b/platform/android/scripts/parse-jacoco-report.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import os +import re +from io import open + +reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +with open(reportPath, 'r', encoding='utf-8') as jacocoReport: + line = jacocoReport.readline().strip() + + # find the last INSTRUCTION coverage report which is a sum of all separate ones + instructionIndex = line.rfind('type="INSTRUCTION"') + startIndex = line.find('missed', instructionIndex) + endIndex = line.find('/>', startIndex) + + # find the missed and covered lines counts + numbers = re.match(r'missed="(\d+)" covered="(\d+)"', line[startIndex:endIndex]) + missed = int(numbers.group(1)) + covered = int(numbers.group(2)) + + # calculate the code coverage percentage + percentage = round(covered * 100.0 / (missed + covered), 2) + print("Android tests code coverage: %s%%" % (str(percentage))) + + # invoke the script that send the data to s3 + testEnvironment = "LOCAL" + if os.environ.get('IS_LOCAL_DEVELOPMENT').lower()=='false': + testEnvironment = "CI" + + cmd = os.getcwd() + ("/scripts/code-coverage.sh %.2f %s %s" % (percentage, "Android", testEnvironment)) + os.system(cmd) -- cgit v1.2.1