Run gradle spock test task in parallel - testing

In my build.gradle I have the following test task
task test1(type: Test) {
ignoreFailures true
testLogging {
events 'started', 'passed', 'skipped', 'failed'
exceptionFormat "full"
showStandardStreams = true
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
failedTest += result.failedTestCount
}
}
}
include "org/company/project/test/Test1.class"
}
task test2(type: Test) {
ignoreFailures true
testLogging {
events 'started', 'passed', 'skipped', 'failed'
exceptionFormat "full"
showStandardStreams = true
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
failedTest += result.failedTestCount
}
}
}
include "org/company/project/test/Test2.class"
}
I want these 2 tests to run in parallel, currently I use this command to run them ./gradlew cleanTest test1 test2 --info --rerun-tasks command to run them.
I tried --parallel, --max-workers=3 options nothing helped.

Gradle doesn't support running tasks inside the same project in parallel, unless you get a configuration cache hit, but that is an incubating feature and it might not work for you.
Is there any reason why you don't use forking inside the test task (docs)?
test {
maxParallelForks = 3
}
or for all test tasks
tasks.withType(Test) {
maxParallelForks = 3
}

Related

Error publishing to Sonatype because "repositoryUrl" is null

I've been trying to publish a project to Sonatype's repository, but I got an error and I can't find the solution online.
I have the following publishing block on my build.gradle.kts file:
publishing {
publications {
create<MavenPublication>("mavenJava") {
pom {
name.set("Keen")
description.set("A genetic algorithm framework for Kotlin")
url.set("https://github.com/r8vnhill/keen")
licenses {
license {
name.set("Attribution 4.0 International (CC BY 4.0)")
url.set("https://creativecommons.org/licenses/by/4.0/legalcode")
}
}
}
groupId = "cl.ravenhill"
artifactId = "keen"
version = projectVersion
from(components["java"])
}
}
repositories {
maven {
name = "sonatype"
if (version.toString().endsWith("SNAPSHOT")) {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "ossrh"
credentials(PasswordCredentials::class)
}
} else {
maven("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
name = "ossrh"
credentials(PasswordCredentials::class)
}
}
}
}
}
And the error I've got:
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':publishMavenJavaPublicationToSonatypeRepository'.
> Failed to publish publication 'mavenJava' to repository 'sonatype'
> Cannot invoke "java.net.URI.getScheme()" because "repositoryUrl" is null
Any idea of what could be happening?
The repository called 'sonatype' doesn't have a URL.
Assuming the version is a snapshot version, e.g. 1.2.3-SNAPSHOT, what you've written is
repositories {
maven {
name = "sonatype"
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "ossrh"
credentials(PasswordCredentials::class)
}
}
}
This is also equivalent to
repositories {
maven {
name = "sonatype"
}
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "ossrh"
credentials(PasswordCredentials::class)
}
}
So repository 'sonatype' has a name, but doesn't have a URL.
Gradle will create a publication task for each defined repository, even if the definition isn't valid (which can't be known ahead of time). If you ran the Gradle task
./gradlew publishMavenJavaPublicationToOssrhRepository
it would succeed.
To correct the problem, remove the 'sonatype' repository. It would also be more clear if you defined the target URL in a separate variable.
val ossrhRepositoryUrl = if (version.toString().endsWith("SNAPSHOT")) {
"https://s01.oss.sonatype.org/content/repositories/snapshots/"
} else {
"https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
}
publishing {
repositories {
maven(ossrhRepositoryUrl) {
name = "ossrh"
credentials(PasswordCredentials::class)
}
}
}

gradle publishing not working - No such Algorithm

