This is an automated email from the ASF dual-hosted git repository.
markusthoemmes pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git
The following commit(s) were added to refs/heads/master by this push:
new f8a1506 Enable test code coverage collection for containers. (#3685)
f8a1506 is described below
commit f8a1506b2edc5e61476e44b924962a567c283b22
Author: Chetan Mehrotra <[email protected]>
AuthorDate: Tue Jul 31 17:16:08 2018 +0530
Enable test code coverage collection for containers. (#3685)
---
ansible/environments/local/group_vars/all | 2 ++
ansible/roles/controller/tasks/deploy.yml | 33 +++++++++++++++++++---
ansible/roles/invoker/tasks/deploy.yml | 23 ++++++++++++++-
ansible/templates/whisk.properties.j2 | 1 +
core/controller/.dockerignore | 3 +-
core/controller/Dockerfile.cov | 15 ++++++++++
core/controller/build.gradle | 6 ++++
core/invoker/.dockerignore | 3 +-
core/invoker/Dockerfile.cov | 15 ++++++++++
core/invoker/build.gradle | 5 ++++
gradle/docker.gradle | 42 +++++++++++++++++++++++++++
tests/build.gradle | 47 +++++++++++++++++++++++++++++++
tools/travis/distDocker.sh | 3 ++
tools/travis/runSystemTests.sh | 1 +
14 files changed, 192 insertions(+), 7 deletions(-)
diff --git a/ansible/environments/local/group_vars/all
b/ansible/environments/local/group_vars/all
index 30464ef..65e0a5a 100755
--- a/ansible/environments/local/group_vars/all
+++ b/ansible/environments/local/group_vars/all
@@ -4,6 +4,8 @@
openwhisk_tmp_dir: "{{ lookup('env', 'OPENWHISK_TMP_DIR')|default('/tmp',
true) }}"
config_root_dir: "{{ openwhisk_tmp_dir }}/wskconf"
whisk_logs_dir: "{{ openwhisk_tmp_dir }}/wsklogs"
+coverage_enabled: "{{ lookup('env', 'GRADLE_COVERAGE') | default('false',
true) | bool}}"
+coverage_logs_dir: "{{ openwhisk_tmp_dir }}/wskcov"
docker_registry: ""
docker_dns: ""
runtimes_bypass_pull_for_local_images: true
diff --git a/ansible/roles/controller/tasks/deploy.yml
b/ansible/roles/controller/tasks/deploy.yml
index 11d7269..91d132d 100644
--- a/ansible/roles/controller/tasks/deploy.yml
+++ b/ansible/roles/controller/tasks/deploy.yml
@@ -244,6 +244,33 @@
set_fact:
env: "{{ env | combine(controller.extraEnv) }}"
+- name: populate volumes for controller
+ set_fact:
+ controller_volumes:
+ - "{{ whisk_logs_dir }}/{{ controller_name }}:/logs"
+ - "{{ controller.confdir }}/{{ controller_name }}:/conf"
+
+- name: check if coverage collection is enabled
+ set_fact:
+ coverage_enabled: false
+ when: coverage_enabled is undefined
+
+- name: ensure controller coverage directory is created with permissions
+ file:
+ path: "{{ coverage_logs_dir }}/controller/{{ item }}"
+ state: directory
+ mode: 0777
+ with_items:
+ - controller
+ - common
+ become: "{{ logs.dir.become }}"
+ when: coverage_enabled
+
+- name: extend controller volume for coverage
+ set_fact:
+ controller_volumes: "{{ controller_volumes|default({}) +
[coverage_logs_dir+'/controller:/coverage'] }}"
+ when: coverage_enabled
+
- name: include plugins
include_tasks: "{{ item }}.yml"
with_items: "{{ controller_plugins | default([]) }}"
@@ -252,15 +279,13 @@
docker_container:
name: "{{ controller_name }}"
image:
- "{{docker_registry~docker.image.prefix}}/controller:{{docker.image.tag}}"
+ "{{docker_registry~docker.image.prefix}}/controller:{{ 'cov' if
(coverage_enabled) else docker.image.tag }}"
state: started
recreate: true
restart_policy: "{{ docker.restart.policy }}"
hostname: "{{ controller_name }}"
env: "{{ env }}"
- volumes:
- - "{{ whisk_logs_dir }}/{{ controller_name }}:/logs"
- - "{{ controller.confdir }}/{{ controller_name }}:/conf"
+ volumes: "{{ controller_volumes }}"
ports: "{{ ports_to_expose }}"
command:
/bin/sh -c
diff --git a/ansible/roles/invoker/tasks/deploy.yml
b/ansible/roles/invoker/tasks/deploy.yml
index 40b4b7c..0a1e793 100644
--- a/ansible/roles/invoker/tasks/deploy.yml
+++ b/ansible/roles/invoker/tasks/deploy.yml
@@ -252,6 +252,27 @@
volumes: "{{ volumes|default('')
}},/usr/lib/x86_64-linux-gnu/libapparmor.so.1:/usr/lib/x86_64-linux-gnu/libapparmor.so.1"
when: ansible_distribution == "Ubuntu"
+- name: check if coverage collection is enabled
+ set_fact:
+ coverage_enabled: false
+ when: coverage_enabled is undefined
+
+- name: ensure invoker coverage directory is created with permissions
+ file:
+ path: "{{ coverage_logs_dir }}/invoker/{{ item }}"
+ state: directory
+ mode: 0777
+ with_items:
+ - invoker
+ - common
+ become: "{{ logs.dir.become }}"
+ when: coverage_enabled
+
+- name: extend invoker volume for coverage
+ set_fact:
+ volumes: "{{ volumes|default('') }},{{ coverage_logs_dir
}}/invoker:/coverage"
+ when: coverage_enabled
+
- name: start invoker using docker cli
docker_container:
userns_mode: "host"
@@ -260,7 +281,7 @@
name: "{{ invoker_name }}"
hostname: "{{ invoker_name }}"
restart_policy: "{{ docker.restart.policy }}"
- image: "{{ docker_registry }}{{ docker.image.prefix }}/invoker:{{
docker.image.tag }}"
+ image: "{{ docker_registry }}{{ docker.image.prefix }}/invoker:{{ 'cov' if
(coverage_enabled) else docker.image.tag }}"
state: started
recreate: true
env: "{{ env }}"
diff --git a/ansible/templates/whisk.properties.j2
b/ansible/templates/whisk.properties.j2
index ce3f2db..c18e22a 100644
--- a/ansible/templates/whisk.properties.j2
+++ b/ansible/templates/whisk.properties.j2
@@ -7,6 +7,7 @@ testing.auth={{ openwhisk_home }}/ansible/files/auth.guest
vcap.services.file=
whisk.logs.dir={{ whisk_logs_dir }}
+whisk.coverage.logs.dir={{ coverage_logs_dir | default('') }}
environment.type={{ environmentInformation.type }}
whisk.ssl.client.verification={{ nginx.ssl.verify_client }}
whisk.ssl.cert={{ nginx.ssl.path }}/{{ nginx.ssl.cert }}
diff --git a/core/controller/.dockerignore b/core/controller/.dockerignore
index 802f440..d6a369a 100644
--- a/core/controller/.dockerignore
+++ b/core/controller/.dockerignore
@@ -1,3 +1,4 @@
*
!init.sh
-!build/distributions
\ No newline at end of file
+!build/distributions
+!build/tmp/docker-coverage
diff --git a/core/controller/Dockerfile.cov b/core/controller/Dockerfile.cov
new file mode 100644
index 0000000..035ce29
--- /dev/null
+++ b/core/controller/Dockerfile.cov
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
+FROM controller
+
+ARG OW_ROOT_DIR
+
+RUN mkdir -p /coverage/common && \
+ mkdir -p /coverage/controller && \
+ mkdir -p "${OW_ROOT_DIR}/common/scala/build" && \
+ mkdir -p "${OW_ROOT_DIR}/core/controller/build" && \
+ ln -s /coverage/common "${OW_ROOT_DIR}/common/scala/build/scoverage" && \
+ ln -s /coverage/controller "${OW_ROOT_DIR}/core/controller/build/scoverage"
+
+COPY build/tmp/docker-coverage /controller/
\ No newline at end of file
diff --git a/core/controller/build.gradle b/core/controller/build.gradle
index ca4f3b5..b7cfb8e 100644
--- a/core/controller/build.gradle
+++ b/core/controller/build.gradle
@@ -27,6 +27,12 @@ distDocker.dependsOn ':common:scala:distDocker', 'distTar'
project.archivesBaseName = "openwhisk-controller"
+ext.coverageJars = [
+ "${buildDir}/libs/${project.archivesBaseName}-$version-scoverage.jar",
+
"${project(':common:scala').buildDir.absolutePath}/libs/openwhisk-common-$version-scoverage.jar"
+]
+distDockerCoverage.dependsOn ':common:scala:jarScoverage', 'jarScoverage'
+
repositories {
mavenCentral()
}
diff --git a/core/invoker/.dockerignore b/core/invoker/.dockerignore
index 802f440..d6a369a 100644
--- a/core/invoker/.dockerignore
+++ b/core/invoker/.dockerignore
@@ -1,3 +1,4 @@
*
!init.sh
-!build/distributions
\ No newline at end of file
+!build/distributions
+!build/tmp/docker-coverage
diff --git a/core/invoker/Dockerfile.cov b/core/invoker/Dockerfile.cov
new file mode 100644
index 0000000..0fbf1ba
--- /dev/null
+++ b/core/invoker/Dockerfile.cov
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
+FROM invoker
+
+ARG OW_ROOT_DIR
+
+RUN mkdir -p /coverage/common && \
+ mkdir -p /coverage/invoker && \
+ mkdir -p "${OW_ROOT_DIR}/common/scala/build" && \
+ mkdir -p "${OW_ROOT_DIR}/core/invoker/build" && \
+ ln -s /coverage/common "${OW_ROOT_DIR}/common/scala/build/scoverage" && \
+ ln -s /coverage/invoker "${OW_ROOT_DIR}/core/invoker/build/scoverage"
+
+COPY build/tmp/docker-coverage /invoker/
\ No newline at end of file
diff --git a/core/invoker/build.gradle b/core/invoker/build.gradle
index 327dc78..6ead95b 100644
--- a/core/invoker/build.gradle
+++ b/core/invoker/build.gradle
@@ -26,6 +26,11 @@ apply from: '../../gradle/docker.gradle'
distDocker.dependsOn ':common:scala:distDocker', 'distTar'
project.archivesBaseName = "openwhisk-invoker"
+ext.coverageJars = [
+ "${buildDir}/libs/${project.archivesBaseName}-$version-scoverage.jar",
+
"${project(':common:scala').buildDir.absolutePath}/libs/openwhisk-common-$version-scoverage.jar"
+]
+distDockerCoverage.dependsOn ':common:scala:jarScoverage', 'jarScoverage'
repositories {
mavenCentral()
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
index 6ad6850..1377f0e 100644
--- a/gradle/docker.gradle
+++ b/gradle/docker.gradle
@@ -67,6 +67,48 @@ task distDocker {
println("Building '${dockerImageName}' took ${TimeCategory.minus(new
Date(), start)}")
}
}
+
+task distDockerCoverage() {
+ doLast {
+ def start = new Date()
+ //Copy the scoverage runtime jars
+ copy {from configurations.scoverage - configurations.compile; into
"build/tmp/docker-coverage/ext-lib"}
+ //Copy the scoverage prepared jars
+ coverageJars.each {jar ->
+ copy {from file(jar); into "build/tmp/docker-coverage/lib"; rename
{ it.replace('-scoverage', '')}}
+ }
+
+ def buildArgs = [
+ "OW_ROOT_DIR=${project.rootProject.projectDir.absolutePath}"
+ ]
+ def dockerImageNameOrig = dockerImageName
+ dockerImageName = "$dockerImageName-cov"
+
+ //Use absolute paths for dockerFile and build directory
+ String dockerFileDir =
project.buildscript.sourceFile.getParentFile().getAbsolutePath()
+ String dockerFile = "$dockerFileDir/Dockerfile.cov"
+
+ def cmd = dockerBinary + prepareBuildArgs(buildArgs) + ['-f',
dockerFile, '-t', dockerImageName, dockerFileDir]
+ retry(cmd, dockerRetries, dockerTimeout)
+ println("Building '${dockerImageName}' took ${TimeCategory.minus(new
Date(), start)}")
+
+ //Replace the original image with coverage one
+ project.ext.dockerTaggedImageName = dockerImagePrefix + '/' +
dockerImageNameOrig + ':' + "cov"
+ }
+ finalizedBy('tagImage')
+}
+
+def prepareBuildArgs(List buildArgs) {
+ def result = ['build']
+ if(project.hasProperty('dockerBuildArgs')) {
+ buildArgs.addAll(dockerBuildArgs)
+ }
+ buildArgs.each {arg ->
+ result += ['--build-arg', arg]
+ }
+ result
+}
+
task tagImage {
doLast {
def versionString = (dockerBinary + ['-v']).execute().text
diff --git a/tests/build.gradle b/tests/build.gradle
index 05561e7..e82c59d 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -198,17 +198,64 @@ gradle.projectsEvaluated {
}
}
+task copyMeasurementFiles() {
+ doLast{
+ Project common = project(":common:scala")
+ Project controller = project(":core:controller")
+ Project invoker = project(":core:invoker")
+
+ Properties wskProps = loadWhiskProps()
+ String covLogsDir = wskProps.getProperty('whisk.coverage.logs.dir')
+ assert covLogsDir : "Did not find coverage logs property
'whisk.coverage.logs.dir' in whisk props"
+
+ File covLogs = new File(covLogsDir)
+
+ copyAndRenameMeasurementFile(covLogs, 'controller', "common", common)
+ copyAndRenameMeasurementFile(covLogs, 'controller', "controller",
controller)
+ copyAndRenameMeasurementFile(covLogs, 'invoker', "common", common)
+ copyAndRenameMeasurementFile(covLogs, 'invoker', "invoker", invoker)
+ }
+}
+
/**
* Task to generate coverage xml report. Requires the
* tests to be executed prior to its invocation
*/
task reportCoverage(type: ScoverageReport) {
dependsOn([
+ copyMeasurementFiles,
':common:scala:reportScoverage',
':core:controller:reportScoverage',
':core:invoker:reportScoverage',
':tools:admin:reportScoverage'
])
+
+}
+
+/**
+ * Scoverage measurement files are named like scoverage.measurements.xxx.
Where xxx is thread id. While
+ * consolidating the files between container run and normal test run we need
to rename the files generated by
+ * container run so that the file name becomes unique
+ */
+def copyAndRenameMeasurementFile(File covLogDir, String containerName, String
moduleName, Project dest){
+ File dir = new File(new File(covLogDir, containerName), moduleName)
+ if (!dir.exists()) {
+ println "Coverage logs directory ${dir.absolutePath} does not exist.
Skipping measurement file collection"
+ return
+ }
+ copy{
+ from(dir)
+ into("${dest.buildDir.absolutePath}/scoverage")
+ rename {it+".$containerName-container"}
+ }
+}
+
+def loadWhiskProps(){
+ Properties p = new Properties()
+ file('../whisk.properties').withInputStream {is ->
+ p.load(is)
+ }
+ p
}
/**
diff --git a/tools/travis/distDocker.sh b/tools/travis/distDocker.sh
index 4415fc3..7f40d0b 100755
--- a/tools/travis/distDocker.sh
+++ b/tools/travis/distDocker.sh
@@ -27,4 +27,7 @@ ROOTDIR="$SCRIPTDIR/../.."
cd $ROOTDIR
TERM=dumb ./gradlew distDocker -PdockerImagePrefix=testing $GRADLE_PROJS_SKIP
+TERM=dumb ./gradlew :core:controller:distDockerCoverage
-PdockerImagePrefix=testing
+TERM=dumb ./gradlew :core:invoker:distDockerCoverage
-PdockerImagePrefix=testing
+
echo "Time taken for ${0##*/} is $SECONDS secs"
diff --git a/tools/travis/runSystemTests.sh b/tools/travis/runSystemTests.sh
index 7d1619b..f9c9ad3 100755
--- a/tools/travis/runSystemTests.sh
+++ b/tools/travis/runSystemTests.sh
@@ -25,6 +25,7 @@ ROOTDIR="$SCRIPTDIR/../.."
cd $ROOTDIR/tools/travis
export ORG_GRADLE_PROJECT_testSetName="REQUIRE_SYSTEM"
+export GRADLE_COVERAGE=true
./setupPrereq.sh