blob: 20c052e1ae581989e3605ca6cc6040e88cf0023c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
import org.scoverage.ScoverageReport
import static groovy.json.JsonOutput.*
plugins {
id 'eclipse'
id 'maven'
id 'org.hidetake.swagger.generator' version '2.18.1'
id 'org.scoverage'
id 'scala'
}
compileTestScala.options.encoding = 'UTF-8'
install.dependsOn ':tools:admin:install'
project.archivesBaseName = "openwhisk-tests"
def leanExcludes = [
'**/MaxActionDurationTests*',
'invokerShoot/**'
]
def projectsWithCoverage = [
':common:scala',
':core:controller',
':core:scheduler',
':core:invoker',
':tools:admin',
':core:cosmosdb:cache-invalidator'
]
def systemIncludes = [
"org/apache/openwhisk/core/limits/**",
"org/apache/openwhisk/core/admin/**",
"org/apache/openwhisk/core/cli/test/**",
"org/apache/openwhisk/core/apigw/actions/test/**",
"org/apache/openwhisk/core/database/test/*CacheConcurrencyTests*",
"org/apache/openwhisk/core/controller/test/*ControllerApiTests*",
"apigw/healthtests/**",
"ha/**",
"services/**",
"system/basic/**",
"system/rest/**",
]
ext.testSets = [
"REQUIRE_ONLY_DB" : [
"includes" : [
"org/apache/openwhisk/**"
],
"excludes" : [
"org/apache/openwhisk/core/admin/**",
"org/apache/openwhisk/core/apigw/actions/test/**",
"org/apache/openwhisk/standalone/**",
"org/apache/openwhisk/core/cli/test/**",
"org/apache/openwhisk/core/limits/**",
"org/apache/openwhisk/core/scheduler/**",
"org/apache/openwhisk/common/etcd/**",
"**/*CacheConcurrencyTests*",
"**/*ControllerApiTests*",
"org/apache/openwhisk/testEntities/**",
"invokerShoot/**"
]
],
"REQUIRE_SYSTEM" : [
"includes" : systemIncludes,
"excludes": [
"system/basic/WskMultiRuntimeTests*",
'invokerShoot/**'
]
],
"REQUIRE_SCHEDULER" : [
"includes" : [
"org/apache/openwhisk/common/etcd/**",
"org/apache/openwhisk/core/containerpool/v2/test/**",
"org/apache/openwhisk/core/scheduler/**",
"org/apache/openwhisk/core/service/**",
]
],
"REQUIRE_MULTI_RUNTIME" : [
"includes" : [
"system/basic/*MultiRuntimeTests*",
"system/basic/*UnicodeTests*",
"limits/**"
]
],
"LEAN" : [
"excludes" : leanExcludes
],
"REQUIRE_SYSTEM_BASIC" : [
"includes" : [
"system/basic/**"
]
],
"REQUIRE_LEAN_SYSTEM" : [
"includes" : systemIncludes,
// Tests suits below require Kafka so they are excluded for Lean System tests
"excludes" : [
"**/*KafkaConnectorTests*",
"system/basic/WskMultiRuntimeTests*",
"invokerShoot/**"
]
],
"REQUIRE_STANDALONE" : [
"includes" : [
"org/apache/openwhisk/standalone/**"
]
]
]
testSets.each {setName, patterns ->
def excludes = patterns["excludes"] ?: new HashSet<>()
excludes.addAll(leanExcludes)
patterns["excludes"] = excludes
}
//The value can be specified either via env variable
// ORG_GRADLE_PROJECT_testSetName
//Or via property -PtestSetName
if (!project.hasProperty("testSetName")) {
ext.testSetName = "LEAN"
}
def getPattern(String name, String type) {
def patterns = testSets[name]
assert patterns : "No pattern found for $name"
return patterns[type] ?: []
}
def logTestSetInfo(){
println "Using testSet $testSetName - ${prettyPrint(toJson(testSets[testSetName]))}"
}
test {
// Use command line option "-D testResultsDirName=<name>" to change the default test results directory ("test-results").
// Specify a path relative to the build directory or an absolute path.
testResultsDirName = System.getProperty('testResultsDirName', testResultsDirName)
exclude 'invokerShoot/**'
}
task testShootInvoker(type: Test) {
include 'invokerShoot/**'
}
task testLean(type: Test) {
doFirst {
logTestSetInfo()
}
exclude getPattern(testSetName, "excludes")
include getPattern(testSetName, "includes")
}
task testSystemBasic(type: Test) {
exclude getPattern("REQUIRE_SYSTEM_BASIC", "excludes")
include getPattern("REQUIRE_SYSTEM_BASIC", "includes")
}
task testSystemKCF(type: Test) {
exclude getPattern("REQUIRE_SYSTEM_BASIC", "excludes")
include getPattern("REQUIRE_SYSTEM_BASIC", "includes")
// KubernetesContainerFactory's logs API is not reliable and mixes stdout/stderr into a single stream
exclude "**/*ActivationLogsTests*"
// These tests fail almost all the time in openwhisk-deploy-kube TravisCI. Disabling to unblock PRs.
exclude "**/*WskPackageTests*"
exclude "**/*WskSequenceTests*"
}
task testUnit(type: Test) {
systemProperty("whisk.spi.ArtifactStoreProvider", "org.apache.openwhisk.core.database.memory.MemoryArtifactStoreProvider")
exclude getPattern("REQUIRE_ONLY_DB", "excludes")
include getPattern("REQUIRE_ONLY_DB", "includes")
//Test below have direct dependency on CouchDB running
def couchDbExcludes = [
"**/*NamespaceBlacklistTests*",
"**/*CleanUpActivationsTest*",
"**/*CouchDbRestClientTests*",
"**/*RemoveLogsTests*",
"**/*ReplicatorTest*",
"**/*CouchDBArtifactStoreTests*",
"invokerShoot/**"
]
exclude couchDbExcludes
}
dependencies {
compile "org.scala-lang:scala-library:${gradle.scala.version}"
compile "org.apache.commons:commons-lang3:3.3.2"
compile "org.apache.httpcomponents:httpclient:4.5.2:tests"
compile "org.apache.httpcomponents:httpmime:4.3.6"
compile "junit:junit:4.11"
compile "io.rest-assured:rest-assured:4.0.0"
compile "org.scalatest:scalatest_${gradle.scala.depVersion}:3.0.8"
compile "com.typesafe.akka:akka-testkit_${gradle.scala.depVersion}:${gradle.akka.version}"
compile "com.google.code.gson:gson:2.3.1"
compile "org.scalamock:scalamock_${gradle.scala.depVersion}:4.4.0"
compile "com.typesafe.akka:akka-http-testkit_${gradle.scala.depVersion}:${gradle.akka_http.version}"
compile "com.github.java-json-tools:json-schema-validator:2.2.8"
compile "org.mockito:mockito-core:2.27.0"
compile "io.opentracing:opentracing-mock:0.31.0"
compile "org.apache.curator:curator-test:${gradle.curator.version}"
compile "com.atlassian.oai:swagger-request-validator-core:1.4.5"
compile "io.github.embeddedkafka:embedded-kafka_${gradle.scala.depVersion}:2.4.0"
compile "com.typesafe.akka:akka-stream-kafka-testkit_${gradle.scala.depVersion}:${gradle.akka_kafka.version}"
compile "com.typesafe.akka:akka-stream-testkit_${gradle.scala.depVersion}:${gradle.akka.version}"
compile "io.fabric8:kubernetes-server-mock:${gradle.kube_client.version}"
compile "com.amazonaws:aws-java-sdk-s3:1.11.295"
compile "org.testcontainers:elasticsearch:1.15.3"
compile project(':common:scala')
compile project(':core:controller')
compile project(':core:scheduler')
compile project(':core:invoker')
compile project(':core:cosmosdb:cache-invalidator')
compile project(':core:monitoring:user-events')
compile project(':tools:admin')
swaggerCodegen 'io.swagger:swagger-codegen-cli:2.4.9'
}
def keystorePath = new File(sourceSets.test.scala.outputDir, 'keystore')
task deleteKeystore(type: Delete) {
delete keystorePath
}
task createKeystore(dependsOn: deleteKeystore) {
doLast {
def propsFile = file('../whisk.properties')
if (propsFile.exists()) {
Properties props = new Properties()
props.load(new FileInputStream(propsFile))
keystorePath.parentFile.mkdirs()
def cmd = ['keytool', '-import', '-alias', 'Whisk', '-noprompt', '-trustcacerts', '-file', file(props['whisk.ssl.cert']), '-keystore', keystorePath, '-storepass', 'openwhisk']
cmd.execute().waitForProcessOutput(System.out, System.err)
}
}
}
task buildArtifacts(type:Exec) {
workingDir 'dat/actions'
commandLine './build.sh'
}
tasks.withType(Test) {
dependsOn createKeystore
dependsOn buildArtifacts
}
createKeystore.mustRunAfter(testClasses)
buildArtifacts.mustRunAfter(testClasses)
gradle.projectsEvaluated {
task testCoverageLean(type: Test) {
doFirst {
logTestSetInfo()
}
classpath = getScoverageClasspath(project, projectsWithCoverage)
exclude getPattern(testSetName, "excludes")
include getPattern(testSetName, "includes")
}
task testCoverage(type: Test) {
classpath = getScoverageClasspath(project, projectsWithCoverage)
}
tasks.withType(ScalaCompile) {
configure(scalaCompileOptions.forkOptions) {
memoryMaximumSize = '1g'
}
}
tasks.withType(Test) {
systemProperties(System.getProperties())
systemProperty("whisk.server.jar", getStandaloneJarFilePath())
testLogging {
events "passed", "skipped", "failed"
showStandardStreams = true
exceptionFormat = 'full'
}
maxHeapSize = "1024m" //Gradle 5.5 defaults to 512MB which is low
outputs.upToDateWhen { false } // force tests to run every time
}
/**
* Task to generate coverage xml report. Requires the
* tests to be executed prior to its invocation
*/
task reportCoverage(type: ScoverageReport) {
def dependentTasks = []
dependentTasks << copyMeasurementFiles
projectsWithCoverage.forEach {
dependentTasks << it + ':reportScoverage'
}
dependsOn(dependentTasks)
//Need to recreate the logic from
//https://github.com/scoverage/gradle-scoverage/blob/924bf49a8f981f119d0604b44a782f3f8eecb359/src/main/groovy/org/scoverage/ScoveragePlugin.groovy#L137
//default tasks retrigger the tests. As ours is a multi module integration
//test we have to adapt the classpath and hence cannot use default reportXXXScoverage tasks
runner = new org.scoverage.ScoverageRunner(project.configurations.scoverage)
reportDir = reportTestScoverage.reportDir
sources = reportTestScoverage.sources
sourceEncoding = 'UTF-8'
dataDir = reportTestScoverage.dataDir
coverageOutputCobertura = reportTestScoverage.coverageOutputCobertura
coverageOutputXML = reportTestScoverage.coverageOutputXML
coverageOutputHTML = reportTestScoverage.coverageOutputHTML
coverageDebug = reportTestScoverage.coverageDebug
}
}
task copyMeasurementFiles() {
doLast{
Project common = project(":common:scala")
Project controller = project(":core:controller")
Project scheduler = project(":core:scheduler")
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, 'scheduler', "common", common)
copyAndRenameMeasurementFile(covLogs, 'scheduler', "scheduler", scheduler)
copyAndRenameMeasurementFile(covLogs, 'invoker', "common", common)
copyAndRenameMeasurementFile(covLogs, 'invoker', "invoker", invoker)
}
}
/**
* 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
}
/**
* Prepares the classpath which refer to scoverage instrumented classes from
* dependent projects "before" the non instrumented classes
*/
def getScoverageClasspath(Project project, List<String> projectNames) {
def combinedClasspath = projectNames.inject(project.files([])) { result, name ->
def cp = project.project(name).sourceSets.scoverage.runtimeClasspath
result + cp.filter {it.name.contains('scoverage')}
}
combinedClasspath + sourceSets.test.runtimeClasspath
}
swaggerSources {
java {
inputFile = file("$projectDir/../core/controller/src/main/resources/apiv1swagger.json")
code {
language = 'java'
configFile = file('src/test/resources/swagger-config.json')
dependsOn validation
}
}
}
task testSwaggerCodegen(type: GradleBuild) {
dependsOn swaggerSources.java.code
buildFile = "${buildDir}/swagger-code-java/build.gradle"
tasks = ['build']
}
def getStandaloneJarFilePath(){
project(":core:standalone").jar.archivePath
}