I have a nexus repository that I want to publish my gradles versions catalog to. Here's the gradle build script:
buildscript {
dependencies {
classpath("com.android.tools.build:gradle:7.2.0")
}
}
plugins {
id ("version-catalog")
id ("maven-publish")
}
catalog {
versionCatalog {
from(files("gradle/libs.versions.toml"))
}
}
publishing {
publications {
create<MavenPublication>("VersionCatalog") {
groupId = "com.phinneyridge"
artifactId = "com.phinneyridge.version.catalog"
version = "1.0.0"
from(components["versionCatalog"])
}
repositories {
maven {
name = "PhinneyRidgeRepository"
url = uri(System.getenv()["PhinneyRidgeReleaseRepoUrl"].toString())
credentials {
username = System.getenv().get("PhinneyRidgeRepoUser").toString()
password = System.getenv().get("PhinneyRidgeRepoUserPW").toString()
}
println(url)
println(credentials.username + ":" + credentials.password)
}
}
}
}
Here's the output I get when I try to publish:
gradlew publish
Type-safe dependency accessors is an incubating feature.
Configure project :
https://ridgetop/nexus/repository/maven-releases/
publisher:mavenpublisher
Task :publishVersionCatalogPublicationToPhinneyRidgeRepositoryRepository FAILED
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':publishVersionCatalogPublicationToPhinneyRidgeRepositoryRepository'.
Failed to publish publication 'VersionCatalog' to repository 'PhinneyRidgeRepository'
java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.
SSLContextImpl$DefaultSSLContext)
If I changed the maven repository to mavenLocal(), the script actually publishes the version catalog to the local maven repository just fine.
What's also interesting, is that I have a custom gradle plugin in a different build script and it fairly well the same looking code pattern, and it successfully publishes the custom gradle plugin to same repository. Here's the code for that working script:
plugins {
id ("java-gradle-plugin")
"java-library"
id ("maven-publish")
id("com.gradle.plugin-publish") version "0.20.0"
id("org.jetbrains.kotlin.jvm") version "1.6.20"
id("org.gradle.kotlin.kotlin-dsl") version "2.1.7"
}
gradlePlugin {
group = "com.phinneyridge"
plugins {
create("PhinneyRidgePlugin") {
id = "com.phinneyridge.project"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeProjectPlugin"
}
create("PhinneyRidgeAndroidAppPlugin") {
id = "com.phinneyridge.android.application"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeAndroidAppPlugin"
}
create("PhinneyRidgeAndroidLibPlugin") {
id = "com.phinneyridge.android.library"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeAndroidLibPlugin"
}
create("PhinneyRidgeAndroidKotlinAppPlugin") {
id = "com.phinneyridge.android.kotlin.application"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeAndroidKotlinAppPlugin"
}
create("PhinneyRidgeAndroidKotlinLibPlugin") {
id = "com.phinneyridge.android.kotlin.library"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeAndroidKotlinLibPlugin"
}
create("PhinneyRidgeJavaAppPlugin") {
id = "com.phinneyridge.java.application"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeJavaAppPlugin"
}
create("PhinneyRidgeJavaLibPlugin") {
id = "com.phinneyridge.java.library"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeJavaLibPlugin"
}
create("PhinneyRidgeJavaKotlinAppPlugin") {
id = "com.phinneyridge.java.kotlin.application"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeJavaKotlinAppPlugin"
}
create("PhinneyRidgeJavaKotlinLibPlugin") {
id = "com.phinneyridge.java.kotlin.library"
implementationClass = "com.phinneyridge.android.gradle.PhinneyRidgeJavaKotlinLibPlugin"
}
create("PhinneyRidgeDSAnnotations") {
id = "com.phinneyridge.dsannotations"
implementationClass = "com.phinneyridge.osgi.DSAnnotations"
}
create("Aar2Jar") {
id = "com.phinneyridge.aar2jar"
implementationClass = "com.phinneyridge.android.Aar2Jar"
}
}
}
group = "com.phinneyridge"
version = "1.0.0"
publishing {
repositories {
maven {
url = uri(System.getenv().get("PhinneyRidgeReleaseRepoUrl").toString())
credentials {
username = System.getenv().get("PhinneyRidgeRepoUser").toString()
password = System.getenv().get("PhinneyRidgeRepoUserPW").toString()
}
}
}
}
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
gradleApi();
implementation ("com.android.tools.build:gradle:7.1.3")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20")
}
There's some differences, but the maven repository is constructed exactly the same. So the question is why am I getting the NoSuchAlgorithm error when I try to publish the version catalog?
If I try publishing with stacktrace I see the following:
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.securit
y.ssl.SSLContextImpl$DefaultSSLContext)
at org.gradle.internal.resource.transport.http.HttpClientConfigurer.jdkSupportsTLSProtocol(HttpClientConfigurer.java:115)
And here's what jdkSupportTLSProtocol looks like:
private static boolean jdkSupportsTLSProtocol(#SuppressWarnings("SameParameterValue") final String protocol) {
try {
for (String supportedProtocol : SSLContext.getDefault().getSupportedSSLParameters().getProtocols()) {
if (protocol.equals(supportedProtocol)) {
return true;
}
}
return false;
} catch (NoSuchAlgorithmException e) {
throw UncheckedException.throwAsUncheckedException(e);
}
}
It's the SSLContext.getDefault() that throws the NoSuchAlgorithException. I'm just currently at a lost understand what I need to change to get around this problem.
I figured out a solution to the problem.
I added a line of code to the maven repository declaration:
maven {
javax.net.ssl.SSLContext.setDefault(javax.net.ssl.SSLContext.getInstance("default"))
name = "PhinneyRidgeRepository"
url = uri(System.getenv()["PhinneyRidgeReleaseRepoUrl"].toString())
credentials {
username = System.getenv().get("PhinneyRidgeRepoUser").toString()
password = System.getenv().get("PhinneyRidgeRepoUserPW").toString()
}
println(url)
println(credentials.username + ":" + credentials.password)
}
}
That solved the problem, but I don't have an explanation why I had to set the SSLContext in one situation and not the other. According to the gradle documentation SSLContext.getDefault() is supposeto automagically call SSLContext.getInstance("Default") when the SSLContext is not initialized. (By the way the instance name seems to be case insensitive, so "default" or "Default" both worked.) My speculation is that this is a gradle bug, probably because the publication in one case is from component. That's the only obvious difference that I see that sets the two contrasting situations apart. By the way SSLContext.getInstance("TLSv1.2") would not work; I had to use "default"

