├── .github └── workflows │ └── nebula.yml ├── .gitignore ├── .java-version ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── gradle.lockfile ├── gradle.properties ├── gradle ├── gradle-daemon-jvm.properties ├── m2-init.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── gradleTest └── simpleplugin │ ├── build.gradle │ └── src │ ├── main │ ├── groovy │ │ └── simple │ │ │ └── SimplePlugin.groovy │ └── resources │ │ └── META-INF │ │ └── gradle-plugins │ │ └── test.simple-plugin.properties │ └── test │ └── groovy │ └── simple │ ├── DependenciesSpec.groovy │ └── SimplePluginSpec.groovy ├── main └── groovy │ └── nebula │ └── test │ ├── AbstractProjectSpec.groovy │ ├── BaseIntegrationSpec.groovy │ ├── Integration.groovy │ ├── IntegrationBase.groovy │ ├── IntegrationSpec.groovy │ ├── IntegrationTestKitBase.groovy │ ├── IntegrationTestKitSpec.groovy │ ├── PluginProjectSpec.groovy │ ├── ProjectSpec.groovy │ ├── dependencies │ ├── Coordinate.groovy │ ├── DependencyGraph.groovy │ ├── DependencyGraphBuilder.groovy │ ├── DependencyGraphNode.groovy │ ├── GradleDependencyGenerator.groovy │ ├── ModuleBuilder.groovy │ ├── ivy │ │ └── Descriptor.groovy │ ├── maven │ │ ├── Artifact.groovy │ │ ├── ArtifactType.groovy │ │ └── Pom.groovy │ └── repositories │ │ ├── IvyRepo.groovy │ │ └── MavenRepo.groovy │ ├── functional │ ├── ExecutionResult.groovy │ ├── GradleRunner.groovy │ ├── GradleRunnerFactory.groovy │ ├── PreExecutionAction.groovy │ └── internal │ │ ├── DefaultExecutionResult.groovy │ │ ├── DefaultGradleRunner.groovy │ │ ├── ExecutedTask.groovy │ │ ├── GradleHandle.groovy │ │ ├── GradleHandleBuildListener.groovy │ │ ├── GradleHandleFactory.groovy │ │ ├── classpath │ │ ├── ClasspathAddingInitScriptBuilder.groovy │ │ └── ClasspathInjectingGradleHandleFactory.groovy │ │ └── toolingapi │ │ ├── BuildLauncherBackedGradleHandle.groovy │ │ ├── MinimalExecutedTask.groovy │ │ ├── ToolingApiGradleHandleFactory.groovy │ │ └── ToolingExecutionResult.groovy │ ├── gradle │ └── GradleVersionComparator.groovy │ ├── multiproject │ ├── MultiProjectHelper.groovy │ ├── MultiProjectInfo.groovy │ ├── MultiProjectIntegrationHelper.groovy │ └── MultiProjectIntegrationInfo.groovy │ └── package-info.groovy └── test ├── groovy └── nebula │ └── test │ ├── BuildScanIntegrationSpec.groovy │ ├── ConcreteIntegrationSpec.groovy │ ├── ConcretePluginProjectSpec.groovy │ ├── ConcreteProjectSpec.groovy │ ├── CustomCleanupProjectSpec.groovy │ ├── DeprecationCheckIntegrationSpec.groovy │ ├── FakePlugin.java │ ├── IntegrationTestKitSpecCustomBaseFolderSpec.groovy │ ├── IntegrationTestKitSpecSpec.groovy │ ├── JvmArgumentsIntegrationSpec.groovy │ ├── MutableProjectStateWarningCheckIntegrationSpec.groovy │ ├── ProjectDirCleanupProjectSpec.groovy │ ├── SpecifiedGradleVersionIntegrationSpec.groovy │ ├── SystemPropertyCleanupProjectSpec.groovy │ ├── dependencies │ ├── DependencyGraphBuilderSpec.groovy │ ├── DependencyGraphSpec.groovy │ ├── GradleDependencyGeneratorSpec.groovy │ ├── ModuleBuilderSpec.groovy │ ├── maven │ │ └── PomSpec.groovy │ └── repositories │ │ └── MavenRepoSpec.groovy │ ├── functional │ ├── GradleRunnerSpec.groovy │ ├── OutputsGradle2Spec.groovy │ ├── SomePlugin.groovy │ ├── TestSpec.groovy │ ├── ToolingApiGradleHandleFactorySpec.groovy │ ├── foo │ │ └── Thing.groovy │ └── internal │ │ ├── DefaultGradleRunnerSpec.groovy │ │ └── classpath │ │ ├── ClasspathAddingInitScriptBuilderFixture.groovy │ │ ├── ClasspathAddingInitScriptBuilderFunctionalTest.groovy │ │ └── ClasspathAddingInitScriptBuilderIntegrationTest.groovy │ ├── gradle │ └── GradleVersionComparatorSpec.groovy │ └── multiproject │ ├── MultiProjectHelperSpec.groovy │ └── MultiProjectIntegrationHelperSpec.groovy └── resources └── META-INF └── gradle-plugins └── fake-plugin.properties /.github/workflows/nebula.yml: -------------------------------------------------------------------------------- 1 | name: Nebula Build 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | tags: 7 | - v*.*.* 8 | - v*.*.*-rc.* 9 | pull_request: 10 | 11 | jobs: 12 | validation: 13 | name: "Gradle Wrapper Validation" 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: gradle/wrapper-validation-action@v1 18 | buildmultijdk: 19 | if: (!startsWith(github.ref, 'refs/tags/v')) 20 | needs: validation 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | # test against latest update of some major Java version(s), as well as specific LTS version(s) 25 | java: [8, 17, 21] 26 | name: Gradle Build without Publish 27 | steps: 28 | - uses: actions/checkout@v1 29 | - name: Setup git user 30 | run: | 31 | git config --global user.name "Nebula Plugin Maintainers" 32 | git config --global user.email "nebula-plugins-oss@netflix.com" 33 | - name: Set up JDKs 34 | uses: actions/setup-java@v4 35 | with: 36 | distribution: 'zulu' 37 | java-version: | 38 | 8 39 | ${{ matrix.java }} 40 | java-package: jdk 41 | - uses: actions/cache@v4 42 | id: gradle-cache 43 | with: 44 | path: ~/.gradle/caches 45 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }} 46 | restore-keys: | 47 | - ${{ runner.os }}-gradle- 48 | - uses: actions/cache@v4 49 | id: gradle-wrapper-cache 50 | with: 51 | path: ~/.gradle/wrapper 52 | key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }} 53 | restore-keys: | 54 | - ${{ runner.os }}-gradlewrapper- 55 | - name: Gradle build 56 | run: ./gradlew --info --stacktrace build 57 | env: 58 | JDK_VERSION_FOR_TESTS: ${{ matrix.java }} 59 | validatepluginpublication: 60 | if: startsWith(github.ref, 'refs/tags/v') 61 | needs: validation 62 | runs-on: ubuntu-latest 63 | name: Gradle Plugin Publication Validation 64 | env: 65 | NETFLIX_OSS_SONATYPE_USERNAME: ${{ secrets.ORG_SONATYPE_USERNAME }} 66 | NETFLIX_OSS_SONATYPE_PASSWORD: ${{ secrets.ORG_SONATYPE_PASSWORD }} 67 | steps: 68 | - uses: actions/checkout@v1 69 | - name: Setup git user 70 | run: | 71 | git config --global user.name "Nebula Plugin Maintainers" 72 | git config --global user.email "nebula-plugins-oss@netflix.com" 73 | - name: Set up JDKs 74 | uses: actions/setup-java@v4 75 | with: 76 | distribution: 'zulu' 77 | java-version: | 78 | 8 79 | 21 80 | java-package: jdk 81 | - uses: actions/cache@v4 82 | id: gradle-cache 83 | with: 84 | path: ~/.gradle/caches 85 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }} 86 | restore-keys: | 87 | - ${{ runner.os }}-gradle- 88 | - uses: actions/cache@v4 89 | id: gradle-wrapper-cache 90 | with: 91 | path: ~/.gradle/wrapper 92 | key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }} 93 | restore-keys: | 94 | - ${{ runner.os }}-gradlewrapper- 95 | - name: Verify plugin publication 96 | if: | 97 | startsWith(github.ref, 'refs/tags/v') && 98 | (!contains(github.ref, '-rc.')) 99 | run: ./gradlew --stacktrace -Dgradle.publish.key=${{ secrets.gradlePublishKey }} -Dgradle.publish.secret=${{ secrets.gradlePublishSecret }} -Prelease.useLastTag=true final publishPlugin --validate-only -x check -x signPluginMavenPublication 100 | publish: 101 | if: startsWith(github.ref, 'refs/tags/v') 102 | needs: validatepluginpublication 103 | runs-on: ubuntu-latest 104 | name: Gradle Build and Publish 105 | env: 106 | NETFLIX_OSS_SONATYPE_USERNAME: ${{ secrets.ORG_SONATYPE_USERNAME }} 107 | NETFLIX_OSS_SONATYPE_PASSWORD: ${{ secrets.ORG_SONATYPE_PASSWORD }} 108 | NETFLIX_OSS_SIGNING_KEY: ${{ secrets.ORG_SIGNING_KEY }} 109 | NETFLIX_OSS_SIGNING_PASSWORD: ${{ secrets.ORG_SIGNING_PASSWORD }} 110 | NETFLIX_OSS_REPO_USERNAME: ${{ secrets.ORG_NETFLIXOSS_USERNAME }} 111 | NETFLIX_OSS_REPO_PASSWORD: ${{ secrets.ORG_NETFLIXOSS_PASSWORD }} 112 | steps: 113 | - uses: actions/checkout@v1 114 | - name: Setup git user 115 | run: | 116 | git config --global user.name "Nebula Plugin Maintainers" 117 | git config --global user.email "nebula-plugins-oss@netflix.com" 118 | - name: Set up JDKs 119 | uses: actions/setup-java@v4 120 | with: 121 | distribution: 'zulu' 122 | java-version: | 123 | 8 124 | 21 125 | java-package: jdk 126 | - uses: actions/cache@v4 127 | id: gradle-cache 128 | with: 129 | path: ~/.gradle/caches 130 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }} 131 | restore-keys: | 132 | - ${{ runner.os }}-gradle- 133 | - uses: actions/cache@v4 134 | id: gradle-wrapper-cache 135 | with: 136 | path: ~/.gradle/wrapper 137 | key: ${{ runner.os }}-gradlewrapper-${{ hashFiles('gradle/wrapper/*') }} 138 | restore-keys: | 139 | - ${{ runner.os }}-gradlewrapper- 140 | - name: Publish candidate 141 | if: | 142 | startsWith(github.ref, 'refs/tags/v') && 143 | contains(github.ref, '-rc.') 144 | run: ./gradlew --info --stacktrace -Prelease.useLastTag=true candidate 145 | - name: Publish release 146 | if: | 147 | startsWith(github.ref, 'refs/tags/v') && 148 | (!contains(github.ref, '-rc.')) 149 | run: ./gradlew --info --stacktrace -Dgradle.publish.key=${{ secrets.gradlePublishKey }} -Dgradle.publish.secret=${{ secrets.gradlePublishSecret }} -Prelease.useLastTag=true final 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | .gradletasknamecache 4 | 5 | .idea/ 6 | *.ipr 7 | *.iml 8 | *.iws 9 | out/ 10 | -------------------------------------------------------------------------------- /.java-version: -------------------------------------------------------------------------------- 1 | 1.8 -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 5.1.3 / 2017-03-08 2 | ================== 3 | 4 | * Fix for multiproject helper in IntegrationTestKitSpec 5 | 6 | 5.1.2 / 2017-03-03 7 | ================== 8 | 9 | * make projectdir absolute 10 | 11 | 5.1.1 / 2017-03-02 12 | ================== 13 | 14 | * Fix to IntegrationTestKitSpec 15 | 16 | 5.1.0 / 2017-03-01 17 | ================== 18 | 19 | * Add IntegrationTestKitSpec -- helper for Gradle TestKit 20 | * Remove a shaded library 21 | 22 | 5.0.1 / 2017-02-14 23 | ================== 24 | 25 | * BUGFIX: Fixes for Windows users 26 | * Thanks Björn Kautler github: Vampire 27 | * Thanks Willie Slepecki github: scphantm 28 | 29 | 5.0.0 / 2017-01-04 30 | ================== 31 | 32 | * Update to Gradle 3.3 33 | * BREAKING CHANGE no longer works with earlier versions of gradle 34 | 35 | 4.4.3 / 2017-01-03 36 | ================== 37 | 38 | * Gradle 3.3 updates 39 | 40 | 4.4.2 / 2016-12-13 41 | ================== 42 | 43 | * BUGFIX: maven bom generation 44 | 45 | 4.4.1 / 2016-12-09 46 | ================== 47 | 48 | 4.4.0 / 2016-12-08 49 | ================== 50 | 51 | 4.3.0 / 2016-12-06 52 | ================== 53 | 54 | * Add maven bom generation helper 55 | 56 | 4.2.2 / 2016-06-09 57 | ================== 58 | 59 | 4.2.1 / 2016-05-31 60 | ================== 61 | 62 | 4.2.0 / 2016-05-30 63 | ================== 64 | 65 | * Add objenesis for Spock 66 | 67 | 4.1.0 / 2016-05-30 68 | ================== 69 | 70 | * Gradle 2.14 compatibility 71 | 72 | 4.0.0 / 2015-09-30 73 | ================== 74 | 75 | * Compatibility with Gradle 2.8 76 | 77 | 3.1.0 / 2015-09-11 78 | ================== 79 | 80 | * Added support for Pre-build hooks from ethankhall 81 | 82 | 3.0.0 / 2015-08-18 83 | ================== 84 | 85 | * Move to gradle 2.6 86 | * Switch to new publishing 87 | 88 | 2.2.2 / 2015-06-22 89 | ================== 90 | 91 | * Add classpath filtering to prevent Gradle, IntelliJ and JVM classes from being added to the IntegrationSpec init script classpath. Set classpathFilter to nebula.test.functional.GradleRunner#CLASSPATH_ALL to restore the default behaviour, or implement your own predicate to control the filtering for your use case 92 | 93 | 2.2.1 / 2015-03-25 94 | ================== 95 | 96 | * move to spock 1.0-groovy-2.3 97 | * Improve debugging support for forked tests 98 | 99 | 2.2.0 / 2015-01-30 100 | =================== 101 | 102 | * Move to gradle 2.2.1 103 | 104 | 2.0.2 / 2014-10-24 105 | =================== 106 | 107 | * Add ability to choose Gradle version 108 | 109 | 2.0.1 / 2014-09-26 110 | ================== 111 | 112 | * Merged in dependency generation improvements from 1.12.4 113 | 114 | 1.12.5 / 2014-10-23 115 | =================== 116 | 117 | * Add ability to choose Gradle version 118 | 119 | 1.12.4 / 2014-09-25 120 | =================== 121 | 122 | * Improve dependency generation, add builder syntax, add useful helpers 123 | 124 | 1.12.3 / 2014-09-22 125 | =================== 126 | 127 | * Add multi-project helpers 128 | 129 | 1.12.2 / 2014-07-31 130 | =================== 131 | 132 | * Bug fixes 133 | 134 | 1.12.1 / 2014-07-31 135 | =================== 136 | 137 | * Methods to gain more insight into what tasks were run 138 | * Ability to configure if an integration project should clean it self up 139 | 140 | 1.12.0 / 2014-06-09 141 | =================== 142 | 143 | * Move to gradle 1.12 144 | 145 | 1.11.1 / 2014-04-25 146 | =================== 147 | * Under lying implementation of IntegrationSpec can now be backed by the Tooling API or a GradleLauncher. 148 | * BREAKING: Return type from runTask* is now ExecutionResult. And depending on the implemention it might not support 149 | additional insight, like the Gradle object or the task state. 150 | 151 | 1.9.8 / 2014-04-16 152 | ================== 153 | * Added helper methods to IntegrationSpec class 154 | 155 | 1.9.7 / 2014-04-16 156 | ================== 157 | * Bug fixes for writeHelloWorld 158 | * Add ability to specify URI of gradle distribution during generation 159 | * Use contacts plugin 160 | 161 | 1.9.6 / 2014-04-14 162 | ================== 163 | * Ensure that up to date applies to real tasks 164 | * Bug fix to how nebula.test.dependencies parses the -> syntax 165 | 166 | 1.9.5 / 2014-04-10 167 | ================== 168 | * Add nebula.test.dependencies package to allow users to create local ivy and maven repositories 169 | 170 | 1.9.4 / 2014-04-08 171 | ================== 172 | * Improvements to documentation 173 | * Added PluginProjectSpec for people to extend to run some basic tests 174 | 175 | 1.9.3 / 2014-01-22 176 | ================== 177 | * Remove UpToDateCategory 178 | 179 | 1.9.2 / 2014-01-21 180 | ================== 181 | * rev nebula-plugin-plugin to 1.9.5 182 | * stop using dynamic versions of libraries 183 | 184 | 1.9.1 / 2014-01-17 185 | ================== 186 | * improvements to project strucgture 187 | * fix import for FileUtils 188 | 189 | 1.9.0 / 2014-01-10 190 | ================== 191 | * Initial release 192 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Nebula 2 | 3 | If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request. When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. 4 | 5 | ## License 6 | 7 | By contributing your code, you agree to license your contribution under the terms of the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0). Your contributions should also include the following header: 8 | 9 | ``` 10 | /** 11 | * Copyright 2017 Netflix, Inc. 12 | * 13 | * Licensed under the Apache License, Version 2.0 (the "License"); 14 | * you may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at 16 | * 17 | * http://www.apache.org/licenses/LICENSE-2.0 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | */ 25 | ``` 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nebula Test 2 | =========== 3 | 4 | ![Support Status](https://img.shields.io/badge/nebula-active-green.svg) 5 | [![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/nebula-test)](https://maven-badges.herokuapp.com/maven-central/com.netflix.nebula/nebula-test) 6 | ![Build](https://github.com/nebula-plugins/nebula-test/actions/workflows/nebula.yml/badge.svg) 7 | [![Apache 2.0](https://img.shields.io/github/license/nebula-plugins/nebula-test.svg)](http://www.apache.org/licenses/LICENSE-2.0) 8 | 9 | Classes specific to testing a Gradle project, leveraging [Spock](http://spockframework.org) 10 | 11 | # Documentation 12 | 13 | The project wiki contains the [full documentation](https://github.com/nebula-plugins/nebula-test/wiki) for the library. 14 | 15 | 16 | LICENSE 17 | ======= 18 | 19 | Copyright 2014-2021 Netflix, Inc. 20 | 21 | Licensed under the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | 25 | 26 | 27 | Unless required by applicable law or agreed to in writing, software 28 | distributed under the License is distributed on an "AS IS" BASIS, 29 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 | See the License for the specific language governing permissions and 31 | limitations under the License. 32 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import org.gradle.api.tasks.testing.Test 2 | 3 | /* 4 | * Copyright 2014-2019 Netflix, Inc. 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 | * http://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 | plugins { 20 | id 'com.netflix.nebula.plugin-plugin' version '21.2.2' 21 | id 'java-library' 22 | } 23 | 24 | description 'Test harness for Gradle plugins. Hopefully retiring in favor of Gradle TestKit' 25 | 26 | contacts { 27 | 'nebula-plugins-oss@netflix.com' { 28 | moniker 'Nebula Plugins Maintainers' 29 | github 'nebula-plugins' 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation gradleTestKit() 35 | api('org.spockframework:spock-core:2.3-groovy-3.0') { 36 | exclude group: 'org.codehaus.groovy' 37 | } 38 | api 'org.spockframework:spock-junit4:2.3-groovy-3.0' 39 | runtimeOnly 'cglib:cglib-nodep:3.2.2' 40 | runtimeOnly 'org.objenesis:objenesis:2.4' 41 | testImplementation 'uk.org.webcompere:system-stubs-junit4:2.0.1' 42 | } 43 | 44 | tasks.withType(Test) { 45 | useJUnitPlatform() 46 | } 47 | 48 | publishPlugins.enabled = false 49 | -------------------------------------------------------------------------------- /gradle.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | cglib:cglib-nodep:3.2.2=integTestRuntimeClasspath,runtimeClasspath,testRuntimeClasspath 5 | junit:junit:4.13.2=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 6 | net.bytebuddy:byte-buddy-agent:1.11.13=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 7 | net.bytebuddy:byte-buddy:1.11.13=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 8 | org.apiguardian:apiguardian-api:1.1.2=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 9 | org.codehaus.groovy:groovy:3.0.12=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 10 | org.hamcrest:hamcrest-core:1.3=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 11 | org.hamcrest:hamcrest:2.2=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 12 | org.junit.platform:junit-platform-commons:1.9.0=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 13 | org.junit.platform:junit-platform-engine:1.9.0=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 14 | org.mockito:mockito-core:3.12.4=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 15 | org.mockito:mockito-inline:3.12.4=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 16 | org.objenesis:objenesis:2.4=runtimeClasspath 17 | org.objenesis:objenesis:3.2=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 18 | org.opentest4j:opentest4j:1.2.0=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 19 | org.spockframework:spock-core:2.3-groovy-3.0=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 20 | org.spockframework:spock-junit4:2.3-groovy-3.0=compileClasspath,integTestCompileClasspath,integTestRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 21 | uk.org.webcompere:system-stubs-core:2.0.1=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 22 | uk.org.webcompere:system-stubs-junit4:2.0.1=integTestCompileClasspath,integTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath 23 | empty=annotationProcessor,integTestAnnotationProcessor,testAnnotationProcessor 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | systemProp.nebula.features.coreLockingSupport=true 2 | -------------------------------------------------------------------------------- /gradle/gradle-daemon-jvm.properties: -------------------------------------------------------------------------------- 1 | toolchainVersion=21 -------------------------------------------------------------------------------- /gradle/m2-init.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | buildscript { 3 | repositories { 4 | mavenLocal() 5 | } 6 | configurations.all { 7 | resolutionStrategy.cacheChangingModulesFor 0, 'hours' 8 | } 9 | } 10 | 11 | repositories { 12 | mavenLocal() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebula-plugins/nebula-test/e13406b27fb874a9662719db33b4238ec2adf14d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /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 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /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 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradle.enterprise' version '3.8.1' 3 | } 4 | 5 | gradleEnterprise { 6 | buildScan { 7 | publishAlways() 8 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 9 | termsOfServiceAgree = 'yes' 10 | } 11 | } 12 | 13 | rootProject.name='nebula-test' 14 | -------------------------------------------------------------------------------- /src/gradleTest/simpleplugin/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy' 3 | } 4 | 5 | repositories { 6 | flatDir { 7 | dirs '../../../libs' 8 | } 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile localGroovy() 14 | compile gradleApi() 15 | testCompile 'com.netflix.nebula:nebula-test:%%VERSION%%' 16 | testCompile('org.spockframework:spock-core:1.0-groovy-2.3') { exclude group: 'org.codehaus.groovy' } 17 | } 18 | 19 | task runGradleTest(dependsOn: ['test']) 20 | -------------------------------------------------------------------------------- /src/gradleTest/simpleplugin/src/main/groovy/simple/SimplePlugin.groovy: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | 6 | class SimplePlugin implements Plugin { 7 | @Override 8 | void apply(Project project) { 9 | project.tasks.create('sampleTask') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/gradleTest/simpleplugin/src/main/resources/META-INF/gradle-plugins/test.simple-plugin.properties: -------------------------------------------------------------------------------- 1 | implementation-class=simple.SimplePlugin 2 | -------------------------------------------------------------------------------- /src/gradleTest/simpleplugin/src/test/groovy/simple/DependenciesSpec.groovy: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import nebula.test.IntegrationSpec 4 | import nebula.test.dependencies.DependencyGraphBuilder 5 | import nebula.test.dependencies.GradleDependencyGenerator 6 | import nebula.test.dependencies.ModuleBuilder 7 | 8 | class DependenciesSpec extends IntegrationSpec { 9 | def 'generate some dependencies'() { 10 | def graph = new DependencyGraphBuilder() 11 | .addModule('testjava:a:0.1.0') 12 | .addModule(new ModuleBuilder('testjava:b:0.1.0') 13 | .addDependency('testjava:a:0.1.0').build()) 14 | .addModule('testjava:c:0.1.0').build() 15 | File mavenrepo = new GradleDependencyGenerator(graph, "${projectDir}/testrepogen").generateTestMavenRepo() 16 | 17 | buildFile << """\ 18 | apply plugin: 'war' 19 | repositories { 20 | maven { url = '${mavenrepo.absolutePath}' } 21 | } 22 | dependencies { 23 | compile 'testjava:a:0.1.0' 24 | compile 'testjava:b:0.1.0' 25 | compile 'testjava:c:0.1.0' 26 | } 27 | """.stripIndent() 28 | 29 | when: 30 | def result = runTasksSuccessfully('dependencies') 31 | 32 | then: 33 | String dependencies = '''\ 34 | +--- testjava:a:0.1.0 35 | +--- testjava:b:0.1.0 36 | | \\--- testjava:a:0.1.0 37 | \\--- testjava:c:0.1.0 38 | '''.stripIndent() 39 | 40 | result.standardOutput.contains(dependencies) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/gradleTest/simpleplugin/src/test/groovy/simple/SimplePluginSpec.groovy: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import nebula.test.PluginProjectSpec 4 | 5 | class SimplePluginSpec extends PluginProjectSpec { 6 | String pluginName = 'test.simple-plugin' 7 | 8 | def 'apply creates task'() { 9 | when: 10 | project.plugins.apply(SimplePlugin) 11 | 12 | then: 13 | project.tasks.findByName('sampleTask') != null 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/AbstractProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import groovy.transform.CompileStatic 4 | import nebula.test.multiproject.MultiProjectHelper 5 | import org.gradle.api.Project 6 | import org.gradle.testfixtures.ProjectBuilder 7 | import org.gradle.testfixtures.internal.ProjectBuilderImpl 8 | import org.junit.Rule 9 | import org.junit.rules.TestName 10 | import spock.lang.Specification 11 | 12 | /** 13 | * Setup a temporary project on the fly, uses Spock. 14 | * 15 | * Caveat, this is ONLY setting up the Project data structure, and not running through the completely lifecycle, Like to 16 | * see http://issues.gradle.org/browse/GRADLE-1619 17 | * 18 | * Its value lays in being able to execute method with a proper Project object, which can flush out most groovy functions, 19 | * finding basic compiler like issues. 20 | */ 21 | @CompileStatic 22 | public abstract class AbstractProjectSpec extends Specification { 23 | static final String CLEAN_PROJECT_DIR_SYS_PROP = 'cleanProjectDir' 24 | File ourProjectDir 25 | 26 | @Rule TestName testName = new TestName() 27 | String canonicalName 28 | Project project 29 | MultiProjectHelper helper 30 | 31 | def setup() { 32 | ourProjectDir = new File("build/nebulatest/${this.class.canonicalName}/${testName.methodName.replaceAll(/\W+/, '-')}").absoluteFile 33 | if (ourProjectDir.exists()) { 34 | ourProjectDir.deleteDir() 35 | } 36 | ourProjectDir.mkdirs() 37 | canonicalName = testName.getMethodName().replaceAll(' ', '-') 38 | project = ProjectBuilder.builder().withName(canonicalName).withProjectDir(ourProjectDir).build() 39 | helper = new MultiProjectHelper(project) 40 | } 41 | 42 | def cleanup() { 43 | if(deleteProjectDir()) { 44 | ourProjectDir.deleteDir() 45 | } 46 | } 47 | 48 | /** 49 | * Determines if project directory should be deleted after a test was executed. By default the logic checks for 50 | * the system property "cleanProjectDir". If the system property is provided and has the value "true", the project 51 | * directory is deleted. If this system property is not provided, the project directory is always deleted. Test 52 | * classes that inherit from this class, can override the method to provide custom logic. 53 | * 54 | * @return Flag 55 | */ 56 | boolean deleteProjectDir() { 57 | String cleanProjectDirSystemProperty = System.getProperty(CLEAN_PROJECT_DIR_SYS_PROP) 58 | cleanProjectDirSystemProperty ? cleanProjectDirSystemProperty.toBoolean() : true 59 | } 60 | 61 | Project addSubproject(String subprojectName) { 62 | helper.addSubproject(subprojectName) 63 | } 64 | 65 | Project addSubprojectWithDirectory(String subprojectName) { 66 | helper.addSubprojectWithDirectory(subprojectName) 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/BaseIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 Netflix, Inc. 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 nebula.test 17 | 18 | import groovy.transform.CompileStatic 19 | import org.junit.Rule 20 | import org.junit.rules.TestName 21 | import spock.lang.Specification 22 | 23 | /** 24 | * {@link Specification} implementation of the {@link IntegrationBase}. 25 | */ 26 | @CompileStatic 27 | /** 28 | * BaseIntegrationSpec is not recommended as it is not compatible with Gradle's instrumentation mechanisms 29 | * ex. https://github.com/gradle/gradle/issues/27956 and https://github.com/gradle/gradle/issues/27639 30 | * 31 | * This will be removed in the next nebula-test major version 32 | */ 33 | abstract class BaseIntegrationSpec extends Specification implements IntegrationBase { 34 | @Rule 35 | TestName testName = new TestName() 36 | 37 | void setup() { 38 | IntegrationBase.super.initialize(getClass(), testName.methodName) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/Integration.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 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 nebula.test 17 | 18 | import groovy.transform.CompileStatic 19 | import groovy.transform.TypeCheckingMode 20 | import nebula.test.functional.ExecutionResult 21 | import nebula.test.functional.GradleRunner 22 | import nebula.test.functional.GradleRunnerFactory 23 | import nebula.test.functional.PreExecutionAction 24 | import nebula.test.functional.internal.GradleHandle 25 | import nebula.test.multiproject.MultiProjectIntegrationHelper 26 | import org.gradle.api.logging.LogLevel 27 | import org.gradle.util.GFileUtils 28 | 29 | import java.util.function.Predicate 30 | 31 | /** 32 | * @author Justin Ryan 33 | * @author Marcin Erdmann 34 | */ 35 | @CompileStatic 36 | abstract trait Integration extends IntegrationBase { 37 | private static final String DEFAULT_REMOTE_DEBUG_JVM_ARGUMENTS = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" 38 | private static final Integer DEFAULT_DAEMON_MAX_IDLE_TIME_IN_SECONDS_IN_MEMORY_SAFE_MODE = 15; 39 | 40 | // Holds State of last run 41 | private ExecutionResult result 42 | 43 | String gradleVersion 44 | File settingsFile 45 | File buildFile 46 | boolean fork = false 47 | boolean remoteDebug = false 48 | List jvmArguments = [] 49 | MultiProjectIntegrationHelper helper 50 | Predicate classpathFilter 51 | List preExecutionActions = [] 52 | //Shutdown Gradle daemon after a few seconds to release memory. Useful for testing with multiple Gradle versions on shared CI server 53 | boolean memorySafeMode = false 54 | Integer daemonMaxIdleTimeInSecondsInMemorySafeMode = DEFAULT_DAEMON_MAX_IDLE_TIME_IN_SECONDS_IN_MEMORY_SAFE_MODE 55 | 56 | 57 | 58 | def initialize(Class testClass, String testMethodName) { 59 | super.initialize(testClass, testMethodName) 60 | setLogLevel(LogLevel.INFO) 61 | if (!settingsFile) { 62 | settingsFile = new File(getProjectDir(), 'settings.gradle') 63 | settingsFile.text = "rootProject.name='${moduleName}'\n" 64 | } 65 | 66 | if (!buildFile) { 67 | buildFile = new File(getProjectDir(), 'build.gradle') 68 | } 69 | 70 | println "Running test from ${getProjectDir()}" 71 | 72 | buildFile << "// Running test for ${moduleName}\n" 73 | 74 | helper = new MultiProjectIntegrationHelper(getProjectDir(), settingsFile) 75 | } 76 | 77 | GradleHandle launcher(String... args) { 78 | List arguments = calculateArguments(args) 79 | List jvmArguments = calculateJvmArguments() 80 | Integer daemonMaxIdleTimeInSeconds = calculateMaxIdleDaemonTimeoutInSeconds() 81 | 82 | GradleRunner runner = GradleRunnerFactory.createTooling(fork, gradleVersion, daemonMaxIdleTimeInSeconds, classpathFilter) 83 | runner.handle(getProjectDir(), arguments, jvmArguments, preExecutionActions) 84 | } 85 | 86 | private List calculateJvmArguments() { 87 | return jvmArguments + (remoteDebug ? [DEFAULT_REMOTE_DEBUG_JVM_ARGUMENTS] : [] as List) as List 88 | } 89 | 90 | private Integer calculateMaxIdleDaemonTimeoutInSeconds() { 91 | return memorySafeMode ? daemonMaxIdleTimeInSecondsInMemorySafeMode : null 92 | } 93 | 94 | void addInitScript(File initFile) { 95 | initScripts.add(initFile) 96 | } 97 | 98 | void addPreExecute(PreExecutionAction preExecutionAction) { 99 | preExecutionActions.add(preExecutionAction) 100 | } 101 | 102 | void copyResources(String srcDir, String destination) { 103 | ClassLoader classLoader = getClass().getClassLoader(); 104 | URL resource = classLoader.getResource(srcDir); 105 | if (resource == null) { 106 | throw new RuntimeException("Could not find classpath resource: $srcDir") 107 | } 108 | 109 | File destinationFile = file(destination) 110 | File resourceFile = new File(resource.toURI()) 111 | if (resourceFile.file) { 112 | GFileUtils.copyFile(resourceFile, destinationFile) 113 | } else { 114 | GFileUtils.copyDirectory(resourceFile, destinationFile) 115 | } 116 | } 117 | 118 | String applyPlugin(Class pluginClass) { 119 | "apply plugin: $pluginClass.name" 120 | } 121 | 122 | /* Checks */ 123 | boolean fileExists(String path) { 124 | new File(projectDir, path).exists() 125 | } 126 | 127 | @Deprecated 128 | boolean wasExecuted(String taskPath) { 129 | result.wasExecuted(taskPath) 130 | } 131 | 132 | @Deprecated 133 | boolean wasUpToDate(String taskPath) { 134 | result.wasUpToDate(taskPath) 135 | } 136 | 137 | @Deprecated 138 | String getStandardError() { 139 | result.standardError 140 | } 141 | 142 | @Deprecated 143 | String getStandardOutput() { 144 | result.standardOutput 145 | } 146 | 147 | /* Execution */ 148 | ExecutionResult runTasksSuccessfully(String... tasks) { 149 | ExecutionResult result = runTasks(tasks) 150 | if (result.failure) { 151 | result.rethrowFailure() 152 | } 153 | result 154 | } 155 | 156 | @CompileStatic(TypeCheckingMode.SKIP) 157 | ExecutionResult runTasksWithFailure(String... tasks) { 158 | ExecutionResult result = runTasks(tasks) 159 | assert result.failure 160 | result 161 | } 162 | 163 | ExecutionResult runTasks(String... tasks) { 164 | GradleHandle gradleHandle = launcher(tasks) 165 | ExecutionResult result = gradleHandle.run() 166 | this.result = result 167 | gradleHandle.disconnect() 168 | checkOutput(result.standardOutput) 169 | checkOutput(result.standardError) 170 | return result 171 | } 172 | 173 | File addSubproject(String subprojectName) { 174 | helper.addSubproject(subprojectName) 175 | } 176 | 177 | File addSubproject(String subprojectName, String subBuildGradleText) { 178 | helper.addSubproject(subprojectName, subBuildGradleText) 179 | } 180 | 181 | File getSettingsFile() { 182 | return settingsFile 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/IntegrationBase.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 Netflix, Inc. 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 nebula.test 17 | 18 | import groovy.transform.CompileStatic 19 | import groovy.transform.TypeCheckingMode 20 | import org.gradle.api.logging.LogLevel 21 | 22 | import java.lang.management.ManagementFactory 23 | import java.lang.management.RuntimeMXBean 24 | 25 | /** 26 | * Base class which provides useful methods for testing a gradle plugin. 27 | * 28 | *

