├── settings.gradle ├── gradle.properties ├── src ├── integration │ ├── resources │ │ ├── simple-application-forked │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── erizo │ │ │ │ └── gradle │ │ │ │ └── jcstress │ │ │ │ └── test │ │ │ │ └── simple │ │ │ │ └── TwoFieldTest.java │ │ ├── simple-application-sanity │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── erizo │ │ │ │ └── gradle │ │ │ │ └── jcstress │ │ │ │ └── test │ │ │ │ └── simple │ │ │ │ └── TwoFieldTest.java │ │ ├── simple-application-twojar │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── erizo │ │ │ │ └── gradle │ │ │ │ └── jcstress │ │ │ │ └── test │ │ │ │ └── simple │ │ │ │ └── TwoFieldTest.java │ │ ├── simple-application-include-tests │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldSecondClass.java │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── erizo │ │ │ │ └── gradle │ │ │ │ └── jcstress │ │ │ │ └── test │ │ │ │ └── simple │ │ │ │ └── TwoFieldTest.java │ │ ├── simple-application-sanity-java-17 │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── erizo │ │ │ │ └── gradle │ │ │ │ └── jcstress │ │ │ │ └── test │ │ │ │ └── simple │ │ │ │ └── TwoFieldTest.java │ │ ├── simple-application-new-gradle-apisample │ │ │ ├── settings.gradle │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── openjdk │ │ │ │ └── jcstress │ │ │ │ └── samples │ │ │ │ └── APISample_02_Arbiters.java │ │ └── simple-application-new-gradle-apisample-kt │ │ │ ├── settings.gradle.kts │ │ │ ├── src │ │ │ ├── main │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── github │ │ │ │ │ │ └── erizo │ │ │ │ │ │ └── gradle │ │ │ │ │ │ └── jcstress │ │ │ │ │ │ └── test │ │ │ │ │ │ └── simple │ │ │ │ │ │ └── AtomicInt.kt │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── erizo │ │ │ │ │ └── gradle │ │ │ │ │ └── jcstress │ │ │ │ │ └── test │ │ │ │ │ └── simple │ │ │ │ │ └── TwoFieldClass.java │ │ │ └── jcstress │ │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── openjdk │ │ │ │ └── jcstress │ │ │ │ └── samples │ │ │ │ └── APISample_02_Arbiters.java │ │ │ └── build.gradle.kts │ └── groovy │ │ └── com │ │ └── github │ │ └── erizo │ │ └── gradle │ │ ├── JcstressPluginForkedTestSpec.groovy │ │ ├── JcstressPluginIncludeTestsSpec.groovy │ │ ├── JcstressPluginUnforkedTestSpec.groovy │ │ ├── JcstressPluginJava17Spec.groovy │ │ ├── JcstressPluginFunctionalSpec.groovy │ │ ├── JcstressPluginIntegrationCasesSpec.groovy │ │ └── JcstressPluginCompatibleVersionsSpec.groovy ├── main │ └── java │ │ └── com │ │ └── github │ │ └── erizo │ │ └── gradle │ │ ├── JcstressTask.java │ │ ├── JcstressPluginExtension.java │ │ └── JcstressPlugin.java └── test │ └── groovy │ └── com │ └── github │ └── erizo │ └── gradle │ └── JcstressPluginSpec.groovy ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .github └── workflows │ └── gradle.yml ├── gradlew.bat ├── README.md ├── gradlew └── LICENSE /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-gradle-plugin' 2 | 3 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | #Thu, 13 Apr 2017 21:22:52 +0200 2 | version=0.9.1-SNAPSHOT 3 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-forked/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-test-simple' -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-test-simple' -------------------------------------------------------------------------------- /src/integration/resources/simple-application-twojar/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'simple-application-twojar' -------------------------------------------------------------------------------- /src/integration/resources/simple-application-include-tests/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-test-simple' -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity-java-17/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-test-simple' -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reyerizo/jcstress-gradle-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jcstress-test-apisample-new-gradle' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /.idea 3 | /build 4 | /*.iml 5 | /classes 6 | /out 7 | /.settings 8 | /.project 9 | /.classpath 10 | /bin 11 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample-kt/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "jcstress-test-apisample-new-gradle-kt" 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample-kt/src/main/kotlin/com/github/erizo/gradle/jcstress/test/simple/AtomicInt.kt: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering 2 | 3 | class AtomicInt { 4 | @Volatile 5 | private var value: Int = 0 6 | 7 | fun inc() { 8 | value++ 9 | } 10 | 11 | fun get() = value 12 | } 13 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-twojar/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | jcstress { 18 | verbose = true 19 | timeMillis = "200" 20 | iterations = 1 21 | } 22 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-forked/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | jcstress { 18 | verbose = true 19 | timeMillis = "200" 20 | iterations = 1 21 | forks = 1 22 | } 23 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | jcstress { 18 | verbose = true 19 | timeMillis = "200" 20 | mode = "sanity" 21 | iterations = 1 22 | } 23 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-include-tests/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | jcstress { 18 | verbose = true 19 | timeMillis = "200" 20 | iterations = 1 21 | includeTests = true 22 | } 23 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | jcstress { 18 | verbose = true 19 | timeMillis = "200" 20 | mode = 'sanity' 21 | iterations = 1 22 | } 23 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity-java-17/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'io.github.reyerizo.gradle.jcstress' 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | mavenLocal() 15 | } 16 | 17 | java { 18 | toolchain { 19 | languageVersion.set(JavaLanguageVersion.of(17)) 20 | } 21 | } 22 | 23 | jcstress { 24 | verbose = true 25 | timeMillis = "200" 26 | mode = "sanity" 27 | iterations = 1 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample-kt/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | repositories { 4 | mavenCentral() 5 | mavenLocal() 6 | } 7 | 8 | dependencies { 9 | } 10 | 11 | plugins { 12 | id("io.github.reyerizo.gradle.jcstress") 13 | kotlin("jvm") version "1.4.21" 14 | kotlin("kapt") version "1.4.21" 15 | } 16 | 17 | jcstress { 18 | verbose = "true" 19 | timeMillis = "200" 20 | mode = "sanity" 21 | iterations = "1" 22 | } 23 | 24 | tasks.withType() { 25 | kotlinOptions.jvmTarget = "1.8" 26 | } 27 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-forked/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-twojar/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity-java-17/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-include-tests/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample-kt/src/main/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-include-tests/src/test/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldSecondClass.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | public class TwoFieldSecondClass { 4 | 5 | long x; 6 | long y; 7 | 8 | public TwoFieldSecondClass(int x, long y) { 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | public long getX() { 14 | return x; 15 | } 16 | 17 | public void setX(long x) { 18 | this.x = x; 19 | } 20 | 21 | public long getY() { 22 | return y; 23 | } 24 | 25 | public void setY(long y) { 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | - name: Set up JDK 11 19 | uses: actions/setup-java@v2 20 | with: 21 | java-version: '11' 22 | distribution: 'adopt' 23 | - name: Grant execute permission for gradlew 24 | run: chmod +x gradlew 25 | - name: Build with Gradle 26 | run: ./gradlew clean build iT -i --stacktrace 27 | - name: Coverage 28 | run: ./gradlew jacocoTestReport coveralls -i --stacktrace 29 | - name: Publish test results 30 | uses: dorny/test-reporter@v2 31 | if: ${{ !cancelled() }} 32 | with: 33 | name: Unit Tests 34 | path: build/test-results/**/TEST-*.xml 35 | reporter: java-junit 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/erizo/gradle/JcstressTask.java: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.gradle.api.tasks.Input; 8 | import org.gradle.api.tasks.JavaExec; 9 | import org.gradle.api.tasks.Optional; 10 | import org.gradle.api.tasks.OutputDirectory; 11 | import org.gradle.api.tasks.options.Option; 12 | 13 | public class JcstressTask extends JavaExec { 14 | 15 | private String jcstressTestName; 16 | 17 | File reportsDirectory; 18 | 19 | @Option(option = "tests", description = "JCstress tests to execute.") 20 | public void setJcstressTestName(String jcstressTestName) { 21 | this.jcstressTestName = jcstressTestName; 22 | } 23 | 24 | @Input 25 | @Optional 26 | public String getJcstressTestName() { 27 | return jcstressTestName; 28 | } 29 | 30 | @OutputDirectory 31 | public File getReportsDirectory() { 32 | return reportsDirectory; 33 | } 34 | 35 | public List jcstressArgs() { 36 | List result = new ArrayList<>(); 37 | if (jcstressTestName != null) { 38 | result.add("-t"); 39 | result.add(jcstressTestName); 40 | } 41 | return result; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-forked/src/jcstress/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldTest.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | import org.openjdk.jcstress.annotations.*; 4 | import org.openjdk.jcstress.infra.results.LL_Result; 5 | 6 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; 7 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING; 8 | 9 | @JCStressTest 10 | @Description("Tests safeIncrementValue is threadsafe") 11 | @Outcome.Outcomes({ 12 | @Outcome(id = "[0, 0]", expect = ACCEPTABLE, desc = "Object not constructed yet"), 13 | @Outcome(id = "[1, 0]", expect = ACCEPTABLE, desc = "Object half-way"), 14 | @Outcome(id = "[1, 2]", expect = ACCEPTABLE, desc = "Object fully constructed"), 15 | @Outcome(expect = ACCEPTABLE_INTERESTING, desc = "Reordered"), 16 | }) 17 | @State() 18 | public class TwoFieldTest { 19 | 20 | private pl.erizo.gradle.jcstress.reordering.TwoFieldClass twoFieldClass = new pl.erizo.gradle.jcstress.reordering.TwoFieldClass(0, 0); 21 | 22 | @Actor 23 | public void actor1() { 24 | twoFieldClass.setX(1); 25 | twoFieldClass.setY(2); 26 | } 27 | 28 | @Actor 29 | public void actor2(LL_Result longResult) { 30 | longResult.r1 = twoFieldClass.x; 31 | longResult.r2 = twoFieldClass.y; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity/src/jcstress/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldTest.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | import org.openjdk.jcstress.annotations.*; 4 | import org.openjdk.jcstress.infra.results.LL_Result; 5 | 6 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; 7 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING; 8 | 9 | @JCStressTest 10 | @Description("Tests safeIncrementValue is threadsafe") 11 | @Outcome.Outcomes({ 12 | @Outcome(id = "[0, 0]", expect = ACCEPTABLE, desc = "Object not constructed yet"), 13 | @Outcome(id = "[1, 0]", expect = ACCEPTABLE, desc = "Object half-way"), 14 | @Outcome(id = "[1, 2]", expect = ACCEPTABLE, desc = "Object fully constructed"), 15 | @Outcome(expect = ACCEPTABLE_INTERESTING, desc = "Reordered"), 16 | }) 17 | @State() 18 | public class TwoFieldTest { 19 | 20 | private pl.erizo.gradle.jcstress.reordering.TwoFieldClass twoFieldClass = new pl.erizo.gradle.jcstress.reordering.TwoFieldClass(0, 0); 21 | 22 | @Actor 23 | public void actor1() { 24 | twoFieldClass.setX(1); 25 | twoFieldClass.setY(2); 26 | } 27 | 28 | @Actor 29 | public void actor2(LL_Result longResult) { 30 | longResult.r1 = twoFieldClass.x; 31 | longResult.r2 = twoFieldClass.y; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-twojar/src/jcstress/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldTest.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | import org.openjdk.jcstress.annotations.*; 4 | import org.openjdk.jcstress.infra.results.LL_Result; 5 | 6 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; 7 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING; 8 | 9 | @JCStressTest 10 | @Description("Tests safeIncrementValue is threadsafe") 11 | @Outcome.Outcomes({ 12 | @Outcome(id = "[0, 0]", expect = ACCEPTABLE, desc = "Object not constructed yet"), 13 | @Outcome(id = "[1, 0]", expect = ACCEPTABLE, desc = "Object half-way"), 14 | @Outcome(id = "[1, 2]", expect = ACCEPTABLE, desc = "Object fully constructed"), 15 | @Outcome(expect = ACCEPTABLE_INTERESTING, desc = "Reordered"), 16 | }) 17 | @State() 18 | public class TwoFieldTest { 19 | 20 | private pl.erizo.gradle.jcstress.reordering.TwoFieldClass twoFieldClass = new pl.erizo.gradle.jcstress.reordering.TwoFieldClass(0, 0); 21 | 22 | @Actor 23 | public void actor1() { 24 | twoFieldClass.setX(1); 25 | twoFieldClass.setY(2); 26 | } 27 | 28 | @Actor 29 | public void actor2(LL_Result longResult) { 30 | longResult.r1 = twoFieldClass.x; 31 | longResult.r2 = twoFieldClass.y; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-sanity-java-17/src/jcstress/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldTest.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | import org.openjdk.jcstress.annotations.*; 4 | import org.openjdk.jcstress.infra.results.LL_Result; 5 | 6 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; 7 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING; 8 | 9 | @JCStressTest 10 | @Description("Tests safeIncrementValue is threadsafe") 11 | @Outcome.Outcomes({ 12 | @Outcome(id = "[0, 0]", expect = ACCEPTABLE, desc = "Object not constructed yet"), 13 | @Outcome(id = "[1, 0]", expect = ACCEPTABLE, desc = "Object half-way"), 14 | @Outcome(id = "[1, 2]", expect = ACCEPTABLE, desc = "Object fully constructed"), 15 | @Outcome(expect = ACCEPTABLE_INTERESTING, desc = "Reordered"), 16 | }) 17 | @State() 18 | public class TwoFieldTest { 19 | 20 | private pl.erizo.gradle.jcstress.reordering.TwoFieldClass twoFieldClass = new pl.erizo.gradle.jcstress.reordering.TwoFieldClass(0, 0); 21 | 22 | @Actor 23 | public void actor1() { 24 | twoFieldClass.setX(1); 25 | twoFieldClass.setY(2); 26 | } 27 | 28 | @Actor 29 | public void actor2(LL_Result longResult) { 30 | longResult.r1 = twoFieldClass.x; 31 | longResult.r2 = twoFieldClass.y; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-include-tests/src/jcstress/java/com/github/erizo/gradle/jcstress/test/simple/TwoFieldTest.java: -------------------------------------------------------------------------------- 1 | package pl.erizo.gradle.jcstress.reordering; 2 | 3 | import org.openjdk.jcstress.annotations.*; 4 | import org.openjdk.jcstress.infra.results.LL_Result; 5 | 6 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; 7 | import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING; 8 | 9 | @JCStressTest 10 | @Description("Tests safeIncrementValue is threadsafe") 11 | @Outcome.Outcomes({ 12 | @Outcome(id = "[0, 0]", expect = ACCEPTABLE, desc = "Object not constructed yet"), 13 | @Outcome(id = "[1, 0]", expect = ACCEPTABLE, desc = "Object half-way"), 14 | @Outcome(id = "[1, 2]", expect = ACCEPTABLE, desc = "Object fully constructed"), 15 | @Outcome(expect = ACCEPTABLE_INTERESTING, desc = "Reordered"), 16 | }) 17 | @State() 18 | public class TwoFieldTest { 19 | 20 | private pl.erizo.gradle.jcstress.reordering.TwoFieldClass twoFieldClass = new pl.erizo.gradle.jcstress.reordering.TwoFieldClass(0, 0); 21 | 22 | private pl.erizo.gradle.jcstress.reordering.TwoFieldSecondClass twoFieldSecondClass; 23 | 24 | @Actor 25 | public void actor1() { 26 | twoFieldClass.setX(1); 27 | twoFieldClass.setY(2); 28 | } 29 | 30 | @Actor 31 | public void actor2(LL_Result longResult) { 32 | longResult.r1 = twoFieldClass.x; 33 | longResult.r2 = twoFieldClass.y; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginForkedTestSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Specification 8 | import spock.lang.TempDir 9 | 10 | import java.nio.file.Paths 11 | 12 | class JcstressPluginForkedTestSpec extends Specification { 13 | 14 | @TempDir 15 | File testProjectDir 16 | 17 | def pluginClasspath 18 | 19 | def setup() { 20 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 21 | new File(it) 22 | } 23 | } 24 | 25 | def "should complete a forked run"() { 26 | given: 27 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-forked").toURI()).toFile() 28 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 29 | 30 | when: 31 | def result = runGradleTask('jcstress') 32 | def errorMessage = result.output.find('FATAL: (.*)') 33 | def runResults = result.output.find('RUN RESULTS') 34 | 35 | then: 36 | verifyAll { 37 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 38 | errorMessage == null 39 | runResults == 'RUN RESULTS' 40 | } 41 | } 42 | 43 | private BuildResult runGradleTask(String taskName) { 44 | GradleRunner.create() 45 | .withProjectDir(testProjectDir) 46 | .withArguments(taskName, '-i', '--stacktrace', '--refresh-dependencies') 47 | .forwardStdOutput(System.out.newPrintWriter()) 48 | .forwardStdError(System.err.newPrintWriter()) 49 | .withPluginClasspath(pluginClasspath) 50 | .build() 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginIncludeTestsSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Specification 8 | import spock.lang.TempDir 9 | 10 | import java.nio.file.Paths 11 | 12 | class JcstressPluginIncludeTestsSpec extends Specification { 13 | 14 | @TempDir 15 | File testProjectDir 16 | 17 | def pluginClasspath 18 | 19 | def setup() { 20 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 21 | new File(it) 22 | } 23 | } 24 | 25 | def "should include a test class a simple run"() { 26 | given: 27 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-include-tests").toURI()).toFile() 28 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 29 | 30 | when: 31 | def result = runGradleTask('jcstress') 32 | def errorMessage = result.output.find('FATAL: (.*)') 33 | def runResults = result.output.find('RUN RESULTS') 34 | 35 | then: 36 | verifyAll { 37 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 38 | errorMessage == null 39 | runResults == 'RUN RESULTS' 40 | } 41 | } 42 | 43 | private BuildResult runGradleTask(String taskName) { 44 | GradleRunner.create() 45 | .withProjectDir(testProjectDir) 46 | .forwardStdOutput(System.out.newPrintWriter()) 47 | .forwardStdError(System.err.newPrintWriter()) 48 | .withArguments(taskName, '-i', '--stacktrace', '--refresh-dependencies') 49 | .withPluginClasspath(pluginClasspath) 50 | .build() 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginUnforkedTestSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Specification 8 | import spock.lang.TempDir 9 | 10 | import java.nio.file.Paths 11 | 12 | class JcstressPluginUnforkedTestSpec extends Specification { 13 | 14 | @TempDir 15 | File testProjectDir 16 | 17 | def pluginClasspath 18 | 19 | def setup() { 20 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 21 | new File(it) 22 | } 23 | } 24 | 25 | def "should complete an unforked run"() { 26 | given: 27 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 28 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 29 | 30 | when: 31 | def result = runGradleTask('jcstress') 32 | 33 | def errorMessage = result.output.find('FATAL: (.*)') 34 | def runResults = result.output.find('RUN RESULTS') 35 | 36 | then: 37 | verifyAll { 38 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 39 | errorMessage == null 40 | runResults == 'RUN RESULTS' 41 | } 42 | } 43 | 44 | private BuildResult runGradleTask(String taskName) { 45 | GradleRunner.create() 46 | .withProjectDir(testProjectDir) 47 | .withArguments(taskName, '-i', '--stacktrace', '--refresh-dependencies') 48 | .forwardStdOutput(System.out.newPrintWriter()) 49 | .forwardStdError(System.err.newPrintWriter()) 50 | .withPluginClasspath(pluginClasspath) 51 | .withDebug(true) 52 | .build() 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginJava17Spec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Requires 8 | import spock.lang.Specification 9 | import spock.lang.TempDir 10 | 11 | import java.nio.file.Paths 12 | 13 | @Requires({ jvm.java17Compatible && !jvm.java19Compatible }) // Java 19 support was added in Gradle 7.6 14 | class JcstressPluginJava17Spec extends Specification { 15 | 16 | @TempDir 17 | File testProjectDir 18 | 19 | def pluginClasspath 20 | 21 | def setup() { 22 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 23 | new File(it) 24 | } 25 | } 26 | 27 | def "should run with 7.5.1 and java 17"() { 28 | given: 29 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity-java-17").toURI()).toFile() 30 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 31 | 32 | when: 33 | def result = runGradleTask('7.5.1', 'jcstress') 34 | def errorMessage = result.output.find('FATAL: (.*)') 35 | def runResults = result.output.find('RUN RESULTS') 36 | 37 | then: 38 | verifyAll { 39 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 40 | errorMessage == null 41 | runResults == 'RUN RESULTS' 42 | } 43 | } 44 | 45 | private BuildResult runGradleTask(String gradleVersion, String... taskNames) { 46 | def arguments = new ArrayList() 47 | arguments.addAll(taskNames) 48 | arguments.addAll(['-i', '--stacktrace', '--refresh-dependencies']) 49 | 50 | GradleRunner.create() 51 | .withProjectDir(testProjectDir) 52 | .withGradleVersion(gradleVersion) 53 | .forwardStdOutput(System.out.newPrintWriter()) 54 | .forwardStdError(System.err.newPrintWriter()) 55 | .withArguments(arguments) 56 | .withPluginClasspath(pluginClasspath) 57 | .withDebug(true) 58 | .build() 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginFunctionalSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.GradleRunner 5 | import org.gradle.testkit.runner.TaskOutcome 6 | import spock.lang.Specification 7 | import spock.lang.TempDir 8 | 9 | import java.nio.file.Paths 10 | 11 | class JcstressPluginFunctionalSpec extends Specification { 12 | 13 | @TempDir 14 | File testProjectDir 15 | 16 | def buildFile 17 | def settingsFile 18 | def pluginClasspath 19 | 20 | def setup() { 21 | buildFile = new File(testProjectDir, 'build.gradle') 22 | settingsFile = new File(testProjectDir, 'settings.gradle') 23 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 24 | new File(it) 25 | } 26 | buildFile << buildFileContents 27 | settingsFile << settingsFileContents 28 | } 29 | 30 | def "should create a Linux script"() { 31 | when: 32 | def result = runGradleTask('jcstressScripts') 33 | 34 | then: 35 | result.task(":jcstressScripts").outcome == TaskOutcome.SUCCESS 36 | 37 | def fileText = getFileContents("build", "scripts", "myTestProject-jcstress") 38 | fileText.contains("jcstress-core-0.15.jar") 39 | } 40 | 41 | def "should create a Windows script"() { 42 | when: 43 | def result = runGradleTask('jcstressScripts') 44 | 45 | then: 46 | result.task(":jcstressScripts").outcome == TaskOutcome.SUCCESS 47 | 48 | def fileText = getFileContents("build", "scripts", "myTestProject-jcstress.bat") 49 | fileText.contains("jcstress-core-0.15.jar") 50 | } 51 | 52 | private BuildResult runGradleTask(String taskName) { 53 | GradleRunner.create() 54 | .withProjectDir(testProjectDir) 55 | .withArguments(taskName, '-i', '--stacktrace', '--refresh-dependencies') 56 | .forwardStdOutput(System.out.newPrintWriter()) 57 | .forwardStdError(System.err.newPrintWriter()) 58 | .withPluginClasspath(pluginClasspath) 59 | .build() 60 | } 61 | 62 | private String getFileContents(String... pathElements) { 63 | Paths.get(testProjectDir.toString(), pathElements).text 64 | } 65 | 66 | def buildFileContents = 67 | """ 68 | plugins { 69 | id 'io.github.reyerizo.gradle.jcstress' 70 | } 71 | 72 | repositories { 73 | mavenCentral() 74 | } 75 | 76 | jcstress { 77 | } 78 | """ 79 | 80 | def settingsFileContents = "rootProject.name = 'myTestProject'" 81 | } 82 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample-kt/src/jcstress/java/org/openjdk/jcstress/samples/APISample_02_Arbiters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Red Hat Inc. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | package org.openjdk.jcstress.samples; 26 | 27 | import org.openjdk.jcstress.annotations.*; 28 | import org.openjdk.jcstress.infra.results.I_Result; 29 | 30 | /* 31 | Another flavor of the same test as JCStress_APISample_01_Simple is using 32 | arbiters. Arbiters run after both actors, and therefore can observe the 33 | final result. 34 | 35 | This allows to directly observe the atomicity failure: 36 | 37 | [OK] org.openjdk.jcstress.samples.JCStress_APISample_02_Arbiters 38 | (JVM args: [-server]) 39 | Observed state Occurrences Expectation Interpretation 40 | 1 940,359 ACCEPTABLE_INTERESTING One update lost: atomicity failure. 41 | 2 168,950,601 ACCEPTABLE Actors updated independently. 42 | 43 | How to run this test: 44 | $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_02_Arbiters 45 | */ 46 | 47 | @JCStressTest 48 | 49 | // These are the test outcomes. 50 | @Outcome(id = "1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "One update lost: atomicity failure.") 51 | @Outcome(id = "2", expect = Expect.ACCEPTABLE, desc = "Actors updated independently.") 52 | @State 53 | public class APISample_02_Arbiters { 54 | 55 | int v; 56 | 57 | @Actor 58 | public void actor1() { 59 | v++; 60 | } 61 | 62 | @Actor 63 | public void actor2() { 64 | v++; 65 | } 66 | 67 | @Arbiter 68 | public void arbiter(I_Result r) { 69 | r.r1 = v; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/integration/resources/simple-application-new-gradle-apisample/src/jcstress/java/org/openjdk/jcstress/samples/APISample_02_Arbiters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Red Hat Inc. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | package org.openjdk.jcstress.samples; 26 | 27 | import org.openjdk.jcstress.annotations.*; 28 | import org.openjdk.jcstress.infra.results.I_Result; 29 | 30 | /* 31 | Another flavor of the same test as JCStress_APISample_01_Simple is using 32 | arbiters. Arbiters run after both actors, and therefore can observe the 33 | final result. 34 | 35 | This allows to directly observe the atomicity failure: 36 | 37 | [OK] org.openjdk.jcstress.samples.JCStress_APISample_02_Arbiters 38 | (JVM args: [-server]) 39 | Observed state Occurrences Expectation Interpretation 40 | 1 940,359 ACCEPTABLE_INTERESTING One update lost: atomicity failure. 41 | 2 168,950,601 ACCEPTABLE Actors updated independently. 42 | 43 | How to run this test: 44 | $ java -jar jcstress-samples/target/jcstress.jar -t JCStress_APISample_02_Arbiters 45 | */ 46 | 47 | @JCStressTest 48 | 49 | // These are the test outcomes. 50 | @Outcome(id = "1", expect = Expect.ACCEPTABLE_INTERESTING, desc = "One update lost: atomicity failure.") 51 | @Outcome(id = "2", expect = Expect.ACCEPTABLE, desc = "Actors updated independently.") 52 | @State 53 | public class APISample_02_Arbiters { 54 | 55 | int v; 56 | 57 | @Actor 58 | public void actor1() { 59 | v++; 60 | } 61 | 62 | @Actor 63 | public void actor2() { 64 | v++; 65 | } 66 | 67 | @Arbiter 68 | public void arbiter(I_Result r) { 69 | r.r1 = v; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginIntegrationCasesSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Requires 8 | import spock.lang.Specification 9 | import spock.lang.TempDir 10 | 11 | import java.nio.file.Path 12 | import java.nio.file.Paths 13 | 14 | @Requires({ !jvm.java16Compatible }) // Java16 support was added in Gradle 7 15 | class JcstressPluginIntegrationCasesSpec extends Specification { 16 | 17 | @TempDir 18 | File testProjectDir 19 | 20 | def pluginClasspath 21 | 22 | def setup() { 23 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 24 | new File(it) 25 | } 26 | } 27 | 28 | def "should produce two separate jars"() { 29 | given: 30 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-twojar").toURI()).toFile() 31 | def projectRoot = testProjectDir 32 | FileUtils.copyDirectory(jcstressProjectRoot, projectRoot, false) 33 | 34 | when: 35 | runGradleTask('jar', 'jcstressJar') 36 | def fileNames = Path.of(projectRoot.toString(), 'build', 'libs').toFile().list() 37 | 38 | then: 39 | fileNames.sort() == ['simple-application-twojar.jar', 'simple-application-twojar-jcstress.jar'].sort() 40 | } 41 | 42 | def "should not throw a null pointer on a new gradle and apisample"() { 43 | given: 44 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-new-gradle-apisample").toURI()).toFile() 45 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 46 | 47 | when: 48 | def result = runGradleTask('jcstress') 49 | def errorMessage = result.output.find('FATAL: (.*)') 50 | def runResults = result.output.find('RUN RESULTS') 51 | 52 | then: 53 | verifyAll { 54 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 55 | errorMessage == null 56 | runResults == 'RUN RESULTS' 57 | } 58 | } 59 | 60 | def "should not throw a null pointer on a new gradle, apisample and Kotlin"() { 61 | given: 62 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-new-gradle-apisample-kt").toURI()).toFile() 63 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 64 | 65 | when: 66 | def result = runGradleTask('jcstress') 67 | def errorMessage = result.output.find('FATAL: (.*)') 68 | def runResults = result.output.find('RUN RESULTS') 69 | 70 | then: 71 | verifyAll { 72 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 73 | errorMessage == null 74 | runResults == 'RUN RESULTS' 75 | } 76 | } 77 | 78 | private BuildResult runGradleTask(String... taskNames) { 79 | def arguments = new ArrayList() 80 | arguments.addAll(taskNames) 81 | arguments.addAll(['-i', '--stacktrace', '--refresh-dependencies']) 82 | 83 | GradleRunner.create() 84 | .withProjectDir(testProjectDir) 85 | .withGradleVersion("6.7") 86 | .forwardStdOutput(System.out.newPrintWriter()) 87 | .forwardStdError(System.err.newPrintWriter()) 88 | .withArguments(arguments) 89 | .withPluginClasspath(pluginClasspath) 90 | .withDebug(true) 91 | .build() 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/integration/groovy/com/github/erizo/gradle/JcstressPluginCompatibleVersionsSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.apache.commons.io.FileUtils 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.Requires 8 | import spock.lang.Specification 9 | import spock.lang.TempDir 10 | 11 | import java.nio.file.Paths 12 | 13 | class JcstressPluginCompatibleVersionsSpec extends Specification { 14 | 15 | @TempDir 16 | File testProjectDir 17 | 18 | def pluginClasspath 19 | 20 | def setup() { 21 | pluginClasspath = getClass().classLoader.findResource('plugin-classpath.txt').readLines().collect { 22 | new File(it) 23 | } 24 | } 25 | 26 | @Requires({ !jvm.java17Compatible }) // Java17 support was added in Gradle 7.3 27 | def "should run with 7.0"() { 28 | given: 29 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 30 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 31 | 32 | when: 33 | def result = runGradleTask('7.0', 'jcstress') 34 | def errorMessage = result.output.find('FATAL: (.*)') 35 | def runResults = result.output.find('RUN RESULTS') 36 | 37 | then: 38 | verifyAll { 39 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 40 | errorMessage == null 41 | runResults == 'RUN RESULTS' 42 | } 43 | 44 | } 45 | 46 | @Requires({ !jvm.java16Compatible }) // Java16 support was added in Gradle 7 47 | def "should run with 6.6.1"() { 48 | given: 49 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 50 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 51 | 52 | when: 53 | def result = runGradleTask('6.6.1', 'jcstress') 54 | def errorMessage = result.output.find('FATAL: (.*)') 55 | def runResults = result.output.find('RUN RESULTS') 56 | 57 | then: 58 | verifyAll { 59 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 60 | errorMessage == null 61 | runResults == 'RUN RESULTS' 62 | } 63 | } 64 | 65 | @Requires({ !jvm.java19Compatible }) // Java19 support was added in Gradle 7.6 66 | def "should run with 7.5.1"() { 67 | given: 68 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 69 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 70 | 71 | when: 72 | def result = runGradleTask('7.5.1', 'jcstress') 73 | def errorMessage = result.output.find('FATAL: (.*)') 74 | def runResults = result.output.find('RUN RESULTS') 75 | 76 | then: 77 | verifyAll { 78 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 79 | errorMessage == null 80 | runResults == 'RUN RESULTS' 81 | } 82 | } 83 | 84 | @Requires({ !jvm.java20Compatible }) // Java20 support was added in Gradle 8.3 85 | def "should run with 8.0.1"() { 86 | given: 87 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 88 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 89 | 90 | when: 91 | def result = runGradleTask('8.0.1', 'jcstress') 92 | def errorMessage = result.output.find('FATAL: (.*)') 93 | def runResults = result.output.find('RUN RESULTS') 94 | 95 | then: 96 | verifyAll { 97 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 98 | errorMessage == null 99 | runResults == 'RUN RESULTS' 100 | } 101 | } 102 | 103 | @Requires({ jvm.java17Compatible }) 104 | def "should run with 9.0.0"() { 105 | given: 106 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 107 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 108 | 109 | when: 110 | def result = runGradleTask('9.0.0', 'jcstress') 111 | def errorMessage = result.output.find('FATAL: (.*)') 112 | def runResults = result.output.find('RUN RESULTS') 113 | 114 | then: 115 | verifyAll { 116 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 117 | errorMessage == null 118 | runResults == 'RUN RESULTS' 119 | } 120 | } 121 | 122 | @Requires({ !jvm.java18Compatible }) // Java18 support was added in Gradle 7.5 123 | def "should run with 7.3.2"() { 124 | given: 125 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 126 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 127 | 128 | when: 129 | def result = runGradleTask('7.3.2', 'jcstress') 130 | def errorMessage = result.output.find('FATAL: (.*)') 131 | def runResults = result.output.find('RUN RESULTS') 132 | 133 | then: 134 | verifyAll { 135 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 136 | errorMessage == null 137 | runResults == 'RUN RESULTS' 138 | } 139 | } 140 | 141 | @Requires({ !jvm.java13Compatible }) // Java13 support was added in Gradle 6 142 | def "should run with 5.6.4"() { 143 | given: 144 | def jcstressProjectRoot = Paths.get(getClass().classLoader.getResource("simple-application-sanity").toURI()).toFile() 145 | FileUtils.copyDirectory(jcstressProjectRoot, testProjectDir, false) 146 | 147 | when: 148 | def result = runGradleTask('5.6.4', 'jcstress') 149 | def errorMessage = result.output.find('FATAL: (.*)') 150 | def runResults = result.output.find('RUN RESULTS') 151 | 152 | then: 153 | verifyAll { 154 | result.task(":jcstress").outcome == TaskOutcome.SUCCESS 155 | errorMessage == null 156 | runResults == 'RUN RESULTS' 157 | } 158 | } 159 | 160 | private BuildResult runGradleTask(String gradleVersion, String... taskNames) { 161 | def arguments = new ArrayList() 162 | arguments.addAll(taskNames) 163 | arguments.addAll(['-i', '--stacktrace', '--refresh-dependencies']) 164 | 165 | GradleRunner.create() 166 | .withProjectDir(testProjectDir) 167 | .withGradleVersion(gradleVersion) 168 | .forwardStdOutput(System.out.newPrintWriter()) 169 | .forwardStdError(System.err.newPrintWriter()) 170 | .withArguments(arguments) 171 | .withPluginClasspath(pluginClasspath) 172 | .build() 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jcstress Gradle Plugin 2 | 3 | [![Maven Status](https://maven-badges.herokuapp.com/maven-central/io.github.reyerizo.gradle/jcstress-gradle-plugin/badge.svg?style=flat)](https://mvnrepository.com/artifact/io.github.reyerizo.gradle/jcstress-gradle-plugin) 4 | [![Build Status](https://github.com/reyerizo/jcstress-gradle-plugin/actions/workflows/gradle.yml/badge.svg)](https://github.com/reyerizo/jcstress-gradle-plugin/actions/workflows/gradle.yml) 5 | [![Coverage Status](https://coveralls.io/repos/github/reyerizo/jcstress-gradle-plugin/badge.svg?branch=master)](https://coveralls.io/github/reyerizo/jcstress-gradle-plugin?branch=master) 6 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 7 | 8 | This plugin integrates [The Java Concurrency Stress tests](http://openjdk.java.net/projects/code-tools/jcstress) with Gradle. 9 | 10 | ### Usage 11 | 12 | 1. Add the following to your `build.gradle`: 13 | 14 | _build.gradle:_ 15 | ```groovy 16 | plugins { 17 | id "io.github.reyerizo.gradle.jcstress" version "0.9.0" 18 | } 19 | ``` 20 | 21 | 2. Put your tests in `jcstress` sourceset: 22 | 23 | ``` 24 | /src/jcstress/java // <--- JCStress code goes here 25 | /src/jcstress/resources // <--- Resources go here 26 | 27 | /src/main/java // <--- The rest of the app 28 | /src/main/resources // <--- The rest of the app 29 | ``` 30 | 31 | 3. for reference, check the sample project: 32 | 33 | [https://github.com/reyerizo/jcstress-example](https://github.com/reyerizo/jcstress-example) 34 | 35 | 36 | ### Tasks 37 | 38 | Execute your tests with the following: 39 | 40 | ``` 41 | gradle jcstress 42 | ``` 43 | 44 | or a subset of your tests: 45 | 46 | ``` 47 | gradle jcstress --tests "MyFirstTest|MySecondTest" 48 | ``` 49 | 50 | The latter is an equivalent of `regexp` option below. 51 | 52 | ### Configuration 53 | 54 | If you need to customize the configuration, add a block like the following to configure the plugin: 55 | 56 | ``` 57 | jcstress { 58 | verbose = true 59 | timeMillis = "200" 60 | spinStyle = "THREAD_YIELD" 61 | } 62 | ``` 63 | 64 | These are all possible configuration options: 65 | 66 | | Name | Description | 67 | |--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 68 | | `affinityMode` | Use the specific affinity mode, if available. `NONE` = No affinity whatsoever; `GLOBAL` = Affnity for the entire JVM; `LOCAL` = Affinity for the individual actors. | 69 | | `cpuCount` | Number of CPUs to use. Defaults to all CPUs in the system. Reducing the number of CPUs limits the amount of resources (including memory) the run is using. | 70 | | `heapPerFork` | Java heap size per fork, in megabytes. This affects the stride size: maximum footprint will never be exceeded, regardless of min/max stride sizes. | 71 | | `forkMultiplier` | "Fork multiplier for randomized/stress tests. This allows more efficient randomized testing, as each fork would use a different seed." | 72 | | `forks` | Should fork each test N times. Must be 1 or higher. | 73 | | `iterations` | Iterations per test. | 74 | | `jvmArgs` | Use given JVM arguments. This disables JVM flags auto-detection, and runs only the single JVM mode. Either a single space-separated option line, or multiple options are accepted. This option only affects forked runs. | 75 | | `jvmArgsPrepend` | Prepend given JVM arguments to auto-detected configurations. This option only affects forked runs." | 76 | | `mode` | Test mode preset: `sanity`, `quick`, `default`, `tough`, `stress`. | 77 | | `regexp` | Regexp selector for tests. | 78 | | `reportDir` | Target destination to put the report into. | 79 | | `spinStyle` | Busy loop wait style. `HARD` = hard busy loop; `THREAD_YIELD` = use `Thread.yield()`; `THREAD_SPIN_WAIT` = use `Thread.onSpinWait()`; `LOCKSUPPORT_PARK_NANOS` = use `LockSupport.parkNanos()`. | 80 | | `splitPerActor` | Use split per-actor compilation mode, if available. | 81 | | `strideCount` | Internal stride count per epoch. Larger value increases cache footprint. | 82 | | `strideSize` | Internal stride size. Larger value decreases the synchronization overhead, but also reduces the number of collisions. | 83 | | `timeMillis` | Time to spend in single test iteration. Larger value improves test reliability, since schedulers do better job in the long run. | 84 | | `verbose` | Be extra verbose. | 85 | 86 | 87 | More options are available, but you probably won't need them: 88 | 89 | | Name | Description | 90 | | --- | --- | 91 | | `language` | format numbers according to the given locale, eg `en`, `fr`, etc. Will default to `en`. If unsure, just leave as is) | 92 | 93 | Options deprecated - will be removed completely in the next version. In current version, they don't have any effect. 94 | 95 | | Name | Description | 96 | |---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 97 | | `concurrency` | Number of CPUs to use. Defaults to all CPUs in the system. Reducing the number of CPUs limits the amount of resources (including memory) the run is using. | 98 | | `deoptratio` | Java heap size per fork, in megabytes. This affects the stride size: maximum footprint will never be exceeded, regardless of min/max stride sizes. | 99 | | `maxStride` | Should fork each test N times. `0` to run in the embedded mode with occasional forking, `-1` to never ever fork. | 100 | | `minStride` | Iterations per test. | 101 | 102 | The plugin uses a separate location for `jcstress` files: 103 | 104 | ``` 105 | src/jcstress/java // java sources 106 | src/jcstress/resources // resources 107 | ``` 108 | 109 | By default, the plugin uses `jcstress-core-0.15`. This can be easily changed with the following: 110 | 111 | ```groovy 112 | jcstress { 113 | jcstressDependency 'org.openjdk.jcstress:jcstress-core:0.x' 114 | } 115 | ``` 116 | 117 | ### Notes 118 | 119 | - This plugin is heavily based on [jmh-gradle-plugin](https://github.com/melix/jmh-gradle-plugin) and should behave in a similar way. 120 | -------------------------------------------------------------------------------- /src/main/java/com/github/erizo/gradle/JcstressPluginExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle; 2 | 3 | import org.gradle.api.Project; 4 | import org.gradle.api.model.ReplacedBy; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author jerzykrlk 11 | */ 12 | public class JcstressPluginExtension { 13 | 14 | public static final String JCSTRESS_DEFAULT_VERSION = "0.15"; 15 | 16 | private Project project; 17 | private String jcstressDependency = "org.openjdk.jcstress:jcstress-core:" + JCSTRESS_DEFAULT_VERSION; 18 | private String language = "en"; 19 | private Boolean includeTests = false; 20 | private String concurrency; 21 | private String deoptRatio; 22 | private String forks; 23 | private String forkMultiplier; 24 | private String iterations; 25 | private String jvmArgs; 26 | private String jvmArgsPrepend; 27 | private boolean list; 28 | private String mode; 29 | private String strideSize; 30 | private String strideCount; 31 | private String maxStride; 32 | private String minStride; 33 | private String reportDir; 34 | private boolean parse; 35 | private String cpuCount; 36 | private String regexp; 37 | private String timeMillis; 38 | private String verbose; 39 | private String spinStyle; 40 | private String heapPerFork; 41 | private boolean splitPerActor; 42 | private String affinityMode; 43 | 44 | public JcstressPluginExtension(final Project project) { 45 | this.project = project; 46 | } 47 | 48 | public List buildArgs() { 49 | List result = new ArrayList<>(); 50 | addParameter(result, "-c", cpuCount); 51 | addParameter(result, "-deoptRatio", deoptRatio); 52 | addParameter(result, "-f", forks); 53 | addParameter(result, "-fsm", forkMultiplier); 54 | addParameter(result, "-iters", iterations); 55 | addParameter(result, "-jvmArgs", jvmArgs); 56 | addParameter(result, "-jvmArgsPrepend", jvmArgsPrepend); 57 | if (this.list) { 58 | addParameter(result, "-l", Boolean.toString(list)); 59 | } 60 | addParameter(result, "-m", mode); 61 | addParameter(result, "-strideSize", strideSize); 62 | addParameter(result, "-strideCount", strideCount); 63 | addParameter(result, "-r", reportDir); 64 | if (this.parse) { 65 | addParameter(result, "-p", "true"); 66 | } 67 | addParameter(result, "-t", regexp); 68 | addParameter(result, "-time", timeMillis); 69 | addParameter(result, "-v", verbose); 70 | addParameter(result, "-spinStyle", spinStyle); 71 | addParameter(result, "-hs", heapPerFork); 72 | addParameter(result, "-sc", Boolean.toString(splitPerActor)); 73 | addParameter(result, "-af", affinityMode); 74 | return result; 75 | } 76 | 77 | public static void addParameter(List result, String param, String value) { 78 | if ("-v".equals(param) && "true".equals(value)) { 79 | result.add(param); 80 | } else if (value != null) { 81 | result.add(param); 82 | result.add(value); 83 | } 84 | } 85 | 86 | public Project getProject() { 87 | return project; 88 | } 89 | 90 | public void setProject(Project project) { 91 | this.project = project; 92 | } 93 | 94 | public String getJcstressDependency() { 95 | return jcstressDependency; 96 | } 97 | 98 | public void setJcstressDependency(String jcstressDependency) { 99 | this.jcstressDependency = jcstressDependency; 100 | } 101 | 102 | public String getLanguage() { 103 | return language; 104 | } 105 | 106 | public void setLanguage(String language) { 107 | this.language = language; 108 | } 109 | 110 | public Boolean getIncludeTests() { 111 | return includeTests; 112 | } 113 | 114 | public void setIncludeTests(Boolean includeTests) { 115 | this.includeTests = includeTests; 116 | } 117 | 118 | @Deprecated 119 | @ReplacedBy("cpuCount") 120 | public String getConcurrency() { 121 | return concurrency; 122 | } 123 | 124 | @Deprecated 125 | public void setConcurrency(String concurrency) { 126 | this.concurrency = concurrency; 127 | } 128 | 129 | public boolean isList() { 130 | return list; 131 | } 132 | 133 | public void setList(boolean list) { 134 | this.list = list; 135 | } 136 | 137 | /** 138 | * Completely removed from jcstress. No direct replacement. 139 | */ 140 | @Deprecated 141 | public String getDeoptRatio() { 142 | return deoptRatio; 143 | } 144 | 145 | @Deprecated 146 | public void setDeoptRatio(String deoptRatio) { 147 | this.deoptRatio = deoptRatio; 148 | } 149 | 150 | public String getForks() { 151 | return forks; 152 | } 153 | 154 | public void setForks(String forks) { 155 | this.forks = forks; 156 | } 157 | 158 | public String getIterations() { 159 | return iterations; 160 | } 161 | 162 | public void setIterations(String iterations) { 163 | this.iterations = iterations; 164 | } 165 | 166 | public String getJvmArgs() { 167 | return jvmArgs; 168 | } 169 | 170 | public void setJvmArgs(String jvmArgs) { 171 | this.jvmArgs = jvmArgs; 172 | } 173 | 174 | public String getMode() { 175 | return mode; 176 | } 177 | 178 | public void setMode(String mode) { 179 | this.mode = mode; 180 | } 181 | 182 | @Deprecated 183 | @ReplacedBy("strideSize,strideCount") 184 | public String getMaxStride() { 185 | return maxStride; 186 | } 187 | 188 | @Deprecated 189 | public void setMaxStride(String maxStride) { 190 | this.maxStride = maxStride; 191 | } 192 | 193 | @Deprecated 194 | @ReplacedBy("strideSize,strideCount") 195 | public String getMinStride() { 196 | return minStride; 197 | } 198 | 199 | @Deprecated 200 | public void setMinStride(String minStride) { 201 | this.minStride = minStride; 202 | } 203 | 204 | public String getStrideSize() { 205 | return strideSize; 206 | } 207 | 208 | public void setStrideSize(String strideSize) { 209 | this.strideSize = strideSize; 210 | } 211 | 212 | public String getStrideCount() { 213 | return strideCount; 214 | } 215 | 216 | public void setStrideCount(String strideCount) { 217 | this.strideCount = strideCount; 218 | } 219 | 220 | public String getReportDir() { 221 | return reportDir; 222 | } 223 | 224 | public void setReportDir(String reportDir) { 225 | this.reportDir = reportDir; 226 | } 227 | 228 | public String getCpuCount() { 229 | return cpuCount; 230 | } 231 | 232 | public void setCpuCount(String cpuCount) { 233 | this.cpuCount = cpuCount; 234 | } 235 | 236 | public String getRegexp() { 237 | return regexp; 238 | } 239 | 240 | public void setRegexp(String regexp) { 241 | this.regexp = regexp; 242 | } 243 | 244 | public String getTimeMillis() { 245 | return timeMillis; 246 | } 247 | 248 | public void setTimeMillis(String timeMillis) { 249 | this.timeMillis = timeMillis; 250 | } 251 | 252 | public String getVerbose() { 253 | return verbose; 254 | } 255 | 256 | public void setVerbose(String verbose) { 257 | this.verbose = verbose; 258 | } 259 | 260 | public String getSpinStyle() { 261 | return spinStyle; 262 | } 263 | 264 | public void setSpinStyle(String spinStyle) { 265 | this.spinStyle = spinStyle; 266 | } 267 | 268 | public String getHeapPerFork() { 269 | return heapPerFork; 270 | } 271 | 272 | public void setHeapPerFork(String heapPerFork) { 273 | this.heapPerFork = heapPerFork; 274 | } 275 | 276 | public String getForkMultiplier() { 277 | return forkMultiplier; 278 | } 279 | 280 | public void setForkMultiplier(String forkMultiplier) { 281 | this.forkMultiplier = forkMultiplier; 282 | } 283 | 284 | public String getJvmArgsPrepend() { 285 | return jvmArgsPrepend; 286 | } 287 | 288 | public void setJvmArgsPrepend(String jvmArgsPrepend) { 289 | this.jvmArgsPrepend = jvmArgsPrepend; 290 | } 291 | 292 | public Boolean getSplitPerActor() { 293 | return splitPerActor; 294 | } 295 | 296 | public void setSplitPerActor(Boolean splitPerActor) { 297 | this.splitPerActor = splitPerActor; 298 | } 299 | 300 | public String getAffinityMode() { 301 | return affinityMode; 302 | } 303 | 304 | public void setAffinityMode(String affinityMode) { 305 | this.affinityMode = affinityMode; 306 | } 307 | 308 | public boolean getParse() { 309 | return parse; 310 | } 311 | 312 | public void setParse(boolean parse) { 313 | this.parse = parse; 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command; 206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 207 | # shell script including quotes and variable substitutions, so put them in 208 | # double quotes to make sure that they get re-expanded; and 209 | # * put everything else in single quotes, so that it's not re-expanded. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /src/test/groovy/com/github/erizo/gradle/JcstressPluginSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.github.erizo.gradle 2 | 3 | import org.gradle.api.artifacts.Configuration 4 | import org.gradle.api.distribution.plugins.DistributionPlugin 5 | import org.gradle.api.internal.file.DefaultSourceDirectorySet 6 | import org.gradle.api.internal.project.DefaultProject 7 | import org.gradle.api.plugins.GroovyPlugin 8 | import org.gradle.api.plugins.JavaPlugin 9 | import org.gradle.api.tasks.JavaExec 10 | import org.gradle.api.tasks.Sync 11 | import org.gradle.api.tasks.application.CreateStartScripts 12 | import org.gradle.jvm.tasks.Jar 13 | import org.gradle.plugins.ide.idea.IdeaPlugin 14 | import org.gradle.testfixtures.ProjectBuilder 15 | import org.gradle.util.GradleVersion 16 | import spock.lang.Ignore 17 | import spock.lang.Specification 18 | 19 | import java.nio.file.Files 20 | import java.nio.file.Paths 21 | 22 | class JcstressPluginSpec extends Specification { 23 | 24 | private final DefaultProject project = createRootProject() 25 | private final JcstressPlugin plugin = new JcstressPlugin() 26 | 27 | def setup() { 28 | project.repositories { 29 | mavenCentral() 30 | mavenLocal() 31 | } 32 | } 33 | 34 | def "should apply JavaPlugin"() { 35 | when: 36 | plugin.apply(project) 37 | 38 | then: 39 | project.plugins.hasPlugin(JavaPlugin) 40 | } 41 | 42 | def "should apply DistributionPlugin"() { 43 | when: 44 | plugin.apply(project) 45 | 46 | then: 47 | project.plugins.hasPlugin(DistributionPlugin) 48 | } 49 | 50 | def "should add jcstress task"() { 51 | when: 52 | plugin.apply(project) 53 | 54 | then: 55 | project.tasks['jcstress'] instanceof JavaExec 56 | } 57 | 58 | def "should create jcstress source set"() { 59 | when: 60 | plugin.apply(project) 61 | 62 | then: 63 | project.sourceSets.jcstress.java.srcDirs == [project.file('src/jcstress/java')] as Set 64 | project.sourceSets.jcstress.resources.srcDirs == [project.file('src/jcstress/resources')] as Set 65 | } 66 | 67 | def "should add groovy source set if groovy plugin enabled"() { 68 | when: 69 | project.apply(plugin: GroovyPlugin) 70 | plugin.apply(project) 71 | 72 | def javaSourceSet = project.sourceSets.jcstress.java as DefaultSourceDirectorySet 73 | def groovySourceSet = project.sourceSets.jcstress.groovy as DefaultSourceDirectorySet 74 | def resourcesSourceSet = project.sourceSets.jcstress.resources as DefaultSourceDirectorySet 75 | 76 | then: 77 | javaSourceSet.name == 'java' 78 | groovySourceSet.name == 'groovy' 79 | resourcesSourceSet.name == 'resources' 80 | } 81 | 82 | def "should add jcstress configuration"() { 83 | when: 84 | plugin.apply(project) 85 | 86 | then: 87 | project.configurations['jcstress'] instanceof Configuration 88 | } 89 | 90 | def "should add jcstressJar task"() { 91 | when: 92 | plugin.apply(project) 93 | 94 | then: 95 | project.tasks['jcstressJar'] instanceof Jar 96 | } 97 | 98 | def "should include a class from jcstress sourceSet in jcstress jar"() { 99 | given: 100 | def jcstressClassFile = createNewFile("build", "classes", "java", "jcstress", "jcstress.class") 101 | 102 | when: 103 | plugin.apply(project) 104 | project.evaluate() 105 | 106 | then: 107 | Jar task = project.tasks['jcstressJar'] as Jar 108 | task.source.files.contains(jcstressClassFile) 109 | } 110 | 111 | def "should include a resource from jcstress sourceSet in jcstress jar"() { 112 | given: 113 | def jcstressClassFile = createNewFile("build", "resources", "jcstress", "jcstress.txt") 114 | 115 | when: 116 | plugin.apply(project) 117 | project.evaluate() 118 | 119 | then: 120 | Jar task = project.tasks['jcstressJar'] as Jar 121 | task.source.files.contains(jcstressClassFile) 122 | } 123 | 124 | def "should include a class from test sourceSet in jcstress jar when test enabled"() { 125 | given: 126 | def jcstressClassFile = createNewFile("build", "classes", "java", "test", "jcstress.class") 127 | plugin.apply(project) 128 | project.jcstress { 129 | includeTests = true 130 | } 131 | 132 | when: 133 | project.evaluate() 134 | 135 | then: 136 | Jar task = project.tasks['jcstressJar'] as Jar 137 | task.source.files.contains(jcstressClassFile) 138 | } 139 | 140 | def "should not include a class from test sourceSet in jcstress jar when test disabled"() { 141 | given: 142 | def jcstressClassFile = createNewFile("build", "classes", "test", "jcstress.class") 143 | plugin.apply(project) 144 | 145 | when: 146 | project.evaluate() 147 | 148 | then: 149 | Jar task = project.tasks['jcstressJar'] as Jar 150 | !task.source.files.contains(jcstressClassFile) 151 | } 152 | 153 | def "should add jcstressInstall task"() { 154 | when: 155 | plugin.apply(project) 156 | 157 | then: 158 | project.tasks['jcstressInstall'] instanceof Sync 159 | } 160 | 161 | def "should add default jvm args to jsctress task"() { 162 | when: 163 | plugin.apply(project) 164 | project.evaluate() 165 | def jcstressTask = project.tasks['jcstress'] 166 | 167 | then: 168 | jcstressTask.jvmArgs.containsAll(['-XX:+UnlockDiagnosticVMOptions', '-XX:+WhiteBoxAPI', '-XX:-RestrictContended']) 169 | } 170 | 171 | def "should add default language set to English"() { 172 | when: 173 | plugin.apply(project) 174 | project.evaluate() 175 | def jcstressTask = project.tasks['jcstress'] 176 | 177 | then: 178 | jcstressTask.allJvmArgs.contains('-Duser.language=en') 179 | } 180 | 181 | def "should add jcstress configuration arguments to jsctress task"() { 182 | given: 183 | plugin.apply(project) 184 | project.jcstress { 185 | timeMillis = "200" 186 | forks = 30 187 | } 188 | 189 | when: 190 | project.tasks.jcstress.args = ["asdf"] 191 | project.evaluate() 192 | def jcstressTask = project.tasks['jcstress'] 193 | 194 | then: 195 | jcstressTask.args.containsAll(['asdf', '-f', '30', '-time', '200']) 196 | } 197 | 198 | @Ignore("only manually") 199 | def "should start jcstress suite inline and fail"() { 200 | given: 201 | plugin.apply(project) 202 | project.jcstress { 203 | timeMillis = "200" 204 | forks = 30 205 | } 206 | 207 | when: 208 | project.tasks.jcstress.args = ["asdf"] 209 | project.evaluate() 210 | def jcstressTask = project.tasks['jcstress'] as JcstressTask 211 | jcstressTask.getActions().forEach({ action -> action.execute(jcstressTask) }) 212 | 213 | then: 214 | jcstressTask.args.containsAll(['asdf', '-f', '30', '-time', '200']) 215 | } 216 | 217 | def "should change default language to French"() { 218 | given: 219 | plugin.apply(project) 220 | project.jcstress { 221 | timeMillis = "200" 222 | forks = 30 223 | language = 'fr' 224 | } 225 | 226 | when: 227 | project.evaluate() 228 | def jcstressTask = project.tasks['jcstress'] 229 | 230 | then: 231 | jcstressTask.allJvmArgs.contains('-Duser.language=en') 232 | } 233 | 234 | def "should include tests in jcstress tasks if includeTests is true"() { 235 | given: 236 | plugin.apply(project) 237 | 238 | project.jcstress { 239 | includeTests = true 240 | } 241 | 242 | project.dependencies { 243 | testImplementation 'org.springframework:spring-core:4.0.0.RELEASE' 244 | } 245 | 246 | when: 247 | project.evaluate() 248 | def jcstressTask = project.tasks.jcstress 249 | 250 | then: 251 | jcstressTask.classpath.files.containsAll(project.configurations.testCompileClasspath.files) 252 | } 253 | 254 | def "should not include tests in jcstress tasks if includeTests is false"() { 255 | given: 256 | plugin.apply(project) 257 | 258 | project.jcstress { 259 | includeTests = false 260 | } 261 | 262 | project.dependencies { 263 | testImplementation 'org.springframework:spring-core:4.0.0.RELEASE' 264 | } 265 | 266 | when: 267 | project.evaluate() 268 | def jcstressTask = project.tasks.jcstress 269 | 270 | then: 271 | jcstressTask.classpath.filter({ it.name.contains('spring-core') }).size() == 0 272 | } 273 | 274 | def "should include tests in jcstress sourceSet classpath if includeTests is true"() { 275 | given: 276 | plugin.apply(project) 277 | 278 | project.jcstress { 279 | includeTests = true 280 | } 281 | 282 | project.dependencies { 283 | testImplementation 'org.springframework:spring-core:4.0.0.RELEASE' 284 | } 285 | 286 | when: 287 | project.evaluate() 288 | def compileClasspath = project.sourceSets.jcstress.compileClasspath 289 | def runtimeClasspath = project.sourceSets.jcstress.runtimeClasspath 290 | 291 | then: 292 | compileClasspath.files.containsAll(project.configurations.testCompileClasspath.files) 293 | runtimeClasspath.files.containsAll(project.configurations.testRuntimeClasspath.files) 294 | } 295 | 296 | def "should put jcstress results to temp dir"() { 297 | given: 298 | plugin.apply(project) 299 | 300 | when: 301 | project.evaluate() 302 | 303 | then: 304 | project.tasks['jcstress'].workingDir.toPath() == Paths.get(project.buildDir.path, "tmp", "jcstress") 305 | } 306 | 307 | def "should set report dir to build when not defined"() { 308 | given: 309 | plugin.apply(project) 310 | 311 | when: 312 | project.evaluate() 313 | def jcstressTask = project.tasks['jcstress'] as JavaExec 314 | 315 | then: 316 | def reportDirSwitchIndex = jcstressTask.args.indexOf("-r") 317 | Paths.get(jcstressTask.args[reportDirSwitchIndex + 1]).endsWith("build/reports/jcstress") 318 | } 319 | 320 | def "should not set report dir to build when already defined"() { 321 | given: 322 | plugin.apply(project) 323 | 324 | project.jcstress { 325 | reportDir = "my/report/dir" 326 | } 327 | 328 | when: 329 | project.evaluate() 330 | def jcstressTask = project.tasks['jcstress'] as JavaExec 331 | 332 | then: 333 | def reportDirSwitchIndex = jcstressTask.args.indexOf("-r") 334 | Paths.get(jcstressTask.args[reportDirSwitchIndex + 1]).endsWith("my/report/dir") 335 | } 336 | 337 | def "should add jcstress dependencies to jcstress configuration"() { 338 | given: 339 | plugin.apply(project) 340 | def jcstressDependency = project.dependencies.create("org.openjdk.jcstress:jcstress-core:${JcstressPluginExtension.JCSTRESS_DEFAULT_VERSION}") 341 | 342 | when: 343 | project.evaluate() 344 | 345 | then: 346 | getConfiguration("jcstressImplementation").allDependencies.contains(jcstressDependency) 347 | } 348 | 349 | def "should add jcstress dependencies to kapt if it is enabled"() { 350 | given: 351 | project.getConfigurations().create("kaptJcstress") 352 | plugin.apply(project) 353 | def jcstressDependency = project.dependencies.create("org.openjdk.jcstress:jcstress-core:${JcstressPluginExtension.JCSTRESS_DEFAULT_VERSION}") 354 | 355 | when: 356 | project.evaluate() 357 | 358 | then: 359 | getConfiguration("kaptJcstress").allDependencies.contains(jcstressDependency) 360 | !getConfiguration("jcstressAnnotationProcessor").allDependencies.contains(jcstressDependency) 361 | } 362 | 363 | def "should add jcstress dependencies to annotation processor if no kapt available"() { 364 | given: 365 | plugin.apply(project) 366 | def jcstressDependency = project.dependencies.create("org.openjdk.jcstress:jcstress-core:${JcstressPluginExtension.JCSTRESS_DEFAULT_VERSION}") 367 | 368 | when: 369 | project.evaluate() 370 | 371 | then: 372 | getConfiguration("jcstressAnnotationProcessor").allDependencies.contains(jcstressDependency) 373 | } 374 | 375 | def "should override jcstress dependency with gradle configuration"() { 376 | given: 377 | def newJcstressDependency = project.dependencies.create('org.springframework:spring-core:4.0.0.RELEASE') 378 | def defaultJcstressDependency = project.dependencies.create('org.openjdk.jcstress:jcstress-core:0.1.2') 379 | 380 | when: 381 | plugin.apply(project) 382 | 383 | project.jcstress { 384 | jcstressDependency = 'org.springframework:spring-core:4.0.0.RELEASE' 385 | } 386 | 387 | project.evaluate() 388 | 389 | then: 390 | getConfiguration("jcstressImplementation").allDependencies.contains(newJcstressDependency) 391 | !getConfiguration("jcstressImplementation").allDependencies.contains(defaultJcstressDependency) 392 | } 393 | 394 | def "should not add jcstress dependencies to compile configuration"() { 395 | given: 396 | def jcstressDependency = project.dependencies.create("org.openjdk.jcstress:jcstress-core:${JcstressPluginExtension.JCSTRESS_DEFAULT_VERSION}") 397 | 398 | when: 399 | plugin.apply(project) 400 | project.evaluate() 401 | 402 | then: 403 | verifyAll { 404 | !getConfiguration("compileOnly").allDependencies.contains(jcstressDependency) 405 | !getConfiguration("compileClasspath").allDependencies.contains(jcstressDependency) 406 | getConfiguration("jcstressImplementation").allDependencies.contains(jcstressDependency) 407 | } 408 | } 409 | 410 | def "should add jcstress configuration to test scope with Intellij plugin"() { 411 | given: 412 | project.apply(plugin: IdeaPlugin) 413 | 414 | when: 415 | plugin.apply(project) 416 | project.evaluate() 417 | 418 | then: 419 | project.idea.module.scopes.TEST.plus.contains(project.configurations.jcstress) 420 | } 421 | 422 | def "should add jcstress sources to test sources with Intellij plugin"() { 423 | given: 424 | project.apply(plugin: IdeaPlugin) 425 | 426 | when: 427 | plugin.apply(project) 428 | project.evaluate() 429 | 430 | def testSourceDirs = project.idea.module.testSources.files 431 | def jcstressSrcDirs = project.sourceSets.jcstress.java.srcDirs 432 | 433 | then: 434 | testSourceDirs.containsAll(jcstressSrcDirs) 435 | } 436 | 437 | def "should add jsctress scripts task"() { 438 | given: 439 | plugin.apply(project) 440 | 441 | when: 442 | def scriptTask = project.tasks.jcstressScripts 443 | 444 | then: 445 | scriptTask instanceof CreateStartScripts 446 | scriptTask.mainClassName == 'org.openjdk.jcstress.Main' 447 | scriptTask.applicationName == 'myjcstressproject-jcstress' 448 | } 449 | 450 | def "should include compile, runtime and jcstress dependencies in script task classpath"() { 451 | given: 452 | plugin.apply(project) 453 | 454 | project.dependencies { 455 | implementation 'org.springframework:spring-core:4.0.0.RELEASE' 456 | runtimeOnly 'org.springframework:spring-webmvc:4.0.0.RELEASE' 457 | } 458 | 459 | when: 460 | project.evaluate() 461 | def classpathFiles = project.tasks.jcstressScripts.classpath.files 462 | 463 | then: 464 | verifyAll { 465 | classpathFiles.containsAll(project.configurations.compileClasspath.files) 466 | classpathFiles.containsAll(project.configurations.runtimeClasspath.files) 467 | } 468 | } 469 | 470 | def "should not include test in script task classpath if includeTests is not set"() { 471 | given: 472 | plugin.apply(project) 473 | 474 | project.dependencies { 475 | testImplementation 'org.springframework:spring-test:4.0.0.RELEASE' 476 | } 477 | 478 | when: 479 | project.evaluate() 480 | def classpathFiles = project.tasks.jcstressScripts.classpath.files 481 | 482 | then: 483 | !classpathFiles.containsAll(project.configurations.testCompileClasspath.files) 484 | } 485 | 486 | def "should include test in script task classpath if includeTests is true"() { 487 | given: 488 | plugin.apply(project) 489 | 490 | project.dependencies { 491 | testImplementation 'org.springframework:spring-test:4.0.0.RELEASE' 492 | } 493 | 494 | project.jcstress { 495 | includeTests = true 496 | } 497 | 498 | when: 499 | project.evaluate() 500 | def classpathFiles = project.tasks.jcstressScripts.classpath.files 501 | 502 | then: 503 | classpathFiles.containsAll(project.configurations.testCompileClasspath.files) 504 | } 505 | 506 | def "should extract file name from Gradle dependency"() { 507 | expect: 508 | plugin.getFileNameFromDependency('com.github.reyerizo.gradle:jcstress-core:1.0-20160519191500') == "jcstress-core-1.0-20160519191500.jar" 509 | } 510 | 511 | def "should get the right Gradle version hierarchy"() { 512 | when: 513 | def gradle10 = GradleVersion.version("10.0.0") 514 | def gradle7 = GradleVersion.version("7.0.0") 515 | def gradle5 = GradleVersion.version("5.5.0") 516 | then: 517 | verifyAll { 518 | gradle10.compareTo(gradle5) > 0 519 | gradle10.compareTo(gradle7) > 0 520 | gradle5.compareTo(gradle7) < 0 521 | } 522 | } 523 | 524 | static DefaultProject createRootProject() { 525 | return ProjectBuilder 526 | .builder() 527 | .withProjectDir(Files.createTempDirectory("my-jcstress-project-").toFile()) 528 | .withName("myjcstressproject") 529 | .build() as DefaultProject 530 | } 531 | 532 | private Configuration getConfiguration(String configurationName) { 533 | return project.configurations[configurationName] 534 | } 535 | 536 | private File createNewFile(String... filePath) { 537 | def result = Paths.get(project.rootDir.toString(), filePath).toFile() 538 | result.parentFile.mkdirs() 539 | result.createNewFile() 540 | return result 541 | } 542 | 543 | } 544 | -------------------------------------------------------------------------------- /src/main/java/com/github/erizo/gradle/JcstressPlugin.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 the original author or authors. 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.erizo.gradle; 17 | 18 | import org.gradle.api.Action; 19 | import org.gradle.api.GradleException; 20 | import org.gradle.api.Plugin; 21 | import org.gradle.api.Project; 22 | import org.gradle.api.Task; 23 | import org.gradle.api.artifacts.Configuration; 24 | import org.gradle.api.artifacts.Dependency; 25 | import org.gradle.api.artifacts.dsl.DependencyHandler; 26 | import org.gradle.api.distribution.Distribution; 27 | import org.gradle.api.distribution.DistributionContainer; 28 | import org.gradle.api.distribution.plugins.DistributionPlugin; 29 | import org.gradle.api.file.CopySpec; 30 | import org.gradle.api.file.FileCollection; 31 | import org.gradle.api.plugins.JavaPlugin; 32 | import org.gradle.api.plugins.JavaPluginConvention; 33 | import org.gradle.api.plugins.JavaPluginExtension; 34 | import org.gradle.api.provider.Property; 35 | import org.gradle.api.tasks.SourceSet; 36 | import org.gradle.api.tasks.SourceSetContainer; 37 | import org.gradle.api.tasks.Sync; 38 | import org.gradle.api.tasks.application.CreateStartScripts; 39 | import org.gradle.api.tasks.bundling.Jar; 40 | import org.gradle.plugins.ide.idea.IdeaPlugin; 41 | import org.gradle.plugins.ide.idea.model.IdeaModel; 42 | import org.gradle.plugins.ide.idea.model.IdeaModule; 43 | import org.gradle.util.GradleVersion; 44 | 45 | import java.io.File; 46 | import java.io.IOException; 47 | import java.io.UncheckedIOException; 48 | import java.lang.reflect.InvocationTargetException; 49 | import java.lang.reflect.Method; 50 | import java.nio.file.Files; 51 | import java.nio.file.Path; 52 | import java.nio.file.Paths; 53 | import java.nio.file.attribute.PosixFilePermission; 54 | import java.nio.file.attribute.PosixFilePermissions; 55 | import java.util.ArrayList; 56 | import java.util.Arrays; 57 | import java.util.Set; 58 | 59 | /** 60 | * Configures the Jcstress Plugin. 61 | * 62 | * @author Cédric Champeau 63 | * @author jerzykrlk 64 | */ 65 | public class JcstressPlugin implements Plugin { 66 | 67 | private static final String JCSTRESS_NAME = "jcstress"; 68 | private static final String JCSTRESS_SOURCESET_NAME = JCSTRESS_NAME; 69 | private static final String JCSTRESS_CONFIGURATION_NAME = JCSTRESS_NAME; 70 | private static final String TASK_JCSTRESS_NAME = JCSTRESS_NAME; 71 | private static final String TASK_JCSTRESS_JAR_NAME = "jcstressJar"; 72 | private static final String TASK_JCSTRESS_INSTALL_NAME = "jcstressInstall"; 73 | private static final String TASK_JCSTRESS_SCRIPTS_NAME = "jcstressScripts"; 74 | public static final String KAPT_JCSTRESS_CONFIGURATION_NAME = "kaptJcstress"; 75 | 76 | private Project project; 77 | 78 | private String jcstressApplicationName; 79 | 80 | private SourceSet jcstressSourceSet; 81 | private SourceSet mainSourceSet; 82 | private SourceSet testSourceSet; 83 | 84 | private Configuration jcstressConfiguration; 85 | 86 | private Configuration mainCompileClasspath; 87 | private Configuration mainRuntimeClasspath; 88 | private Configuration testCompileClasspath; 89 | private Configuration testRuntimeClasspath; 90 | 91 | private Jar jcstressJarTask; 92 | private Task jcstressClassesTask; 93 | 94 | private JcstressPluginExtension jcstressPluginExtension; 95 | 96 | public void apply(Project project) { 97 | this.project = project; 98 | this.jcstressApplicationName = project.getName() + "-jcstress"; 99 | 100 | configureJavaPlugin(); 101 | configureDistributionPlugin(); 102 | 103 | jcstressPluginExtension = project.getExtensions().create(JCSTRESS_NAME, JcstressPluginExtension.class, project); 104 | 105 | this.jcstressConfiguration = createJcstressConfiguration(); 106 | 107 | addJcstressJarDependencies(); 108 | 109 | this.jcstressSourceSet = createJcstressSourceSet(); 110 | 111 | this.jcstressClassesTask = getJcstressClassesTask(); 112 | 113 | this.jcstressJarTask = createJcstressJarTask(); 114 | 115 | addJcstressTask(); 116 | 117 | addCreateStartScriptsTask(); 118 | 119 | Sync installAppTask = addInstallAppTask(); 120 | 121 | configureInstallTasks(installAppTask); 122 | 123 | updateIdeaPluginConfiguration(); 124 | 125 | } 126 | 127 | private Task getJcstressClassesTask() { 128 | return project.getTasks().getByName(JCSTRESS_SOURCESET_NAME + "Classes"); 129 | } 130 | 131 | private void configureJavaPlugin() { 132 | project.getPluginManager().apply(JavaPlugin.class); 133 | 134 | mainSourceSet = getProjectSourceSets().getByName("main"); 135 | testSourceSet = getProjectSourceSets().getByName("test"); 136 | 137 | this.mainCompileClasspath = project.getConfigurations().getByName("compileClasspath"); 138 | this.mainRuntimeClasspath = project.getConfigurations().getByName("runtimeClasspath"); 139 | this.testCompileClasspath = project.getConfigurations().getByName("testCompileClasspath"); 140 | this.testRuntimeClasspath = project.getConfigurations().getByName("testRuntimeClasspath"); 141 | } 142 | 143 | private void configureDistributionPlugin() { 144 | project.getPluginManager().apply(DistributionPlugin.class); 145 | } 146 | 147 | private Configuration createJcstressConfiguration() { 148 | return project.getConfigurations().create(JCSTRESS_CONFIGURATION_NAME); 149 | } 150 | 151 | private void addJcstressJarDependencies() { 152 | project.afterEvaluate(proj -> { 153 | addDependency(proj, JCSTRESS_SOURCESET_NAME + "Implementation", jcstressPluginExtension.getJcstressDependency()); 154 | if (hasConfiguration(proj, KAPT_JCSTRESS_CONFIGURATION_NAME)) { 155 | addDependency(proj, KAPT_JCSTRESS_CONFIGURATION_NAME, jcstressPluginExtension.getJcstressDependency()); 156 | } else { 157 | addDependency(proj, JCSTRESS_SOURCESET_NAME + "AnnotationProcessor", jcstressPluginExtension.getJcstressDependency()); 158 | } 159 | }); 160 | } 161 | 162 | private boolean hasConfiguration(Project project, String configurationName) { 163 | return project.getConfigurations().findByName(configurationName) != null; 164 | } 165 | 166 | private SourceSet createJcstressSourceSet() { 167 | 168 | SourceSet jcstressSourceSet = getProjectSourceSets().create(JCSTRESS_SOURCESET_NAME); 169 | 170 | FileCollection compileClasspath = jcstressSourceSet.getCompileClasspath() 171 | .plus(jcstressConfiguration) 172 | .plus(mainCompileClasspath) 173 | .plus(mainSourceSet.getOutput()); 174 | 175 | jcstressSourceSet.setCompileClasspath(compileClasspath); 176 | 177 | FileCollection runtimeClasspath = jcstressSourceSet.getRuntimeClasspath() 178 | .plus(jcstressConfiguration) 179 | .plus(mainRuntimeClasspath) 180 | .plus(mainSourceSet.getOutput()); 181 | 182 | jcstressSourceSet.setRuntimeClasspath(runtimeClasspath); 183 | 184 | project.afterEvaluate(proj -> { 185 | if (jcstressPluginExtension.getIncludeTests()) { 186 | FileCollection ccp = jcstressSourceSet.getCompileClasspath() 187 | .plus(testCompileClasspath) 188 | .plus(testSourceSet.getOutput()); 189 | jcstressSourceSet.setCompileClasspath(ccp); 190 | 191 | FileCollection rcp = jcstressSourceSet.getRuntimeClasspath() 192 | .plus(testRuntimeClasspath) 193 | .plus(testSourceSet.getOutput()); 194 | jcstressSourceSet.setRuntimeClasspath(rcp); 195 | } 196 | }); 197 | 198 | return jcstressSourceSet; 199 | } 200 | 201 | private Jar createJcstressJarTask() { 202 | 203 | Action jcstressExclusions = copySpec -> copySpec.exclude("**/META-INF/BenchmarkList", "**/META-INF/CompilerHints"); 204 | 205 | Jar jcstressJarTask = project.getTasks().create(TASK_JCSTRESS_JAR_NAME, Jar.class); 206 | 207 | jcstressJarTask.dependsOn(jcstressClassesTask); 208 | jcstressJarTask.getInputs().files(jcstressSourceSet.getOutput().getFiles()); 209 | 210 | project.afterEvaluate(proj -> { 211 | jcstressJarTask.from(jcstressSourceSet.getOutput()); 212 | jcstressJarTask.from(mainSourceSet.getOutput(), jcstressExclusions); 213 | if (jcstressPluginExtension.getIncludeTests()) { 214 | jcstressJarTask.from(testSourceSet.getOutput(), jcstressExclusions); 215 | } 216 | jcstressJarTask.getArchiveClassifier().set("jcstress"); 217 | }); 218 | 219 | return jcstressJarTask; 220 | } 221 | 222 | private JcstressTask addJcstressTask() { 223 | final JcstressTask jcstressTask = project.getTasks().create(TASK_JCSTRESS_NAME, JcstressTask.class); 224 | 225 | jcstressTask.dependsOn(jcstressJarTask); 226 | setMainClass(jcstressTask); 227 | jcstressTask.setGroup("Verification"); 228 | jcstressTask.setDescription("Runs jcstress benchmarks."); 229 | jcstressTask.setJvmArgs(Arrays.asList("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:-RestrictContended", "-Duser.language=" + jcstressPluginExtension.getLanguage())); 230 | jcstressTask.setClasspath(jcstressConfiguration.plus(project.getConfigurations().getByName(JCSTRESS_SOURCESET_NAME + "RuntimeClasspath").plus(mainRuntimeClasspath))); 231 | jcstressTask.doFirst(new Action() { 232 | @Override 233 | public void execute(Task task1) { 234 | getAndCreateDirectory(project.getBuildDir(), "tmp", "jcstress"); 235 | } 236 | }); 237 | 238 | project.afterEvaluate(project -> { 239 | if (jcstressPluginExtension.getReportDir() == null) { 240 | jcstressPluginExtension.setReportDir(getAndCreateDirectory(project.getBuildDir(), "reports", "jcstress").getAbsolutePath()); 241 | } 242 | jcstressTask.args(jcstressPluginExtension.buildArgs()); 243 | 244 | jcstressTask.reportsDirectory = new File(jcstressPluginExtension.getReportDir()); 245 | 246 | jcstressTask.setProperty("classpath", jcstressTask.getClasspath().plus(project.files(jcstressJarTask.getArchiveFile()))); 247 | filterConfiguration(jcstressConfiguration, "jcstress-core"); 248 | if (jcstressPluginExtension.getIncludeTests()) { 249 | jcstressTask.setProperty("classpath", jcstressTask.getClasspath().plus(testRuntimeClasspath)); 250 | } 251 | 252 | File path = getAndCreateDirectory(project.getBuildDir(), "tmp", "jcstress"); 253 | jcstressTask.setWorkingDir(path); 254 | }); 255 | 256 | jcstressTask.doFirst(new Action() { 257 | @Override 258 | public void execute(Task task1) { 259 | jcstressTask.args(jcstressTask.jcstressArgs()); 260 | } 261 | }); 262 | 263 | return jcstressTask; 264 | } 265 | 266 | private CreateStartScripts addCreateStartScriptsTask() { 267 | CreateStartScripts createStartScriptsTask = project.getTasks().create(TASK_JCSTRESS_SCRIPTS_NAME, CreateStartScripts.class); 268 | 269 | createStartScriptsTask.setDescription("Creates OS specific scripts to run the project as a jcstress test suite."); 270 | createStartScriptsTask.setClasspath(jcstressJarTask.getOutputs().getFiles() 271 | .plus(project.getConfigurations().getByName(JCSTRESS_SOURCESET_NAME + "RuntimeClasspath")) 272 | .plus(mainRuntimeClasspath)); 273 | 274 | String mainClassName = "org.openjdk.jcstress.Main"; 275 | if(isAtLeastGradle("6.0")) { 276 | createStartScriptsTask.getMainClass().set(mainClassName); 277 | } else { 278 | createStartScriptsTask.setMainClassName(mainClassName); 279 | } 280 | 281 | createStartScriptsTask.setApplicationName(jcstressApplicationName); 282 | createStartScriptsTask.setOutputDir(new File(project.getBuildDir(), "scripts")); 283 | createStartScriptsTask.setDefaultJvmOpts(new ArrayList<>(Arrays.asList( 284 | "-XX:+UnlockDiagnosticVMOptions", 285 | "-XX:+WhiteBoxAPI", 286 | "-XX:-RestrictContended", 287 | "-Duser.language=" + jcstressPluginExtension.getLanguage()))); 288 | 289 | project.afterEvaluate(it -> { 290 | if (jcstressPluginExtension.getIncludeTests()) { 291 | FileCollection classpath = createStartScriptsTask.getClasspath(); 292 | createStartScriptsTask.setClasspath(classpath.plus(testRuntimeClasspath)); 293 | } 294 | }); 295 | 296 | return createStartScriptsTask; 297 | } 298 | 299 | private static boolean isAtLeastGradle(String gradleVersion) { 300 | return GradleVersion.current().compareTo(GradleVersion.version(gradleVersion)) >= 0; 301 | } 302 | 303 | private void configureInstallTasks(Sync installTask) { 304 | installTask.doFirst(task -> { 305 | File destinationDir = installTask.getDestinationDir(); 306 | if (destinationDir.isDirectory()) { 307 | if (!new File(destinationDir, "lib").isDirectory() || !new File(destinationDir, "bin").isDirectory()) { 308 | throw new GradleException("The specified installation directory '" + destinationDir 309 | + "' is neither empty nor does it contain an installation for this application.\n" 310 | + "If you really want to install to this directory, delete it and run the install task again.\n" 311 | + "Alternatively, choose a different installation directory."); 312 | } 313 | } 314 | }); 315 | 316 | installTask.doLast(task -> 317 | { 318 | Path bin = Paths.get(installTask.getDestinationDir().getAbsolutePath(), "bin", jcstressApplicationName); 319 | try { 320 | Set posixFilePermissions = PosixFilePermissions.fromString("ugo+x"); 321 | Files.setPosixFilePermissions(bin, posixFilePermissions); 322 | } catch (IOException e) { 323 | throw new UncheckedIOException("Failed to update attributes of [" + bin + "]", e); 324 | } 325 | }); 326 | } 327 | 328 | private Sync addInstallAppTask() { 329 | DistributionContainer distributions = (DistributionContainer) project.getExtensions().getByName("distributions"); 330 | 331 | Distribution distribution = distributions.create("jcstress"); 332 | setDistributionBaseName(distribution); 333 | configureDistSpec(distribution.getContents()); 334 | 335 | Sync installTask = project.getTasks().create(TASK_JCSTRESS_INSTALL_NAME, Sync.class); 336 | 337 | installTask.setDescription("Installs the project as a JVM application along with libs and OS specific scripts."); 338 | installTask.setGroup("Verification"); 339 | installTask.with(distribution.getContents()); 340 | installTask.into(project.file(project.getBuildDir() + "/install/" + jcstressApplicationName)); 341 | 342 | return installTask; 343 | } 344 | 345 | private void setDistributionBaseName(Distribution distribution) { 346 | if (isAtLeastGradle("7.0")) { 347 | setGradle7BaseName(distribution); 348 | } else { 349 | setGradle6BaseName(distribution); 350 | } 351 | } 352 | 353 | private void setGradle7BaseName(Distribution distribution) { 354 | try { 355 | Method method = Distribution.class.getDeclaredMethod("getDistributionBaseName"); 356 | Property distributionBaseName = (Property) method.invoke(distribution); 357 | distributionBaseName.set(jcstressApplicationName); 358 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 359 | throw new IllegalStateException("Failed to set distribution base name", e); 360 | } 361 | } 362 | 363 | private void setGradle6BaseName(Distribution distribution) { 364 | try { 365 | Method method = Distribution.class.getDeclaredMethod("setBaseName", String.class); 366 | method.invoke(distribution, jcstressApplicationName); 367 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 368 | throw new IllegalStateException("Failed to set distribution base name", e); 369 | } 370 | } 371 | 372 | private void setMainClass(JcstressTask jcstressTask) { 373 | if (isAtLeastGradle("8.0")) { 374 | jcstressTask.getMainClass().set("org.openjdk.jcstress.Main"); 375 | } else { 376 | try { 377 | Method setMainMethod = JcstressTask.class.getMethod("setMain", String.class); 378 | setMainMethod.invoke(jcstressTask, "org.openjdk.jcstress.Main"); 379 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 380 | throw new IllegalStateException("Failed to set main class to [org.openjdk.jcstress.Main]", e); 381 | } 382 | } 383 | } 384 | 385 | 386 | private void configureDistSpec(CopySpec distSpec) { 387 | final Task jar = project.getTasks().getByName(TASK_JCSTRESS_JAR_NAME); 388 | final Task startScripts = project.getTasks().getByName(TASK_JCSTRESS_SCRIPTS_NAME); 389 | 390 | CopySpec copy = project.copySpec(); 391 | copy.from(project.file("src/dist")); 392 | copy.into("lib", cs -> { 393 | cs.from(jar); 394 | cs.from(jcstressConfiguration.plus(mainRuntimeClasspath)); 395 | }); 396 | 397 | copy.into("bin", cs -> { 398 | cs.from(startScripts); 399 | if(isAtLeastGradle("8.3")) { 400 | cs.filePermissions(filePermissions -> { 401 | filePermissions.unix(0755); 402 | }); 403 | } else { 404 | cs.setFileMode(0755); 405 | } 406 | }); 407 | 408 | distSpec.with(copy); 409 | } 410 | 411 | private static File getAndCreateDirectory(File dir, String... subdirectory) { 412 | File path = Paths.get(dir.getPath(), subdirectory).toFile(); 413 | path.mkdirs(); 414 | return path; 415 | } 416 | 417 | private void updateIdeaPluginConfiguration() { 418 | project.afterEvaluate(project -> { 419 | IdeaPlugin ideaPlugin = project.getPlugins().findPlugin(IdeaPlugin.class); 420 | if (ideaPlugin != null) { 421 | IdeaModel ideaModel = project.getExtensions().getByType(IdeaModel.class); 422 | IdeaModule module = ideaModel.getModule(); 423 | module.getScopes() 424 | .get("TEST") 425 | .get("plus") 426 | .add(jcstressConfiguration); 427 | 428 | Set jcstressSourceDirs = jcstressSourceSet.getJava().getSrcDirs(); 429 | module.getTestSources().from(jcstressSourceDirs); 430 | } 431 | }); 432 | } 433 | 434 | private SourceSetContainer getProjectSourceSets() { 435 | if(isAtLeastGradle("7.1")) { 436 | JavaPluginExtension plugin = project.getExtensions().getByType(JavaPluginExtension.class); 437 | return plugin.getSourceSets(); 438 | } else { 439 | JavaPluginConvention convention = project.getConvention().getPlugin(JavaPluginConvention.class); 440 | return convention.getSourceSets(); 441 | } 442 | } 443 | 444 | private void addDependency(Project project, String configurationName, String dependencyName) { 445 | DependencyHandler dependencyHandler = this.project.getDependencies(); 446 | Dependency dependency = dependencyHandler.create(dependencyName); 447 | 448 | project.getConfigurations().getByName(configurationName).getDependencies().add(dependency); 449 | } 450 | 451 | 452 | public static String getFileNameFromDependency(String gradleDependencyName) { 453 | String[] split = gradleDependencyName.split(":"); 454 | return split[1] + "-" + split[2] + ".jar"; 455 | } 456 | 457 | /** 458 | * Dummy method, loads configuration dependencies. 459 | * 460 | * @param configuration configuration 461 | * @param jarFileName jar file name 462 | * @return ignored 463 | */ 464 | private static Set filterConfiguration(Configuration configuration, final String jarFileName) { 465 | return configuration.filter(it -> it.getName().contains(jarFileName)).getFiles(); 466 | } 467 | 468 | } 469 | --------------------------------------------------------------------------------