How to get publish to wait on AAR file to exist before trying to publish?

Problem Statment
I am trying to create a build and publish a library based on properties I pass in through command line. I would like to use :
./gradlew clean build publish -PnexusUsername=* -PnexusPassword=* -PmajorVersion=x -PminorVersion=x -PbuildNumber=x
Work Around
My current work around for this is I use
./gradlew clean; ./gradlew build; ./gradlew publish -PnexusUsername=* -PnexusPassword=* -PmajorVersion=x -PminorVersion=x -PbuildNumber=x
Below you will find my main build gradle. I have tried many ideas of waiting for assembleRelease to be added and publishing being finalized by it, but alas I am not a gradle expert, so I am asking for help. I have two POJO/POKO libraries and one Android Library that I am publishing out as an AAR. The error I receive is that the POM file cannot be made because the AAR does not exist.
import CiCdDependencies.BOSS_SDK_SNAPSHOT
import CiCdDependencies.buildNumber
import CiCdDependencies.majorVersion
import CiCdDependencies.minorVersion
import CiCdDependencies.nexusPassword
import CiCdDependencies.NEXUS_URL
import CiCdDependencies.nexusUserName
import CiCdDependencies.productVersion
import CiCdDependencies.VERSION_NAME
import Coverage.androidCoverage
import Coverage.testCoverage
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.0.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0")
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3")
}
}
plugins {
id("java")
id("maven-publish")
id("org.sonarqube").version("3.3")
}
ext {
// Major / Minor / Release and Build numbering
productVersion = (project.findProperty("productVersion") ?: (System.getenv("PRODUCT_VERSION")
?: "0")).toString()
majorVersion =
(project.findProperty("majorVersion") ?: (System.getenv("MAJOR_VERSION") ?: "0")).toString()
minorVersion =
(project.findProperty("minorVersion") ?: (System.getenv("MINOR_VERSION") ?: "0")).toString()
buildNumber =
(project.findProperty("buildNumber") ?: (System.getenv("BUILD_NUMBER") ?: "0")).toString()
//for publishing
nexusUserName =
(project.findProperty("nexusUsername") ?: (System.getenv("NEXUS_USERNAME"))).toString()
nexusPassword =
(project.findProperty("nexusPassword") ?: (System.getenv("NEXUS_PASSWORD"))).toString()
testCoverage = project.hasProperty("TEST_COVERAGE")
androidCoverage = project.hasProperty("ANDROID_COVERAGE")
}
description = "MAFIA BOSS SDK (Kotlin)"
allprojects {
apply {
plugin("jacoco")
}
// Read only repositories for dependencies; this should never be used to publish
repositories {
google()
mavenCentral()
maven {
name = "DI2E-BossSdkReleases"
setUrl("$NEXUS_URL$BOSS_SDK_RELEASES")
credentials {
username = nexusUserName
password = nexusPassword
}
}
maven {
name = "DI2E-BossSdkSnapshots"
setUrl("$NEXUS_URL$BOSS_SDK_SNAPSHOT")
credentials {
username = nexusUserName
password = nexusPassword
}
}
}
}
sonarqube {
properties {
val gitBranch = "git rev-parse --abbrev-ref HEAD".runCommand()
property("sonar.sourceEncoding", "UTF-8")
property("sonar.host.url", "https://sonarqube.di2e.net")
property("sonar.projectVersion", gitBranch)
property("sonar.projectKey", "MAFIA-KotlinSDK")
property("sonar.login", "c58feafd2a81797dec0361dd2d8758885e4145d7")
property("sonar.junit.reportPaths", "**/test-results/**/*.xml")
property("sonar.coverage.jacoco.xmlReportPaths", "**/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")
}
}
tasks.getByName("publish").dependsOn("build")
/**
* Publishing configuration
*/
afterEvaluate {
publishing {
logger.lifecycle("Publishing ${VERSION_NAME()}")
publications {
val isSnapshot = !project.hasProperty("RELEASE")
create<MavenPublication>("BOSSSDKJAVA") {
groupId = "BOSS"
artifactId = "SDK-KOTLIN"
version = if (isSnapshot) {
"${VERSION_NAME()}-SNAPSHOT"
} else {
VERSION_NAME()
}
// The interfaces JAR
artifact("${rootProject.projectDir}/InfrastructureBase/build/libs/InfrastructureBase.jar") {
classifier = "InfrastructureBase"
}
// The implementations JAR
artifact("${rootProject.projectDir}/InfrastructureImpl/build/libs/InfrastructureImpl.jar") {
classifier = "InfrastructureImpl"
}
}
create<MavenPublication>("BOSSSDKANDROID") {
groupId = "BOSS"
artifactId = "SDK-ANDROID"
version = if (isSnapshot) {
"${VERSION_NAME()}-SNAPSHOT"
} else {
VERSION_NAME()
}
// The implementations AAR
artifact("${rootProject.projectDir}/InfrastructureAndroidImpl/build/outputs/aar/InfrastructureAndroidImpl-release.aar") {
classifier = "InfrastructureAndroidImpl"
}
}
repositories {
maven {
url = if (isSnapshot) {
logger.lifecycle("Performing snapshot build.")
uri("$NEXUS_URL$BOSS_SDK_SNAPSHOT")
} else {
logger.lifecycle("Performing release build.")
uri("$NEXUS_URL$BOSS_SDK_RELEASES")
}
credentials {
username = nexusUserName
password = nexusPassword
}
}
}
}
}
}
afterEvaluate {
tasks.getByName("jacocoTestReport", type = JacocoReport::class) {
reports {
print("I am reporting" )
xml.required.set(testCoverage)
html.required.set(testCoverage)
}
val fileFilter = mutableSetOf(
"**/R.class",
"**/R\$*.class",
"**/BuildConfig.*",
"**/Manifest*.*",
"**/*Test*.*",
"android/**/*.*",
"**/*\$Lambda$*.*", // Jacoco can not handle several "$" in class name.
"**/*\$inlined$*.*" // Kotlin specific, Jacoco can not handle several "$" in class name.
)
val debugTree = fileTree("${buildDir}/tmp/kotlin-classes/debug") {
exclude(fileFilter)
}
val mainSrc = "${project.projectDir}/src/main/java"
sourceDirectories.from(files(mainSrc))
classDirectories.setFrom(debugTree)
if (androidCoverage) {
executionData.setFrom(fileTree("$buildDir") {
include(
setOf(
"jacoco/*.exec",
"outputs/code-coverage/debugAndroidTest/connected/*coverage.ec",
"outputs/unit_test_code_coverage/*.exec"
)
)
})
} else if (testCoverage) {
executionData.setFrom(fileTree("$buildDir") {
include(
setOf(
"jacoco/*.exec",
"outputs/unit_test_code_coverage/*.exec"
)
)
})
}
configurations.all {
resolutionStrategy {
eachDependency {
if ("org.jacoco" == requested.group) {
useVersion("0.8.7")
}
}
}
}
}
}
tasks.getByName("sonarqube"){
dependsOn(tasks.getByName("jacocoTestReport"))
}
fun String.runCommand(currentWorkingDir: File = file("./")): String {
val byteOut = getByteOutput()
project.exec {
workingDir = currentWorkingDir
commandLine = this#runCommand.split("\\s".toRegex())
standardOutput = byteOut
}
return String(byteOut.toByteArray()).trim()
}```
I believe AGP has done something to make it easier, check it here: https://developer.android.com/studio/build/maven-publish-plugin
release(MavenPublication) {
// Applies the component for the release build variant.
from components.release
// You can then customize attributes of the publication as shown below.
groupId = 'com.example.MyLibrary'
artifactId = 'final'
version = '1.0'
}
The Android Gradle plugin creates a component for each build variant artifact in your app or library module that you can use to customize a publication to a Maven repository.
And you may need to move the android part to that android library's build.gradle(.kts).

Tests executes by priority through entire suite instead of class using TestNG and Gradle

all. I'm using IntelliJ IDEA with Selenium, TestNG and Gradle. After I had added a Gradle to the project my tests running in strange priority.
So, I have a XML file for run with TestNG:
<suite name="Mobile. Firefox. 320x480">
<parameter name="browserType" value="firefox" />
<parameter name="resolution" value="320x480"/>
<listeners>
<listener class-name="Listeners.Listeners"/>
</listeners>
<test name="320x480">
<classes>
<class name="TestsPerPage.TopMenu.TopMenuTests"/>
<class name="TestsPerPage.TopMenu.EstimateProjectTests"/>
</classes>
</test>
Test classes looks like:
TopMenuTests.class:
public class TopMenuTests extends SetupDriver {
TopMenuPageObjects topmenuPO;
#BeforeClass
public void initClasses(){
topmenuPO = new TopMenuPageObjects(driver);
System.out.println("Before Class TM");
}
#Test(groups = {"mobile"}, priority = 3)
public void mobilePortfolioOpen() {
System.out.println("Test TM, priority = 3");
}
#Test(groups = {"mobile"}, priority = 4)
public void mobileHomePageOpen() {
System.out.println("Test TM, priority = 4");
}
#Test(groups = {"mobile"}, priority = 5)
public void mobileCompanyPageOpen() {
System.out.println("Test TM, priority = 5");
}
EstimateProjectTests.class:
public class EstimateProjectTests extends SetupDriver {
EstimatePageObjects estimatePO;
#BeforeClass(groups = "mobile")
public void initMobileClasses() {
estimatePO = new EstimatePageObjects(driver);
System.out.println("Before Class EP");
}
#Test
public void estimatePageOpen(){
System.out.println("Test EP, priority = 0");
}
#Test(priority = 1)
public void mandatoryFieldsCheck(){
System.out.println("Test EP, priority = 1");
}
#Test(priority = 1)
public void labelsCheck(){
System.out.println("Test EP, priority = 1");
}
So, at the end, after running an XML file it should:
Run TopMenuTests.class -> run BeforeClass -> All tests by priority
Run EstimateProjectTests.clall -> run BeforeClass -> All tests by priority
Output shold be:
Before Class Tm
Test TM, priority = 3
Test TM, priority = 4
Test TM, priority = 5
Before Class EP
Test EP, priority = 0
Test EP, priority = 1
Test EP, priority = 1
But after I'd connected Gradle to the project I have this output:
Before Class Tm
Before Class EP
Test EP, priority = 0
Test EP, priority = 1
Test EP, priority = 1
Test TM, priority = 3
Test TM, priority = 4
Test TM, priority = 5
So, firstly had run all #BeforeClass and then all tests by, some kind of, "global" priority.
Have anyone faces the same issue?
My Gradle code:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.qameta.allure:allure-gradle:2.3"
}
}
plugins {
id "io.qameta.allure" version "2.5"
}
group 'com.indeema.web-site-automation'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: "io.qameta.allure"
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
allure {
version = "2.2.1"
autoconfigure = true
aspectjweaver = true
allureJavaVersion = "2.0-BETA18"
}
dependencies {
testCompile group: 'org.testng', name: 'testng', version: '6.10'
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.8.1'
}
test {
useTestNG()
}
P.S. Sorry for such big amount of the text, don't know how to explain it in a shorter way.

Protractor IE11 random failing tests

I have 45 tests that I run on protractor, when I run on chrome all tests pass, I have angular-typescript app.
when I run on IE11 the whole things become slower and 1-2 random tests fail sometimes and sometimes they all pass.
helper.ts:
public static clickAndWait(element: ElementFinder): webdriver.promise.Promise<void> {
return element.click();
}
public static ElementById(idStr: string ): ElementFinder {
browser.wait(function() { return ( element( by.id(idStr)).isPresent()); }, 32000);
return element( by.id(idStr));
}
public static getElementByRepeater(repeater: string): ElementArrayFinder {
return(element.all(by.repeater(repeater)));
}
public static getElementByRepeaterAndIndex(repeater: string , index : number): ElementFinder {
browser.wait(function() { return (element.all(by.repeater(repeater)).get(index)).isPresent(); }, 32000);
return (element.all(by.repeater(repeater)).get(index));
}
public static getElementByRepeaterLast (repeater: string ): ElementFinder {
browser.wait(function() { return (element.all(by.repeater(repeater)).last()).isPresent(); }, 32000);
return (element.all(by.repeater(repeater)).last());
}
The error that I tend to get Failed: Wait timed out after 32084ms.
I know that because of timeout of my function but i need a fix.
Should I add protractor expectedConditions ? should i clear the cache/cookies on every test run?.
npm version: 3.10 protractor version: 4.0.9 jasmine version: 2.5.2.
Thanks.