This is testing framework agnostic and can be either extended (see {@link BaseIntegrationSpec}) or composed, by 29 | * including it inside a test class as field. 30 | */ 31 | @CompileStatic 32 | abstract trait IntegrationBase { 33 | File projectDir 34 | String moduleName 35 | LogLevel logLevel = LogLevel.LIFECYCLE 36 | List initScripts = [] 37 | boolean parallelEnabled = false 38 | 39 | private static final String LOGGING_LEVEL_ENV_VARIABLE = "NEBULA_TEST_LOGGING_LEVEL" 40 | 41 | def initialize(Class testClass, String testMethodName, String baseFolderName = 'nebulatest') { 42 | projectDir = new File("build/${baseFolderName}/${testClass.canonicalName}/${testMethodName.replaceAll(/\W+/, '-')}").absoluteFile 43 | if (projectDir.exists()) { 44 | projectDir.deleteDir() 45 | } 46 | projectDir.mkdirs() 47 | moduleName = this.findModuleName() 48 | } 49 | 50 | /** 51 | * Override to alter its value 52 | * @return 53 | */ 54 | LogLevel getLogLevel() { 55 | String levelFromEnv = System.getenv(LOGGING_LEVEL_ENV_VARIABLE) 56 | if(!levelFromEnv) { 57 | return logLevel 58 | } 59 | return LogLevel.valueOf(levelFromEnv.toUpperCase()) 60 | } 61 | 62 | void setLogLevel(LogLevel logLevel) { 63 | this.logLevel = logLevel 64 | } 65 | 66 | /* Setup */ 67 | 68 | File directory(String path, File baseDir = getProjectDir()) { 69 | new File(baseDir, path).with { 70 | mkdirs() 71 | it 72 | } 73 | } 74 | 75 | File file(String path, File baseDir = getProjectDir()) { 76 | def splitted = path.split('/') 77 | def directory = splitted.size() > 1 ? directory(splitted[0..-2].join('/'), baseDir) : baseDir 78 | def file = new File(directory, splitted[-1]) 79 | file.createNewFile() 80 | file 81 | } 82 | 83 | @CompileStatic(TypeCheckingMode.SKIP) 84 | File createFile(String path, File baseDir = getProjectDir()) { 85 | File file = file(path, baseDir) 86 | if (!file.exists()) { 87 | assert file.parentFile.mkdirs() || file.parentFile.exists() 88 | file.createNewFile() 89 | } 90 | file 91 | } 92 | 93 | static void checkOutput(String output) { 94 | outputBuildScan(output) 95 | checkForMutableProjectState(output) 96 | checkForDeprecations(output) 97 | } 98 | 99 | static void outputBuildScan(String output) { 100 | boolean foundPublishingLine = false 101 | output.readLines().find {line -> 102 | if (foundPublishingLine) { 103 | if (line.startsWith("http")) { 104 | println("Build scan: $line") 105 | } else { 106 | println("Build scan was enabled but did not publish: $line") 107 | } 108 | return true 109 | } 110 | if (line == "Publishing build scan...") { 111 | foundPublishingLine = true 112 | } 113 | return false 114 | } 115 | } 116 | 117 | static void checkForDeprecations(String output) { 118 | def deprecations = output.readLines().findAll { 119 | it.contains("has been deprecated and is scheduled to be removed in Gradle") || 120 | it.contains("Deprecated Gradle features were used in this build") || 121 | it.contains("has been deprecated. This is scheduled to be removed in Gradle") || 122 | it.contains("This will fail with an error in Gradle") || 123 | it.contains("This behaviour has been deprecated and is scheduled to be removed in Gradle") 124 | } 125 | // temporary for known issue with overwriting task 126 | // overridden task expected to not be needed in future version 127 | if (deprecations.size() == 1 && deprecations.first().contains("Creating a custom task named 'dependencyInsight' has been deprecated and is scheduled to be removed in Gradle 5.0.")) { 128 | return 129 | } 130 | if (!System.getProperty("ignoreDeprecations") && !deprecations.isEmpty()) { 131 | throw new IllegalArgumentException("Deprecation warnings were found (Set the ignoreDeprecations system property during the test to ignore):\n" + deprecations.collect { 132 | " - $it" 133 | }.join("\n")) 134 | } 135 | } 136 | 137 | static void checkForMutableProjectState(String output) { 138 | def mutableProjectStateWarnings = output.readLines().findAll { 139 | it.contains("was resolved without accessing the project in a safe manner") || 140 | it.contains("This may happen when a configuration is resolved from a thread not managed by Gradle or from a different project") || 141 | it.contains("was resolved from a thread not managed by Gradle.") || 142 | it.contains("was attempted from a context different than the project context") 143 | 144 | } 145 | 146 | if (!System.getProperty("ignoreMutableProjectStateWarnings") && !mutableProjectStateWarnings.isEmpty()) { 147 | throw new IllegalArgumentException("Mutable Project State warnings were found (Set the ignoreMutableProjectStateWarnings system property during the test to ignore):\n" + mutableProjectStateWarnings.collect { 148 | " - $it" 149 | }.join("\n")) 150 | } 151 | } 152 | 153 | void writeHelloWorld(File baseDir = getProjectDir()) { 154 | writeHelloWorld('nebula', baseDir) 155 | } 156 | 157 | void writeHelloWorld(String packageDotted, File baseDir = getProjectDir()) { 158 | writeJavaSourceFile("""\ 159 | package ${packageDotted}; 160 | 161 | public class HelloWorld { 162 | public static void main(String[] args) { 163 | System.out.println("Hello Integration Test"); 164 | } 165 | } 166 | """.stripIndent(), 'src/main/java', baseDir) 167 | } 168 | 169 | void writeJavaSourceFile(String source, File projectDir = getProjectDir()) { 170 | writeJavaSourceFile(source, 'src/main/java', projectDir) 171 | } 172 | 173 | void writeJavaSourceFile(String source, String sourceFolderPath, File projectDir = getProjectDir()) { 174 | File javaFile = createFile(sourceFolderPath + '/' + fullyQualifiedName(source).replaceAll(/\./, '/') + '.java', projectDir) 175 | javaFile.text = source 176 | } 177 | 178 | /** 179 | * Creates a passing unit test for testing your plugin. 180 | * @param baseDir the directory to begin creation from, defaults to projectDir 181 | */ 182 | void writeUnitTest(File baseDir = getProjectDir()) { 183 | writeTest('src/test/java/', 'nebula', false, baseDir) 184 | } 185 | 186 | /** 187 | * Creates a unit test for testing your plugin. 188 | * @param failTest true if you want the test to fail, false if the test should pass 189 | * @param baseDir the directory to begin creation from, defaults to projectDir 190 | */ 191 | void writeUnitTest(boolean failTest, File baseDir = getProjectDir()) { 192 | writeTest('src/test/java/', 'nebula', failTest, baseDir) 193 | } 194 | 195 | void writeUnitTest(String source, File baseDir = getProjectDir()) { 196 | writeJavaSourceFile(source, 'src/test/java', baseDir) 197 | } 198 | 199 | /** 200 | * 201 | * Creates a unit test for testing your plugin. 202 | * @param srcDir the directory in the project where the source file should be created. 203 | * @param packageDotted the package for the unit test class, written in dot notation (ex. - nebula.integration) 204 | * @param failTest true if you want the test to fail, false if the test should pass 205 | * @param baseDir the directory to begin creation from, defaults to projectDir 206 | */ 207 | void writeTest(String srcDir, String packageDotted, boolean failTest, File baseDir = getProjectDir()) { 208 | writeJavaSourceFile("""\ 209 | package ${packageDotted}; 210 | import org.junit.Test; 211 | import static org.junit.Assert.assertFalse; 212 | 213 | public class HelloWorldTest { 214 | @Test public void doesSomething() { 215 | assertFalse( $failTest ); 216 | } 217 | } 218 | """.stripIndent(), srcDir, baseDir) 219 | } 220 | 221 | private String fullyQualifiedName(String sourceStr) { 222 | def pkgMatcher = sourceStr =~ /\s*package\s+([\w\.]+)/ 223 | def pkg = pkgMatcher.find() ? (pkgMatcher[0] as List)[1] + '.' : '' 224 | 225 | def classMatcher = sourceStr =~ /\s*(class|interface)\s+(\w+)/ 226 | return classMatcher.find() ? pkg + (classMatcher[0] as List)[2] : null 227 | } 228 | 229 | /** 230 | * Creates a properties file to included as project resource. 231 | * @param srcDir the directory in the project where the source file should be created. 232 | * @param fileName to be used for the file, sans extension. The .properties extension will be added to the name. 233 | * @param baseDir the directory to begin creation from, defaults to projectDir 234 | */ 235 | void writeResource(String srcDir, String fileName, File baseDir = getProjectDir()) { 236 | def path = "$srcDir/${fileName}.properties" 237 | def resourceFile = createFile(path, baseDir) 238 | resourceFile.text = "firstProperty=foo.bar" 239 | } 240 | 241 | void addResource(String srcDir, String filename, String contents, File baseDir = getProjectDir()) { 242 | def resourceFile = createFile("${srcDir}/${filename}", baseDir) 243 | resourceFile.text = contents 244 | } 245 | 246 | String findModuleName() { 247 | getProjectDir().getName().replaceAll(/_\d+/, '') 248 | } 249 | 250 | List calculateArguments(String... args) { 251 | List arguments = [] 252 | // Gradle will use these files name from the PWD, instead of the project directory. It's easier to just leave 253 | // them out and let the default find them, since we're not changing their default names. 254 | //arguments += '--build-file' 255 | //arguments += (buildFile.canonicalPath - projectDir.canonicalPath).substring(1) 256 | //arguments += '--settings-file' 257 | //arguments += (settingsFile.canonicalPath - projectDir.canonicalPath).substring(1) 258 | //arguments += '--no-daemon' 259 | switch (getLogLevel()) { 260 | case LogLevel.INFO: 261 | arguments += '--info' 262 | break 263 | case LogLevel.DEBUG: 264 | arguments += '--debug' 265 | break 266 | } 267 | if(parallelEnabled) { 268 | arguments += '--parallel' 269 | } 270 | arguments += '--stacktrace' 271 | arguments += '-Dorg.gradle.warning.mode=all' 272 | arguments.addAll(args) 273 | arguments.addAll(initScripts.collect { file -> '-I' + file.absolutePath }) 274 | arguments 275 | } 276 | 277 | static def dependencies(File _buildFile, String... confs = ['compile', 'testCompile', 'implementation', 'testImplementation', 'api']) { 278 | _buildFile.text.readLines() 279 | .collect { it.trim() } 280 | .findAll { line -> confs.any { c -> line.startsWith(c) } } 281 | .collect { it.split(/\s+/)[1].replaceAll(/['"]/, '') } 282 | .sort() 283 | } 284 | 285 | } 286 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/IntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 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 nebula.test 17 | 18 | 19 | import groovy.transform.CompileStatic 20 | 21 | /** 22 | * @author Justin Ryan 23 | * @author Marcin Erdmann 24 | */ 25 | @CompileStatic 26 | /** 27 | * IntegrationSpec is not recommended as it is not compatible with Gradle's instrumentation mechanisms 28 | * ex. https://github.com/gradle/gradle/issues/27956 and https://github.com/gradle/gradle/issues/27639 29 | * 30 | * This will be removed in the next nebula-test major version 31 | */ 32 | @Deprecated 33 | abstract class IntegrationSpec extends BaseIntegrationSpec implements Integration { 34 | def setup() { 35 | Integration.super.initialize(getClass(), testName.methodName) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/IntegrationTestKitBase.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 Netflix, Inc. 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 nebula.test 17 | 18 | import groovy.transform.CompileStatic 19 | import nebula.test.functional.internal.classpath.ClasspathAddingInitScriptBuilder 20 | import org.gradle.testkit.runner.BuildResult 21 | import org.gradle.testkit.runner.GradleRunner 22 | import org.gradle.util.GFileUtils 23 | 24 | import java.lang.management.ManagementFactory 25 | import java.lang.management.RuntimeMXBean 26 | 27 | import static org.gradle.testkit.runner.TaskOutcome.SUCCESS 28 | import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE 29 | 30 | /** 31 | * Base trait for implementing gradle integration tests using the {@code gradle-test-kit} runner. 32 | */ 33 | @CompileStatic 34 | abstract trait IntegrationTestKitBase extends IntegrationBase { 35 | static final String LINE_END = System.getProperty('line.separator') 36 | boolean keepFiles = false 37 | boolean debug 38 | File buildFile 39 | File settingsFile 40 | String gradleVersion 41 | String gradleDistribution 42 | boolean forwardOutput = false 43 | 44 | /** 45 | * Automatic addition of `GradleRunner.withPluginClasspath()` _only_ works if the plugin under test is applied using the plugins DSL 46 | * This enables us to add the plugin-under-test classpath via an init script 47 | * https://docs.gradle.org/4.6/userguide/test_kit.html#sub:test-kit-automatic-classpath-injection 48 | */ 49 | boolean definePluginOutsideOfPluginBlock = false 50 | 51 | @Override 52 | def initialize(Class testClass, String testMethodName, String baseFolderName = 'nebulatest') { 53 | super.initialize(testClass, testMethodName, baseFolderName) 54 | if (!settingsFile) { 55 | settingsFile = new File(projectDir, "settings.gradle") 56 | settingsFile.text = "rootProject.name='${moduleName}'\n" 57 | } 58 | buildFile = new File(projectDir, "build.gradle") 59 | } 60 | 61 | def traitCleanup() { 62 | if (!keepFiles) { 63 | projectDir.deleteDir() 64 | } 65 | } 66 | 67 | File addSubproject(String name) { 68 | File subprojectDir = new File(projectDir, name) 69 | subprojectDir.mkdirs() 70 | settingsFile << "include \"${name}\"${LINE_END}" 71 | return subprojectDir 72 | } 73 | 74 | File addSubproject(String name, String buildGradle) { 75 | def subdir = addSubproject(name) 76 | new File(subdir, "build.gradle").text = buildGradle 77 | return subdir 78 | } 79 | 80 | BuildResult runTasks(String... tasks) { 81 | BuildResult result = createRunner(tasks) 82 | .build() 83 | checkOutput(result.output) 84 | return result 85 | } 86 | 87 | BuildResult runTasksAndFail(String... tasks) { 88 | BuildResult result = createRunner(tasks) 89 | .buildAndFail() 90 | checkOutput(result.output) 91 | return result 92 | } 93 | 94 | def tasksWereSuccessful(BuildResult result, String... tasks) { 95 | tasks.each { task -> 96 | if (!task.contains('-P') && !task.contains('--')) { 97 | String modTask = task.startsWith(':') ? task : ":$task" 98 | def outcome = result.task(modTask).outcome 99 | assert outcome == SUCCESS || outcome == UP_TO_DATE 100 | } 101 | } 102 | } 103 | 104 | GradleRunner createRunner(String... tasks) { 105 | List pluginArgs = definePluginOutsideOfPluginBlock 106 | ? createGradleTestKitInitArgs() 107 | : new ArrayList() 108 | debug = debug ? true : isJwdpLoaded() 109 | def gradleRunnerBuilder = GradleRunner.create() 110 | .withProjectDir(projectDir) 111 | .withArguments(pluginArgs + calculateArguments(tasks)) 112 | .withDebug(debug) 113 | .withPluginClasspath() 114 | 115 | gradleRunnerBuilder.forwardStdError(new PrintWriter(System.err)) 116 | if (forwardOutput) { 117 | gradleRunnerBuilder.forwardStdOutput(new PrintWriter(System.out)) 118 | } 119 | if (gradleVersion != null) { 120 | gradleRunnerBuilder.withGradleVersion(gradleVersion) 121 | } 122 | if (gradleDistribution != null) { 123 | gradleRunnerBuilder.withGradleDistribution(URI.create(gradleDistribution)) 124 | } 125 | return gradleRunnerBuilder 126 | } 127 | 128 | private List createGradleTestKitInitArgs() { 129 | File testKitDir = new File(projectDir, ".gradle-test-kit") 130 | if (!testKitDir.exists()) { 131 | GFileUtils.mkdirs(testKitDir) 132 | } 133 | 134 | File initScript = new File(testKitDir, "init.gradle") 135 | ClassLoader classLoader = this.getClass().getClassLoader() 136 | def classpathFilter = nebula.test.functional.GradleRunner.CLASSPATH_DEFAULT 137 | ClasspathAddingInitScriptBuilder.build(initScript, classLoader, classpathFilter) 138 | 139 | return Arrays.asList("--init-script", initScript.getAbsolutePath()) 140 | } 141 | 142 | static boolean isJwdpLoaded() { 143 | RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean() 144 | List args = runtime.getInputArguments() 145 | return args.toString().contains("-agentlib:jdwp") 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/IntegrationTestKitSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 Netflix, Inc. 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 nebula.test 17 | 18 | 19 | import org.junit.Rule 20 | import org.junit.rules.TestName 21 | import spock.lang.Specification 22 | 23 | abstract class IntegrationTestKitSpec extends Specification implements IntegrationTestKitBase { 24 | @Rule 25 | TestName testName = new TestName() 26 | 27 | String getProjectBaseFolderName() { 28 | return 'nebulatest' 29 | } 30 | 31 | void setup() { 32 | IntegrationTestKitBase.super.initialize(getClass(), testName.methodName, getProjectBaseFolderName()) 33 | } 34 | 35 | void cleanup() { 36 | traitCleanup() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/PluginProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Netflix, Inc. 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 nebula.test 17 | 18 | import groovy.transform.CompileStatic 19 | import org.gradle.api.Project 20 | import org.gradle.testfixtures.ProjectBuilder 21 | 22 | /** 23 | * Create some basic tests that all plugins should pass 24 | */ 25 | @CompileStatic 26 | abstract class PluginProjectSpec extends ProjectSpec { 27 | abstract String getPluginName() 28 | 29 | def 'apply does not throw exceptions'() { 30 | when: 31 | project.apply plugin: pluginName 32 | 33 | then: 34 | noExceptionThrown() 35 | } 36 | 37 | def 'apply is idempotent'() { 38 | when: 39 | project.apply plugin: pluginName 40 | project.apply plugin: pluginName 41 | 42 | then: 43 | noExceptionThrown() 44 | } 45 | 46 | def 'apply is fine on all levels of multiproject'() { 47 | def sub = createSubproject(project, 'sub') 48 | project.subprojects.add(sub) 49 | 50 | when: 51 | project.apply plugin: pluginName 52 | sub.apply plugin: pluginName 53 | 54 | then: 55 | noExceptionThrown() 56 | } 57 | 58 | def 'apply to multiple subprojects'() { 59 | def subprojectNames = ['sub1', 'sub2', 'sub3'] 60 | 61 | subprojectNames.each { subprojectName -> 62 | def subproject = createSubproject(project, subprojectName) 63 | project.subprojects.add(subproject) 64 | } 65 | 66 | when: 67 | project.apply plugin: pluginName 68 | 69 | subprojectNames.each { subprojectName -> 70 | def subproject = project.subprojects.find { it.name == subprojectName } 71 | subproject.apply plugin: pluginName 72 | } 73 | 74 | then: 75 | noExceptionThrown() 76 | } 77 | 78 | Project createSubproject(Project parentProject, String name) { 79 | ProjectBuilder.builder().withName(name).withProjectDir(new File(projectDir, name)).withParent(parentProject).build() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/ProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import groovy.transform.CompileStatic 4 | 5 | /** 6 | * Created by rspieldenner on 3/25/15. 7 | */ 8 | @CompileStatic 9 | class ProjectSpec extends AbstractProjectSpec { 10 | File getProjectDir() { 11 | ourProjectDir 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/Coordinate.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Netflix, Inc. 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 nebula.test.dependencies 17 | 18 | import groovy.transform.Immutable 19 | 20 | @Immutable 21 | class Coordinate { 22 | String group 23 | String artifact 24 | String version 25 | 26 | @Override 27 | String toString() { 28 | "${group}:${artifact}:${version}" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/DependencyGraph.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Netflix, Inc. 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 nebula.test.dependencies 17 | 18 | class DependencyGraph { 19 | Collection nodes = [] 20 | 21 | DependencyGraph(List graph) { 22 | graph.each { nodes << parseNode(it) } 23 | } 24 | 25 | DependencyGraph(String... graph) { 26 | this(graph as List) 27 | } 28 | 29 | DependencyGraph(Map tuple) { 30 | nodes = tuple.nodes 31 | } 32 | 33 | private DependencyGraphNode parseNode(String s) { 34 | // Don't use tokenize, it'll make each character a possible delimeter, e.g. \t\n would tokenize on both 35 | // \t OR \n, not the combination of \t\n. 36 | def parts = s.split('->') 37 | def (group, artifact, version) = parts[0].trim().tokenize(':') 38 | def coordinate = new Coordinate(group: group, artifact: artifact, version: version) 39 | def dependencies = (parts.size() > 1) ? parseDependencies(parts[1]) : [] 40 | 41 | new DependencyGraphNode(coordinate: coordinate, dependencies: dependencies, status: "integration") 42 | } 43 | 44 | private List parseDependencies(String s) { 45 | List dependencies = [] 46 | s.tokenize('|').each { String dependency -> 47 | def (group, artifact, version) = dependency.trim().tokenize(':') 48 | dependencies << new Coordinate(group: group, artifact: artifact, version: version) 49 | } 50 | 51 | dependencies 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/DependencyGraphBuilder.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies 2 | 3 | class DependencyGraphBuilder { 4 | 5 | private static final DEFAULT_STATUS = 'integration' 6 | 7 | Map modules = [:] 8 | 9 | DependencyGraphBuilder addModule(String coordinate) { 10 | def (group, artifact, version, status) = coordinate.trim().tokenize(':') 11 | addModule(group, artifact, version, status) 12 | } 13 | 14 | DependencyGraphBuilder addModule(String group, String artifact, String version) { 15 | addModule(group, artifact, version, DEFAULT_STATUS) 16 | } 17 | 18 | DependencyGraphBuilder addModule(String group, String artifact, String version, String status) { 19 | String key = "${group}:${artifact}:${version}".toString() 20 | modules[key] = new DependencyGraphNode(coordinate: new Coordinate(group: group, artifact: artifact, version: version), status: status ?: DEFAULT_STATUS) 21 | this 22 | } 23 | 24 | DependencyGraphBuilder addModule(DependencyGraphNode node) { 25 | modules[node.coordinate.toString()] = node 26 | 27 | node.dependencies.each { Coordinate dep -> 28 | if (!modules.containsKey(dep.toString())) { 29 | modules[dep.toString()] = new DependencyGraphNode(coordinate: dep) 30 | } 31 | } 32 | 33 | this 34 | } 35 | 36 | DependencyGraph build() { 37 | new DependencyGraph(nodes: modules.values()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/DependencyGraphNode.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Netflix, Inc. 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 nebula.test.dependencies 17 | 18 | import groovy.transform.Immutable 19 | import org.gradle.api.JavaVersion 20 | 21 | @Immutable(knownImmutableClasses = [Coordinate]) 22 | class DependencyGraphNode { 23 | @Delegate Coordinate coordinate 24 | List dependencies = [] 25 | String status = "integration" 26 | JavaVersion targetCompatibility = JavaVersion.VERSION_1_8 27 | 28 | @Override 29 | String toString() { 30 | "${group}:${artifact}:${version}:${status}" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/GradleDependencyGenerator.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2017 Netflix, Inc. 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 nebula.test.dependencies 17 | 18 | import nebula.test.functional.GradleRunnerFactory 19 | import nebula.test.gradle.GradleVersionComparator 20 | import org.gradle.api.invocation.Gradle 21 | 22 | class GradleDependencyGenerator { 23 | private static final String DEFAULT_GRADLE_VERSION = '5.2.1' 24 | private static final String GRADLE_FIVE_ZERO = '5.0.0' 25 | private static final String LEGACY_PATTERN_LAYOUT = "layout('pattern')" 26 | private static final String PATTERN_LAYOUT = "patternLayout" 27 | 28 | static final String STANDARD_SUBPROJECT_BLOCK = '''\ 29 | subprojects { 30 | apply plugin: 'maven-publish' 31 | apply plugin: 'ivy-publish' 32 | apply plugin: 'java-library' 33 | 34 | publishing { 35 | repositories { 36 | maven { 37 | url = "../mavenrepo" 38 | } 39 | ivy { 40 | url = "../ivyrepo" 41 | patternLayout { 42 | ivy '[organisation]/[module]/[revision]/[module]-[revision]-ivy.[ext]' 43 | artifact '[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]' 44 | m2compatible = true 45 | } 46 | } 47 | } 48 | } 49 | } 50 | '''.stripIndent() 51 | 52 | static final String LEGACY_STANDARD_SUBPROJECT_BLOCK = '''\ 53 | subprojects { 54 | apply plugin: 'maven-publish' 55 | apply plugin: 'ivy-publish' 56 | apply plugin: 'java-library' 57 | 58 | publishing { 59 | repositories { 60 | maven { 61 | url = "../mavenrepo" 62 | } 63 | ivy { 64 | url = "../ivyrepo" 65 | layout('pattern') { 66 | ivy '[organisation]/[module]/[revision]/[module]-[revision]-ivy.[ext]' 67 | artifact '[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]' 68 | m2compatible = true 69 | } 70 | } 71 | } 72 | } 73 | } 74 | '''.stripIndent() 75 | 76 | static final String BUILD_GRADLE = 'build.gradle' 77 | 78 | private boolean generated = false 79 | 80 | DependencyGraph graph 81 | File gradleRoot 82 | File ivyRepoDir 83 | File mavenRepoDir 84 | String gradleVersion 85 | 86 | GradleDependencyGenerator(String gradleVersion, DependencyGraph graph, String directory = 'build/testrepogen') { 87 | this.graph = graph 88 | this.gradleRoot = new File(directory) 89 | this.ivyRepoDir = new File(directory, 'ivyrepo') 90 | this.mavenRepoDir = new File(directory, 'mavenrepo') 91 | this.gradleVersion = gradleVersion 92 | generateGradleFiles(gradleVersion) 93 | } 94 | 95 | GradleDependencyGenerator(Gradle gradle, DependencyGraph graph, String directory = 'build/testrepogen') { 96 | this(gradle.gradleVersion, graph, directory) 97 | } 98 | 99 | GradleDependencyGenerator(DependencyGraph graph, String directory = 'build/testrepogen') { 100 | this(DEFAULT_GRADLE_VERSION, graph, directory) 101 | } 102 | 103 | File generateTestMavenRepo() { 104 | runTasks('publishMavenPublicationToMavenRepository') 105 | 106 | mavenRepoDir 107 | } 108 | 109 | String getMavenRepoDirPath() { 110 | mavenRepoDir.absolutePath 111 | } 112 | 113 | String getMavenRepoUrl() { 114 | mavenRepoDir.toURI().toURL() 115 | } 116 | 117 | String getMavenRepositoryBlock() { 118 | """\ 119 | maven { url = '${getMavenRepoUrl()}' } 120 | """.stripIndent() 121 | } 122 | 123 | File generateTestIvyRepo() { 124 | runTasks('publishIvyPublicationToIvyRepository') 125 | 126 | ivyRepoDir 127 | } 128 | 129 | String getIvyRepoDirPath() { 130 | ivyRepoDir.absolutePath 131 | } 132 | 133 | String getIvyRepoUrl() { 134 | ivyRepoDir.toURI().toURL() 135 | } 136 | 137 | String getIvyRepositoryBlock() { 138 | use(GradleVersionComparator) { 139 | boolean isGradleOlderThanGradleFive = gradleVersion.versionLessThan(GRADLE_FIVE_ZERO) 140 | String layoutPattern = isGradleOlderThanGradleFive ? LEGACY_PATTERN_LAYOUT : PATTERN_LAYOUT 141 | return """\ 142 | ivy { 143 | url = '${getIvyRepoUrl()}' 144 | ${layoutPattern} { 145 | ivy '[organisation]/[module]/[revision]/[module]-[revision]-ivy.[ext]' 146 | artifact '[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]' 147 | m2compatible = true 148 | } 149 | } 150 | """.stripIndent() 151 | } 152 | } 153 | 154 | private void generateGradleFiles(String gradleVersion) { 155 | use(GradleVersionComparator) { 156 | if (generated) { 157 | return 158 | } else { 159 | generated = true 160 | } 161 | 162 | gradleRoot.mkdirs() 163 | def rootBuildGradle = new File(gradleRoot, BUILD_GRADLE) 164 | rootBuildGradle.text = gradleVersion.versionLessThan(GRADLE_FIVE_ZERO) ? LEGACY_STANDARD_SUBPROJECT_BLOCK : STANDARD_SUBPROJECT_BLOCK 165 | def includes = [] 166 | graph.nodes.each { DependencyGraphNode n -> 167 | String subName = "${n.group}.${n.artifact}_${n.version.replaceAll(/\./, '_')}" 168 | includes << subName 169 | def subfolder = new File(gradleRoot, subName) 170 | subfolder.mkdir() 171 | def subBuildGradle = new File(subfolder, BUILD_GRADLE) 172 | subBuildGradle.text = generateSubBuildGradle(n) 173 | } 174 | def settingsGradle = new File(gradleRoot, 'settings.gradle') 175 | settingsGradle.text = 'include ' + includes.collect { "'${it}'" }.join(', ') 176 | } 177 | } 178 | 179 | private String generateSubBuildGradle(DependencyGraphNode node) { 180 | 181 | StringWriter block = new StringWriter() 182 | if (node.dependencies) { 183 | block.withPrintWriter { writer -> 184 | writer.println 'dependencies {' 185 | node.dependencies.each { writer.println " api '${it}'" } 186 | writer.println '}' 187 | } 188 | } 189 | 190 | """\ 191 | group = '${node.group}' 192 | version = '${node.version}' 193 | ext { 194 | artifactName = '${node.artifact}' 195 | } 196 | 197 | targetCompatibility = ${node.targetCompatibility} 198 | 199 | publishing { 200 | publications { 201 | maven(MavenPublication) { 202 | artifactId artifactName 203 | from components.java 204 | } 205 | ivy(IvyPublication) { 206 | module artifactName 207 | from components.java 208 | descriptor.status = '${node.status}' 209 | } 210 | } 211 | } 212 | """.stripIndent() + block.toString() 213 | } 214 | 215 | private void runTasks(String tasks) { 216 | def runner = GradleRunnerFactory.createTooling() // Could optionally use Launcher 217 | runner.run(gradleRoot, tasks.tokenize()).rethrowFailure() 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/ModuleBuilder.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies 2 | 3 | class ModuleBuilder { 4 | Coordinate module 5 | String status = 'integration' 6 | List dependencies = [] 7 | 8 | ModuleBuilder(String coordinate) { 9 | def (group, artifact, version) = coordinate.tokenize(':') 10 | module = new Coordinate(group: group, artifact: artifact, version: version) 11 | } 12 | 13 | ModuleBuilder(String group, String artifact, String version) { 14 | module = new Coordinate(group: group, artifact: artifact, version: version) 15 | } 16 | 17 | ModuleBuilder addDependency(String dependency) { 18 | def (group, artifact, version) = dependency.tokenize(':') 19 | dependencies << new Coordinate(group: group, artifact: artifact, version: version) 20 | 21 | this 22 | } 23 | 24 | ModuleBuilder addDependency(String group, String artifact, String version) { 25 | dependencies << new Coordinate(group: group, artifact: artifact, version: version) 26 | 27 | this 28 | } 29 | 30 | ModuleBuilder setStatus(String status) { 31 | this.status = status 32 | 33 | this 34 | } 35 | 36 | DependencyGraphNode build() { 37 | new DependencyGraphNode(coordinate: module, dependencies: dependencies, status: status) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/ivy/Descriptor.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies.ivy 2 | 3 | /** 4 | * Created by rspieldenner on 11/14/16. 5 | */ 6 | class Descriptor { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/maven/Artifact.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Netflix, Inc. 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 nebula.test.dependencies.maven 17 | 18 | import groovy.transform.Canonical 19 | import groovy.transform.Sortable 20 | 21 | @Canonical 22 | @Sortable 23 | class Artifact { 24 | String group 25 | String artifact 26 | String version 27 | ArtifactType type = ArtifactType.JAR 28 | 29 | Artifact(String group, String artifact, String version) { 30 | this.group = group 31 | this.artifact = artifact 32 | this.version = version 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/maven/ArtifactType.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Netflix, Inc. 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 nebula.test.dependencies.maven 17 | 18 | enum ArtifactType { 19 | POM('pom'), 20 | JAR('jar') 21 | 22 | ArtifactType(String packaging) { 23 | this.packaging = packaging 24 | } 25 | 26 | String packaging 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/maven/Pom.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Netflix, Inc. 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 nebula.test.dependencies.maven 17 | 18 | import groovy.xml.MarkupBuilder 19 | 20 | class Pom { 21 | Artifact artifact 22 | Set dependencies = new TreeSet<>() 23 | Set dependencyManagementArtifacts = new TreeSet<>() 24 | 25 | Pom(String group, String artifact, String version) { 26 | this.artifact = new Artifact(group, artifact, version) 27 | } 28 | 29 | Pom(String group, String artifact, String version, ArtifactType type) { 30 | this(group, artifact, version) 31 | this.artifact.type = type 32 | } 33 | 34 | Pom addDependency(Artifact artifact) { 35 | dependencies.add(artifact) 36 | 37 | this 38 | } 39 | 40 | Pom addDependency(String group, String name, String version) { 41 | dependencies.add(new Artifact(group, name, version)) 42 | 43 | this 44 | } 45 | 46 | Pom addManagementDependency(Artifact artifact) { 47 | dependencyManagementArtifacts.add(artifact) 48 | 49 | this 50 | } 51 | 52 | Pom addManagementDependency(String group, String name, String version) { 53 | dependencyManagementArtifacts.add(new Artifact(group, name, version)) 54 | 55 | this 56 | } 57 | 58 | String getFilename() { 59 | "${artifact.artifact}-${artifact.version}.pom" 60 | } 61 | 62 | String generate() { 63 | def writer = new StringWriter() 64 | def pom = new MarkupBuilder(writer) 65 | pom.setDoubleQuotes(true) 66 | pom.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8') 67 | pom.project('xsi:schemaLocation' : 'http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd', 'xmlns' : 'http://maven.apache.org/POM/4.0.0', 'xmlns:xsi' : 'http://www.w3.org/2001/XMLSchema-instance') { 68 | modelVersion('4.0.0') 69 | groupId(artifact.group) 70 | artifactId(artifact.artifact) 71 | version(artifact.version) 72 | if (artifact.type != ArtifactType.JAR) { 73 | packaging(artifact.type.packaging) 74 | } 75 | if (dependencyManagementArtifacts) { 76 | dependencyManagement { 77 | dependencies { 78 | dependencyManagementArtifacts.each { Artifact a -> 79 | dependency { 80 | groupId(a.group) 81 | artifactId(a.artifact) 82 | version(a.version) 83 | } 84 | } 85 | } 86 | } 87 | } 88 | if (dependencies) { 89 | dependencies { 90 | dependencies.each { Artifact a -> 91 | dependency { 92 | groupId(a.group) 93 | artifactId(a.artifact) 94 | version(a.version) 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | writer.toString() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/repositories/IvyRepo.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Netflix, Inc. 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 nebula.test.dependencies.repositories 17 | 18 | class IvyRepo { 19 | } 20 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/dependencies/repositories/MavenRepo.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Netflix, Inc. 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 nebula.test.dependencies.repositories 17 | 18 | import groovy.xml.MarkupBuilder 19 | import nebula.test.dependencies.maven.Pom 20 | 21 | import java.text.SimpleDateFormat 22 | 23 | class MavenRepo { 24 | Set poms = new HashSet<>() 25 | File root 26 | 27 | String repoString() { 28 | """\ 29 | maven { url = '${root.absolutePath}' } 30 | """.stripIndent() 31 | } 32 | 33 | void generate() { 34 | if (!root.exists()) { 35 | root.mkdirs() 36 | } 37 | poms.each { Pom pom -> 38 | def path = "${groupAndArtifactPath(pom)}/${pom.artifact.version}" 39 | def dir = new File(root, path) 40 | dir.mkdirs() 41 | new File(dir, pom.filename).text = pom.generate() 42 | } 43 | generateMavenMetadata(poms) 44 | } 45 | 46 | private void generateMavenMetadata(Set poms) { 47 | Map> groupedPoms = poms.groupBy { groupAndArtifactPath(it) } 48 | groupedPoms.each { groupAndArtifactPath, List pomGroup -> 49 | List sortedPoms = pomGroup.sort { it.artifact.version } 50 | File metadataFile = new File(root, "$groupAndArtifactPath/maven-metadata.xml") 51 | def writer = new FileWriter(metadataFile) 52 | def xml = new MarkupBuilder(writer) 53 | xml.metadata { 54 | groupId(sortedPoms.first().artifact.group) 55 | artifactId(sortedPoms.first().artifact.artifact) 56 | versioning { 57 | latest(sortedPoms.last().artifact.version) 58 | release(sortedPoms.last().artifact.version) 59 | versions { 60 | sortedPoms.each { 61 | version(it.artifact.version) 62 | } 63 | } 64 | } 65 | lastUpdated(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())) 66 | } 67 | } 68 | } 69 | 70 | private static String groupAndArtifactPath(Pom pom) { 71 | "${pom.artifact.group.replaceAll(/\./, '/')}/${pom.artifact.artifact}" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/ExecutionResult.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional; 18 | 19 | public interface ExecutionResult { 20 | Boolean getSuccess(); 21 | 22 | String getStandardOutput(); 23 | 24 | String getStandardError(); 25 | 26 | boolean wasExecuted(String taskPath); 27 | 28 | boolean wasUpToDate(String taskPath); 29 | 30 | boolean wasSkipped(String taskPath) 31 | 32 | Throwable getFailure(); 33 | 34 | ExecutionResult rethrowFailure(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/GradleRunner.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2017 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 | 17 | package nebula.test.functional 18 | 19 | import nebula.test.functional.internal.GradleHandle 20 | 21 | import java.util.function.Predicate 22 | 23 | interface GradleRunner { 24 | // These predicates are here, instead of on GradleRunnerFactory due to a Groovy static compiler bug (https://issues.apache.org/jira/browse/GROOVY-7159) 25 | 26 | static final String SHARED_DEPENDENCY_CACHE_ENVIRONMENT_VARIABLE = 'GRADLE_RO_DEP_CACHE' 27 | 28 | static final Predicate CLASSPATH_GRADLE_CACHE = new Predicate() { 29 | @Override 30 | boolean test(URL url) { 31 | String gradleSharedDependencyCache = System.getenv(SHARED_DEPENDENCY_CACHE_ENVIRONMENT_VARIABLE) 32 | boolean cachedModule = url.path.contains('/caches/modules-') 33 | boolean readOnlyCachedModule = gradleSharedDependencyCache && url.path.contains("${gradleSharedDependencyCache}/modules-") 34 | boolean testDistributionOrphanedFile = url.path.contains('/orphan-files/') // test distribution orphans read-only dependency cache files 35 | boolean testDistributionFolder = url.path.contains('/gradle-enterprise-test-distribution-agent-workspace/') // test distribution orphans read-only dependency cache files 36 | return (cachedModule || readOnlyCachedModule || testDistributionOrphanedFile || testDistributionFolder) && !isTestingFramework(url) 37 | } 38 | 39 | static boolean isTestingFramework(URL url) { 40 | return url.path.contains("spock-") || url.path.contains("junit-") 41 | } 42 | } 43 | 44 | static final Predicate MAVEN_LOCAL = new Predicate() { 45 | @Override 46 | boolean test(URL url) { 47 | String m2RepositoryPrefix = System.getProperty("user.home") + "/.m2/repository" 48 | return url.path.contains(m2RepositoryPrefix) 49 | } 50 | } 51 | 52 | static final Predicate CLASSPATH_PROJECT_DIR = new Predicate() { 53 | @Override 54 | boolean test(URL url) { 55 | File userDir = new File(System.getProperty("user.dir")) 56 | return url.path.startsWith(userDir.toURI().toURL().path) 57 | } 58 | } 59 | 60 | static final Predicate CLASSPATH_PROJECT_DEPENDENCIES = new Predicate() { 61 | @Override 62 | boolean test(URL url) { 63 | return url.path.contains('/build/classes') || url.path.contains('/build/resources') || url.path.contains('/build/libs') || url.path.contains('/out/') 64 | } 65 | } 66 | 67 | /** 68 | * Attempts to provide a classpath that approximates the 'normal' Gradle runtime classpath. Use {@link #CLASSPATH_ALL} 69 | * to default to pre-2.2.2 behaviour. 70 | */ 71 | static final Predicate CLASSPATH_DEFAULT = new Predicate() { 72 | @Override 73 | boolean test(URL url) { 74 | return CLASSPATH_PROJECT_DIR.test(url) || CLASSPATH_GRADLE_CACHE.test(url) || CLASSPATH_PROJECT_DEPENDENCIES.test(url) || MAVEN_LOCAL.test(url) 75 | } 76 | } 77 | 78 | /** 79 | * Accept all URLs. Provides pre-2.2.2 behaviour. 80 | */ 81 | static final Predicate CLASSPATH_ALL = new Predicate() { 82 | @Override 83 | boolean test(URL url) { 84 | return true 85 | } 86 | } 87 | 88 | /** 89 | * Create handle and run build 90 | * @param directory 91 | * @param args 92 | * @return results from execution 93 | */ 94 | ExecutionResult run(File directory, List args) 95 | 96 | ExecutionResult run(File directory, List args, List jvmArgs) 97 | 98 | ExecutionResult run(File directory, List args, List jvmArgs, List preExecutionActions) 99 | 100 | /** 101 | * Handle on instance of Gradle that can be run. 102 | * @param directory 103 | * @param args 104 | * @return handle 105 | */ 106 | GradleHandle handle(File directory, List args) 107 | 108 | GradleHandle handle(File directory, List args, List jvmArgs) 109 | 110 | GradleHandle handle(File directory, List args, List jvmArgs, List preExecutionActions) 111 | } 112 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/GradleRunnerFactory.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional 2 | 3 | import groovy.transform.CompileStatic 4 | import nebula.test.functional.internal.DefaultGradleRunner 5 | import nebula.test.functional.internal.GradleHandleFactory 6 | import nebula.test.functional.internal.classpath.ClasspathInjectingGradleHandleFactory 7 | import nebula.test.functional.internal.toolingapi.ToolingApiGradleHandleFactory 8 | 9 | import java.util.function.Predicate 10 | 11 | @CompileStatic 12 | class GradleRunnerFactory { 13 | public static GradleRunner createTooling(boolean fork = false, String version = null, Integer daemonMaxIdleTimeInSeconds = null, 14 | Predicate classpathFilter = null) { 15 | GradleHandleFactory toolingApiHandleFactory = new ToolingApiGradleHandleFactory(fork, version, daemonMaxIdleTimeInSeconds); 16 | return create(toolingApiHandleFactory, classpathFilter ?: GradleRunner.CLASSPATH_DEFAULT); 17 | } 18 | 19 | public static GradleRunner create(GradleHandleFactory handleFactory, Predicate classpathFilter = null) { 20 | // TODO: Which class would be attached to the right classloader? Is using something from the test kit right? 21 | ClassLoader sourceClassLoader = GradleRunnerFactory.class.getClassLoader(); 22 | create(handleFactory, sourceClassLoader, classpathFilter ?: GradleRunner.CLASSPATH_DEFAULT) 23 | } 24 | 25 | public static GradleRunner create(GradleHandleFactory handleFactory, ClassLoader sourceClassLoader, Predicate classpathFilter) { 26 | GradleHandleFactory classpathInjectingHandleFactory = new ClasspathInjectingGradleHandleFactory(sourceClassLoader, handleFactory, classpathFilter); 27 | return new DefaultGradleRunner(classpathInjectingHandleFactory); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/PreExecutionAction.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | 7 | /** 8 | * Executes actions before gradle is called. 9 | */ 10 | interface PreExecutionAction { 11 | void execute(File projectDir, List arguments, List jvmArguments); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/DefaultExecutionResult.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional.internal 18 | 19 | import groovy.transform.CompileStatic 20 | import nebula.test.functional.ExecutionResult 21 | import org.gradle.api.GradleException 22 | 23 | @CompileStatic 24 | abstract class DefaultExecutionResult implements ExecutionResult { 25 | private final Boolean success 26 | private final String standardOutput 27 | private final String standardError 28 | private final List executedTasks 29 | private final Throwable failure 30 | 31 | public DefaultExecutionResult(Boolean success, String standardOutput, String standardError, List executedTasks, Throwable failure) { 32 | this.success = success 33 | this.standardOutput = standardOutput 34 | this.standardError = standardError 35 | this.executedTasks = executedTasks 36 | this.failure = failure 37 | } 38 | 39 | @Override 40 | Boolean getSuccess() { 41 | success 42 | } 43 | 44 | @Override 45 | public String getStandardOutput() { 46 | standardOutput 47 | } 48 | 49 | @Override 50 | public String getStandardError() { 51 | standardError 52 | } 53 | 54 | @Override 55 | boolean wasExecuted(String taskPath) { 56 | executedTasks.any { ExecutedTask task -> 57 | taskPath = normalizeTaskPath(taskPath) 58 | def match = task.path == taskPath 59 | return match 60 | } 61 | } 62 | 63 | @Override 64 | boolean wasUpToDate(String taskPath) { 65 | getExecutedTaskByPath(taskPath).upToDate 66 | } 67 | 68 | @Override 69 | boolean wasSkipped(String taskPath) { 70 | getExecutedTaskByPath(taskPath).skipped 71 | } 72 | 73 | String normalizeTaskPath(String taskPath) { 74 | taskPath.startsWith(':') ? taskPath : ":$taskPath" 75 | } 76 | 77 | private ExecutedTask getExecutedTaskByPath(String taskPath) { 78 | taskPath = normalizeTaskPath(taskPath) 79 | def task = executedTasks.find { ExecutedTask task -> task.path == taskPath } 80 | if (task == null) { 81 | throw new RuntimeException("Task with path $taskPath was not found") 82 | } 83 | task 84 | } 85 | 86 | @Override 87 | public Throwable getFailure() { 88 | failure 89 | } 90 | 91 | @Override 92 | public ExecutionResult rethrowFailure() { 93 | if (failure instanceof GradleException) { 94 | throw (GradleException) failure 95 | } 96 | if (failure != null) { 97 | throw new GradleException("Build aborted because of an internal error.", failure) 98 | } 99 | this 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/DefaultGradleRunner.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional.internal 18 | 19 | import groovy.transform.CompileStatic 20 | import nebula.test.functional.ExecutionResult 21 | import nebula.test.functional.GradleRunner 22 | import nebula.test.functional.PreExecutionAction 23 | 24 | @CompileStatic 25 | class DefaultGradleRunner implements GradleRunner { 26 | private final GradleHandleFactory handleFactory; 27 | 28 | public DefaultGradleRunner(GradleHandleFactory handleFactory) { 29 | this.handleFactory = handleFactory; 30 | } 31 | 32 | @Override 33 | public ExecutionResult run(File projectDir, List arguments, List jvmArguments = [], List preExecutionActions = []) { 34 | return handle(projectDir, arguments, jvmArguments, preExecutionActions).run(); 35 | } 36 | 37 | @Override 38 | public GradleHandle handle(File projectDir, List arguments, List jvmArguments = [], List preExecutionActions = []) { 39 | preExecutionActions?.each { it.execute(projectDir, arguments, jvmArguments) } 40 | return handleFactory.start(projectDir, arguments, jvmArguments); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/ExecutedTask.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal 2 | 3 | interface ExecutedTask { 4 | String getPath() 5 | boolean isUpToDate() 6 | boolean isSkipped() 7 | } 8 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/GradleHandle.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional.internal 18 | 19 | import nebula.test.functional.ExecutionResult 20 | 21 | /** 22 | * Runs a Gradle build, orchestrating the execution so that it can return a result object. 23 | */ 24 | interface GradleHandle { 25 | ExecutionResult run() 26 | void registerBuildListener(GradleHandleBuildListener buildListener) 27 | boolean isForkedProcess() 28 | void disconnect() 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/GradleHandleBuildListener.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal 2 | 3 | interface GradleHandleBuildListener { 4 | void buildStarted() 5 | void buildFinished() 6 | } -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/GradleHandleFactory.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal; 2 | 3 | public interface GradleHandleFactory { 4 | 5 | GradleHandle start(File dir, List arguments); 6 | 7 | GradleHandle start(File dir, List arguments, List jvmArguments); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/classpath/ClasspathAddingInitScriptBuilder.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.classpath 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.internal.ErroringAction 5 | import org.gradle.internal.IoActions 6 | import org.gradle.internal.classloader.ClasspathUtil 7 | import org.gradle.internal.classpath.ClassPath 8 | import org.gradle.util.TextUtil 9 | 10 | import java.util.function.Predicate 11 | 12 | @CompileStatic 13 | class ClasspathAddingInitScriptBuilder { 14 | private ClasspathAddingInitScriptBuilder() { 15 | } 16 | 17 | public static void build(File initScriptFile, final ClassLoader classLoader, Predicate classpathFilter) { 18 | build(initScriptFile, getClasspathAsFiles(classLoader, classpathFilter)); 19 | } 20 | 21 | public static void build(File initScriptFile, final List classpath) { 22 | IoActions.writeTextFile(initScriptFile, new ErroringAction() { 23 | @Override 24 | protected void doExecute(Writer writer) throws Exception { 25 | writer.write("allprojects {\n") 26 | writer.write(" buildscript {\n") 27 | writer.write(" dependencies {\n") 28 | writeClasspath(writer, classpath) 29 | writer.write(" }\n") 30 | writer.write(" }\n") 31 | writer.write("}\n") 32 | writer.write("initscript {\n") 33 | writer.write(" dependencies {\n") 34 | writeClasspath(writer, classpath) 35 | writer.write(" }\n") 36 | writer.write("}\n") 37 | } 38 | }) 39 | } 40 | 41 | public static writeClasspath(Writer writer, List classpath) { 42 | for (File file : classpath) { 43 | // Commons-lang 2.4 does not escape forward slashes correctly, https://issues.apache.org/jira/browse/LANG-421 44 | writer.write(String.format(" classpath files('%s')\n", TextUtil.escapeString(file.getAbsolutePath()))); 45 | } 46 | } 47 | 48 | public static List getClasspathAsFiles(ClassLoader classLoader, Predicate classpathFilter) { 49 | List classpathUrls = getClasspathUrls(classLoader) 50 | return classpathUrls.findAll {classpathFilter.test(it) }.collect { 51 | new File(it.toURI()) 52 | } 53 | } 54 | 55 | private static List getClasspathUrls(ClassLoader classLoader) { 56 | Object cp = ClasspathUtil.getClasspath(classLoader) 57 | if (cp instanceof List) { 58 | return (List) cp 59 | } 60 | if (cp instanceof ClassPath) { // introduced by gradle/gradle@0ab8bc2 61 | return ((ClassPath) cp).asURLs 62 | } 63 | throw new IllegalStateException("Unable to extract classpath urls from type ${cp.class.canonicalName}") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/classpath/ClasspathInjectingGradleHandleFactory.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.classpath 2 | 3 | import groovy.transform.CompileStatic 4 | import nebula.test.functional.internal.GradleHandle 5 | import nebula.test.functional.internal.GradleHandleFactory 6 | import org.gradle.util.GFileUtils 7 | 8 | import java.util.function.Predicate 9 | 10 | @CompileStatic 11 | class ClasspathInjectingGradleHandleFactory implements GradleHandleFactory { 12 | private final ClassLoader classLoader; 13 | private final GradleHandleFactory delegateFactory; 14 | private Predicate classpathFilter 15 | 16 | public ClasspathInjectingGradleHandleFactory(ClassLoader classLoader, GradleHandleFactory delegateFactory, Predicate classpathFilter) { 17 | this.classpathFilter = classpathFilter; 18 | this.classLoader = classLoader; 19 | this.delegateFactory = delegateFactory; 20 | } 21 | 22 | @Override 23 | public GradleHandle start(File projectDir, List arguments, List jvmArguments = []) { 24 | File testKitDir = new File(projectDir, ".gradle-test-kit"); 25 | if (!testKitDir.exists()) { 26 | GFileUtils.mkdirs(testKitDir); 27 | } 28 | 29 | File initScript = new File(testKitDir, "init.gradle"); 30 | ClasspathAddingInitScriptBuilder.build(initScript, classLoader, classpathFilter); 31 | 32 | List ammendedArguments = new ArrayList(arguments.size() + 2); 33 | ammendedArguments.add("--init-script"); 34 | ammendedArguments.add(initScript.getAbsolutePath()); 35 | ammendedArguments.addAll(arguments); 36 | return delegateFactory.start(projectDir, ammendedArguments, jvmArguments); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/toolingapi/BuildLauncherBackedGradleHandle.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional.internal.toolingapi 18 | 19 | import groovy.transform.CompileStatic 20 | import nebula.test.functional.ExecutionResult 21 | import nebula.test.functional.internal.GradleHandle 22 | import nebula.test.functional.internal.GradleHandleBuildListener 23 | import org.gradle.tooling.BuildException 24 | import org.gradle.tooling.BuildLauncher 25 | import org.gradle.tooling.GradleConnector 26 | import org.gradle.tooling.events.ProgressEvent 27 | import org.gradle.tooling.events.ProgressListener 28 | import org.gradle.tooling.events.task.TaskOperationDescriptor 29 | 30 | @CompileStatic 31 | class BuildLauncherBackedGradleHandle implements GradleHandle { 32 | 33 | final private ByteArrayOutputStream standardOutput = new ByteArrayOutputStream(); 34 | final private ByteArrayOutputStream standardError = new ByteArrayOutputStream(); 35 | final private BuildLauncher launcher; 36 | final private boolean forkedProcess 37 | final private List tasksExecuted; 38 | final private GradleConnector connector; 39 | private GradleHandleBuildListener buildListener 40 | 41 | public BuildLauncherBackedGradleHandle(GradleConnector connector, BuildLauncher launcher, boolean forkedProcess) { 42 | this.forkedProcess = forkedProcess 43 | launcher.setStandardOutput(standardOutput); 44 | launcher.setStandardError(standardError); 45 | 46 | tasksExecuted = new ArrayList(); 47 | launcher.addProgressListener(new ProgressListener() { 48 | @Override 49 | public void statusChanged(ProgressEvent event) { 50 | if (event.descriptor instanceof TaskOperationDescriptor) { 51 | def descriptor = (TaskOperationDescriptor) event.descriptor 52 | tasksExecuted.add(descriptor.taskPath) 53 | } 54 | } 55 | }); 56 | this.launcher = launcher; 57 | this.connector = connector 58 | } 59 | 60 | @Override 61 | void registerBuildListener(GradleHandleBuildListener buildListener) { 62 | this.buildListener = buildListener 63 | } 64 | 65 | @Override 66 | boolean isForkedProcess() { 67 | forkedProcess 68 | } 69 | 70 | @Override 71 | void disconnect() { 72 | connector.disconnect() 73 | } 74 | 75 | private String getStandardOutput() { 76 | return standardOutput.toString(); 77 | } 78 | 79 | private String getStandardError() { 80 | return standardError.toString(); 81 | } 82 | 83 | @Override 84 | public ExecutionResult run() { 85 | Throwable failure = null; 86 | try { 87 | buildListener?.buildStarted() 88 | launcher.run(); 89 | } catch(BuildException e) { 90 | failure = e.getCause(); 91 | } catch(Exception e) { 92 | failure = e; 93 | } 94 | finally { 95 | buildListener?.buildFinished() 96 | } 97 | 98 | String stdout = getStandardOutput(); 99 | List tasks = new ArrayList(); 100 | for (String taskName: tasksExecuted) { 101 | // Scan stdout for task's up to date 102 | boolean upToDate = isTaskUpToDate(stdout, taskName) 103 | boolean skipped = isTaskSkipped(stdout, taskName) 104 | tasks.add( new MinimalExecutedTask(taskName, upToDate, skipped) ); 105 | } 106 | boolean success = failure == null 107 | return new ToolingExecutionResult(success, stdout, getStandardError(), tasks, failure); 108 | } 109 | 110 | private isTaskUpToDate(String stdout, String taskName) { 111 | containsOutput(stdout, taskName, 'UP-TO-DATE') 112 | } 113 | 114 | private isTaskSkipped(String stdout, String taskName) { 115 | containsOutput(stdout, taskName, 'SKIPPED') 116 | } 117 | 118 | private boolean containsOutput(String stdout, String taskName, String stateIdentifier) { 119 | stdout.contains("$taskName $stateIdentifier".toString()) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/toolingapi/MinimalExecutedTask.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 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 nebula.test.functional.internal.toolingapi 17 | 18 | import groovy.transform.CompileStatic 19 | import nebula.test.functional.internal.ExecutedTask 20 | 21 | /** 22 | * @author Marcin Erdmann 23 | */ 24 | @CompileStatic 25 | class MinimalExecutedTask implements ExecutedTask { 26 | 27 | String path 28 | boolean upToDate 29 | boolean skipped 30 | 31 | MinimalExecutedTask(String path, boolean upToDate, boolean skipped) { 32 | this.path = path 33 | this.upToDate = upToDate 34 | this.skipped = skipped 35 | } 36 | 37 | String toString() { 38 | "executed $path" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/toolingapi/ToolingApiGradleHandleFactory.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.toolingapi 2 | 3 | import groovy.transform.CompileDynamic 4 | import groovy.transform.CompileStatic 5 | import nebula.test.functional.internal.GradleHandle 6 | import nebula.test.functional.internal.GradleHandleBuildListener 7 | import nebula.test.functional.internal.GradleHandleFactory 8 | import org.gradle.tooling.BuildLauncher 9 | import org.gradle.tooling.GradleConnector 10 | import org.gradle.tooling.ProjectConnection 11 | 12 | import java.util.concurrent.TimeUnit 13 | 14 | @CompileStatic 15 | public class ToolingApiGradleHandleFactory implements GradleHandleFactory { 16 | public static final String FORK_SYS_PROP = 'nebula.test.functional.fork' 17 | 18 | private final boolean fork 19 | private final String version 20 | private final Integer daemonMaxIdleTimeInSeconds 21 | 22 | ToolingApiGradleHandleFactory(boolean fork, String version, Integer daemonMaxIdleTimeInSeconds = null) { 23 | this.fork = fork 24 | this.version = version 25 | this.daemonMaxIdleTimeInSeconds = daemonMaxIdleTimeInSeconds 26 | } 27 | 28 | @Override 29 | @CompileDynamic 30 | public GradleHandle start(File projectDir, List arguments, List jvmArguments = []) { 31 | GradleConnector connector = createGradleConnector(projectDir) 32 | 33 | boolean forkedProcess = isForkedProcess() 34 | 35 | // Allow for in-process debugging 36 | connector.embedded(!forkedProcess) 37 | 38 | if (daemonMaxIdleTimeInSeconds != null) { 39 | connector.daemonMaxIdleTime(daemonMaxIdleTimeInSeconds, TimeUnit.SECONDS) 40 | } 41 | 42 | ProjectConnection connection = connector.connect(); 43 | BuildLauncher launcher = createBuildLauncher(connection, arguments, jvmArguments) 44 | createGradleHandle(connector, connection, launcher, forkedProcess) 45 | } 46 | 47 | private GradleConnector createGradleConnector(File projectDir) { 48 | GradleConnector connector = GradleConnector.newConnector(); 49 | connector.forProjectDirectory(projectDir); 50 | configureGradleVersion(connector, projectDir) 51 | connector 52 | } 53 | 54 | private void configureGradleVersion(GradleConnector connector, File projectDir) { 55 | if (version != null) { 56 | connector.useGradleVersion(version) 57 | } else { 58 | configureWrapperDistributionIfUsed(connector, projectDir) 59 | } 60 | } 61 | 62 | private static void configureWrapperDistributionIfUsed(GradleConnector connector, File projectDir) { 63 | // Search above us, in the project that owns the test 64 | File target = projectDir.absoluteFile 65 | while (target != null) { 66 | URI distribution = prepareDistributionURI(target) 67 | if (distribution) { 68 | connector.useDistribution(distribution) 69 | return 70 | } 71 | target = target.parentFile 72 | } 73 | } 74 | 75 | // Translated from org.gradle.wrapper.WrapperExecutor to avoid coupling to Gradle API 76 | private static URI prepareDistributionURI(File target) { 77 | File propertiesFile = new File(target, "gradle/wrapper/gradle-wrapper.properties") 78 | if (propertiesFile.exists()) { 79 | Properties properties = new Properties() 80 | propertiesFile.withInputStream { 81 | properties.load(it) 82 | } 83 | URI source = new URI(properties.getProperty("distributionUrl")) 84 | return source.getScheme() == null ? (new File(propertiesFile.getParentFile(), source.getSchemeSpecificPart())).toURI() : source; 85 | } 86 | return null 87 | } 88 | 89 | private boolean isForkedProcess() { 90 | if (fork) { 91 | return true 92 | } 93 | 94 | Boolean.parseBoolean(System.getProperty(FORK_SYS_PROP, Boolean.FALSE.toString())) 95 | } 96 | 97 | private static BuildLauncher createBuildLauncher(ProjectConnection connection, List arguments, List jvmArguments) { 98 | BuildLauncher launcher = connection.newBuild(); 99 | launcher.withArguments(arguments as String[]); 100 | launcher.setJvmArguments(jvmArguments as String[]) 101 | launcher 102 | } 103 | 104 | private GradleHandle createGradleHandle(GradleConnector connector, ProjectConnection connection, BuildLauncher launcher, boolean forkedProcess) { 105 | GradleHandleBuildListener toolingApiBuildListener = new ToolingApiBuildListener(connection) 106 | BuildLauncherBackedGradleHandle buildLauncherBackedGradleHandle = new BuildLauncherBackedGradleHandle(connector, launcher, forkedProcess) 107 | buildLauncherBackedGradleHandle.registerBuildListener(toolingApiBuildListener) 108 | buildLauncherBackedGradleHandle 109 | } 110 | 111 | private class ToolingApiBuildListener implements GradleHandleBuildListener { 112 | private final ProjectConnection connection 113 | 114 | ToolingApiBuildListener(ProjectConnection connection) { 115 | assert connection != null, 'Requires a non-null connection' 116 | this.connection = connection 117 | } 118 | 119 | @Override 120 | void buildStarted() {} 121 | 122 | @Override 123 | void buildFinished() { 124 | connection.close() 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/functional/internal/toolingapi/ToolingExecutionResult.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.toolingapi 2 | 3 | import groovy.transform.CompileStatic 4 | import nebula.test.functional.internal.DefaultExecutionResult 5 | 6 | /** 7 | * Hold additional response data, that is only available 8 | */ 9 | @CompileStatic 10 | class ToolingExecutionResult extends DefaultExecutionResult { 11 | 12 | ToolingExecutionResult(Boolean success, String standardOutput, String standardError, List executedTasks, Throwable failure) { 13 | super(success, standardOutput, standardError, executedTasks, failure) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/gradle/GradleVersionComparator.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.gradle 2 | 3 | import org.gradle.util.GradleVersion 4 | 5 | @Category(String) 6 | class GradleVersionComparator { 7 | 8 | boolean versionGreaterThan(String version) { 9 | return versionCompareTo(this, version) > 0 10 | } 11 | 12 | boolean versionLessThan(String version) { 13 | return versionCompareTo(this, version) < 0 14 | } 15 | 16 | int versionCompareTo(String v1, String v2) { 17 | return GradleVersion.version(v1).compareTo(GradleVersion.version(v2)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/multiproject/MultiProjectHelper.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.Project 5 | import org.gradle.testfixtures.ProjectBuilder 6 | 7 | @CompileStatic 8 | class MultiProjectHelper { 9 | Project parent 10 | 11 | MultiProjectHelper(Project parent) { 12 | this.parent = parent 13 | } 14 | 15 | Map create(Collection projectNames) { 16 | Map info = [:] 17 | 18 | projectNames.each { 19 | def subproject = ProjectBuilder.builder().withName(it).withParent(parent).build() 20 | info[it] = new MultiProjectInfo(name: it, project: subproject, parent: parent) 21 | } 22 | 23 | info 24 | } 25 | 26 | Map createWithDirectories(Collection projectNames) { 27 | Map info = [:] 28 | 29 | projectNames.each { 30 | def subDirectory = new File(parent.projectDir, it) 31 | subDirectory.mkdirs() 32 | def subproject = ProjectBuilder.builder().withName(it).withProjectDir(subDirectory).withParent(parent).build() 33 | info[it] = new MultiProjectInfo(name: it, project: subproject, parent: parent, directory: subDirectory) 34 | } 35 | 36 | info 37 | } 38 | 39 | Project addSubproject(String name) { 40 | ProjectBuilder.builder().withName(name).withParent(parent).build() 41 | } 42 | 43 | Project addSubprojectWithDirectory(String name) { 44 | def dir = new File(parent.projectDir, name) 45 | dir.mkdirs() 46 | ProjectBuilder.builder().withName(name).withProjectDir(dir).withParent(parent).build() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/multiproject/MultiProjectInfo.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.Project 5 | 6 | @CompileStatic 7 | class MultiProjectInfo { 8 | String name 9 | Project parent 10 | Project project 11 | File directory 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/multiproject/MultiProjectIntegrationHelper.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import groovy.transform.CompileStatic 4 | import nebula.test.IntegrationSpec 5 | 6 | @CompileStatic 7 | class MultiProjectIntegrationHelper { 8 | static String lineEnd = System.getProperty('line.separator') 9 | 10 | File projectDir 11 | File settingsFile 12 | 13 | MultiProjectIntegrationHelper(File projectDir, File settingsFile) { 14 | this.projectDir = projectDir 15 | this.settingsFile = settingsFile 16 | } 17 | 18 | MultiProjectIntegrationHelper(IntegrationSpec spec) { 19 | this(spec.projectDir, spec.settingsFile) 20 | } 21 | 22 | Map create(Collection projectNames) { 23 | Map info = [:] 24 | 25 | projectNames.each { 26 | settingsFile << "include '${it}'${lineEnd}" 27 | def dir = new File(projectDir, it) 28 | dir.mkdirs() 29 | def buildFile = new File(dir, 'build.gradle') 30 | 31 | info[it] = new MultiProjectIntegrationInfo(name: it, directory: dir, buildGradle: buildFile) 32 | } 33 | 34 | info 35 | } 36 | 37 | File addSubproject(String name) { 38 | settingsFile << "include '${name}'${lineEnd}" 39 | def dir = new File(projectDir, name) 40 | dir.mkdirs() 41 | 42 | dir 43 | } 44 | 45 | File addSubproject(String name, String gradleContents) { 46 | def dir = addSubproject(name) 47 | new File(dir, 'build.gradle').text = gradleContents 48 | 49 | dir 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/multiproject/MultiProjectIntegrationInfo.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import groovy.transform.CompileStatic 4 | 5 | @CompileStatic 6 | class MultiProjectIntegrationInfo { 7 | String name 8 | File directory 9 | File buildGradle 10 | } 11 | -------------------------------------------------------------------------------- /src/main/groovy/nebula/test/package-info.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * The integration/launcher tests copied from: 4 | * https://github.com/golo-lang/gradle-golo-plugin/tree/master/src/integrationTest/groovy/org/gololang/gradle/test/integration/framework 5 | * https://github.com/eriwen/gradle-js-plugin/blob/master/src/test/groovy/com/eriwen/gradle/js/util/ 6 | * 7 | * functional tooling tests copied from: 8 | * https://github.com/alkemist/gradle-test-kit 9 | * 10 | */ 11 | package nebula.test 12 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/BuildScanIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | class BuildScanIntegrationSpec extends IntegrationTestKitSpec { 4 | def origOut = System.out 5 | def out = new ByteArrayOutputStream() 6 | 7 | def setup() { 8 | new File(projectDir, "settings.gradle") << """ 9 | gradleEnterprise { 10 | buildScan { 11 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 12 | termsOfServiceAgree = 'yes' 13 | } 14 | } 15 | """ 16 | def printStream = new PrintStream(out) 17 | System.setOut(printStream) 18 | } 19 | 20 | def cleanup() { 21 | System.setOut(origOut) 22 | } 23 | 24 | def 'build scan url is reported in test output'() { 25 | when: 26 | runTasks('help', '--scan') 27 | 28 | then: 29 | out.toString("UTF-8").contains("Build scan:") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/ConcreteIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import nebula.test.functional.ExecutionResult 4 | import nebula.test.functional.PreExecutionAction 5 | import spock.lang.Unroll 6 | 7 | class ConcreteIntegrationSpec extends IntegrationSpec { 8 | def 'runs build'() { 9 | when: 10 | ExecutionResult buildResult = runTasks('dependencies') 11 | 12 | then: 13 | buildResult.failure == null 14 | } 15 | 16 | @Unroll 17 | def 'setup and run build for #type execution'() { 18 | buildFile << ''' 19 | apply plugin: 'java' 20 | '''.stripIndent() 21 | fork = forked 22 | 23 | when: 24 | writeHelloWorld('nebula.test.hello') 25 | 26 | then: 27 | fileExists('src/main/java/nebula/test/hello/HelloWorld.java') 28 | 29 | when: 30 | def result = runTasksSuccessfully('build', '--info') 31 | 32 | then: 33 | fileExists('build/classes/java/main/nebula/test/hello/HelloWorld.class') 34 | result.wasExecuted(':compileTestJava') 35 | result.getStandardOutput().contains('Skipping task \':compileTestJava\' as it has no source files and no previous output files.') 36 | 37 | where: 38 | type | forked 39 | 'in-process' | false 40 | 'forked' | true 41 | } 42 | 43 | 44 | @Unroll 45 | def 'can import from classpath using #desc #testTooling'(String desc, boolean testTooling) { 46 | buildFile << ''' 47 | import nebula.test.FakePlugin 48 | apply plugin: FakePlugin 49 | '''.stripIndent() 50 | 51 | when: 52 | runTasksSuccessfully('tasks') 53 | 54 | then: 55 | noExceptionThrown() 56 | 57 | where: 58 | desc | testTooling 59 | "Tooling" | true 60 | "Launcher" | false 61 | } 62 | 63 | def 'init scripts will be appended to arguments provided to gradle'() { 64 | setup: 65 | def initScript = file('foo.gradle') 66 | initScript.text = ''' 67 | gradle.projectsLoaded { 68 | gradle.rootProject.tasks.create('foo') 69 | } 70 | '''.stripIndent() 71 | when: 72 | def failure = runTasksWithFailure('foo') 73 | 74 | then: 75 | failure.failure != null 76 | 77 | when: 78 | addInitScript(initScript) 79 | failure = runTasksSuccessfully('foo') 80 | failure.failure == null 81 | 82 | then: 83 | noExceptionThrown() 84 | } 85 | 86 | def 'pre execution tasks will run before gradle'() { 87 | def initScript = file('foo.gradle') 88 | 89 | when: 90 | addPreExecute(new PreExecutionAction() { 91 | @Override 92 | void execute(File projectDir, List arguments, List jvmArguments) { 93 | initScript.text = ''' 94 | gradle.projectsLoaded { 95 | gradle.rootProject.tasks.create('foo') 96 | } 97 | '''.stripIndent() 98 | } 99 | }) 100 | addInitScript(initScript) 101 | runTasksSuccessfully('foo') 102 | 103 | then: 104 | noExceptionThrown() 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/ConcretePluginProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | class ConcretePluginProjectSpec extends PluginProjectSpec { 4 | @Override 5 | String getPluginName() { 6 | 'fake-plugin' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/ConcreteProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean 4 | 5 | class ConcreteProjectSpec extends ProjectSpec { 6 | def 'has Project'() { 7 | expect: 8 | project != null 9 | projectDir.exists() 10 | } 11 | 12 | def 'can evaluate'() { 13 | setup: 14 | def signal = new AtomicBoolean(false) 15 | project.afterEvaluate { 16 | signal.getAndSet(true) 17 | } 18 | when: 19 | project.evaluate() 20 | 21 | then: 22 | noExceptionThrown() 23 | signal.get() == true 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/CustomCleanupProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import spock.lang.Shared 4 | 5 | class CustomCleanupProjectSpec extends ProjectSpec { 6 | @Shared 7 | File refProjectDir 8 | 9 | def setup() { 10 | refProjectDir = projectDir 11 | } 12 | 13 | def cleanupSpec() { 14 | assert refProjectDir.exists() 15 | } 16 | 17 | @Override 18 | boolean deleteProjectDir() { 19 | false 20 | } 21 | 22 | def "Avoids cleaning project directory after test"() { 23 | expect: 24 | project != null 25 | projectDir.exists() 26 | } 27 | } -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/DeprecationCheckIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import spock.lang.Ignore 4 | import spock.lang.IgnoreIf 5 | 6 | class DeprecationCheckIntegrationSpec extends IntegrationSpec { 7 | @Ignore 8 | def 'deprecation warnings cause test to fail'() { 9 | given: 10 | buildFile << """ 11 | apply plugin: 'java' 12 | 13 | repositories { 14 | mavenCentral() 15 | } 16 | 17 | dependencies { 18 | implementation('com.google.guava:guava:19.0') { 19 | force = true 20 | } 21 | } 22 | """ 23 | 24 | when: 25 | runTasks('help') 26 | 27 | then: 28 | def e = thrown(IllegalArgumentException) 29 | e.message.startsWith('Deprecation warnings were found (Set the ignoreDeprecations system property during the test to ignore)') 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/FakePlugin.java: -------------------------------------------------------------------------------- 1 | package nebula.test; 2 | 3 | 4 | import org.gradle.api.Plugin; 5 | import org.gradle.api.Project; 6 | 7 | public class FakePlugin implements Plugin { 8 | @Override 9 | public void apply(Project project) { 10 | // Intentionally empty 11 | } 12 | } -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/IntegrationTestKitSpecCustomBaseFolderSpec.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020 Netflix, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package nebula.test 20 | 21 | class IntegrationTestKitSpecCustomBaseFolderSpec extends IntegrationTestKitSpec { 22 | 23 | def setup() { 24 | // used to test trait & groovy setup method https://stackoverflow.com/questions/56464191/public-groovy-method-must-be-public-says-the-compiler 25 | } 26 | 27 | def cleanup() { 28 | // used to test trait & groovy cleanup method https://stackoverflow.com/questions/56464191/public-groovy-method-must-be-public-says-the-compiler 29 | } 30 | 31 | @Override 32 | String getProjectBaseFolderName() { 33 | return 'notnebulatest' 34 | } 35 | 36 | def 'can override project dir base folder name'() { 37 | expect: 38 | !projectDir.absolutePath.contains("/build/nebulatest/") 39 | projectDir.absolutePath.contains("/build/notnebulatest/") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/IntegrationTestKitSpecSpec.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020 Netflix, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package nebula.test 20 | 21 | import nebula.test.dependencies.DependencyGraphBuilder 22 | import nebula.test.dependencies.GradleDependencyGenerator 23 | import nebula.test.dependencies.ModuleBuilder 24 | 25 | class IntegrationTestKitSpecSpec extends IntegrationTestKitSpec { 26 | 27 | def setup() { 28 | // used to test trait & groovy setup method https://stackoverflow.com/questions/56464191/public-groovy-method-must-be-public-says-the-compiler 29 | } 30 | 31 | def cleanup() { 32 | // used to test trait & groovy cleanup method https://stackoverflow.com/questions/56464191/public-groovy-method-must-be-public-says-the-compiler 33 | } 34 | 35 | def 'dependencies method should list buildfile dependencies'() { 36 | when: 37 | def graph = new DependencyGraphBuilder() 38 | .addModule('testjava:a:0.1.0') 39 | .addModule(new ModuleBuilder('testjava:b:0.1.0') 40 | .addDependency('testjava:a:0.1.0').build()) 41 | .addModule('testjava:c:0.1.0').build() 42 | File mavenrepo = new GradleDependencyGenerator(graph, "${projectDir}/testrepogen").generateTestMavenRepo() 43 | 44 | buildFile << """ 45 | apply plugin 'java-library' 46 | repositories { 47 | maven { url = '${mavenrepo.absolutePath}' } 48 | } 49 | dependencies { 50 | implementation 'testjava:a:0.1.0' 51 | api 'testjava:b:0.1.0' 52 | testImplementation 'testjava:c:0.1.0' 53 | } 54 | """.stripIndent() 55 | 56 | then: 57 | dependencies(buildFile, 'implementation') == ['testjava:a:0.1.0'] 58 | dependencies(buildFile, 'api') == ['testjava:b:0.1.0'] 59 | dependencies(buildFile, 'testImplementation') == ['testjava:c:0.1.0'] 60 | dependencies(buildFile) == ['testjava:a:0.1.0', 'testjava:b:0.1.0', 'testjava:c:0.1.0'] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/JvmArgumentsIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | class JvmArgumentsIntegrationSpec extends IntegrationSpec { 4 | 5 | private static final String TEST_JVM_ARGUMENT = "-XX:-PrintClassHistogram" 6 | 7 | def "should start Gradle with custom JVM argument in fork mode"() { 8 | given: 9 | writeHelloWorld('nebula.test.hello') 10 | buildFile << ''' 11 | apply plugin: 'java' 12 | '''.stripIndent() 13 | and: 14 | fork = true 15 | jvmArguments = [TEST_JVM_ARGUMENT] 16 | when: 17 | def result = runTasksSuccessfully('compileJava', '--debug') 18 | then: 19 | result.standardOutput.contains(TEST_JVM_ARGUMENT) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/MutableProjectStateWarningCheckIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import spock.lang.IgnoreIf 4 | 5 | @IgnoreIf({ System.getenv('TITUS_TASK_ID') }) 6 | class MutableProjectStateWarningCheckIntegrationSpec extends IntegrationSpec { 7 | 8 | def setup() { 9 | System.setProperty("ignoreDeprecations", "true") 10 | } 11 | 12 | def 'mutable project state warning when configuration in another project is resolved unsafely'() { 13 | given: 14 | settingsFile << """ 15 | rootProject.name = "foo" 16 | """ 17 | addSubproject('bar', """ 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | configurations { 23 | bar 24 | } 25 | 26 | dependencies { 27 | bar group: 'junit', name: 'junit', version: '4.12' 28 | } 29 | """) 30 | buildFile << """ 31 | task resolve { 32 | doLast { 33 | println project(':bar').configurations.bar.files 34 | } 35 | } 36 | """ 37 | 38 | 39 | when: 40 | runTasks("resolve", "--parallel", "--warning-mode", "all") 41 | 42 | then: 43 | def e = thrown(IllegalArgumentException) 44 | e.message.contains('Mutable Project State warnings were found (Set the ignoreMutableProjectStateWarnings system property during the test to ignore)') 45 | } 46 | 47 | def 'mutable project state warning when configuration is resolved from a non-gradle thread'() { 48 | given: 49 | settingsFile << """ 50 | rootProject.name = "foo" 51 | """ 52 | addSubproject('bar', """ 53 | repositories { 54 | mavenCentral() 55 | } 56 | 57 | configurations { 58 | bar 59 | } 60 | 61 | dependencies { 62 | bar group: 'junit', name: 'junit', version: '4.12' 63 | } 64 | """) 65 | buildFile << """ 66 | task resolve { 67 | def thread = new Thread({ 68 | println project(':bar').configurations.bar.files 69 | }) 70 | doFirst { 71 | thread.start() 72 | thread.join() 73 | } 74 | } 75 | """ 76 | 77 | 78 | when: 79 | runTasks("resolve", "--warning-mode", "all") 80 | 81 | then: 82 | def e = thrown(IllegalArgumentException) 83 | e.message.contains('Mutable Project State warnings were found (Set the ignoreMutableProjectStateWarnings system property during the test to ignore)') 84 | } 85 | 86 | def 'mutable project state warning when configuration is resolved while evaluating a different project'() { 87 | given: 88 | settingsFile << """ 89 | rootProject.name = "foo" 90 | include ":bar", ":baz" 91 | """ 92 | 93 | buildFile << """ 94 | project(':baz') { 95 | repositories { 96 | mavenCentral() 97 | } 98 | 99 | configurations { 100 | baz 101 | } 102 | 103 | dependencies { 104 | baz group: 'junit', name: 'junit', version: '4.12' 105 | } 106 | } 107 | 108 | project(':bar') { 109 | println project(':baz').configurations.baz.files 110 | } 111 | """ 112 | 113 | 114 | when: 115 | runTasks(":bar:help", "--parallel", "--warning-mode", "all") 116 | 117 | then: 118 | def e = thrown(IllegalArgumentException) 119 | e.message.contains('Mutable Project State warnings were found (Set the ignoreMutableProjectStateWarnings system property during the test to ignore)') 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/ProjectDirCleanupProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import spock.lang.Shared 4 | 5 | class ProjectDirCleanupProjectSpec extends ProjectSpec { 6 | @Shared 7 | File refProjectDir 8 | 9 | def setup() { 10 | refProjectDir = projectDir 11 | } 12 | 13 | def cleanupSpec() { 14 | assert !refProjectDir.exists() 15 | } 16 | 17 | def "Cleans project directory after test"() { 18 | expect: 19 | project != null 20 | projectDir.exists() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/SpecifiedGradleVersionIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Netflix, Inc. 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 nebula.test 17 | 18 | import org.gradle.api.logging.LogLevel 19 | import spock.lang.Ignore 20 | import spock.lang.IgnoreIf 21 | import spock.lang.Unroll 22 | import spock.util.environment.OperatingSystem 23 | 24 | class SpecifiedGradleVersionIntegrationSpec extends IntegrationSpec { 25 | def setup() { 26 | fork = true 27 | } 28 | 29 | 30 | @IgnoreIf({ OperatingSystem.current.linux || OperatingSystem.current.macOs || jvm.isJava9Compatible()}) 31 | @Unroll("should use Gradle #requestedGradleVersion when requested ") 32 | def "should allow to run functional tests with different Gradle versions Windows"() { 33 | given: 34 | writeHelloWorld('nebula.test.hello') 35 | buildFile << ''' 36 | apply plugin: 'java' 37 | 38 | task showVersion { 39 | doLast { 40 | println "Gradle Version: ${gradle.gradleVersion}" 41 | } 42 | } 43 | '''.stripIndent() 44 | 45 | and: 46 | gradleVersion = requestedGradleVersion 47 | 48 | when: 49 | def result = runTasksSuccessfully('showVersion') 50 | 51 | then: 52 | 53 | result.standardOutput.contains("Gradle Version: $requestedGradleVersion") 54 | 55 | where: 56 | requestedGradleVersion << ['7.0-milestone-2'] 57 | } 58 | 59 | @IgnoreIf({ OperatingSystem.current.windows || jvm.isJava9Compatible() }) 60 | @Unroll("should use Gradle #requestedGradleVersion when requested ") 61 | def "should allow to run functional tests with different Gradle versions Linux - Mac"() { 62 | given: 63 | writeHelloWorld('nebula.test.hello') 64 | buildFile << ''' 65 | apply plugin: 'java' 66 | 67 | task showVersion { 68 | doLast { 69 | println "Gradle Version: ${gradle.gradleVersion}" 70 | } 71 | } 72 | '''.stripIndent() 73 | 74 | and: 75 | gradleVersion = requestedGradleVersion 76 | 77 | when: 78 | def result = runTasksSuccessfully('showVersion') 79 | 80 | then: 81 | 82 | result.standardOutput.contains("Gradle Version: $requestedGradleVersion") 83 | 84 | 85 | where: 86 | requestedGradleVersion << ['7.0-milestone-2'] 87 | } 88 | 89 | static final String CUSTOM_DISTRIBUTION = 'https://dl.bintray.com/nebula/gradle-distributions/1.12-20140608201532+0000/gradle-1.12-20140608201532+0000-bin.zip' 90 | 91 | @Ignore("Only works with a custom distribution that is compatible with our runtime, of which 1.12 is not compatible with our spock 2.0 dependency") 92 | def 'should be able to use custom distribution'() { 93 | buildFile << ''' 94 | task showVersion << { 95 | println "Gradle Version: ${gradle.gradleVersion}" 96 | } 97 | '''.stripIndent() 98 | File wrapperProperties = new File(projectDir, 'gradle/wrapper/gradle-wrapper.properties') 99 | wrapperProperties.parentFile.mkdirs() 100 | wrapperProperties << """ 101 | #Tue Jun 03 14:28:56 PDT 2014 102 | distributionBase=GRADLE_USER_HOME 103 | distributionPath=wrapper/dists 104 | zipStoreBase=GRADLE_USER_HOME 105 | zipStorePath=wrapper/dists 106 | distributionUrl=${CUSTOM_DISTRIBUTION} 107 | """ 108 | 109 | when: 110 | def result = runTasksSuccessfully('showVersion') 111 | 112 | then: 113 | result.standardOutput.contains("Gradle Version: 1.12-20140608201532+0000") 114 | } 115 | 116 | @Ignore("Only works with a custom distribution that is compatible with our runtime, of which 1.12 is not compatible with our spock 2.0 dependency") 117 | def 'should be able to use custom distribution in a test'() { 118 | def testFile = new File(projectDir, "src/test/groovy/testing/DistributionTest.groovy") 119 | testFile.parentFile.mkdirs() 120 | testFile << ''' 121 | package testing 122 | 123 | import nebula.test.IntegrationSpec 124 | import nebula.test.functional.ExecutionResult 125 | 126 | class DistributionTest extends IntegrationSpec { 127 | def 'confirm distribution'() { 128 | buildFile << """ 129 | task print << { 130 | println "Gradle Inner Test Version: \\${gradle.gradleVersion}" 131 | } 132 | """.stripIndent() 133 | expect: 134 | runTasksSuccessfully('print') 135 | } 136 | } 137 | '''.stripIndent() 138 | buildFile << ''' 139 | apply plugin: 'groovy' 140 | dependencies { 141 | testCompile localGroovy() 142 | } 143 | sourceSets.test.compileClasspath += [buildscript.configurations.classpath] 144 | test { 145 | classpath += [buildscript.configurations.classpath] 146 | testLogging { 147 | events "passed", "skipped", "failed", "standardOut", "standardError" 148 | } 149 | } 150 | '''.stripIndent() 151 | writeHelloWorld('testing') 152 | 153 | File wrapperProperties = new File(projectDir, 'gradle/wrapper/gradle-wrapper.properties') 154 | wrapperProperties.parentFile.mkdirs() 155 | wrapperProperties << """ 156 | #Tue Jun 03 14:28:56 PDT 2014 157 | distributionBase=GRADLE_USER_HOME 158 | distributionPath=wrapper/dists 159 | zipStoreBase=GRADLE_USER_HOME 160 | zipStorePath=wrapper/dists 161 | distributionUrl=${CUSTOM_DISTRIBUTION} 162 | """.stripIndent() 163 | 164 | when: 165 | def result = runTasksSuccessfully('test') 166 | 167 | then: 168 | result.standardOutput.contains("Gradle Inner Test Version: 1.12-20140608201532+0000") 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/SystemPropertyCleanupProjectSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test 2 | 3 | import spock.lang.Shared 4 | 5 | class SystemPropertyCleanupProjectSpec extends ProjectSpec { 6 | @Shared 7 | File refProjectDir 8 | 9 | def setup() { 10 | refProjectDir = projectDir 11 | } 12 | 13 | def cleanupSpec() { 14 | assert !refProjectDir.exists() 15 | } 16 | 17 | def "Cleans project directory after test"() { 18 | setup: 19 | System.setProperty('CLEAN_PROJECT_DIR_SYS_PROP', 'true') 20 | 21 | expect: 22 | project != null 23 | projectDir.exists() 24 | 25 | cleanup: 26 | System.clearProperty('CLEAN_PROJECT_DIR_SYS_PROP') 27 | } 28 | } -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/dependencies/DependencyGraphBuilderSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies 2 | 3 | import spock.lang.Specification 4 | 5 | class DependencyGraphBuilderSpec extends Specification { 6 | def 'add one dependency'() { 7 | def builder = new DependencyGraphBuilder() 8 | builder.addModule('test.nebula:foo:1.0.0') 9 | 10 | when: 11 | DependencyGraph graph = builder.build() 12 | 13 | then: 14 | graph.nodes.size() == 1 15 | Coordinate foo = graph.nodes.find().coordinate 16 | foo.group == 'test.nebula' 17 | foo.artifact == 'foo' 18 | foo.version == '1.0.0' 19 | } 20 | 21 | def 'add one dependency with group, artifact, version syntax'() { 22 | def builder = new DependencyGraphBuilder() 23 | builder.addModule('test.nebula', 'foo', '1.0.0') 24 | 25 | when: 26 | DependencyGraph graph = builder.build() 27 | 28 | then: 29 | graph.nodes.size() == 1 30 | Coordinate foo = graph.nodes.find().coordinate 31 | foo.group == 'test.nebula' 32 | foo.artifact == 'foo' 33 | foo.version == '1.0.0' 34 | } 35 | 36 | def 'add multiple dependencies'() { 37 | def builder = new DependencyGraphBuilder() 38 | builder.addModule('test.nebula:foo:1.0.0') 39 | .addModule('a.nebula:bar:2.0.0') 40 | 41 | when: 42 | DependencyGraph graph = builder.build() 43 | 44 | then: 45 | graph.nodes.size() == 2 46 | Coordinate foo = graph.nodes.find { it.coordinate.artifact == 'foo' }.coordinate 47 | foo.group == 'test.nebula' 48 | foo.artifact == 'foo' 49 | foo.version == '1.0.0' 50 | Coordinate bar = graph.nodes.find { it.coordinate.artifact == 'bar' }.coordinate 51 | bar.group == 'a.nebula' 52 | bar.artifact == 'bar' 53 | bar.version == '2.0.0' 54 | } 55 | 56 | def 'add module with dependencies'() { 57 | def builder = new DependencyGraphBuilder() 58 | builder.addModule(new ModuleBuilder('test.nebula:foo:1.0.0').addDependency('test.nebula:bar:1.1.1').build()) 59 | 60 | when: 61 | DependencyGraph graph = builder.build() 62 | 63 | then: 64 | graph.nodes.size() == 2 65 | graph.nodes.find { it.artifact == 'bar' } != null 66 | } 67 | 68 | def 'add module with dependencies, add another module make sure it replaces with the one with dependencies'() { 69 | def builder = new DependencyGraphBuilder() 70 | builder.addModule(new ModuleBuilder('test.nebula:foo:1.0.0').addDependency('test.nebula:bar:1.1.1').build()) 71 | .addModule(new ModuleBuilder('test.nebula:bar:1.1.1').addDependency('test.nebula:baz:23.1.3').build()) 72 | 73 | when: 74 | DependencyGraph graph = builder.build() 75 | 76 | then: 77 | graph.nodes.size() == 3 78 | def bar = graph.nodes.find { it.artifact == 'bar' } 79 | bar.dependencies.size() == 1 80 | def dep = bar.dependencies.find() 81 | dep.group == 'test.nebula' 82 | dep.artifact == 'baz' 83 | dep.version == '23.1.3' 84 | } 85 | 86 | def 'add module with dependencies, verify modules are not replaced with placeholder'() { 87 | def builder = new DependencyGraphBuilder() 88 | builder.addModule(new ModuleBuilder('test.nebula:bar:1.1.1').addDependency('test.nebula:baz:23.1.3').build()) 89 | .addModule(new ModuleBuilder('test.nebula:foo:1.0.0').addDependency('test.nebula:bar:1.1.1').build()) 90 | 91 | 92 | when: 93 | DependencyGraph graph = builder.build() 94 | 95 | then: 96 | graph.nodes.size() == 3 97 | def bar = graph.nodes.find { it.artifact == 'bar' } 98 | bar.dependencies.size() == 1 99 | def dep = bar.dependencies.find() 100 | dep.group == 'test.nebula' 101 | dep.artifact == 'baz' 102 | dep.version == '23.1.3' 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/dependencies/DependencyGraphSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Netflix, Inc. 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 nebula.test.dependencies 17 | 18 | import spock.lang.Specification 19 | 20 | class DependencyGraphSpec extends Specification { 21 | def 'one node graph'() { 22 | when: 23 | def graph = new DependencyGraph(['test:foo:1.0.0']) 24 | 25 | then: 26 | graph.nodes.size() == 1 27 | DependencyGraphNode node = graph.nodes[0] 28 | node.group == 'test' 29 | node.artifact == 'foo' 30 | node.version == '1.0.0' 31 | node.dependencies.size() == 0 32 | node.toString() == 'test:foo:1.0.0:integration' 33 | } 34 | 35 | def 'node with dependencies'() { 36 | when: 37 | def graph = new DependencyGraph(['test:foo:1.0.0 -> test:bar:1.+']) 38 | 39 | then: 40 | graph.nodes.size() == 1 41 | DependencyGraphNode node = graph.nodes[0] 42 | node.group == 'test' 43 | node.artifact == 'foo' 44 | node.version == '1.0.0' 45 | node.dependencies.size() == 1 46 | Coordinate dependency = node.dependencies[0] 47 | dependency.group == 'test' 48 | dependency.artifact == 'bar' 49 | dependency.version == '1.+' 50 | } 51 | 52 | def 'node with multiple dependencies'() { 53 | when: 54 | def graph = new DependencyGraph(['test:foo:1.0.0 -> test:bar:1.+|g:a:[1.0.0,2.0.0)|g1:a1:1.1.1']) 55 | 56 | then: 57 | graph.nodes.size() == 1 58 | graph.nodes[0].dependencies.size() == 3 59 | def dependencies = graph.nodes[0].dependencies.collect { it.toString() } 60 | dependencies.contains 'test:bar:1.+' 61 | dependencies.contains 'g:a:[1.0.0,2.0.0)' 62 | dependencies.contains 'g1:a1:1.1.1' 63 | } 64 | 65 | def 'check var arg constructor'() { 66 | when: 67 | def graph = new DependencyGraph('test:foo:1.0.0', 'test:bar:1.1.1') 68 | 69 | then: 70 | graph.nodes.size() == 2 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/dependencies/ModuleBuilderSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies 2 | 3 | import spock.lang.Specification 4 | 5 | class ModuleBuilderSpec extends Specification { 6 | def 'build module with no dependencies'() { 7 | def builder = new ModuleBuilder('test.modulebuilder:foo:1.0.0') 8 | 9 | when: 10 | DependencyGraphNode module = builder.build() 11 | 12 | then: 13 | module.group == 'test.modulebuilder' 14 | module.artifact == 'foo' 15 | module.version == '1.0.0' 16 | module.dependencies.size() == 0 17 | } 18 | 19 | def 'build module with no dependencies separate group, artifact, version'() { 20 | def builder = new ModuleBuilder('test.modulebuilder', 'foo', '1.0.0') 21 | 22 | when: 23 | DependencyGraphNode module = builder.build() 24 | 25 | then: 26 | module.group == 'test.modulebuilder' 27 | module.artifact == 'foo' 28 | module.version == '1.0.0' 29 | module.dependencies.size() == 0 30 | } 31 | 32 | def 'build module with specific status'() { 33 | def builder = new ModuleBuilder('test.modulebuilder', 'foo', '1.0.0').setStatus('snapshot') 34 | 35 | when: 36 | DependencyGraphNode module = builder.build() 37 | 38 | then: 39 | module.group == 'test.modulebuilder' 40 | module.artifact == 'foo' 41 | module.version == '1.0.0' 42 | module.status == 'snapshot' 43 | 44 | } 45 | 46 | def 'add dependency'() { 47 | def builder = new ModuleBuilder('test.modulebuilder', 'bar', '1.0.0') 48 | builder.addDependency('test.dependency', 'baz', '2.0.1') 49 | 50 | when: 51 | DependencyGraphNode module = builder.build() 52 | 53 | then: 54 | module.dependencies.size() == 1 55 | def dep = module.dependencies.find() 56 | dep.group == 'test.dependency' 57 | dep.artifact == 'baz' 58 | dep.version == '2.0.1' 59 | } 60 | 61 | def 'add dependencies'() { 62 | def builder = new ModuleBuilder('test.modulebuilder', 'bar', '1.0.0') 63 | builder.addDependency('test.dependency', 'baz', '2.0.1') 64 | .addDependency('test.dependency:qux:42.13.0') 65 | 66 | when: 67 | DependencyGraphNode module = builder.build() 68 | 69 | then: 70 | module.dependencies.size() == 2 71 | def baz = module.dependencies.find { it.artifact == 'baz' } 72 | baz.group == 'test.dependency' 73 | baz.artifact == 'baz' 74 | baz.version == '2.0.1' 75 | def qux = module.dependencies.find { it.artifact == 'qux' } 76 | qux.group == 'test.dependency' 77 | qux.artifact == 'qux' 78 | qux.version == '42.13.0' 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/dependencies/maven/PomSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies.maven 2 | 3 | import spock.lang.Specification 4 | 5 | class PomSpec extends Specification { 6 | def 'generate basic pom'() { 7 | def pom = new Pom('nebula.test', 'basic', '0.1.0') 8 | 9 | when: 10 | def pomXml = pom.generate() 11 | 12 | then: 13 | def expected = '''\ 14 | 15 | 16 | 4.0.0 17 | nebula.test 18 | basic 19 | 0.1.0 20 | '''.stripIndent() 21 | pomXml == expected 22 | } 23 | 24 | def 'generate bom'() { 25 | def pom = new Pom('nebula.test', 'basic', '0.1.0', ArtifactType.POM) 26 | pom.addManagementDependency('foo', 'bar', '1.2.3') 27 | 28 | when: 29 | def pomXml = pom.generate() 30 | 31 | then: 32 | def expected = '''\ 33 | 34 | 35 | 4.0.0 36 | nebula.test 37 | basic 38 | 0.1.0 39 | pom 40 | 41 | 42 | 43 | foo 44 | bar 45 | 1.2.3 46 | 47 | 48 | 49 | '''.stripIndent() 50 | pomXml == expected 51 | } 52 | 53 | def 'generate pom with dependency'() { 54 | def pom = new Pom('nebula.test', 'basic', '0.1.0') 55 | pom.addDependency('foo', 'bar', '1.2.3') 56 | pom.addDependency(new Artifact('baz', 'qux', '2.0.1')) 57 | 58 | when: 59 | def pomXml = pom.generate() 60 | 61 | then: 62 | def expected = '''\ 63 | 64 | 65 | 4.0.0 66 | nebula.test 67 | basic 68 | 0.1.0 69 | 70 | 71 | baz 72 | qux 73 | 2.0.1 74 | 75 | 76 | foo 77 | bar 78 | 1.2.3 79 | 80 | 81 | '''.stripIndent() 82 | pomXml == expected 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/dependencies/repositories/MavenRepoSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.dependencies.repositories 2 | 3 | import nebula.test.dependencies.maven.ArtifactType 4 | import nebula.test.dependencies.maven.Pom 5 | import spock.lang.Specification 6 | 7 | class MavenRepoSpec extends Specification { 8 | def 'create repo'() { 9 | def repo = new MavenRepo() 10 | final String rootDir = 'build/test/nebula.test.dependencies.repositories.MavenRepoSpec/create_repo/mavenrepo' 11 | repo.root = new File(rootDir) 12 | if (repo.root.exists()) { 13 | repo.root.deleteDir() 14 | } 15 | def example = new Pom('test.nebula', 'ourbom', '0.1.0', ArtifactType.POM) 16 | def example2 = new Pom('test.nebula', 'ourbom', '0.2.0', ArtifactType.POM) 17 | repo.poms.add(example) 18 | repo.poms.add(example2) 19 | 20 | when: 21 | repo.generate() 22 | 23 | then: 24 | def pom = new File("${rootDir}/test/nebula/ourbom/0.1.0/ourbom-0.1.0.pom") 25 | pom.exists() 26 | 27 | def metadataFile = new File("${rootDir}/test/nebula/ourbom/maven-metadata.xml") 28 | metadataFile.exists() 29 | 30 | def metadata = new XmlSlurper().parse(metadataFile) 31 | metadata.groupId == 'test.nebula' 32 | metadata.artifactId == 'ourbom' 33 | metadata.versioning.latest == '0.2.0' 34 | metadata.versioning.release == '0.2.0' 35 | metadata.versioning.versions.children().toSet().collect { it.toString() }.containsAll(['0.1.0', '0.2.0']) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/GradleRunnerSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2017 Netflix, Inc. 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 nebula.test.functional 17 | 18 | import spock.lang.IgnoreIf 19 | import spock.lang.Specification 20 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables 21 | 22 | /** 23 | * Tests for predicates that live on {@link GradleRunner}. 24 | */ 25 | class GradleRunnerSpec extends Specification { 26 | List classpath 27 | 28 | def workDir = new File(System.getProperty("user.dir")) 29 | def siblingDir = new File(workDir.parentFile, 'sibling') 30 | def sharedDependencyCache = new File(workDir.parentFile, 'sharedDependencyCache') 31 | def testDistributionWorkspace = new File(workDir.parentFile, 'gradle-enterprise-test-distribution-agent-workspace') 32 | 33 | def setup() { 34 | // Partial real-world classpath from a IntegrationSpec launch, only the workDir/siblingDir paths matter, otherwise these are just string comparisons 35 | def classpathUris = [ 36 | "file:/Applications/IntelliJ%20IDEA%2015%20EAP.app/Contents/lib/serviceMessages.jar", 37 | "file:/Applications/IntelliJ%20IDEA%2015%20EAP.app/Contents/lib/idea_rt.jar", 38 | "file:/Applications/IntelliJ%20IDEA%2015%20EAP.app/Contents/plugins/junit/lib/junit-rt.jar", 39 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/ant-javafx.jar", 40 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/dt.jar", 41 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/javafx-doclet.jar", 42 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/javafx-mx.jar", 43 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/jconsole.jar", 44 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/sa-jdi.jar", 45 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/lib/tools.jar", 46 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/charsets.jar", 47 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/deploy.jar", 48 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/htmlconverter.jar", 49 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/javaws.jar", 50 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/jce.jar", 51 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/jfr.jar", 52 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/jfxrt.jar", 53 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/jsse.jar", 54 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/management-agent.jar", 55 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/plugin.jar", 56 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/resources.jar", 57 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/rt.jar", 58 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/dnsns.jar", 59 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/localedata.jar", 60 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/sunec.jar", 61 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar", 62 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar", 63 | "file:/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/ext/zipfs.jar", 64 | 65 | // The project that is being tested always appears as follows: 66 | new File(workDir, 'build/classes/test/').toURI() as String, 67 | new File(workDir, 'build/classes/main/').toURI() as String, 68 | new File(workDir, 'build/resources/test/').toURI() as String, 69 | new File(workDir, 'build/resources/main/').toURI() as String, 70 | 71 | // when launched from IDE, project dependencies appear this way: 72 | new File(siblingDir, 'build/classes/test/').toURI() as String, 73 | new File(siblingDir, 'build/classes/main/').toURI() as String, 74 | new File(siblingDir, 'build/resources/test/').toURI() as String, 75 | new File(siblingDir, 'build/resources/main/').toURI() as String, 76 | 77 | // when launched from IntelliJ, and not delegating to Gradle for compilation, project dependencies appear this way: 78 | new File(siblingDir, 'out/integTest/classes').toURI() as String, 79 | new File(siblingDir, 'out/test/classes').toURI() as String, 80 | new File(siblingDir, 'out/test/resources').toURI() as String, 81 | new File(siblingDir, 'out/production/classes').toURI() as String, 82 | new File(siblingDir, 'out/production/resources').toURI() as String, 83 | 84 | // when launched from Gradle, project dependencies appear as jars: 85 | new File(siblingDir, 'build/libs/repos-4.0.0.jar').toURI() as String, 86 | 87 | new File(workDir, ".gradle/caches/modules-2/files-2.1/org.spockframework/spock-core/1.0-groovy-2.3/762fbf6c5f24baabf9addcf9cf3647151791f7eb/spock-core-1.0-groovy-2.3.jar").toURI() as String, 88 | new File(workDir, ".gradle/caches/modules-2/files-2.1/cglib/cglib-nodep/2.2.2/d456bb230c70c0b95c76fb28e429d42f275941/cglib-nodep-2.2.2.jar").toURI() as String, 89 | new File(workDir, ".gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar").toURI() as String, 90 | new File(workDir, ".gradle/caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/junit-4.12.jar").toURI() as String, 91 | new File(workDir, ".gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar").toURI() as String, 92 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/gradle-core-2.2.1.jar").toURI() as String, 93 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/groovy-all-2.3.6.jar").toURI() as String, 94 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/asm-all-5.0.3.jar").toURI() as String, 95 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/ant-1.9.3.jar").toURI() as String, 96 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/commons-collections-3.2.1.jar").toURI() as String, 97 | new File(workDir, ".gradle/wrapper/dists/gradle-2.2.1-bin/3rn023ng4778ktj66tonmgpbv/gradle-2.2.1/lib/commons-io-1.4.jar").toURI() as String, 98 | 99 | new File(sharedDependencyCache, "/modules-2/files-2.1/junit/junit/4.13/2973d150c0dc1fefe998f834810d68f278ea58ec/junit-4.13.jar").toURI() as String, 100 | new File(testDistributionWorkspace, "/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58dc/junit-4.12.jar").toURI() as String, 101 | new File(testDistributionWorkspace, "/modules-2/files-2.1/commons-lang/commons-lang/2.2/ce1edb914c94ebc388f086c6827e8bdeec71ac1/commons-lang-2.2.jar").toURI() as String, 102 | 103 | new File(System.getProperty('user.home'), '.m2/repository/com/netflix/genie/genie-common/4.0.0-SNAPSHOT/genie-common-4.0.0-SNAPSHOT.jar').toURI() as String 104 | ] 105 | classpath = classpathUris.collect { new URI(it).toURL() } 106 | } 107 | 108 | def 'gradle distribution predicate matches expected files'() { 109 | expect: 110 | def filtered = classpath.findAll {GradleRunner.CLASSPATH_GRADLE_CACHE.test(it) } 111 | filtered.size() == 4 112 | } 113 | 114 | @IgnoreIf({ !jvm.isJava8()}) 115 | def 'gradle distribution predicate matches expected files with GRADLE_RO_DEP_CACHE support'() { 116 | setup: 117 | EnvironmentVariables environmentVariables = new EnvironmentVariables() 118 | environmentVariables.set("GRADLE_RO_DEP_CACHE", sharedDependencyCache.absolutePath) 119 | 120 | expect: 121 | def filtered = environmentVariables.execute(() -> 122 | classpath.findAll {GradleRunner.CLASSPATH_GRADLE_CACHE.test(it) } 123 | ) 124 | filtered.size() == 4 125 | filtered.any { it.file.contains('commons-lang-2.6') } 126 | } 127 | 128 | def 'gradle distribution predicate matches expected files with test distribution folder support'() { 129 | expect: 130 | def filtered = classpath.findAll {GradleRunner.CLASSPATH_GRADLE_CACHE.test(it) } 131 | 132 | filtered.size() == 4 133 | filtered.any { it.file.contains('commons-lang-2.2') } 134 | } 135 | 136 | def 'jvm predicate matches expected files'() { 137 | expect: 138 | def filtered = classpath.findAll {GradleRunner.CLASSPATH_PROJECT_DIR.test(it) } 139 | filtered.size() == 15 140 | } 141 | 142 | def 'project dependencies matches expected files'() { 143 | expect: 144 | def filtered = classpath.findAll {GradleRunner.CLASSPATH_PROJECT_DEPENDENCIES.test(it) } 145 | filtered.size() == 14 146 | } 147 | 148 | def 'maven local dependencies matches expected files'() { 149 | expect: 150 | def filtered = classpath.findAll {GradleRunner.MAVEN_LOCAL.test(it) } 151 | filtered.size() == 1 152 | filtered.every {it.file.contains(".m2/repository") } 153 | } 154 | 155 | def 'default classpath matches only application class paths and dependencies'() { 156 | expect: 157 | def filtered = classpath.findAll {GradleRunner.CLASSPATH_DEFAULT.test(it) } 158 | filtered.size() == 27 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/OutputsGradle2Spec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional 2 | 3 | import org.junit.Rule 4 | import org.junit.rules.TemporaryFolder 5 | import spock.lang.Issue 6 | import spock.lang.Specification 7 | 8 | @Issue("https://github.com/nebula-plugins/nebula-test/issues/29") 9 | class OutputsGradle2Spec extends Specification { 10 | 11 | private static final boolean FORK_MODE = true 12 | 13 | @Rule TemporaryFolder tmp 14 | 15 | def "println included in standardOutput in fork mode"() { 16 | given: 17 | GradleRunner runner = GradleRunnerFactory.createTooling(FORK_MODE) 18 | tmp.newFile("build.gradle") << """ 19 | apply plugin: ${SomePlugin.name} 20 | """ 21 | 22 | when: 23 | ExecutionResult result = runner.run(tmp.root, ["print"]) 24 | 25 | then: 26 | result.standardOutput.contains("Printed (stdout)") 27 | } 28 | 29 | def "err.println included in standardError or standardOutput in fork mode"() { 30 | given: 31 | GradleRunner runner = GradleRunnerFactory.createTooling(FORK_MODE) 32 | tmp.newFile("build.gradle") << """ 33 | apply plugin: ${SomePlugin.name} 34 | """ 35 | 36 | when: 37 | ExecutionResult result = runner.run(tmp.root, ["print"]) 38 | 39 | then: 40 | def expectedMessage = "Printed (stderr)" 41 | //Gradle 4.7 started to print error log messages into standard output 42 | //we run build with version lower then 4.7 as well higher so we check both places 43 | result.standardError.contains(expectedMessage) || result.standardOutput.contains(expectedMessage) 44 | 45 | } 46 | 47 | def "stdout redirected to WARN included in standardOutput in fork mode"() { 48 | given: 49 | GradleRunner runner = GradleRunnerFactory.createTooling(FORK_MODE) 50 | tmp.newFile("build.gradle") << """ 51 | logging.captureStandardOutput LogLevel.WARN 52 | apply plugin: ${SomePlugin.name} 53 | """ 54 | 55 | when: 56 | ExecutionResult result = runner.run(tmp.root, ["print"]) 57 | 58 | then: 59 | result.standardOutput.contains("Printed (stdout)") 60 | } 61 | 62 | def "stdout redirected to ignored logging level not included in standardOutput in fork mode"() { 63 | given: 64 | GradleRunner runner = GradleRunnerFactory.createTooling(FORK_MODE) 65 | tmp.newFile("build.gradle") << """ 66 | logging.captureStandardOutput LogLevel.TRACE 67 | apply plugin: ${SomePlugin.name} 68 | """ 69 | 70 | when: 71 | ExecutionResult result = runner.run(tmp.root, ["print"]) 72 | 73 | then: 74 | !result.standardOutput.contains("Printed (stdout)") 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/SomePlugin.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional 2 | 3 | import nebula.test.functional.foo.Thing 4 | import org.gradle.api.Plugin 5 | import org.gradle.api.Project 6 | 7 | class SomePlugin implements Plugin { 8 | 9 | @Override 10 | void apply(Project project) { 11 | project.task("echo") { 12 | outputs.upToDateWhen { 13 | project.hasProperty('upToDate') ? project.properties['upToDate'].toBoolean() : false 14 | } 15 | 16 | doLast { 17 | new Thing() // Class in another package 18 | org.hamcrest.Matcher // is a compile dependency, test it's available 19 | project.logger.quiet "I ran!" 20 | } 21 | } 22 | 23 | project.task("doIt") { 24 | onlyIf { 25 | project.hasProperty('skip') ? !project.properties['skip'].toBoolean() : true 26 | } 27 | doLast { project.logger.quiet 'Did it!' } 28 | } 29 | 30 | project.task("print") { 31 | doLast { 32 | println "Printed (stdout)" 33 | System.err.println 'Printed (stderr)' 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/TestSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 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 | 17 | package nebula.test.functional 18 | 19 | import org.junit.Rule 20 | import org.junit.rules.TemporaryFolder 21 | import spock.lang.Specification 22 | import spock.lang.Unroll 23 | 24 | class TestSpec extends Specification { 25 | 26 | @Rule TemporaryFolder tmp 27 | 28 | @Unroll 29 | def "Check up-to-date and skipped task states for #type GradleRunner"() { 30 | given: 31 | GradleRunner runner = GradleRunnerFactory.createTooling(forked) 32 | tmp.newFile("build.gradle") << """ 33 | apply plugin: ${SomePlugin.name} 34 | """ 35 | 36 | when: 37 | ExecutionResult result = runner.run(tmp.root, ["echo", "doIt", "-PupToDate=false", "-Pskip=false"]) 38 | !result.wasExecuted(":hush") 39 | result.wasExecuted(":echo") 40 | !result.wasUpToDate(":echo") 41 | result.wasExecuted(":doIt") 42 | !result.wasSkipped(":doIt") 43 | 44 | then: 45 | result.standardOutput.contains("I ran!") 46 | result.standardOutput.contains("Did it!") 47 | 48 | when: 49 | result = runner.run(tmp.root, ["echo", "doIt", "-PupToDate=true", "-Pskip=true"]) 50 | 51 | then: 52 | !result.standardOutput.contains("I ran!") 53 | !result.standardOutput.contains("Did it!") 54 | result.wasExecuted(":echo") 55 | result.wasUpToDate(":echo") 56 | result.wasExecuted(":doIt") 57 | result.wasSkipped(":doIt") 58 | 59 | where: 60 | type | forked 61 | 'in-process' | false 62 | 'forked' | true 63 | } 64 | 65 | @Unroll 66 | def "Task path doesn't need to start with colon for #type GradleRunner"() { 67 | given: 68 | GradleRunner runner = GradleRunnerFactory.createTooling(false) 69 | tmp.newFile("build.gradle") << """ 70 | apply plugin: ${SomePlugin.name} 71 | """ 72 | 73 | when: 74 | ExecutionResult result = runner.run(tmp.root, ["echo", "doIt"]) 75 | result.wasExecuted("echo") 76 | !result.wasUpToDate("echo") 77 | !result.wasSkipped("doIt") 78 | 79 | then: 80 | result.standardOutput.contains("I ran!") 81 | result.standardOutput.contains("Did it!") 82 | 83 | where: 84 | type | forked 85 | 'in-process' | false 86 | 'forked' | true 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/ToolingApiGradleHandleFactorySpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional 2 | 3 | import nebula.test.functional.internal.GradleHandle 4 | import nebula.test.functional.internal.GradleHandleFactory 5 | import nebula.test.functional.internal.toolingapi.ToolingApiGradleHandleFactory 6 | import spock.lang.Specification 7 | 8 | class ToolingApiGradleHandleFactorySpec extends Specification { 9 | File projectDir = new File('myProject') 10 | 11 | def "Creates embedded handle if requested through constructor"() { 12 | when: 13 | GradleHandleFactory gradleHandleFactory = new ToolingApiGradleHandleFactory(false, null) 14 | GradleHandle gradleHandle = gradleHandleFactory.start(projectDir, []) 15 | 16 | then: 17 | gradleHandle 18 | !gradleHandle.forkedProcess 19 | } 20 | 21 | def "Creates forked handle if requested through constructor"() { 22 | when: 23 | GradleHandleFactory gradleHandleFactory = new ToolingApiGradleHandleFactory(true, null) 24 | GradleHandle gradleHandle = gradleHandleFactory.start(projectDir, []) 25 | 26 | then: 27 | gradleHandle 28 | gradleHandle.forkedProcess 29 | } 30 | 31 | def "Creates forked handle if requested through system property"() { 32 | setup: 33 | System.setProperty(ToolingApiGradleHandleFactory.FORK_SYS_PROP, Boolean.TRUE.toString()) 34 | 35 | when: 36 | GradleHandleFactory gradleHandleFactory = new ToolingApiGradleHandleFactory(false, null) 37 | GradleHandle gradleHandle = gradleHandleFactory.start(projectDir, []) 38 | 39 | then: 40 | gradleHandle 41 | gradleHandle.forkedProcess 42 | 43 | cleanup: 44 | System.clearProperty(ToolingApiGradleHandleFactory.FORK_SYS_PROP) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/foo/Thing.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.foo 2 | 3 | class Thing { 4 | } 5 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/internal/DefaultGradleRunnerSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal 2 | 3 | 4 | import nebula.test.functional.PreExecutionAction 5 | import org.junit.Rule 6 | import org.junit.rules.TemporaryFolder 7 | import spock.lang.Specification 8 | 9 | class DefaultGradleRunnerSpec extends Specification { 10 | 11 | @Rule TemporaryFolder temporaryFolder 12 | 13 | def 'will execute actions before run is called'() { 14 | setup: 15 | def projectDir = temporaryFolder.newFolder() 16 | def handleFactory = Mock(GradleHandleFactory) 17 | def runner = new DefaultGradleRunner(handleFactory) 18 | 19 | when: 20 | runner.handle(projectDir, ['arg'], ['jvm'], [new WriteFileAction(projectDir)]) 21 | 22 | then: 23 | 1 * handleFactory.start(projectDir, ['arg'], ['jvm']) 24 | } 25 | 26 | static class WriteFileAction implements PreExecutionAction { 27 | File expectedDir 28 | 29 | WriteFileAction(File expectedDir) { 30 | this.expectedDir = expectedDir 31 | } 32 | 33 | @Override 34 | void execute(File projectDir, List arguments, List jvmArguments) { 35 | assert expectedDir.absolutePath == projectDir.absolutePath 36 | 37 | assert arguments.size() == 1 38 | assert arguments.first() == 'arg' 39 | 40 | assert jvmArguments.size() == 1 41 | assert jvmArguments.first() == 'jvm' 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/internal/classpath/ClasspathAddingInitScriptBuilderFixture.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.classpath 2 | 3 | import org.gradle.util.GFileUtils 4 | 5 | final class ClasspathAddingInitScriptBuilderFixture { 6 | private ClasspathAddingInitScriptBuilderFixture() {} 7 | 8 | static List createLibraries(File projectDir, int numberOfLibs = 500) { 9 | def libraries = [] 10 | 11 | (1..numberOfLibs).each { counter -> 12 | File libDir = new File(projectDir, 'build/libs') 13 | libDir.mkdirs() 14 | File jar = new File(libDir, "lib${counter}.jar") 15 | GFileUtils.touch(jar) 16 | libraries << jar 17 | } 18 | 19 | libraries 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/internal/classpath/ClasspathAddingInitScriptBuilderFunctionalTest.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.classpath 2 | 3 | import nebula.test.IntegrationSpec 4 | import nebula.test.functional.ExecutionResult 5 | 6 | class ClasspathAddingInitScriptBuilderFunctionalTest extends IntegrationSpec { 7 | def "can use generated init script with huge amount of dependencies"() { 8 | given: 9 | File initScript = new File(projectDir, 'build/init.gradle') 10 | List libs = ClasspathAddingInitScriptBuilderFixture.createLibraries(projectDir) 11 | ClasspathAddingInitScriptBuilder.build(initScript, libs) 12 | 13 | buildFile << """ 14 | task helloWorld { 15 | doLast { 16 | logger.quiet 'Hello World!' 17 | } 18 | } 19 | """ 20 | when: 21 | ExecutionResult executionResult = runTasksSuccessfully('helloWorld', '--init-script', initScript.canonicalPath) 22 | 23 | then: 24 | executionResult.standardOutput.contains('Hello World!') 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/functional/internal/classpath/ClasspathAddingInitScriptBuilderIntegrationTest.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.functional.internal.classpath 2 | 3 | import nebula.test.ProjectSpec 4 | import org.gradle.util.TextUtil 5 | 6 | class ClasspathAddingInitScriptBuilderIntegrationTest extends ProjectSpec { 7 | def 'can build init script with huge amount of dependencies'() { 8 | given: 9 | File initScript = project.file('build/init.gradle') 10 | List libs = ClasspathAddingInitScriptBuilderFixture.createLibraries(projectDir) 11 | 12 | when: 13 | ClasspathAddingInitScriptBuilder.build(initScript, libs) 14 | 15 | then: 16 | initScript.exists() 17 | String initScriptContent = initScript.text 18 | 19 | libs.each { lib -> 20 | assert initScriptContent.contains("classpath files('${TextUtil.escapeString(lib.getAbsolutePath())}')") 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/gradle/GradleVersionComparatorSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.gradle 2 | 3 | import spock.lang.Specification 4 | import spock.lang.Subject 5 | 6 | @Subject(GradleVersionComparator) 7 | class GradleVersionComparatorSpec extends Specification { 8 | 9 | def 'checks if version is greater than'() { 10 | given: 11 | String version = '5.0' 12 | Boolean result 13 | 14 | when: 15 | use(GradleVersionComparator) { 16 | result = version.versionGreaterThan('4.10.3') 17 | } 18 | 19 | then: 20 | result 21 | } 22 | 23 | def 'checks if version is less than'() { 24 | given: 25 | String version = '5.0' 26 | Boolean result 27 | 28 | when: 29 | use(GradleVersionComparator) { 30 | result = version.versionLessThan('5.1') 31 | } 32 | 33 | then: 34 | result 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/multiproject/MultiProjectHelperSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import nebula.test.ProjectSpec 4 | import org.gradle.api.Project 5 | 6 | class MultiProjectHelperSpec extends ProjectSpec { 7 | def 'create single subproject in multiproject'() { 8 | when: 9 | Map info = helper.create(['sub']) 10 | 11 | then: 12 | info['sub'].project.parent == project 13 | info['sub'].directory == null 14 | project.subprojects.find { it.name == 'sub' } != null 15 | } 16 | 17 | def 'create single subproject with directory in multiproject'() { 18 | when: 19 | Map info = helper.createWithDirectories(['sub']) 20 | 21 | then: 22 | info['sub'].directory == new File(project.projectDir, 'sub') 23 | } 24 | 25 | def 'create multiple subproject in multiproject'() { 26 | when: 27 | Map info = helper.create(['sub1', 'sub2']) 28 | 29 | then: 30 | info['sub1'].project.parent == project 31 | info['sub1'].directory == null 32 | project.subprojects.find { it.name == 'sub1' } != null 33 | info['sub2'].project.parent == project 34 | info['sub2'].directory == null 35 | project.subprojects.find { it.name == 'sub2' } != null 36 | } 37 | 38 | def 'add a subproject'() { 39 | when: 40 | Project sub = addSubproject('sub') 41 | 42 | then: 43 | sub.parent == project 44 | project.subprojects.find { it == sub } != null 45 | } 46 | 47 | def 'add a subproject with directory'() { 48 | when: 49 | Project sub = addSubprojectWithDirectory('sub') 50 | 51 | then: 52 | sub.parent == project 53 | project.subprojects.find { it == sub } != null 54 | sub.projectDir.toURI().toURL() == new File(projectDir, 'sub').toURI().toURL() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/groovy/nebula/test/multiproject/MultiProjectIntegrationHelperSpec.groovy: -------------------------------------------------------------------------------- 1 | package nebula.test.multiproject 2 | 3 | import nebula.test.IntegrationSpec 4 | 5 | class MultiProjectIntegrationHelperSpec extends IntegrationSpec { 6 | def 'create multi-project'() { 7 | when: 8 | helper.create(['sub']) 9 | 10 | then: 11 | new File(projectDir, 'sub').exists() 12 | settingsFile.text.contains "include 'sub'" 13 | } 14 | 15 | def 'created multi-project can run build'() { 16 | helper.create(['sub']) 17 | 18 | buildFile << '''\ 19 | subprojects { 20 | apply plugin: 'java' 21 | } 22 | '''.stripIndent() 23 | 24 | when: 25 | def result = runTasksSuccessfully('build') 26 | 27 | then: 28 | noExceptionThrown() 29 | result.standardOutput.contains ':sub:build' 30 | result.standardOutput.contains 'BUILD SUCCESSFUL' 31 | } 32 | 33 | def 'can create multi-projects with deeper directory structure'() { 34 | when: 35 | helper.create(['structure/sub']) 36 | 37 | then: 38 | def structure = new File(projectDir, 'structure') 39 | structure.isDirectory() 40 | new File(structure, 'sub').isDirectory() 41 | settingsFile.text.contains "include 'structure/sub'" 42 | } 43 | 44 | def 'add a subproject and build.gradle'() { 45 | String subBuildGradle = '''\ 46 | apply plugin: 'java' 47 | '''.stripIndent() 48 | 49 | when: 50 | File directory = helper.addSubproject('sub', subBuildGradle) 51 | 52 | then: 53 | new File(directory, 'build.gradle').text == subBuildGradle 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/resources/META-INF/gradle-plugins/fake-plugin.properties: -------------------------------------------------------------------------------- 1 | implementation-class=nebula.test.FakePlugin 2 | --------------------------------------------------------------------------------