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 <chet...@apache.org>
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
 

Reply via email to