├── .coveralls.yml
├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── MAINTAINERS
├── README.md
├── RELEASE.md
├── dist
└── pom.xml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── remote-test
├── .gitignore
├── README.md
├── pom.xml
└── src
│ └── test
│ ├── groovy
│ ├── TestNGTest.groovy
│ └── Tester.groovy
│ └── resources
│ ├── grapeConfig.xml
│ └── testng-remote.xml
├── remote
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── testng
│ │ │ ├── remote
│ │ │ ├── AbstractRemoteTestNG.java
│ │ │ ├── AbstractRemoteTestNGFactory.java
│ │ │ ├── IRemoteTestNG.java
│ │ │ ├── Orderable.java
│ │ │ ├── RemoteArgs.java
│ │ │ ├── RemoteTestNG.java
│ │ │ ├── strprotocol
│ │ │ │ ├── AbstractRemoteTestRunnerClient.java
│ │ │ │ ├── BaseMessageSender.java
│ │ │ │ ├── GenericMessage.java
│ │ │ │ ├── IMessage.java
│ │ │ │ ├── IMessageSender.java
│ │ │ │ ├── IRemoteSuiteListener.java
│ │ │ │ ├── IRemoteTestListener.java
│ │ │ │ ├── IStringMessage.java
│ │ │ │ ├── JsonMessageSender.java
│ │ │ │ ├── MessageHelper.java
│ │ │ │ ├── MessageHub.java
│ │ │ │ ├── MessageType.java
│ │ │ │ ├── RemoteTestListener.java
│ │ │ │ ├── RemoteTestListener1.java
│ │ │ │ ├── SerializedMessageSender.java
│ │ │ │ ├── StdoutMessageSender.java
│ │ │ │ ├── StringMessageSender.java
│ │ │ │ ├── SuiteMessage.java
│ │ │ │ ├── TestMessage.java
│ │ │ │ └── TestResultMessage.java
│ │ │ └── support
│ │ │ │ ├── RemoteTestNGFactory.java
│ │ │ │ └── ServiceLoaderHelper.java
│ │ │ ├── shaded
│ │ │ └── osgi
│ │ │ │ └── framework
│ │ │ │ ├── Version.java
│ │ │ │ └── VersionRange.java
│ │ │ └── xml
│ │ │ ├── ResultContentHandler.java
│ │ │ └── ResultXMLParser.java
│ └── resources
│ │ └── revision.properties
│ └── test
│ ├── java
│ ├── org
│ │ └── testng
│ │ │ └── remote
│ │ │ └── strprotocol
│ │ │ ├── JsonMessageTest.java
│ │ │ └── TestResultMessageTest.java
│ └── test
│ │ ├── SimpleBaseTest.java
│ │ └── remote
│ │ ├── RemoteSampleTest.java
│ │ └── RemoteTest.java
│ └── resources
│ ├── testng-remote.xml
│ └── testng.xml
├── remote6_0
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_0.java
│ │ └── RemoteTestNGFactory6_0.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_0_Test.java
├── remote6_10
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_10.java
│ │ └── RemoteTestNGFactory6_10.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_10_Test.java
├── remote6_12
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_12.java
│ │ └── RemoteTestNGFactory6_12.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_12_Test.java
├── remote6_5
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_5.java
│ │ └── RemoteTestNGFactory6_5.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_5_Test.java
├── remote6_9_10
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_9_10.java
│ │ └── RemoteTestNGFactory6_9_10.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_9_10_Test.java
├── remote6_9_7
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG6_9_7.java
│ │ └── RemoteTestNGFactory6_9_7.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote6_9_7Test.java
├── remote7_8
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── testng
│ │ └── remote
│ │ └── support
│ │ ├── RemoteTestNG7_8.java
│ │ └── RemoteTestNGFactory7_8.java
│ └── test
│ └── java
│ └── test
│ └── remote
│ └── Remote7_8_Test.java
└── remote7_9
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── testng
│ └── remote
│ └── support
│ ├── RemoteTestNG7_9.java
│ └── RemoteTestNGFactory7_9.java
└── test
└── java
└── test
└── remote
└── Remote7_9_Test.java
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @testng-team/testng
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: maven
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 | ignore:
9 | - dependency-name: org.testng:testng
10 | versions:
11 | - "> 6.5.1"
12 | - package-ecosystem: github-actions
13 | directory: "/"
14 | schedule:
15 | interval: weekly
16 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - master
9 | schedule:
10 | - cron: "0 0 * * *"
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-22.04
15 | strategy:
16 | matrix:
17 | java: ['11']
18 |
19 | steps:
20 | - uses: actions/checkout@v3
21 | - name: Set up JDK
22 | uses: actions/setup-java@v3
23 | with:
24 | java-version: ${{ matrix.java }}
25 | distribution: 'temurin'
26 | java-package: 'jdk'
27 | check-latest: true
28 | server-id: 'ossrh' # must match the serverId configured for the nexus-staging-maven-plugin
29 | server-username: OSSRH_USERNAME # Env var that holds your OSSRH user name
30 | server-password: OSSRH_PASSWORD # Env var that holds your OSSRH user pw
31 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} # Substituted with the value stored in the referenced secret
32 | gpg-passphrase: SIGN_KEY_PASS # Env var that holds the key's passphrase
33 | cache: 'maven'
34 |
35 | - name: Build with Maven
36 | run: |
37 | mkdir -p ~/.groovy
38 | ./mvnw --version
39 | cp -f remote-test/src/test/resources/grapeConfig.xml ~/.groovy
40 | # workaround for being failed to download osgi/junit/guice for integration test.
41 | # see: https://alok-mishra.com/2015/10/01/593/
42 | rm -rf ~/.m2/repository/org/osgi ~/.m2/repository/junit/junit ~/.m2/repository/com/google/inject/guice
43 | ./mvnw -e -DskipIntTest=false clean install jacoco:report
44 |
45 | - name: Publish
46 | # publish snapshot only when push to master branch
47 | if: github.event_name == 'push' && github.ref_name == 'master'
48 | run: ./mvnw -U -B clean -DskipTests deploy -P deploy
49 | env:
50 | SIGN_KEY_PASS: ${{ secrets.GPG_PASSPHRASE }}
51 | OSSRH_USERNAME: ${{ secrets.NEXUS_USERNAME }}
52 | OSSRH_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
53 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Create Release
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | releaseVersion:
6 | description: 'The release version. Ex: 1.6.0'
7 | required: true
8 | developmentVersion:
9 | description: 'The next development version. Ex: 1.7.0-SNAPSHOT'
10 | required: true
11 | permissions:
12 | contents: write
13 |
14 | jobs:
15 | release:
16 | name: Create Release
17 | runs-on: ubuntu-22.04
18 | steps:
19 | - name: Checkout code
20 | uses: actions/checkout@v3
21 | with:
22 | fetch-depth: 0
23 | # to bypass the branch protection rule for maven-release-plugin
24 | # see https://github.community/t/push-to-restricted-master-branch/18191/2
25 | persist-credentials: false
26 |
27 | - name: Configure Git user
28 | run: |
29 | git config user.email "cibot@testng.org"
30 | git config user.name "CI Bot"
31 |
32 | - name: Set up JDK
33 | uses: actions/setup-java@v3
34 | with:
35 | java-version: '11'
36 | distribution: 'temurin'
37 | java-package: 'jdk'
38 | check-latest: true
39 | server-id: 'ossrh' # must match the serverId configured for the nexus-staging-maven-plugin
40 | server-username: OSSRH_USERNAME # Env var that holds your OSSRH user name
41 | server-password: OSSRH_PASSWORD # Env var that holds your OSSRH user pw
42 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} # Substituted with the value stored in the referenced secret
43 | gpg-passphrase: SIGN_KEY_PASS # Env var that holds the key's passphrase
44 | cache: 'maven'
45 |
46 | - name: Release
47 | run: |
48 | ./mvnw -DskipTests -Darguments="-DskipTests" \
49 | -Dusername=cibot -Dpassword=${{ secrets.GITHUB_TOKEN }} \
50 | -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }} \
51 | -DreleaseVersion=${{ github.event.inputs.releaseVersion }} \
52 | -B release:prepare release:perform -P deploy
53 | env:
54 | SIGN_KEY_PASS: ${{ secrets.GPG_PASSPHRASE }}
55 | OSSRH_USERNAME: ${{ secrets.NEXUS_USERNAME }}
56 | OSSRH_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.war
8 | *.ear
9 |
10 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
11 | hs_err_pid*
12 | target/
13 | test-output/
14 |
15 | .settings/
16 | .classpath
17 | .project
18 | .idea/
19 | *.iml
20 | .vscode/
21 |
22 | dependency-reduced-pom.xml
23 | .DS_Store
24 |
25 | kobaltBuild
26 | .kobalt
27 |
28 | local.properties
29 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/testng-team/testng-remote/46bc27ec69e84a2fe6a9ae566f4e9d6d14d9464b/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/MAINTAINERS:
--------------------------------------------------------------------------------
1 | missedone
2 | juherr
3 | cbeust
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Remote TestNG
2 | ====
3 |
4 | [](https://travis-ci.org/testng-team/testng-remote)
5 | [](https://coveralls.io/github/testng-team/testng-remote)
6 |
7 | TestNG Remote - the modules for running TestNG remotely. This is normally used by IDE to communicate with TestNG runtime, e.g. receive the Test Result from runtime so that can display them on IDE views.
8 |
9 | ### Current Release Version
10 |
11 | ```xml
12 |
13 | org.testng.testng-remote
14 | testng-remote-dist
15 | 1.7.0
16 | shaded
17 |
18 | ```
19 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | Release Remote TestNG
2 | ====
3 |
4 | ### Perform release
5 |
6 | 1. Create a release branch like `release/1.6.0`
7 | 2. Go to https://github.com/testng-team/testng-remote/actions/workflows/release.yml
8 | * Select the `branch` you just created: `release/1.6.0`
9 | * Set `releaseVersion`: the new release version, for example, `1.6.0`
10 | * Set `developmentVersion`: the next development version, for example, `1.6.1-SNAPSHOT`
11 | 3. Merge the release branch without squashing to retain the git tag
12 |
--------------------------------------------------------------------------------
/dist/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 | org.testng.testng-remote
6 | testng-remote-parent
7 | 1.8.0-SNAPSHOT
8 |
9 |
10 | testng-remote-dist
11 | TestNG Remote - Dist
12 | TestNG Remote - Assemble All-in-One Package
13 |
14 |
15 |
16 | org.testng.testng-remote
17 | testng-remote
18 |
19 |
20 | org.testng.testng-remote
21 | testng-remote6_0
22 |
23 |
24 | org.testng.testng-remote
25 | testng-remote6_5
26 |
27 |
28 | org.testng.testng-remote
29 | testng-remote6_9_7
30 |
31 |
32 | org.testng.testng-remote
33 | testng-remote6_9_10
34 |
35 |
36 | org.testng.testng-remote
37 | testng-remote6_10
38 |
39 |
40 | org.testng.testng-remote
41 | testng-remote6_12
42 |
43 |
44 | org.testng.testng-remote
45 | testng-remote7_8
46 |
47 |
48 | org.testng.testng-remote
49 | testng-remote7_9
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.apache.maven.plugins
57 | maven-shade-plugin
58 |
59 |
60 | package
61 |
62 | shade
63 |
64 |
65 | true
66 |
67 |
68 | org.testng.testng-remote:testng-remote
69 | org.testng.testng-remote:testng-remote6_0
70 | org.testng.testng-remote:testng-remote6_5
71 | org.testng.testng-remote:testng-remote6_9_7
72 | org.testng.testng-remote:testng-remote6_9_10
73 | org.testng.testng-remote:testng-remote6_10
74 | org.testng.testng-remote:testng-remote6_12
75 | org.testng.testng-remote:testng-remote7_8
76 | org.testng.testng-remote:testng-remote7_9
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /usr/local/etc/mavenrc ] ; then
40 | . /usr/local/etc/mavenrc
41 | fi
42 |
43 | if [ -f /etc/mavenrc ] ; then
44 | . /etc/mavenrc
45 | fi
46 |
47 | if [ -f "$HOME/.mavenrc" ] ; then
48 | . "$HOME/.mavenrc"
49 | fi
50 |
51 | fi
52 |
53 | # OS specific support. $var _must_ be set to either true or false.
54 | cygwin=false;
55 | darwin=false;
56 | mingw=false
57 | case "`uname`" in
58 | CYGWIN*) cygwin=true ;;
59 | MINGW*) mingw=true;;
60 | Darwin*) darwin=true
61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
63 | if [ -z "$JAVA_HOME" ]; then
64 | if [ -x "/usr/libexec/java_home" ]; then
65 | export JAVA_HOME="`/usr/libexec/java_home`"
66 | else
67 | export JAVA_HOME="/Library/Java/Home"
68 | fi
69 | fi
70 | ;;
71 | esac
72 |
73 | if [ -z "$JAVA_HOME" ] ; then
74 | if [ -r /etc/gentoo-release ] ; then
75 | JAVA_HOME=`java-config --jre-home`
76 | fi
77 | fi
78 |
79 | if [ -z "$M2_HOME" ] ; then
80 | ## resolve links - $0 may be a link to maven's home
81 | PRG="$0"
82 |
83 | # need this for relative symlinks
84 | while [ -h "$PRG" ] ; do
85 | ls=`ls -ld "$PRG"`
86 | link=`expr "$ls" : '.*-> \(.*\)$'`
87 | if expr "$link" : '/.*' > /dev/null; then
88 | PRG="$link"
89 | else
90 | PRG="`dirname "$PRG"`/$link"
91 | fi
92 | done
93 |
94 | saveddir=`pwd`
95 |
96 | M2_HOME=`dirname "$PRG"`/..
97 |
98 | # make it fully qualified
99 | M2_HOME=`cd "$M2_HOME" && pwd`
100 |
101 | cd "$saveddir"
102 | # echo Using m2 at $M2_HOME
103 | fi
104 |
105 | # For Cygwin, ensure paths are in UNIX format before anything is touched
106 | if $cygwin ; then
107 | [ -n "$M2_HOME" ] &&
108 | M2_HOME=`cygpath --unix "$M2_HOME"`
109 | [ -n "$JAVA_HOME" ] &&
110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
111 | [ -n "$CLASSPATH" ] &&
112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
113 | fi
114 |
115 | # For Mingw, ensure paths are in UNIX format before anything is touched
116 | if $mingw ; then
117 | [ -n "$M2_HOME" ] &&
118 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
119 | [ -n "$JAVA_HOME" ] &&
120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
121 | fi
122 |
123 | if [ -z "$JAVA_HOME" ]; then
124 | javaExecutable="`which javac`"
125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
126 | # readlink(1) is not available as standard on Solaris 10.
127 | readLink=`which readlink`
128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
129 | if $darwin ; then
130 | javaHome="`dirname \"$javaExecutable\"`"
131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
132 | else
133 | javaExecutable="`readlink -f \"$javaExecutable\"`"
134 | fi
135 | javaHome="`dirname \"$javaExecutable\"`"
136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
137 | JAVA_HOME="$javaHome"
138 | export JAVA_HOME
139 | fi
140 | fi
141 | fi
142 |
143 | if [ -z "$JAVACMD" ] ; then
144 | if [ -n "$JAVA_HOME" ] ; then
145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
146 | # IBM's JDK on AIX uses strange locations for the executables
147 | JAVACMD="$JAVA_HOME/jre/sh/java"
148 | else
149 | JAVACMD="$JAVA_HOME/bin/java"
150 | fi
151 | else
152 | JAVACMD="`\\unset -f command; \\command -v java`"
153 | fi
154 | fi
155 |
156 | if [ ! -x "$JAVACMD" ] ; then
157 | echo "Error: JAVA_HOME is not defined correctly." >&2
158 | echo " We cannot execute $JAVACMD" >&2
159 | exit 1
160 | fi
161 |
162 | if [ -z "$JAVA_HOME" ] ; then
163 | echo "Warning: JAVA_HOME environment variable is not set."
164 | fi
165 |
166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
167 |
168 | # traverses directory structure from process work directory to filesystem root
169 | # first directory with .mvn subdirectory is considered project base directory
170 | find_maven_basedir() {
171 |
172 | if [ -z "$1" ]
173 | then
174 | echo "Path not specified to find_maven_basedir"
175 | return 1
176 | fi
177 |
178 | basedir="$1"
179 | wdir="$1"
180 | while [ "$wdir" != '/' ] ; do
181 | if [ -d "$wdir"/.mvn ] ; then
182 | basedir=$wdir
183 | break
184 | fi
185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
186 | if [ -d "${wdir}" ]; then
187 | wdir=`cd "$wdir/.."; pwd`
188 | fi
189 | # end of workaround
190 | done
191 | echo "${basedir}"
192 | }
193 |
194 | # concatenates all lines of a file
195 | concat_lines() {
196 | if [ -f "$1" ]; then
197 | echo "$(tr -s '\n' ' ' < "$1")"
198 | fi
199 | }
200 |
201 | BASE_DIR=`find_maven_basedir "$(pwd)"`
202 | if [ -z "$BASE_DIR" ]; then
203 | exit 1;
204 | fi
205 |
206 | ##########################################################################################
207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
208 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
209 | ##########################################################################################
210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Found .mvn/wrapper/maven-wrapper.jar"
213 | fi
214 | else
215 | if [ "$MVNW_VERBOSE" = true ]; then
216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
217 | fi
218 | if [ -n "$MVNW_REPOURL" ]; then
219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
220 | else
221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
222 | fi
223 | while IFS="=" read key value; do
224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
225 | esac
226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
227 | if [ "$MVNW_VERBOSE" = true ]; then
228 | echo "Downloading from: $jarUrl"
229 | fi
230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
231 | if $cygwin; then
232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
233 | fi
234 |
235 | if command -v wget > /dev/null; then
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Found wget ... using wget"
238 | fi
239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
241 | else
242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
243 | fi
244 | elif command -v curl > /dev/null; then
245 | if [ "$MVNW_VERBOSE" = true ]; then
246 | echo "Found curl ... using curl"
247 | fi
248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
249 | curl -o "$wrapperJarPath" "$jarUrl" -f
250 | else
251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
252 | fi
253 |
254 | else
255 | if [ "$MVNW_VERBOSE" = true ]; then
256 | echo "Falling back to using Java to download"
257 | fi
258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
259 | # For Cygwin, switch paths to Windows format before running javac
260 | if $cygwin; then
261 | javaClass=`cygpath --path --windows "$javaClass"`
262 | fi
263 | if [ -e "$javaClass" ]; then
264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
265 | if [ "$MVNW_VERBOSE" = true ]; then
266 | echo " - Compiling MavenWrapperDownloader.java ..."
267 | fi
268 | # Compiling the Java class
269 | ("$JAVA_HOME/bin/javac" "$javaClass")
270 | fi
271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
272 | # Running the downloader
273 | if [ "$MVNW_VERBOSE" = true ]; then
274 | echo " - Running MavenWrapperDownloader.java ..."
275 | fi
276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
277 | fi
278 | fi
279 | fi
280 | fi
281 | ##########################################################################################
282 | # End of extension
283 | ##########################################################################################
284 |
285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
286 | if [ "$MVNW_VERBOSE" = true ]; then
287 | echo $MAVEN_PROJECTBASEDIR
288 | fi
289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
290 |
291 | # For Cygwin, switch paths to Windows format before running java
292 | if $cygwin; then
293 | [ -n "$M2_HOME" ] &&
294 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
295 | [ -n "$JAVA_HOME" ] &&
296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
297 | [ -n "$CLASSPATH" ] &&
298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
299 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
301 | fi
302 |
303 | # Provide a "standardized" way to retrieve the CLI args that will
304 | # work with both Windows and non-Windows executions.
305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
306 | export MAVEN_CMD_LINE_ARGS
307 |
308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
309 |
310 | exec "$JAVACMD" \
311 | $MAVEN_OPTS \
312 | $MAVEN_DEBUG_OPTS \
313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
314 | "-Dmaven.home=${M2_HOME}" \
315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
317 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
124 |
125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% ^
162 | %JVM_CONFIG_MAVEN_PROPS% ^
163 | %MAVEN_OPTS% ^
164 | %MAVEN_DEBUG_OPTS% ^
165 | -classpath %WRAPPER_JAR% ^
166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
168 | if ERRORLEVEL 1 goto error
169 | goto end
170 |
171 | :error
172 | set ERROR_CODE=1
173 |
174 | :end
175 | @endlocal & set ERROR_CODE=%ERROR_CODE%
176 |
177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
181 | :skipRcPost
182 |
183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
185 |
186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
187 |
188 | cmd /C exit /B %ERROR_CODE%
189 |
--------------------------------------------------------------------------------
/remote-test/.gitignore:
--------------------------------------------------------------------------------
1 | /testng-output/
2 |
--------------------------------------------------------------------------------
/remote-test/README.md:
--------------------------------------------------------------------------------
1 | Test for Remote TestNG
2 | ====
3 |
4 | ## Background
5 |
6 | Since TestNG Eclipse [6.9.11](https://github.com/cbeust/testng-eclipse/blob/master/CHANGES.md#6911),
7 | the plugin does not append any testng.jar to the runtime testng process. Instead, the testng-remote jar is appended,
8 | which is used for communicating between the runtime testng process and the plugin.
9 |
10 | When start the testng process, the testng-remote checks the version of runtime testng
11 | and load the corresponding adapter (aka. version specific) to perform the real testing.
12 |
13 | As we can see there are lots of releases in the past, it's sort of hard to let testng-remote support all the versions,
14 | that's why only testng version >= 6.5.1 are supported.
15 |
16 | However, we still want to have a view of how will testng-remote behave against the older versions.
17 |
18 | ## Usage
19 |
20 | ```bash
21 | cd testng-remote/remote-test
22 | mvn -e -DskipIntTest=false test
23 | ```
24 |
25 | ## Trouble shooting
26 |
27 | * General error during conversion: Error grabbing Grapes -- \[download failed: org.testng\#testng;6.8.3!testng.jar\]
28 | if we get the above error, we need to clean up the cache of grape and maven:
29 | ```
30 | rm -r ~/.groovy/grapes/org.testng/testng
31 | rm -r ~/.m2/repository/org/testng/testng
32 | ```
33 |
--------------------------------------------------------------------------------
/remote-test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 | org.testng.testng-remote
6 | testng-remote-parent
7 | 1.8.0-SNAPSHOT
8 |
9 |
10 | testng-remote-test
11 | TestNG Remote Test
12 |
13 |
14 | 2.3.11
15 | 2.5.3
16 | true
17 |
18 |
19 |
20 |
21 | integration-tests
22 |
23 |
24 | skipIntTest
25 | false
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.codehaus.mojo
33 | exec-maven-plugin
34 | 3.5.0
35 |
36 |
37 |
38 | java
39 |
40 | test
41 |
42 |
43 |
44 | false
45 | true
46 | groovy.ui.GroovyMain
47 |
48 | ${project.basedir}/src/test/groovy/Tester.groovy
49 |
50 |
51 |
52 | PROJECT_BASEDIR
53 | ${project.basedir}
54 |
55 |
56 | PROJECT_VERSION
57 | ${project.version}
58 |
59 |
60 | GROOVY_VERSION
61 | ${groovy.version}
62 |
63 |
64 | IVY_VERSION
65 | ${ivy.version}
66 |
67 |
68 | testng.eclipse.verbose
69 | true
70 |
71 |
72 |
73 |
74 |
75 |
76 | org.codehaus.groovy
77 | groovy-all
78 |
79 | ${groovy.version}
80 |
81 |
82 | org.apache.ivy
83 | ivy
84 | ${ivy.version}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | org.codehaus.groovy
95 | groovy-all
96 |
97 | ${groovy.version}
98 | runtime
99 |
100 |
101 | org.apache.ivy
102 | ivy
103 | ${ivy.version}
104 | runtime
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/remote-test/src/test/groovy/TestNGTest.groovy:
--------------------------------------------------------------------------------
1 | import org.testng.remote.RemoteTestNG;
2 | //import org.testng.annotations.BeforeClass;
3 | //import org.testng.annotations.AfterClass;
4 | import org.testng.annotations.Test;
5 |
6 | class SimpleTest {
7 |
8 | // @BeforeClass
9 | // def setUp() {
10 | // println "BeforeClass: setUp"
11 | // }
12 | //
13 | // @AfterClass
14 | // def tearDown() {
15 | // println "AfterClass: tearDown"
16 | // }
17 |
18 | @Test
19 | void testFoo() {
20 | println "testFoo"
21 | }
22 | }
23 |
24 | def DEBUG = false
25 |
26 | if (DEBUG) {
27 | println "===== Classpath BEGIN ====="
28 | // println "root loader:"
29 | // this.class.classLoader.rootLoader.URLs.each { println it }
30 |
31 | println "\nsystem loader:"
32 | ClassLoader.systemClassLoader.URLs.each { println it }
33 |
34 | println "\ncurrent thread loader"
35 | this.class.classLoader.URLs.each { println it }
36 |
37 | println "\n===== Classpath END =====\n"
38 | }
39 |
40 | def protocol = "stdout"
41 | def port = "12345"
42 |
43 | if (args.length == 2) {
44 | protocol = args[0]
45 | port = args[1]
46 | }
47 |
48 | def args = ["-serport", port, "-protocol", protocol, "-d", "./target/testng-output", "./src/test/resources/testng-remote.xml"] as String[]
49 | RemoteTestNG.main(args)
50 |
--------------------------------------------------------------------------------
/remote-test/src/test/groovy/Tester.groovy:
--------------------------------------------------------------------------------
1 | @Grab(group = 'org.osgi', module = 'osgi.core', version = '6.0.0')
2 | @Grab(group = 'org.testng.testng-remote', module = 'testng-remote', version = '1.5.1')
3 |
4 | import org.osgi.framework.Version
5 | import org.testng.remote.strprotocol.JsonMessageSender
6 |
7 | //
8 | // global var
9 | //
10 |
11 | // need to download the classifier jar for versions <= 5.11
12 | classifierVer = new Version("5.11")
13 |
14 | groovyVer = System.getProperty("GROOVY_VERSION") ?: "2.3.11"
15 | ivyVer = System.getProperty("IVY_VERSION") ?: "2.3.0"
16 | testngRemoteVer = System.getProperty("PROJECT_VERSION") ?: "1.5.1"
17 | jcmdVer = "1.48"
18 | slf4jVer = "1.7.32"
19 |
20 | workingDir = new File(System.getProperty("user.dir"))
21 | if (System.getProperty("PROJECT_BASEDIR")) {
22 | workingDir = new File(System.getProperty("PROJECT_BASEDIR"))
23 | }
24 |
25 | println "\t:::"
26 | println "\t::: workingDir: ${workingDir}"
27 | println "\t::: testng remote version: ${testngRemoteVer}"
28 | println "\t::: groovy version: ${groovyVer}"
29 | println "\t::: ivy version: ${ivyVer}"
30 | println "\t:::"
31 |
32 | scriptDir = new File(workingDir.absolutePath + "/src/test/groovy")
33 |
34 | mvnRepoDir = System.getenv("HOME") + "/.m2/repository"
35 |
36 | groovyJar = "${mvnRepoDir}/org/codehaus/groovy/groovy-all/${groovyVer}/groovy-all-${groovyVer}.jar"
37 | // ivy is required for groovy @Grab annotation
38 | ivyJar = "${mvnRepoDir}/org/apache/ivy/ivy/${ivyVer}/ivy-${ivyVer}.jar"
39 |
40 | grapeRepoDir = System.getenv("HOME") + "/.groovy/grapes"
41 |
42 | remoteTestngJar = "${grapeRepoDir}/org.testng.testng-remote/testng-remote-dist/jars/testng-remote-dist-${testngRemoteVer}-shaded.jar"
43 | jcmdJar = "${grapeRepoDir}/com.beust/jcommander/jars/jcommander-${jcmdVer}.jar"
44 | slf4jJar = "${grapeRepoDir}/org.slf4j/slf4j-api/jars/slf4j-api-${slf4jVer}.jar"
45 |
46 | resultSet = new HashMap()
47 |
48 | //~~
49 |
50 |
51 | def startTime = System.currentTimeMillis()
52 | def metadata = new XmlSlurper().parse("https://repo1.maven.org/maven2/org/testng/testng/maven-metadata.xml")
53 |
54 | def versionBlackList = ['6.12', '6.13', '6.14.0-RC2', '6.14.0-RC3', '7.0.0-beta2', '7.0.0-beta4', '7.1.0', '7.1.1']
55 | if (System.getProperty('java.version').startsWith('1.7')) {
56 | versionBlackList.add('7.*')
57 | }
58 |
59 | metadata.versioning.versions.version.each { version ->
60 | println ">>>>>"
61 | println ">>>>> Testing ${version}"
62 | println ">>>>>"
63 |
64 | // skip invalid testng jar
65 | for (def bver : versionBlackList) {
66 | if (version.toString().matches(bver)) {
67 | println "skip testing ${version} \n"
68 | return
69 | }
70 | }
71 |
72 | def exitValue = runTestNGTest(version)
73 | def rset = resultSet[exitValue]
74 | if (rset == null) {
75 | rset = new ArrayList()
76 | resultSet[exitValue] = rset
77 | }
78 | rset << version
79 |
80 | println "<<<<<"
81 | println ">>>>> Tested ${version}: result=${exitValue}"
82 | println "<<<<<\n"
83 | }
84 |
85 | println "\nCompleted in " + (System.currentTimeMillis() - startTime) + " (ms)"
86 |
87 |
88 | println "\nSummary report:"
89 | resultSet.each {
90 | switch (it.key) {
91 | case 0:
92 | println it.key + " - PASSED:"
93 | break;
94 | case 1:
95 | println it.key + " - unsupported version detected:"
96 | break;
97 | case 2:
98 | println it.key + " - NoClassDefFoundError:"
99 | break;
100 | default:
101 | println it.key + " - OTHERS:"
102 | }
103 |
104 | println "\t" + it.value
105 | }
106 | println ""
107 |
108 | // failed if there's any OTHER failures
109 | assert resultSet[-1] == null
110 |
111 | def minVer = new Version("6.0")
112 | resultSet[1].each {
113 | // no version >= 6.0 will get error 'unsupported version detected'
114 | assert (toVersion(it.toString()).compareTo(minVer) < 0)
115 | }
116 | resultSet[2].each {
117 | // no version >= 6.5.1 will get error 'NoClassDefFoundError'
118 | assert (toVersion(it.toString()).compareTo(minVer) < 0)
119 | }
120 |
121 | /**
122 | * run the testng test with groovy in a separate process
123 | *
124 | * @param ver the testng version
125 | * @return 0 - success; 1 - unsupported version detected; 2 - NoClassDefFoundError; -1 - others;
126 | */
127 | def runTestNGTest(ver) {
128 | if (downloadTestNG(ver) != 0) {
129 | println "failed to download jars for ${ver}, skip testing"
130 | return -1
131 | }
132 |
133 | def port = 12345
134 | def msgHub = new JsonMessageSender("localhost", port)
135 | Thread.start {
136 | msgHub.initReceiver()
137 | }
138 |
139 | try {
140 | def testngJar = "${grapeRepoDir}/org.testng/testng/jars/testng-${ver}.jar"
141 | if (toVersion(ver.toString()).compareTo(classifierVer) <= 0) {
142 | testngJar = "${grapeRepoDir}/org.testng/testng/jars/testng-${ver}-jdk15.jar"
143 | }
144 |
145 | println "classpath: ${groovyJar}:${ivyJar}:${remoteTestngJar}:${testngJar}:${jcmdJar}:${slf4jJar}\n"
146 |
147 | def scriptFile = new File(scriptDir, "TestNGTest.groovy")
148 | // run the groovy script via Java executable rather than groovy executable, because:
149 | // 1) groovy has RootLoader loads groovy distributed testng jar, which is in prior to our own jar;
150 | // 2) groovy @Grad can't specify the order of the jar on the classpath,
151 | // while testng-remote need to be on front of testng
152 | // (since some older version of testng jar contains older version of RemoteTestNG)
153 | def output = new StringBuilder()
154 | def process = new ProcessBuilder(
155 | "java",
156 | "-classpath", "${groovyJar}:${ivyJar}:${remoteTestngJar}:${testngJar}:${jcmdJar}:${slf4jJar}",
157 | "-Dtestng.eclipse.verbose",
158 | "-Dtestng.eclipse.debug",
159 | "groovy.ui.GroovyMain",
160 | scriptFile.absolutePath,
161 | "json", "" + port)
162 | .directory(workingDir).redirectErrorStream(true).start()
163 | process.inputStream.eachLine { println it; output << it.toString() }
164 | process.waitFor();
165 | def exitValue = process.exitValue()
166 | if (exitValue == 0) {
167 | return 0
168 | } else {
169 | if (output.contains("is not a supported TestNG version")) {
170 | return 1
171 | } else if (output.contains("java.lang.NoClassDefFoundError")) {
172 | return 2;
173 | } else {
174 | return -1
175 | }
176 | }
177 | } finally {
178 | msgHub.stopReceiver()
179 | }
180 | }
181 |
182 | /**
183 | * start a new process to download the dep jars,
184 | * since @Grad can't specify the order of the jars on the classpath
185 | * while we do want to make testng-remote on front of testng jar
186 | * that's why we not put @Grab in the TestNGTest.groovy
187 | *
188 | * @param ver the testng version
189 | * @return 0 - success, otherwise - failure
190 | */
191 | def downloadTestNG(ver) {
192 | def grabScriptFile = new File(scriptDir, "grabJar_${ver}.groovy")
193 |
194 | grabScriptFile.withWriter { w ->
195 | w << "@GrabResolver(name = 'jcenter', root = 'http://jcenter.bintray.com/')" + "\n"
196 |
197 | if (toVersion(ver.toString()).compareTo(classifierVer) > 0) {
198 | w << "@Grab(group = 'org.testng', module = 'testng', version = '${ver}')" + "\n"
199 | } else {
200 | w << "@Grab(group = 'org.testng', module = 'testng', version = '${ver}', classifier = 'jdk15')" + "\n"
201 | }
202 |
203 | w << "@GrabExclude('com.google.guava:guava')" + "\n"
204 |
205 | w << "@Grab(group = 'com.beust', module = 'jcommander', version = '${jcmdVer}')" + "\n"
206 | w << "@Grab(group = 'org.slf4j', module = 'slf4j-api', version = '${slf4jVer}')" + "\n"
207 | w << "@Grab(group = 'org.testng.testng-remote', module = 'testng-remote-dist', version = '${testngRemoteVer}', classifier = 'shaded')" + "\n"
208 |
209 | w << "import org.testng.annotations.Test;" + "\n"
210 | }
211 |
212 | try {
213 | def grapeProc = new ProcessBuilder(
214 | "java",
215 | "-classpath", "${groovyJar}:${ivyJar}",
216 | "groovy.ui.GroovyMain",
217 | grabScriptFile.absolutePath)
218 | .directory(workingDir).redirectErrorStream(true).start()
219 | grapeProc.inputStream.eachLine { println it }
220 | grapeProc.waitFor();
221 | return grapeProc.exitValue()
222 | } finally {
223 | grabScriptFile.delete()
224 | }
225 | }
226 |
227 | def Version toVersion(String ver) {
228 | if ("5.5.m".equals(ver)) {
229 | ver = "5.5"
230 | }
231 | def idx = ver.indexOf("-")
232 | if (idx > 0) {
233 | ver = ver.substring(0, idx)
234 | }
235 | return new Version(ver)
236 | }
237 |
--------------------------------------------------------------------------------
/remote-test/src/test/resources/grapeConfig.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/remote-test/src/test/resources/testng-remote.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/remote/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 | org.testng.testng-remote
6 | testng-remote-parent
7 | 1.8.0-SNAPSHOT
8 |
9 |
10 | testng-remote
11 | TestNG Remote
12 |
13 |
14 | 6.5.1
15 |
16 |
17 |
18 |
19 | org.testng
20 | testng
21 | ${testng.version}
22 |
23 |
24 | com.google.code.gson
25 | gson
26 |
27 |
28 |
29 |
30 |
31 |
32 | src/main/resources
33 | true
34 |
35 | revision.properties
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.apache.maven.plugins
43 | maven-shade-plugin
44 |
45 |
46 | package
47 |
48 | shade
49 |
50 |
51 | true
52 |
53 |
54 | com.google.code.gson:gson
55 |
56 |
57 |
58 |
59 | com.google.gson
60 | org.testng.shaded.com.google.gson
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-jar-plugin
70 |
71 |
72 |
73 | test-jar
74 |
75 |
76 |
77 |
78 |
79 | io.github.git-commit-id
80 | git-commit-id-maven-plugin
81 |
82 |
83 |
84 | revision
85 |
86 |
87 |
88 |
89 | true
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/AbstractRemoteTestNG.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote;
2 |
3 | import org.testng.CommandLineArgs;
4 | import org.testng.ISuite;
5 | import org.testng.ISuiteListener;
6 | import org.testng.ITestNGListener;
7 | import org.testng.ITestRunnerFactory;
8 | import org.testng.TestNG;
9 | import org.testng.remote.strprotocol.*;
10 | import org.testng.xml.XmlSuite;
11 |
12 | /**
13 | * Extension of TestNG registering a remote TestListener.
14 | *
15 | * @author Cedric Beust
16 | */
17 | public abstract class AbstractRemoteTestNG extends TestNG implements IRemoteTestNG {
18 | private static final String LOCALHOST = "localhost";
19 |
20 | protected ITestRunnerFactory m_customTestRunnerFactory;
21 | private String m_host;
22 |
23 | /** Port used for the string protocol */
24 | private Integer m_port = null;
25 |
26 | /** Port used for the serialized protocol */
27 | private Integer m_serPort = null;
28 |
29 | /** Protocol used for inter-communication */
30 | private String m_protocol;
31 |
32 | private boolean m_debug;
33 |
34 | private boolean m_dontExit;
35 |
36 | private boolean m_ack;
37 |
38 | @Override
39 | public void dontExit(boolean dontExit) {
40 | m_dontExit = dontExit;
41 | }
42 |
43 | @Override
44 | public void setDebug(boolean debug) {
45 | m_debug = debug;
46 | }
47 |
48 | @Override
49 | public void setAck(boolean ack) {
50 | m_ack = ack;
51 | }
52 |
53 | @Override
54 | public void setHost(String host) {
55 | m_host = defaultIfStringEmpty(host, LOCALHOST);
56 | }
57 |
58 | @Override
59 | public void setSerPort(Integer serPort) {
60 | m_serPort = serPort;
61 | }
62 |
63 | @Override
64 | public void setProtocol(String protocol) {
65 | m_protocol = protocol;
66 | }
67 |
68 | @Override
69 | public void setPort(Integer port) {
70 | m_port = port;
71 | }
72 |
73 | @Override
74 | public void configure(CommandLineArgs cla) {
75 | super.configure(cla);
76 | }
77 |
78 | public static void validateCommandLineParameters(CommandLineArgs args) {
79 | TestNG.validateCommandLineParameters(args);
80 | }
81 |
82 | public static String defaultIfStringEmpty(String s, String defaultValue) {
83 | return isStringEmpty(s) ? defaultValue : s;
84 | }
85 |
86 | public static boolean isStringEmpty(String s) {
87 | return s == null || "".equals(s);
88 | }
89 |
90 | @Override
91 | public void run() {
92 | IMessageSender sender = getMessageSender();
93 | final MessageHub msh = new MessageHub(sender);
94 | msh.setDebug(m_debug);
95 | try {
96 | msh.connect();
97 |
98 | initialize();
99 |
100 | if (canRun()) {
101 | int testCount = 0;
102 |
103 | for (XmlSuite suite : m_suites) {
104 | testCount += suite.getTests().size();
105 | }
106 |
107 | GenericMessage gm = new GenericMessage();
108 | gm.setSuiteCount(m_suites.size());
109 | gm.setTestCount(testCount);
110 | msh.sendMessage(gm);
111 |
112 | super.addListener((ITestNGListener) new RemoteSuiteListener(msh));
113 | setTestRunnerFactory(createDelegatingTestRunnerFactory(buildTestRunnerFactory(), msh));
114 |
115 | super.run();
116 | }
117 | else {
118 | System.err.println("No test suite found. Nothing to run");
119 | }
120 | }
121 | catch(Throwable cause) {
122 | cause.printStackTrace(System.err);
123 | }
124 | finally {
125 | // System.out.println("RemoteTestNG finishing: " + (getEnd() - getStart()) + " ms");
126 | msh.shutDown();
127 | if (! m_debug && ! m_dontExit) {
128 | System.exit(0);
129 | }
130 | }
131 | }
132 |
133 | protected void initialize() {
134 | // We couldn't do this until now in debug mode since the .xml file didn't exist yet.
135 | // Now that we have connected with the Eclipse client, we know that it created the .xml
136 | // file so we can proceed with the initialization
137 | initializeSuitesAndJarFile();
138 | }
139 |
140 | /**
141 | * run after {@link #initialize()}, tell if it's ready for running the test
142 | *
143 | * @return {@code true} for ready.
144 | */
145 | protected boolean canRun() {
146 | return m_suites.size() > 0;
147 | }
148 |
149 | private IMessageSender getMessageSender() {
150 | if (m_protocol != null) {
151 | switch (m_protocol) {
152 | case "object":
153 | return new SerializedMessageSender(m_host, m_serPort, m_ack);
154 | case "string":
155 | return new StringMessageSender(m_host, m_port);
156 | case "json":
157 | return new JsonMessageSender(m_host, m_serPort, m_ack);
158 | case "stdout":
159 | return new StdoutMessageSender();
160 | default:
161 | throw new IllegalArgumentException("unrecognized protocol: " + m_protocol);
162 | }
163 | }
164 |
165 | // fall back to original behaviour
166 | return m_serPort != null
167 | ? new SerializedMessageSender(m_host, m_serPort, m_ack)
168 | : new StringMessageSender(m_host, m_port);
169 | }
170 |
171 | /**
172 | * Override by the plugin if you need to configure differently the TestRunner
173 | * (usually this is needed if different listeners/reporters are needed).
174 | * Note: you don't need to worry about the wiring listener, because it is added
175 | * automatically.
176 | */
177 | protected abstract ITestRunnerFactory buildTestRunnerFactory();
178 |
179 | protected String getHost() {
180 | return m_host;
181 | }
182 |
183 | protected int getPort() {
184 | return m_port;
185 | }
186 |
187 | /** A ISuiteListener wiring the results using the internal string-based protocol. */
188 | private static class RemoteSuiteListener implements ISuiteListener {
189 | private final MessageHub m_messageSender;
190 |
191 | RemoteSuiteListener(MessageHub smsh) {
192 | m_messageSender= smsh;
193 | }
194 |
195 | @Override
196 | public void onFinish(ISuite suite) {
197 | m_messageSender.sendMessage(new SuiteMessage(suite, false /*start*/));
198 | }
199 |
200 | @Override
201 | public void onStart(ISuite suite) {
202 | m_messageSender.sendMessage(new SuiteMessage(suite, true /*start*/));
203 | }
204 | }
205 |
206 | protected abstract ITestRunnerFactory createDelegatingTestRunnerFactory(ITestRunnerFactory trf, MessageHub smsh);
207 | }
208 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/AbstractRemoteTestNGFactory.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote;
2 |
3 | import org.testng.remote.support.RemoteTestNGFactory;
4 | import org.testng.shaded.osgi.framework.Version;
5 | import org.testng.shaded.osgi.framework.VersionRange;
6 |
7 | public abstract class AbstractRemoteTestNGFactory implements RemoteTestNGFactory {
8 |
9 | @Override
10 | public boolean accept(Version version) {
11 | return version == null || getAcceptableVersions().includes(version);
12 | }
13 |
14 | protected abstract VersionRange getAcceptableVersions();
15 | }
16 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/IRemoteTestNG.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote;
2 |
3 | import org.testng.CommandLineArgs;
4 |
5 | public interface IRemoteTestNG {
6 |
7 | void dontExit(boolean dontExit);
8 | void setDebug(boolean debug);
9 | void setAck(boolean ack);
10 | void configure(CommandLineArgs cla);
11 | void setHost(String host);
12 | void setSerPort(Integer serPort);
13 | void setProtocol(String protocol);
14 | void setPort(Integer port);
15 | void run();
16 | }
17 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/Orderable.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote;
2 |
3 | public interface Orderable {
4 |
5 | int getOrder();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/RemoteArgs.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote;
2 |
3 | import org.testng.shaded.osgi.framework.Version;
4 |
5 | import com.beust.jcommander.IStringConverter;
6 | import com.beust.jcommander.Parameter;
7 |
8 | public class RemoteArgs {
9 | public static final String DEBUG = "-serdebug";
10 | @Parameter(names = DEBUG, hidden = true, description = "Used to debug TestNG")
11 | public Boolean debug = Boolean.FALSE;
12 |
13 | public static final String HOST = "-serhost";
14 | @Parameter(names = HOST, description = "The host", hidden = true)
15 | public String host;
16 |
17 | public static final String PORT = "-serport";
18 | @Parameter(names = PORT, description = "The port for the serialization protocol")
19 | public Integer serPort;
20 |
21 | public static final String PROTOCOL = "-protocol";
22 | @Parameter(names = PROTOCOL, description = "The protocol for message inter-communication")
23 | public String protocol;
24 |
25 | public static final String DONT_EXIT= "-dontexit";
26 | @Parameter(names = DONT_EXIT, description = "Do not exit the JVM once done")
27 | public boolean dontExit = false;
28 |
29 | public static final String ACK = "-ack";
30 | @Parameter(names = ACK, description = "Use ACK's")
31 | public boolean ack = false;
32 |
33 | public static final String VERSION = "-version";
34 | @Parameter(names = VERSION, description = "TestNG target version", converter = VersionConverter.class)
35 | public Version version;
36 |
37 | public static class VersionConverter implements IStringConverter {
38 |
39 | @Override
40 | public Version convert(String value) {
41 | if (value == null) {
42 | return null;
43 | }
44 |
45 | return RemoteTestNG.toVersion(value);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/AbstractRemoteTestRunnerClient.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2000, 2004 IBM Corporation and others.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Common Public License v1.0
5 | * which accompanies this distribution, and is available at
6 | * http://www.eclipse.org/legal/cpl-v10.html
7 | *
8 | * Contributors:
9 | * IBM Corporation - initial API and implementation
10 | * Julien Ruaux: jruaux@octo.com
11 | * Vincent Massol: vmassol@octo.com
12 | *
13 | * Adapted by:
14 | * Alexandru Popescu: the_mindstorm@evolva.ro
15 | ******************************************************************************/
16 | package org.testng.remote.strprotocol;
17 |
18 |
19 | import org.testng.TestNGException;
20 |
21 | import java.io.IOException;
22 | import java.net.ServerSocket;
23 | import java.net.Socket;
24 |
25 | /**
26 | * The client side of the RemoteTestRunner. Handles the
27 | * marshaling of the different messages.
28 | */
29 | public abstract class AbstractRemoteTestRunnerClient {
30 | /**
31 | * An array of listeners that are informed about test events.
32 | */
33 | protected IRemoteSuiteListener[] m_suiteListeners;
34 | protected IRemoteTestListener[] m_testListeners;
35 |
36 | /**
37 | * The server socket
38 | */
39 | private ServerSocket fServerSocket;
40 | private Socket fSocket;
41 | private ServerConnection m_serverConnection;
42 | // private PrintWriter m_outputWriter;
43 | // private BufferedReader m_inputReader;
44 |
45 | /**
46 | * Start listening to a test run. Start a server connection that
47 | * the RemoteTestRunner can connect to.
48 | */
49 | public synchronized void startListening(IRemoteSuiteListener[] suiteListeners,
50 | IRemoteTestListener[] testListeners,
51 | ServerConnection serverConnection) {
52 | m_suiteListeners= suiteListeners;
53 | m_testListeners= testListeners;
54 | m_serverConnection = serverConnection;
55 |
56 | serverConnection.start();
57 | }
58 |
59 | public IRemoteSuiteListener[] getSuiteListeners() {
60 | return m_suiteListeners;
61 | }
62 |
63 | public IRemoteTestListener[] getTestListeners() {
64 | return m_testListeners;
65 | }
66 |
67 | private synchronized void shutdown() {
68 | // if(m_outputWriter != null) {
69 | // m_outputWriter.close();
70 | // m_outputWriter = null;
71 | // }
72 | // try {
73 | // if(m_inputReader != null) {
74 | // m_inputReader.close();
75 | // m_inputReader = null;
76 | // }
77 | // }
78 | // catch(IOException e) {
79 | // e.printStackTrace();
80 | // }
81 | try {
82 | if(fSocket != null) {
83 | fSocket.close();
84 | fSocket = null;
85 | }
86 | }
87 | catch(IOException e) {
88 | e.printStackTrace();
89 | }
90 | try {
91 | if(fServerSocket != null) {
92 | fServerSocket.close();
93 | fServerSocket = null;
94 | }
95 | }
96 | catch(IOException e) {
97 | e.printStackTrace();
98 | }
99 | }
100 |
101 | public boolean isRunning() {
102 | return m_serverConnection.getMessageSender() != null;
103 | }
104 |
105 | /**
106 | * Requests to stop the remote test run.
107 | */
108 | public synchronized void stopTest() {
109 | if(isRunning()) {
110 | m_serverConnection.getMessageSender().sendStop();
111 | shutdown();
112 | }
113 | }
114 |
115 | // private String readMessage(BufferedReader in) throws IOException {
116 | // return in.readLine();
117 | // }
118 | //
119 | // private void receiveMessage(String message) {
120 | // int messageType = MessageHelper.getMessageType(message);
121 | //
122 | // try {
123 | // if(messageType < MessageHelper.SUITE) {
124 | // // Generic message
125 | // GenericMessage gm = MessageHelper.unmarshallGenericMessage(message);
126 | // notifyStart(gm);
127 | // }
128 | // else if(messageType < MessageHelper.TEST) {
129 | // // Suite message
130 | // SuiteMessage sm = MessageHelper.createSuiteMessage(message);
131 | // notifySuiteEvents(sm);
132 | // }
133 | // else if(messageType < MessageHelper.TEST_RESULT) {
134 | // // Test message
135 | // TestMessage tm = MessageHelper.createTestMessage(message);
136 | // notifyTestEvents(tm);
137 | // }
138 | // else {
139 | // // TestResult message
140 | // TestResultMessage trm = MessageHelper.unmarshallTestResultMessage(message);
141 | // notifyResultEvents(trm);
142 | // }
143 | // }
144 | // finally {
145 | // if(isRunning() && (null != m_outputWriter)) {
146 | // m_outputWriter.println(MessageHelper.ACK_MSG);
147 | // m_outputWriter.flush();
148 | // }
149 | // }
150 | // }
151 |
152 | protected abstract void notifyStart(final GenericMessage genericMessage);
153 |
154 | protected abstract void notifySuiteEvents(final SuiteMessage suiteMessage);
155 |
156 | protected abstract void notifyTestEvents(final TestMessage testMessage);
157 |
158 | protected abstract void notifyResultEvents(final TestResultMessage testResultMessage);
159 |
160 |
161 | /**
162 | * Reads the message stream from the RemoteTestRunner
163 | */
164 | public abstract class ServerConnection extends Thread {
165 | private MessageHub m_messageHub;
166 |
167 | public ServerConnection(IMessageSender messageMarshaller) {
168 | super("TestNG - ServerConnection"); //$NON-NLS-1$
169 | m_messageHub = new MessageHub(messageMarshaller);
170 | }
171 |
172 | IMessageSender getMessageSender() {
173 | return m_messageHub != null ? m_messageHub.getMessageSender() : null;
174 | }
175 |
176 | @Override
177 | public void run() {
178 | try {
179 | IMessage message = m_messageHub.receiveMessage();
180 | while (message != null) {
181 | switch (message.getType()) {
182 | case GENERIC:
183 | notifyStart((GenericMessage) message);
184 | break;
185 | case SUITE:
186 | notifySuiteEvents((SuiteMessage) message);
187 | break;
188 | case TEST:
189 | notifyTestEvents((TestMessage) message);
190 | break;
191 | case TEST_RESULT:
192 | notifyResultEvents((TestResultMessage) message);
193 | break;
194 | default:
195 | throw new TestNGException("Unknown message type:" + message);
196 | }
197 | // if (isRunning()) {
198 | // m_messageMarshaller.sendAck();
199 | // }
200 | message = m_messageHub.receiveMessage();
201 | }
202 | }
203 | finally {
204 | m_messageHub.shutDown();
205 | m_messageHub = null;
206 | }
207 | // try {
208 | // fServerSocket = new ServerSocket(fServerPort);
209 | // fSocket = fServerSocket.accept();
210 | // try {
211 | // m_inputReader = new BufferedReader(new InputStreamReader(fSocket.getInputStream(),
212 | // "UTF-8")); //$NON-NLS-1$
213 | // }
214 | // catch(UnsupportedEncodingException e) {
215 | // m_inputReader = new BufferedReader(new InputStreamReader(fSocket.getInputStream()));
216 | // }
217 | // try {
218 | // m_outputWriter = new PrintWriter(new OutputStreamWriter(fSocket.getOutputStream(), "UTF-8"),
219 | // true);
220 | // }
221 | // catch(UnsupportedEncodingException e1) {
222 | // m_outputWriter = new PrintWriter(new OutputStreamWriter(fSocket.getOutputStream()), true);
223 | // }
224 | // String message;
225 | // while((m_inputReader != null) && ((message = readMessage(m_inputReader)) != null)) {
226 | // receiveMessage(message);
227 | // }
228 | // }
229 | // catch(SocketException e) {
230 | // handleThrowable(e);
231 | // }
232 | // catch(IOException e) {
233 | // handleThrowable(e);
234 | // }
235 | // finally {
236 | // shutdown();
237 | // }
238 | }
239 |
240 | protected abstract void handleThrowable(Throwable cause);
241 | }
242 |
243 | }
244 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/BaseMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.BufferedWriter;
5 | import java.io.Closeable;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStream;
10 | import java.io.OutputStreamWriter;
11 | import java.io.PrintWriter;
12 | import java.io.UnsupportedEncodingException;
13 | import java.net.ConnectException;
14 | import java.net.InetSocketAddress;
15 | import java.net.ServerSocket;
16 | import java.net.Socket;
17 | import java.net.SocketTimeoutException;
18 |
19 | import org.testng.TestNGException;
20 |
21 | import static org.testng.remote.RemoteTestNG.isVerbose;
22 | import static org.testng.remote.RemoteTestNG.isDebug;
23 |
24 | abstract public class BaseMessageSender implements IMessageSender {
25 | protected Socket m_clientSocket;
26 | private String m_host;
27 | private int m_port;
28 | protected Object m_ackLock = new Object();
29 |
30 | private boolean m_requestStopReceiver;
31 | private ServerSocket m_serverSocket;
32 | /** Outgoing message stream. */
33 | protected OutputStream m_outStream;
34 | /** Used to send ACK and STOP */
35 | private PrintWriter m_outWriter;
36 |
37 | /** Incoming message stream. */
38 | protected volatile InputStream m_inStream;
39 | /** Used to receive ACK and STOP */
40 | protected volatile BufferedReader m_inReader;
41 |
42 | private ReaderThread m_readerThread;
43 | private boolean m_ack;
44 | // protected InputStream m_receiverInputStream;
45 |
46 | public BaseMessageSender(String host, int port, boolean ack) {
47 | m_host = host;
48 | m_port = port;
49 | m_ack = ack;
50 | }
51 |
52 | /**
53 | * Starts the connection.
54 | *
55 | * @throws TestNGException if an exception occurred while establishing the connection
56 | */
57 | @Override
58 | public void connect() throws IOException {
59 | p("Waiting for Eclipse client on " + m_host + ":" + m_port);
60 | while (true) {
61 | try {
62 | m_clientSocket = new Socket();
63 | m_clientSocket.connect(new InetSocketAddress(m_host, m_port), 60 * 1000);
64 | p("Received a connection from Eclipse on " + m_host + ":" + m_port);
65 |
66 | // Output streams
67 | m_outStream = m_clientSocket.getOutputStream();
68 | m_outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(m_outStream)));
69 |
70 | // Input streams
71 | m_inStream = m_clientSocket.getInputStream();
72 | try {
73 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream,
74 | "UTF-8")); //$NON-NLS-1$
75 | }
76 | catch(UnsupportedEncodingException ueex) {
77 | // Should never happen
78 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream));
79 | }
80 |
81 | p("Connection established, starting reader thread");
82 | m_readerThread = new ReaderThread();
83 | m_readerThread.start();
84 | return;
85 | }
86 | catch(SocketTimeoutException | ConnectException ex) {
87 | p("connect failed: " + ex.toString());
88 | // ignore and retry
89 | try {
90 | Thread.sleep(4000);
91 | }
92 | catch(InterruptedException handled) {
93 | Thread.currentThread().interrupt();
94 | }
95 | }
96 | }
97 | }
98 |
99 | private void sendAdminMessage(String message) {
100 | m_outWriter.println(message);
101 | m_outWriter.flush();
102 | }
103 |
104 | private int m_serial = 0;
105 |
106 | @Override
107 | public void sendAck() {
108 | p("Sending ACK " + m_serial);
109 | // Note: adding the serial at the end of this message causes a lock up if interacting
110 | // with TestNG 5.14 and older (reported by JetBrains). The following git commit:
111 | // 5730bdfb33ec7a8bf4104852cd4a5f2875ba8267
112 | // changed equals() to startsWith().
113 | // It's ok to add this serial back for debugging, but don't commit it until JetBrains
114 | // confirms they no longer need backward compatibility with 5.14.
115 | sendAdminMessage(MessageHelper.ACK_MSG); // + m_serial++);
116 | }
117 |
118 | @Override
119 | public void sendStop() {
120 | sendAdminMessage(MessageHelper.STOP_MSG);
121 | }
122 |
123 | @Override
124 | public void initReceiver() throws SocketTimeoutException {
125 | if (m_inStream != null) {
126 | p("Receiver already initialized");
127 | }
128 | try {
129 | p("initReceiver on port " + m_port);
130 | m_serverSocket = new ServerSocket(m_port);
131 | m_serverSocket.setSoTimeout(5000);
132 |
133 | Socket socket = null;
134 | while (!m_requestStopReceiver) {
135 | try {
136 | if (isDebug()) {
137 | p("polling the client connection");
138 | }
139 | socket = m_serverSocket.accept();
140 | // break the loop once the first client connected
141 | break;
142 | }
143 | catch (IOException ioe) {
144 | try {
145 | Thread.sleep(100L);
146 | }
147 | catch (InterruptedException ie) {
148 | // Do nothing.
149 | }
150 | }
151 | }
152 | if (socket != null) {
153 | m_inStream = socket.getInputStream();
154 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream));
155 | m_outStream = socket.getOutputStream();
156 | m_outWriter = new PrintWriter(new OutputStreamWriter(m_outStream));
157 | }
158 | }
159 | catch(SocketTimeoutException ste) {
160 | throw ste;
161 | }
162 | catch (IOException ioe) {
163 | closeQuietly(m_serverSocket);
164 | }
165 | }
166 |
167 | public void stopReceiver() {
168 | m_requestStopReceiver = true;
169 | try {
170 | if (!m_serverSocket.isClosed()) {
171 | m_serverSocket.close();
172 | }
173 | } catch (IOException e) {
174 | if (isDebug()) {
175 | e.printStackTrace();
176 | }
177 | }
178 | p("Stopped receiver");
179 | }
180 |
181 | @Override
182 | public void shutDown() {
183 | closeQuietly(m_outStream);
184 | m_outStream = null;
185 |
186 | if (null != m_readerThread) {
187 | m_readerThread.interrupt();
188 | }
189 |
190 | closeQuietly(m_inReader);
191 | m_inReader = null;
192 |
193 | closeQuietly(m_clientSocket);
194 | m_clientSocket = null;
195 | }
196 |
197 | private void closeQuietly(Closeable c) {
198 | if (c != null) {
199 | try {
200 | c.close();
201 | } catch (IOException e) {
202 | if (isDebug()) {
203 | e.printStackTrace();
204 | }
205 | }
206 | }
207 | }
208 |
209 | private String m_latestAck;
210 |
211 | protected void waitForAck() {
212 | if (m_ack) {
213 | try {
214 | p("Message sent, waiting for ACK...");
215 | synchronized(m_ackLock) {
216 | m_ackLock.wait();
217 | }
218 | p("... ACK received:" + m_latestAck);
219 | }
220 | catch(InterruptedException handled) {
221 | Thread.currentThread().interrupt();
222 | }
223 | }
224 | }
225 |
226 | private static void p(String msg) {
227 | if (isVerbose()) {
228 | System.out.println("[BaseMessageSender] " + msg); //$NON-NLS-1$
229 | }
230 | }
231 |
232 | /**
233 | * Reader thread that processes messages from the client.
234 | */
235 | private class ReaderThread extends Thread {
236 |
237 | public ReaderThread() {
238 | super("ReaderThread"); //$NON-NLS-1$
239 | }
240 |
241 | @Override
242 | public void run() {
243 | try {
244 | p("ReaderThread waiting for an admin message");
245 | String message = m_inReader.readLine();
246 | p("ReaderThread received admin message:" + message);
247 | while (message != null) {
248 | if (isDebug()) {
249 | p("Admin message:" + message); //$NON-NLS-1$
250 | }
251 | boolean acknowledge = message.startsWith(MessageHelper.ACK_MSG);
252 | boolean stop = MessageHelper.STOP_MSG.equals(message);
253 | if(acknowledge || stop) {
254 | if (acknowledge) {
255 | p("Received ACK:" + message);
256 | m_latestAck = message;
257 | }
258 | synchronized(m_ackLock) {
259 | m_ackLock.notifyAll();
260 | }
261 | if (stop) {
262 | break;
263 | }
264 | } else {
265 | p("Received unknown message: '" + message + "'");
266 | }
267 | message = m_inReader != null ? m_inReader.readLine() : null;
268 | }
269 | // while((m_reader != null) && (message = m_reader.readLine()) != null) {
270 | // if (m_debug) {
271 | // p("Admin message:" + message); //$NON-NLS-1$
272 | // }
273 | // boolean acknowledge = MessageHelper.ACK_MSG.equals(message);
274 | // boolean stop = MessageHelper.STOP_MSG.equals(message);
275 | // if(acknowledge || stop) {
276 | // synchronized(m_lock) {
277 | // m_lock.notifyAll();
278 | // }
279 | // if (stop) {
280 | // break;
281 | // }
282 | // }
283 | // }
284 | }
285 | catch(IOException ioe) {
286 | if (isVerbose()) {
287 | ioe.printStackTrace();
288 | }
289 | }
290 | }
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/GenericMessage.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * A generic message to be used with remote listeners.
7 | * It is described by a {@link #m_messageType} and can contain a Map
8 | * or values.
9 | *
10 | * @author Alexandru Popescu
11 | */
12 | public class GenericMessage implements IStringMessage {
13 | private static final long serialVersionUID = 1440074281953763545L;
14 | // protected Map m_properties;
15 | @SerializedName("messageType")
16 | protected final MessageType m_messageType;
17 | @SerializedName("suiteCount")
18 | private int m_suiteCount;
19 | @SerializedName("testCount")
20 | private int m_testCount;
21 |
22 | public GenericMessage() {
23 | this(MessageType.GENERIC);
24 | }
25 |
26 | public GenericMessage(final MessageType type) {
27 | m_messageType = type;
28 | }
29 |
30 | public int getSuiteCount() {
31 | return m_suiteCount;
32 | }
33 |
34 | public void setSuiteCount(int suiteCount) {
35 | m_suiteCount = suiteCount;
36 | }
37 |
38 | public int getTestCount() {
39 | return m_testCount;
40 | }
41 |
42 | public void setTestCount(int testCount) {
43 | m_testCount = testCount;
44 | }
45 |
46 | @Override
47 | public MessageType getType() {
48 | return m_messageType;
49 | }
50 |
51 | @Override
52 | public String getMessageAsString() {
53 | StringBuffer buf = new StringBuffer();
54 |
55 | buf.append(getType().getValue());
56 | buf.append(MessageHelper.DELIMITER).append("testCount").append(getTestCount())
57 | .append(MessageHelper.DELIMITER).append("suiteCount").append(getSuiteCount());
58 |
59 | return buf.toString();
60 | }
61 |
62 | @Override
63 | public String toString() {
64 | StringBuilder sb = new StringBuilder();
65 | sb.append("[GenericMessage ==> suiteCount:").append(m_suiteCount).append(", testCount:").append(m_testCount).append("]");
66 | return sb.toString();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/IMessage.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import java.io.Serializable;
4 |
5 |
6 | /**
7 | * Marker interface for messages exchanged between RemoteTestNG and a client.
8 | *
9 | * @author Cedric Beust
10 | */
11 | public interface IMessage extends Serializable {
12 |
13 | /**
14 | * @return the message type
15 | */
16 | MessageType getType();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/IMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import java.io.IOException;
4 | import java.net.SocketException;
5 | import java.net.SocketTimeoutException;
6 |
7 | public interface IMessageSender {
8 |
9 | void connect() throws IOException;
10 |
11 | /**
12 | * Initialize the receiver.
13 | * the underlying socket server will be polling until a first client connect.
14 | *
15 | * @throws SocketException This exception will be thrown if a connection
16 | * to the remote TestNG instance could not be established after ten
17 | * seconds.
18 | */
19 | void initReceiver() throws SocketTimeoutException;
20 |
21 | /**
22 | * Stop the receiver.
23 | * it provides a way that allow the API invoker to stop the receiver,
24 | * e.g. break from a dead while loop
25 | */
26 | void stopReceiver();
27 |
28 | void sendMessage(IMessage message) throws Exception;
29 |
30 | /**
31 | * Will return null or throw EOFException when the connection has been severed.
32 | */
33 | IMessage receiveMessage() throws Exception;
34 |
35 | void shutDown();
36 |
37 | // These two methods should probably be in a separate class since they should all be
38 | // the same for implementers of this interface.
39 | void sendAck();
40 |
41 | void sendStop();
42 | }
43 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/IRemoteSuiteListener.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 |
4 |
5 | /**
6 | * Interface replicating the ISuiteListener used for remote listeners.
7 | *
8 | * @author Alexandru Popescu
9 | * @see org.testng.ISuiteListener
10 | */
11 | public interface IRemoteSuiteListener {
12 | /**
13 | * General information about the number of suites to be run.
14 | * This is called once before all suites.
15 | *
16 | * @param genericMessage a message containing the number of suites that will be run
17 | */
18 | void onInitialization(GenericMessage genericMessage);
19 |
20 | /**
21 | * @see org.testng.ISuiteListener#onStart(org.testng.ISuite)
22 | *
23 | * @param suiteMessage the suite message containing the description of the suite to be run.
24 | */
25 | void onStart(SuiteMessage suiteMessage);
26 |
27 | /**
28 | * @see org.testng.ISuiteListener#onFinish(org.testng.ISuite)
29 | *
30 | * @param suiteMessage the suite message containing infos about the finished suite.
31 | */
32 | void onFinish(SuiteMessage suiteMessage);
33 | }
34 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/IRemoteTestListener.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 |
4 |
5 | /**
6 | * Interface replicating ITestListener for remote listeners.
7 | *
8 | * @author Alexandru Popescu
9 | * @see org.testng.ITestListener
10 | */
11 | public interface IRemoteTestListener {
12 | void onStart(TestMessage tm);
13 |
14 | void onFinish(TestMessage tm);
15 |
16 | void onTestStart(TestResultMessage trm);
17 |
18 | void onTestSuccess(TestResultMessage trm);
19 |
20 | void onTestFailure(TestResultMessage trm);
21 |
22 | void onTestSkipped(TestResultMessage trm);
23 |
24 | void onTestFailedButWithinSuccessPercentage(TestResultMessage trm);
25 | }
26 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/IStringMessage.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 |
4 | /**
5 | * String based protocol main interface to be used with remote listeners.
6 | *
7 | * @author Alexandru Popescu
8 | */
9 | public interface IStringMessage extends IMessage {
10 | String getMessageAsString();
11 | }
12 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/JsonMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import static org.testng.remote.RemoteTestNG.isVerbose;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.BufferedWriter;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStreamWriter;
10 | import java.io.StringReader;
11 | import java.io.UnsupportedEncodingException;
12 |
13 | import com.google.gson.Gson;
14 | import com.google.gson.GsonBuilder;
15 | import com.google.gson.stream.JsonReader;
16 | import com.google.gson.stream.JsonWriter;
17 |
18 | public class JsonMessageSender extends BaseMessageSender {
19 |
20 | public JsonMessageSender(String host, int port) {
21 | super(host, port, false);
22 | }
23 |
24 | public JsonMessageSender(String host, int port, boolean ack) {
25 | super(host, port, ack);
26 | }
27 |
28 | @Override
29 | public void sendMessage(IMessage message) throws Exception {
30 | if (m_outStream == null) {
31 | throw new IllegalStateException("Trying to send a message on a shutdown sender");
32 | }
33 |
34 | synchronized (m_outStream) {
35 | p("Sending message " + message);
36 |
37 | BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(m_outStream, "UTF-8"));
38 | JsonWriter writer = new JsonWriter(bw);
39 | writeMessage(writer, message);
40 | bw.newLine();
41 | bw.flush();
42 |
43 | waitForAck();
44 | }
45 | }
46 |
47 | void writeMessage(JsonWriter writer, IMessage message) throws IOException {
48 | writer.beginObject();
49 |
50 | MessageType messageType = message.getType();
51 | writer.name("type").value(messageType.getValue());
52 | writer.name("data");
53 | Gson gson = new GsonBuilder().create();
54 | gson.toJson(message, message.getClass(), writer);
55 |
56 | writer.endObject();
57 | }
58 |
59 | @Override
60 | public IMessage receiveMessage() throws Exception {
61 | if (m_inReader == null) {
62 | try {
63 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream, "UTF-8"));
64 | } catch (UnsupportedEncodingException e) {
65 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream));
66 | }
67 | }
68 | String msg = m_inReader.readLine();
69 | p("received message: " + msg);
70 |
71 | IMessage message = null;
72 | if (msg != null) {
73 | message = deserializeMessage(msg);
74 | }
75 |
76 | try {
77 | sendAck();
78 | } catch (Exception e) {
79 | if (isVerbose()) {
80 | System.out.println("sendAck failed with error: " + e.getMessage());
81 | e.printStackTrace();
82 | }
83 | }
84 | return message;
85 | }
86 |
87 | IMessage deserializeMessage(String jsonMsg) throws IOException {
88 | try (JsonReader reader = new JsonReader(new StringReader(jsonMsg))) {
89 | reader.beginObject();
90 |
91 | String name = reader.nextName();
92 | if (!"type".equals(name)) {
93 | throw new IOException("type node first");
94 | }
95 |
96 | int msgType = reader.nextInt();
97 | MessageType type = MessageType.fromValue(msgType);
98 | if (type == null) {
99 | throw new IOException("unknown message type: " + msgType + ", raw json: " + jsonMsg);
100 | }
101 |
102 | name = reader.nextName();
103 | if (!"data".equals(name)) {
104 | throw new IOException("data node then");
105 | }
106 |
107 | Gson gson = new GsonBuilder().create();
108 | IMessage message = null;
109 | switch (type) {
110 | case GENERIC:
111 | message = gson.fromJson(reader, GenericMessage.class);
112 | break;
113 | case SUITE:
114 | message = gson.fromJson(reader, SuiteMessage.class);
115 | break;
116 | case TEST:
117 | message = gson.fromJson(reader, TestMessage.class);
118 | break;
119 | case TEST_RESULT:
120 | message = gson.fromJson(reader, TestResultMessage.class);
121 | break;
122 | default:
123 | throw new IOException("unsupported message type: " + msgType + ", raw json: " + jsonMsg);
124 | }
125 |
126 | reader.endObject();
127 |
128 | return message;
129 | }
130 | }
131 |
132 | private static void p(String msg) {
133 | if (isVerbose()) {
134 | System.out.println("[JsonMessageSender] " + msg); //$NON-NLS-1$
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/MessageHelper.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 |
4 | import org.testng.ITestResult;
5 | import org.testng.collections.Lists;
6 |
7 | import java.util.List;
8 | import java.util.regex.Pattern;
9 |
10 |
11 | /**
12 | * Marshal/unmarshal tool for IStringMessages.
13 | *
14 | * @author Alexandru Popescu
15 | */
16 | public class MessageHelper {
17 | public static final char DELIMITER = '\u0001';
18 | public static final char PARAM_DELIMITER = '\u0004';
19 | private static final char LINE_SEP_DELIMITER_1 = '\u0002';
20 | private static final char LINE_SEP_DELIMITER_2 = '\u0003';
21 |
22 | public static final int GENERIC_SUITE_COUNT = 1;
23 |
24 | public static final int SUITE = 10;
25 | public static final int SUITE_START = 11;
26 | public static final int SUITE_FINISH = 12;
27 |
28 | public static final int TEST = 100;
29 | public static final int TEST_START = 101;
30 | public static final int TEST_FINISH = 102;
31 |
32 | public static final int TEST_RESULT = 1000;
33 | public static final int PASSED_TEST = TEST_RESULT + ITestResult.SUCCESS;
34 | public static final int FAILED_TEST = TEST_RESULT + ITestResult.FAILURE;
35 | public static final int SKIPPED_TEST = TEST_RESULT + ITestResult.SKIP;
36 | public static final int FAILED_ON_PERCENTAGE_TEST = TEST_RESULT + ITestResult.SUCCESS_PERCENTAGE_FAILURE;
37 | public static final int TEST_STARTED = TEST_RESULT + ITestResult.STARTED;
38 |
39 | public static final String STOP_MSG = ">STOP";
40 | public static final String ACK_MSG = ">ACK";
41 |
42 | public static int getMessageType(final String message) {
43 | int idx = message.indexOf(DELIMITER);
44 |
45 | return idx == -1 ? Integer.parseInt(message) : Integer.parseInt(message.substring(0, idx));
46 | }
47 |
48 | public static GenericMessage unmarshallGenericMessage(final String message) {
49 | String[] messageParts = parseMessage(message);
50 | if(messageParts.length == 1) {
51 | return new GenericMessage(MessageType.fromValue(messageParts[0]));
52 | }
53 | else {
54 | GenericMessage result = new GenericMessage(MessageType.fromValue(messageParts[0]));
55 |
56 | for(int i = 1; i < messageParts.length; i+=2) {
57 | if ("testCount".equals(messageParts[i])) {
58 | result.setTestCount(Integer.parseInt(messageParts[i + 1]));
59 | } else if ("suiteCount".equals(messageParts[i])) {
60 | result.setSuiteCount(Integer.parseInt(messageParts[i + 1]));
61 | }
62 | }
63 |
64 | return result;
65 | }
66 | }
67 |
68 | public static SuiteMessage createSuiteMessage(final String message) {
69 | int type = getMessageType(message);
70 | String[] messageParts = parseMessage(message);
71 |
72 | SuiteMessage result = new SuiteMessage(messageParts[1],
73 | MessageHelper.SUITE_START == type,
74 | Integer.parseInt(messageParts[2]));
75 | // Any excluded methods?
76 | if (messageParts.length > 3) {
77 | int count = Integer.parseInt(messageParts[3]);
78 | if (count > 0) {
79 | List methods = Lists.newArrayList();
80 | int i = 4;
81 | while (count-- > 0) {
82 | methods.add(messageParts[i++]);
83 | }
84 | result.setExcludedMethods(methods);
85 | }
86 | }
87 |
88 | return result;
89 | }
90 |
91 | public static TestMessage createTestMessage(final String message) {
92 | int type = getMessageType(message);
93 | String[] messageParts = parseMessage(message);
94 |
95 | return new TestMessage(MessageHelper.TEST_START == type,
96 | messageParts[1],
97 | messageParts[2],
98 | Integer.parseInt(messageParts[3]),
99 | Integer.parseInt(messageParts[4]),
100 | Integer.parseInt(messageParts[5]),
101 | Integer.parseInt(messageParts[6]),
102 | Integer.parseInt(messageParts[7]));
103 | }
104 |
105 | public static TestResultMessage unmarshallTestResultMessage(final String message) {
106 | String[] messageParts = parseMessage(message);
107 |
108 | String parametersFragment= null;
109 | String startTimestampFragment= null;
110 | String stopTimestampFragment= null;
111 | String stackTraceFragment= null;
112 | String testDescriptor= null;
113 | switch(messageParts.length) {
114 | case 10:
115 | {
116 | parametersFragment= messageParts[5];
117 | startTimestampFragment= messageParts[6];
118 | stopTimestampFragment= messageParts[7];
119 | stackTraceFragment= messageParts[8];
120 | testDescriptor= messageParts[9];
121 | }
122 | break;
123 | case 9:
124 | {
125 | parametersFragment= messageParts[5];
126 | startTimestampFragment= messageParts[6];
127 | stopTimestampFragment= messageParts[7];
128 | stackTraceFragment= messageParts[8];
129 | }
130 | break;
131 | default:
132 | {
133 | // HINT: old protocol without parameters
134 | parametersFragment= null;
135 | startTimestampFragment= messageParts[5];
136 | stopTimestampFragment= messageParts[6];
137 | stackTraceFragment= messageParts[7];
138 | }
139 | }
140 | return new TestResultMessage(Integer.parseInt(messageParts[0]),
141 | messageParts[1],
142 | messageParts[2],
143 | messageParts[3],
144 | messageParts[4],
145 | replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(testDescriptor)),
146 | replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(testDescriptor)),
147 | parseParameters(parametersFragment),
148 | Long.parseLong(startTimestampFragment),
149 | Long.parseLong(stopTimestampFragment),
150 | replaceAsciiCharactersWithUnicode(replaceNewLineReplacer(stackTraceFragment)),
151 | 0, 0 /* invocation counts not supported by this protocol */
152 | );
153 | }
154 |
155 | public static String replaceNewLine(String message) {
156 | if(null == message) {
157 | return message;
158 | }
159 |
160 | return message.replace('\n', LINE_SEP_DELIMITER_1).replace('\r', LINE_SEP_DELIMITER_2);
161 | }
162 |
163 | public static String replaceUnicodeCharactersWithAscii(String message) {
164 | if(null == message) {
165 | return message;
166 | }
167 |
168 | return replace(
169 | replace(
170 | replace(
171 | replace(message, "\u0004", "\\u0004"),
172 | "\u0003", "\\u0003"),
173 | "\u0002", "\\u0002"),
174 | "\u0001", "\\u0001");
175 | }
176 |
177 | public static String replaceAsciiCharactersWithUnicode(String message) {
178 | if(null == message) {
179 | return message;
180 | }
181 |
182 | return replace(
183 | replace(
184 | replace(
185 | replace(message, "\\u0004", "\u0004"),
186 | "\\u0003", "\u0003"),
187 | "\\u0002", "\u0002"),
188 | "\\u0001", "\u0001");
189 | }
190 |
191 | public static String replaceNewLineReplacer(String message) {
192 | if(null == message) {
193 | return message;
194 | }
195 |
196 | return message.replace(LINE_SEP_DELIMITER_1, '\n').replace(LINE_SEP_DELIMITER_2, '\r');
197 | }
198 |
199 | private static String[] parseParameters(final String messagePart) {
200 | return tokenize(messagePart, PARAM_DELIMITER);
201 | }
202 |
203 | private static String[] parseMessage(final String message) {
204 | return tokenize(message, DELIMITER);
205 | }
206 |
207 | private static String[] tokenize(final String message, final char separator) {
208 | if(null == message) {
209 | return new String[0];
210 | }
211 |
212 | List tokens = Lists.newArrayList();
213 | int start = 0;
214 | for(int i = 0; i < message.length(); i++) {
215 | if(separator == message.charAt(i)) {
216 | tokens.add(message.substring(start, i));
217 | start = i + 1;
218 | }
219 | }
220 | if(start < message.length()) {
221 | tokens.add(message.substring(start, message.length()));
222 | }
223 |
224 | return tokens.toArray(new String[tokens.size()]);
225 | }
226 |
227 | /**
228 | * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
229 | */
230 | private static final String replace(String original, CharSequence target, CharSequence replacement) {
231 | return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(original)
232 | .replaceAll(quoteReplacement(replacement.toString()));
233 | }
234 |
235 | /**
236 | * Implementation according to JDK5 String.replace(CharSequence,CharSequence)
237 | */
238 | private static String quoteReplacement(String s) {
239 | if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1)) {
240 | return s;
241 | }
242 | StringBuffer sb = new StringBuffer();
243 | for (int i=0; i
13 | */
14 | public class MessageHub {
15 |
16 | private boolean m_debug = false;
17 |
18 | private IMessageSender m_messageSender;
19 |
20 | public MessageHub(IMessageSender messageSender) {
21 | m_messageSender = messageSender;
22 | }
23 |
24 | /**
25 | * Starts the connection.
26 | *
27 | * @throws TestNGException if an exception occurred while establishing the connection
28 | */
29 | public void connect() throws IOException {
30 | m_messageSender.connect();
31 | }
32 |
33 | /**
34 | * Shutsdown the connection to the remote test listener.
35 | */
36 | public void shutDown() {
37 | m_messageSender.shutDown();
38 | }
39 |
40 | public void sendMessage(IMessage message) {
41 | try {
42 | m_messageSender.sendMessage(message);
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | }
47 |
48 | public IMessage receiveMessage() {
49 | IMessage result = null;
50 | try {
51 | result = m_messageSender.receiveMessage();
52 | m_messageSender.sendAck();
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | }
56 | return result;
57 | }
58 |
59 | public void setDebug(boolean debug) {
60 | m_debug = debug;
61 | }
62 |
63 | public void initReceiver() throws SocketTimeoutException {
64 | m_messageSender.initReceiver();
65 | }
66 |
67 | public IMessageSender getMessageSender() {
68 | return m_messageSender;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/MessageType.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | public enum MessageType {
4 |
5 | GENERIC(MessageHelper.GENERIC_SUITE_COUNT),
6 | SUITE(MessageHelper.SUITE),
7 | TEST(MessageHelper.TEST),
8 | TEST_RESULT(MessageHelper.TEST_RESULT);
9 |
10 | private int type;
11 |
12 | MessageType(int type) {
13 | this.type = type;
14 | }
15 |
16 | public int getValue() {
17 | return type;
18 | }
19 |
20 | public static MessageType fromValue(int value) {
21 | for (MessageType type : MessageType.values()) {
22 | if (type.getValue() == value) {
23 | return type;
24 | }
25 | }
26 | return null;
27 | }
28 |
29 | public static MessageType fromValue(String value) {
30 | int val = Integer.parseInt(value);
31 | return fromValue(val);
32 | }
33 |
34 | public static MessageType fromName(String name) {
35 | for (MessageType type : MessageType.values()) {
36 | if (type.name().equals(name)) {
37 | return type;
38 | }
39 | }
40 | return null;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/RemoteTestListener.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import org.testng.ISuite;
4 | import org.testng.ITestResult;
5 | import org.testng.internal.IResultListener2;
6 | import org.testng.xml.XmlTest;
7 |
8 | /**
9 | * A special listener that remote the event with string protocol.
10 | *
11 | * @author Alexandru Popescu
12 | */
13 | public class RemoteTestListener extends RemoteTestListener1 implements IResultListener2 {
14 |
15 | public RemoteTestListener(ISuite suite, XmlTest test, MessageHub msh) {
16 | super(suite, test, msh);
17 | }
18 |
19 | @Override
20 | public void beforeConfiguration(ITestResult tr) {
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/RemoteTestListener1.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import org.testng.ISuite;
4 | import org.testng.ITestContext;
5 | import org.testng.ITestResult;
6 | import org.testng.internal.IResultListener;
7 | import org.testng.xml.XmlTest;
8 |
9 | /**
10 | * A special listener that remote the event with string protocol.
11 | *
12 | * @author Alexandru Popescu
13 | */
14 | public class RemoteTestListener1 implements IResultListener {
15 | private final MessageHub m_sender;
16 | private ISuite m_suite;
17 | private XmlTest m_xmlTest;
18 | private ITestContext m_currentTestContext;
19 |
20 | public RemoteTestListener1(ISuite suite, XmlTest test, MessageHub msh) {
21 | m_sender = msh;
22 | m_suite= suite;
23 | m_xmlTest= test;
24 | }
25 |
26 | @Override
27 | public void onStart(ITestContext testCtx) {
28 | m_currentTestContext = testCtx;
29 | m_sender.sendMessage(new TestMessage(testCtx, true /*start*/));
30 | }
31 |
32 | @Override
33 | public void onFinish(ITestContext testCtx) {
34 | m_sender.sendMessage(new TestMessage(testCtx, false /*end*/));
35 | m_currentTestContext = null;
36 | }
37 |
38 | @Override
39 | public void onTestStart(ITestResult testResult) {
40 | TestResultMessage trm= null;
41 |
42 | if (null == m_currentTestContext) {
43 | trm= new TestResultMessage(m_suite.getName(), m_xmlTest.getName(), testResult);
44 | }
45 | else {
46 | trm= new TestResultMessage(m_currentTestContext, testResult);
47 | }
48 |
49 | m_sender.sendMessage(trm);
50 | }
51 |
52 | @Override
53 | public void onTestFailedButWithinSuccessPercentage(ITestResult testResult) {
54 | if (null == m_currentTestContext) {
55 | m_sender.sendMessage(new TestResultMessage(m_suite.getName(), m_xmlTest.getName(), testResult));
56 | }
57 | else {
58 | m_sender.sendMessage(new TestResultMessage(m_currentTestContext, testResult));
59 | }
60 | }
61 |
62 | @Override
63 | public void onTestFailure(ITestResult testResult) {
64 | if (null == m_currentTestContext) {
65 | m_sender.sendMessage(new TestResultMessage(m_suite.getName(), m_xmlTest.getName(), testResult));
66 | }
67 | else {
68 | m_sender.sendMessage(new TestResultMessage(m_currentTestContext, testResult));
69 | }
70 | }
71 |
72 | @Override
73 | public void onTestSkipped(ITestResult testResult) {
74 | if (null == m_currentTestContext) {
75 | m_sender.sendMessage(new TestResultMessage(m_suite.getName(), m_xmlTest.getName(), testResult));
76 | }
77 | else {
78 | m_sender.sendMessage(new TestResultMessage(m_currentTestContext, testResult));
79 | }
80 | }
81 |
82 | @Override
83 | public void onTestSuccess(ITestResult testResult) {
84 | if (null == m_currentTestContext) {
85 | m_sender.sendMessage(new TestResultMessage(m_suite.getName(), m_xmlTest.getName(), testResult));
86 | }
87 | else {
88 | m_sender.sendMessage(new TestResultMessage(m_currentTestContext, testResult));
89 | }
90 | }
91 |
92 | /**
93 | * @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult)
94 | */
95 | @Override
96 | public void onConfigurationFailure(ITestResult itr) {
97 | // Show configuration failures in the main view for convenience
98 | onTestFailure(itr);
99 | }
100 |
101 | /**
102 | * @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult)
103 | */
104 | @Override
105 | public void onConfigurationSkip(ITestResult itr) {
106 | onTestSkipped(itr);
107 | }
108 |
109 | /**
110 | * @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult)
111 | */
112 | @Override
113 | public void onConfigurationSuccess(ITestResult itr) {
114 | }
115 | }
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/SerializedMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import org.testng.remote.RemoteTestNG;
4 |
5 | import java.io.IOException;
6 | import java.io.ObjectInputStream;
7 | import java.io.ObjectOutputStream;
8 |
9 |
10 | public class SerializedMessageSender extends BaseMessageSender {
11 |
12 | public SerializedMessageSender(String host, int port) {
13 | super(host, port, false /* no ack */);
14 | }
15 |
16 | public SerializedMessageSender(String host, int port, boolean ack) {
17 | super(host, port, ack);
18 | }
19 |
20 | @Override
21 | public void sendMessage(IMessage message) throws IOException {
22 | synchronized(m_outStream) {
23 | p("Sending message " + message);
24 | ObjectOutputStream oos = new ObjectOutputStream(m_outStream);
25 | oos.writeObject(message);
26 | oos.flush();
27 |
28 | waitForAck();
29 | }
30 | }
31 |
32 | @Override
33 | public IMessage receiveMessage() throws IOException, ClassNotFoundException {
34 |
35 | IMessage result = null;
36 | try {
37 | ObjectInputStream ios = new ObjectInputStream(m_inStream);
38 | // synchronized(m_input) {
39 | result = (IMessage) ios.readObject();
40 | p("Received message " + result);
41 | // sendAck();
42 | // }
43 | }
44 | catch(Exception ex) {
45 | if (RemoteTestNG.isVerbose()) {
46 | ex.printStackTrace();
47 | }
48 | }
49 | return result;
50 | }
51 |
52 | static void p(String s) {
53 | if (RemoteTestNG.isVerbose()) {
54 | System.out.println("[SerializedMessageSender] " + s);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/StdoutMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import java.io.IOException;
4 | import java.net.SocketTimeoutException;
5 |
6 | /**
7 | * this is a dummy IMessageSender implementation for test purpose only.
8 | *
9 | * @author nick
10 | */
11 | public class StdoutMessageSender implements IMessageSender {
12 |
13 | @Override
14 | public void connect() throws IOException {
15 | // noop
16 | }
17 |
18 | @Override
19 | public void initReceiver() throws SocketTimeoutException {
20 | // noop
21 | }
22 |
23 | @Override
24 | public void stopReceiver() {
25 | // noop
26 | }
27 |
28 | @Override
29 | public void sendMessage(IMessage message) throws Exception {
30 | System.out.println(message);
31 | }
32 |
33 | @Override
34 | public IMessage receiveMessage() throws Exception {
35 | return null;
36 | }
37 |
38 | @Override
39 | public void shutDown() {
40 | // noop
41 | }
42 |
43 | @Override
44 | public void sendAck() {
45 | // noop
46 | }
47 |
48 | @Override
49 | public void sendStop() {
50 | // noop
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/StringMessageSender.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import org.testng.remote.RemoteTestNG;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.BufferedWriter;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStreamWriter;
10 | import java.io.PrintWriter;
11 | import java.io.UnsupportedEncodingException;
12 |
13 | public class StringMessageSender extends BaseMessageSender {
14 |
15 | private PrintWriter writer;
16 |
17 | public StringMessageSender(String host, int port) {
18 | super(host, port, false /* no ack */);
19 | }
20 |
21 | public StringMessageSender(String host, int port, boolean ack) {
22 | super(host, port, ack);
23 | }
24 |
25 | @Override
26 | public void sendMessage(IMessage message) {
27 | if (m_outStream == null) {
28 | throw new IllegalStateException("Trying to send a message on a shutdown sender");
29 | }
30 | if (writer == null) {
31 | try {
32 | writer = new PrintWriter(new BufferedWriter(
33 | new OutputStreamWriter(m_outStream, "UTF-8")), //$NON-NLS-1$
34 | false /* autoflush */);
35 | } catch (UnsupportedEncodingException e1) {
36 | writer = new PrintWriter(new BufferedWriter(
37 | new OutputStreamWriter(m_outStream)),
38 | false /* autoflush */);
39 | }
40 | }
41 |
42 | String msg = ((IStringMessage) message).getMessageAsString();
43 | if (RemoteTestNG.isVerbose()) {
44 | p("Sending message:" + message);
45 | p(" String version:" + msg);
46 |
47 | StringBuffer buf = new StringBuffer();
48 | for(int i = 0; i < msg.length(); i++) {
49 | if('\u0001' == msg.charAt(i)) {
50 | p(" word:[" + buf.toString() + "]");
51 | buf.delete(0, buf.length());
52 | }
53 | else {
54 | buf.append(msg.charAt(i));
55 | }
56 | }
57 | p(" word:[" + buf.toString() + "]");
58 | }
59 |
60 | synchronized(m_ackLock) {
61 | writer.println(msg);
62 | writer.flush();
63 | waitForAck();
64 | }
65 | }
66 |
67 | private static void p(String msg) {
68 | if (RemoteTestNG.isVerbose()) {
69 | System.out.println("[StringMessageSender] " + msg); //$NON-NLS-1$
70 | }
71 | }
72 |
73 | @Override
74 | public IMessage receiveMessage() {
75 | IMessage result = null;
76 |
77 | if (m_inReader == null) {
78 | try {
79 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream, "UTF-8"));
80 | } catch (UnsupportedEncodingException e) {
81 | m_inReader = new BufferedReader(new InputStreamReader(m_inStream));
82 | }
83 | }
84 | try {
85 | // try {
86 | // m_outputWriter = new PrintWriter(new OutputStreamWriter(fSocket.getOutputStream(), "UTF-8"),
87 | // true);
88 | // }
89 | // catch(UnsupportedEncodingException e1) {
90 | // m_outputWriter = new PrintWriter(new OutputStreamWriter(fSocket.getOutputStream()), true);
91 | // }
92 | result = receiveMessage(m_inReader.readLine());
93 | } catch(IOException e) {
94 | handleThrowable(e);
95 | }
96 |
97 | return result;
98 | // finally {
99 | // shutDown();
100 | // return null;
101 | // }
102 | }
103 |
104 | protected void handleThrowable(Throwable cause) {
105 | if (RemoteTestNG.isVerbose()) {
106 | cause.printStackTrace();
107 | }
108 | }
109 |
110 | // private String readMessage(BufferedReader in) throws IOException {
111 | // return in.readLine();
112 | // }
113 |
114 | private IMessage receiveMessage(String message) {
115 | if (message == null) return null;
116 | IMessage result = null;
117 |
118 | int messageType = MessageHelper.getMessageType(message);
119 |
120 | // try {
121 | if(messageType < MessageHelper.SUITE) {
122 | // Generic message
123 | result = MessageHelper.unmarshallGenericMessage(message);
124 | }
125 | else if(messageType < MessageHelper.TEST) {
126 | // Suite message
127 | result = MessageHelper.createSuiteMessage(message);
128 | }
129 | else if(messageType < MessageHelper.TEST_RESULT) {
130 | // Test message
131 | result = MessageHelper.createTestMessage(message);
132 | }
133 | else {
134 | // TestResult message
135 | result = MessageHelper.unmarshallTestResultMessage(message);
136 | }
137 | // }
138 | // finally {
139 | // if(isRunning() && (null != m_outputWriter)) {
140 | // m_outputWriter.println(MessageHelper.ACK_MSG);
141 | // m_outputWriter.flush();
142 | // }
143 | // }
144 |
145 | p("receiveMessage() received:" + result);
146 | return result;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/SuiteMessage.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import java.util.Collection;
4 | import java.util.List;
5 | import java.util.Map;
6 |
7 | import org.testng.ISuite;
8 | import org.testng.ITestNGMethod;
9 | import org.testng.collections.Lists;
10 | import org.testng.collections.Maps;
11 |
12 | import com.google.gson.annotations.SerializedName;
13 |
14 |
15 | /**
16 | * A IStringMessage implementation for suite running events.
17 | *
18 | * @author Alexandru Popescu
19 | */
20 | public class SuiteMessage implements IStringMessage {
21 | private static final long serialVersionUID = -4298528261942620419L;
22 | @SerializedName("suiteName")
23 | protected final String m_suiteName;
24 | @SerializedName("methodCount")
25 | protected final int m_testMethodCount;
26 | @SerializedName("startSuiteRun")
27 | protected final boolean m_startSuite;
28 | @SerializedName("excludedMethods")
29 | private List m_excludedMethods = Lists.newArrayList();
30 | private Map m_descriptions;
31 |
32 | public SuiteMessage(final String suiteName, final boolean startSuiteRun, final int methodCount) {
33 | m_suiteName = suiteName;
34 | m_startSuite = startSuiteRun;
35 | m_testMethodCount = methodCount;
36 | }
37 |
38 | public SuiteMessage(final ISuite suite, final boolean startSuiteRun) {
39 | m_suiteName = suite.getName();
40 | m_testMethodCount =suite.getAllInvokedMethods().size();
41 | m_startSuite = startSuiteRun;
42 | Collection excludedMethods = suite.getExcludedMethods();
43 | if (excludedMethods != null && excludedMethods.size() > 0) {
44 | m_excludedMethods = Lists.newArrayList();
45 | m_descriptions = Maps.newHashMap();
46 | for (ITestNGMethod m : excludedMethods) {
47 | String methodName = m.getTestClass().getName() + "." + m.getMethodName();
48 | m_excludedMethods.add(methodName);
49 | if (m.getDescription() != null) m_descriptions.put(methodName, m.getDescription());
50 | }
51 | }
52 | }
53 |
54 | public void setExcludedMethods(List methods) {
55 | m_excludedMethods = Lists.newArrayList();
56 | m_excludedMethods.addAll(methods);
57 | }
58 |
59 | public List getExcludedMethods() {
60 | return m_excludedMethods;
61 | }
62 |
63 | public String getDescriptionForMethod(String methodName) {
64 | return m_descriptions.get(methodName);
65 | }
66 |
67 | public boolean isMessageOnStart() {
68 | return m_startSuite;
69 | }
70 |
71 | public String getSuiteName() {
72 | return m_suiteName;
73 | }
74 |
75 | public int getTestMethodCount() {
76 | return m_testMethodCount;
77 | }
78 |
79 | @Override
80 | public String getMessageAsString() {
81 | StringBuffer buf = new StringBuffer();
82 |
83 | buf.append(m_startSuite ? MessageHelper.SUITE_START : MessageHelper.SUITE_FINISH)
84 | .append(MessageHelper.DELIMITER)
85 | .append(m_suiteName)
86 | .append(MessageHelper.DELIMITER)
87 | .append(m_testMethodCount)
88 | ;
89 |
90 | if (m_excludedMethods != null && m_excludedMethods.size() > 0) {
91 | buf.append(MessageHelper.DELIMITER);
92 | buf.append(m_excludedMethods.size());
93 | for (String method : m_excludedMethods) {
94 | buf.append(MessageHelper.DELIMITER);
95 | buf.append(method);
96 | }
97 | }
98 | return buf.toString();
99 | }
100 |
101 | @Override
102 | public MessageType getType() {
103 | return MessageType.SUITE;
104 | }
105 |
106 | @Override
107 | public String toString() {
108 | StringBuilder sb = new StringBuilder();
109 | sb.append("[SuiteMessage ==> suite:").append(m_suiteName)
110 | .append(m_startSuite ? ", starting" : ", ending")
111 | .append(", methodCount:" + m_testMethodCount)
112 | .append("]");
113 | return sb.toString();
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/strprotocol/TestMessage.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.strprotocol;
2 |
3 | import org.testng.ITestContext;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 |
8 | /**
9 | * An IStringMessage implementation for test events.
10 | *
11 | * @author Alexandru Popescu
12 | */
13 | public class TestMessage implements IStringMessage {
14 | private static final long serialVersionUID = -5039267143570559640L;
15 | @SerializedName("testStart")
16 | protected final boolean m_testStart;
17 | @SerializedName("suiteName")
18 | protected final String m_suiteName;
19 | @SerializedName("testName")
20 | protected final String m_testName;
21 | @SerializedName("testMethodCount")
22 | protected final int m_testMethodCount;
23 | @SerializedName("passedTestCount")
24 | protected final int m_passedTestCount;
25 | @SerializedName("failedTestCount")
26 | protected final int m_failedTestCount;
27 | @SerializedName("skippedTestCount")
28 | protected final int m_skippedTestCount;
29 | @SerializedName("successPercentageFailedTestCount")
30 | protected final int m_successPercentageFailedTestCount;
31 |
32 | public TestMessage(final boolean isTestStart,
33 | final String suiteName,
34 | final String testName,
35 | final int methodCount,
36 | final int passedCount,
37 | final int failedCount,
38 | final int skippedCount,
39 | final int percentageCount) {
40 | m_testStart = isTestStart;
41 | m_suiteName = suiteName;
42 | m_testName = testName;
43 | m_testMethodCount = methodCount;
44 | m_passedTestCount = passedCount;
45 | m_failedTestCount = failedCount;
46 | m_skippedTestCount = skippedCount;
47 | m_successPercentageFailedTestCount = percentageCount;
48 | }
49 |
50 | public TestMessage(final ITestContext testContext, final boolean isTestStart) {
51 | this(isTestStart,
52 | testContext.getSuite().getName(),
53 | testContext.getCurrentXmlTest().getName(),
54 | testContext.getAllTestMethods().length,
55 | testContext.getPassedTests().size(),
56 | testContext.getFailedTests().size(),
57 | testContext.getSkippedTests().size(),
58 | testContext.getFailedButWithinSuccessPercentageTests().size());
59 | }
60 |
61 | public boolean isMessageOnStart() {
62 | return m_testStart;
63 | }
64 |
65 | @Override
66 | public String getMessageAsString() {
67 | StringBuffer buf = new StringBuffer();
68 |
69 | buf.append(m_testStart ? MessageHelper.TEST_START : MessageHelper.TEST_FINISH)
70 | .append(MessageHelper.DELIMITER)
71 | .append(m_suiteName)
72 | .append(MessageHelper.DELIMITER)
73 | .append(m_testName)
74 | .append(MessageHelper.DELIMITER)
75 | .append(m_testMethodCount)
76 | .append(MessageHelper.DELIMITER)
77 | .append(m_passedTestCount)
78 | .append(MessageHelper.DELIMITER)
79 | .append(m_failedTestCount)
80 | .append(MessageHelper.DELIMITER)
81 | .append(m_skippedTestCount)
82 | .append(MessageHelper.DELIMITER)
83 | .append(m_successPercentageFailedTestCount)
84 | ;
85 |
86 | return buf.toString();
87 | }
88 |
89 | public String getSuiteName() {
90 | return m_suiteName;
91 | }
92 |
93 | public String getTestName() {
94 | return m_testName;
95 | }
96 |
97 | public boolean isTestStart() {
98 | return m_testStart;
99 | }
100 | public int getTestMethodCount() {
101 | return m_testMethodCount;
102 | }
103 | public int getSuccessPercentageFailedTestCount() {
104 | return m_successPercentageFailedTestCount;
105 | }
106 | public int getFailedTestCount() {
107 | return m_failedTestCount;
108 | }
109 | public int getPassedTestCount() {
110 | return m_passedTestCount;
111 | }
112 | public int getSkippedTestCount() {
113 | return m_skippedTestCount;
114 | }
115 |
116 | @Override
117 | public MessageType getType() {
118 | return MessageType.TEST;
119 | }
120 |
121 | @Override
122 | public String toString() {
123 | StringBuilder sb = new StringBuilder();
124 | sb.append("[TestMessage ==> suite:").append(m_suiteName).append(", testName:").append(m_testName)
125 | .append(", passed:").append(m_passedTestCount).append(", failed:").append(m_failedTestCount)
126 | .append("]");
127 | return sb.toString();
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/support/RemoteTestNGFactory.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.support;
2 |
3 | import org.testng.remote.IRemoteTestNG;
4 | import org.testng.remote.Orderable;
5 | import org.testng.shaded.osgi.framework.Version;
6 |
7 | public interface RemoteTestNGFactory extends Orderable {
8 |
9 | boolean accept(Version version);
10 | IRemoteTestNG createRemoteTestNG();
11 | }
12 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/remote/support/ServiceLoaderHelper.java:
--------------------------------------------------------------------------------
1 | package org.testng.remote.support;
2 |
3 | import java.io.*;
4 | import java.net.URL;
5 | import java.net.URLClassLoader;
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.Comparator;
9 | import java.util.List;
10 | import java.util.ServiceConfigurationError;
11 | import java.util.ServiceLoader;
12 | import java.util.jar.JarEntry;
13 | import java.util.jar.JarFile;
14 |
15 | import org.testng.TestNGException;
16 | import org.testng.remote.RemoteTestNG;
17 | import org.testng.shaded.osgi.framework.Version;
18 |
19 | public final class ServiceLoaderHelper {
20 |
21 | private ServiceLoaderHelper() {}
22 |
23 | public static RemoteTestNGFactory getFirst(Version version) {
24 | List factories = new ArrayList<>();
25 | for (RemoteTestNGFactory factory : ServiceLoader.load(RemoteTestNGFactory.class)) {
26 | if (factory.accept(version)) {
27 | factories.add(factory);
28 | }
29 | }
30 | if (factories.isEmpty()) {
31 | throw new TestNGException(version + " is not a supported TestNG version");
32 | }
33 | if (factories.size() > 1) {
34 | System.err.println("[ServiceLoaderHelper] More than one working implementation for '" + version + "', we will use the first one");
35 | }
36 |
37 | Collections.sort(factories, new Comparator() {
38 | @Override
39 | public int compare(RemoteTestNGFactory o1, RemoteTestNGFactory o2) {
40 | // the newest first
41 | return o2.getOrder() - o1.getOrder();
42 | }
43 | });
44 |
45 | return factories.get(0);
46 | }
47 |
48 | public static RemoteTestNGFactory getFirstQuietly(String version) {
49 | return getFirstQuietly(Version.parseVersion(version));
50 | }
51 |
52 | /**
53 | * Get the first RemoteTestNGFactory on classpath.
54 | *
55 | * this implementation is diff with {@link #getFirst(Version)} that
56 | * it scans the JARs on the classpath, and parse the services file manually.
57 | *
58 | * @param version
59 | * @return
60 | * @throws TestNGException if not found
61 | */
62 | public static RemoteTestNGFactory getFirstQuietly(Version version) {
63 | ClassLoader cl = RemoteTestNGFactory.class.getClassLoader();
64 | if (cl instanceof URLClassLoader) {
65 | for (URL url : ((URLClassLoader) cl).getURLs()) {
66 | File f = new File(url.getFile());
67 | // only check for jar file name starts with 'testng-remote'
68 | if (f.isFile() && f.getName().startsWith("testng-remote")) {
69 | try (JarFile jarFile = new JarFile(f)) {
70 | JarEntry entry = jarFile.getJarEntry("META-INF/services/" + RemoteTestNGFactory.class.getName());
71 | if (entry != null) {
72 | ArrayList names = new ArrayList<>();
73 |
74 | try (BufferedReader r = new BufferedReader(
75 | new InputStreamReader(jarFile.getInputStream(entry), "utf-8"))) {
76 | int lc = 1;
77 | while ((lc = parseLine(RemoteTestNGFactory.class, url, r, lc, names)) >= 0) {
78 | // noop
79 | }
80 |
81 | for (String name : names) {
82 | Class> c = Class.forName(name, false, cl);
83 | RemoteTestNGFactory factory = (RemoteTestNGFactory) c.newInstance();
84 | if (factory.accept(version)) {
85 | return factory;
86 | }
87 | }
88 | }
89 | }
90 | } catch (TestNGException ex) {
91 | throw ex;
92 | } catch (Exception ex) {
93 | if (RemoteTestNG.isDebug()) {
94 | ex.printStackTrace();
95 | }
96 | }
97 | }
98 | }
99 | }
100 |
101 | throw new TestNGException(version + " is not a supported TestNG version");
102 | }
103 |
104 | // Parse a single line from the given configuration file, adding the name
105 | // on the line to the names list.
106 | //
107 | private static int parseLine(Class> service, URL u, BufferedReader r, int lc, List names)
108 | throws IOException, ServiceConfigurationError {
109 | String ln = r.readLine();
110 | if (ln == null) {
111 | return -1;
112 | }
113 | int ci = ln.indexOf('#');
114 | if (ci >= 0) {
115 | ln = ln.substring(0, ci);
116 | }
117 | ln = ln.trim();
118 | int n = ln.length();
119 | if (n != 0) {
120 | if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
121 | fail(service, u, lc, "Illegal configuration-file syntax");
122 | }
123 | int cp = ln.codePointAt(0);
124 | if (!Character.isJavaIdentifierStart(cp)) {
125 | fail(service, u, lc, "Illegal provider-class name: " + ln);
126 | }
127 | for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
128 | cp = ln.codePointAt(i);
129 | if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
130 | fail(service, u, lc, "Illegal provider-class name: " + ln);
131 | }
132 | }
133 | if (!names.contains(ln)) {
134 | names.add(ln);
135 | }
136 | }
137 | return lc + 1;
138 | }
139 |
140 | private static void fail(Class> service, String msg) throws ServiceConfigurationError {
141 | throw new ServiceConfigurationError(service.getName() + ": " + msg);
142 | }
143 |
144 | private static void fail(Class> service, URL u, int line, String msg) throws ServiceConfigurationError {
145 | fail(service, u + ":" + line + ": " + msg);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/xml/ResultContentHandler.java:
--------------------------------------------------------------------------------
1 | package org.testng.xml;
2 |
3 | import static org.testng.reporters.XMLReporterConfig.ATTR_DESC;
4 | import static org.testng.reporters.XMLReporterConfig.ATTR_DURATION_MS;
5 | import static org.testng.reporters.XMLReporterConfig.ATTR_NAME;
6 | import static org.testng.reporters.XMLReporterConfig.ATTR_STATUS;
7 | import static org.testng.reporters.XMLReporterConfig.TAG_CLASS;
8 | import static org.testng.reporters.XMLReporterConfig.TAG_PARAMS;
9 | import static org.testng.reporters.XMLReporterConfig.TAG_SUITE;
10 | import static org.testng.reporters.XMLReporterConfig.TAG_TEST;
11 | import static org.testng.reporters.XMLReporterConfig.TAG_TEST_METHOD;
12 |
13 | import java.util.List;
14 |
15 | import org.testng.ITestResult;
16 | import org.testng.collections.Lists;
17 | import org.testng.remote.strprotocol.GenericMessage;
18 | import org.testng.remote.strprotocol.IRemoteSuiteListener;
19 | import org.testng.remote.strprotocol.IRemoteTestListener;
20 | import org.testng.remote.strprotocol.SuiteMessage;
21 | import org.testng.remote.strprotocol.TestMessage;
22 | import org.testng.remote.strprotocol.TestResultMessage;
23 | import org.testng.reporters.XMLReporterConfig;
24 | import org.xml.sax.Attributes;
25 | import org.xml.sax.helpers.DefaultHandler;
26 |
27 | /**
28 | * Parses testng-result.xml, create TestResultMessages and send them back to the listener
29 | * as we encounter them.
30 | *
31 | * @author Cedric Beust
32 | */
33 | public class ResultContentHandler extends DefaultHandler {
34 | private int m_suiteMethodCount = 0;
35 | private int m_testMethodCount = 0;
36 | private SuiteMessage m_currentSuite;
37 | private TestMessage m_currentTest;
38 | private String m_className;
39 | private int m_passed;
40 | private int m_failed;
41 | private int m_skipped;
42 | private int m_invocationCount;
43 | private int m_currentInvocationCount;
44 | private TestResultMessage m_currentTestResult;
45 | private IRemoteSuiteListener m_suiteListener;
46 | private IRemoteTestListener m_testListener;
47 | private List m_params = null;
48 |
49 | public ResultContentHandler(IRemoteSuiteListener suiteListener,
50 | IRemoteTestListener testListener, boolean resolveClasses /* ignored */) {
51 | m_suiteListener = suiteListener;
52 | m_testListener = testListener;
53 | }
54 |
55 | @Override
56 | public void startElement (String uri, String localName,
57 | String qName, Attributes attributes) {
58 | p("Start " + qName);
59 | if (TAG_SUITE.equals(qName)) {
60 | m_suiteListener.onInitialization(new GenericMessage());
61 | m_suiteMethodCount = 0;
62 | m_currentSuite = new SuiteMessage(attributes.getValue(ATTR_NAME),
63 | true /* start */, m_suiteMethodCount);
64 | m_suiteListener.onStart(m_currentSuite);
65 | } else if (TAG_TEST.equals(qName)) {
66 | m_passed = m_failed = m_skipped = 0;
67 | m_currentTest = new TestMessage(true /* start */, m_currentSuite.getSuiteName(),
68 | attributes.getValue(ATTR_NAME), m_testMethodCount,
69 | m_passed, m_failed, m_skipped, 0);
70 | m_testListener.onStart(m_currentTest);
71 | } else if (TAG_CLASS.equals(qName)) {
72 | m_className = attributes.getValue(ATTR_NAME);
73 | } else if (TAG_TEST_METHOD.equals(qName)) {
74 | Integer status = XMLReporterConfig.getStatus(attributes.getValue(ATTR_STATUS));
75 | m_currentTestResult = new TestResultMessage(status, m_currentSuite.getSuiteName(),
76 | m_currentTest.getTestName(), m_className, attributes.getValue(ATTR_NAME),
77 | attributes.getValue(ATTR_DESC),
78 | attributes.getValue(ATTR_DESC),
79 | new String[0], /* no parameters, filled later */
80 | 0, Long.parseLong(attributes.getValue(ATTR_DURATION_MS)),
81 | "" /* stack trace, filled later */,
82 | m_invocationCount, m_currentInvocationCount);
83 | m_suiteMethodCount++;
84 | m_testMethodCount++;
85 | if (status == ITestResult.SUCCESS) m_passed++;
86 | else if (status == ITestResult.FAILURE) m_failed++;
87 | else if (status == ITestResult.SKIP) m_skipped++;
88 | } else if (TAG_PARAMS.equals(qName)) {
89 | m_params = Lists.newArrayList();
90 | }
91 | }
92 |
93 | @Override
94 | public void characters(char[] ch, int start, int length) {
95 | if (m_params != null) {
96 | String string = new String(ch, start, length);
97 | String parameter = string;
98 | if (parameter.trim().length() != 0) {
99 | m_params.add(parameter);
100 | }
101 | }
102 | }
103 |
104 | @Override
105 | public void endElement (String uri, String localName, String qName) {
106 | if (TAG_SUITE.equals(qName)) {
107 | m_suiteListener.onFinish(new SuiteMessage(null, false /* end */, m_suiteMethodCount));
108 | m_currentSuite = null;
109 | } else if (TAG_TEST.equals(qName)) {
110 | m_currentTest = new TestMessage(false /* start */, m_currentSuite.getSuiteName(),
111 | null, m_testMethodCount,
112 | m_passed, m_failed, m_skipped, 0);
113 | m_testMethodCount = 0;
114 | m_testListener.onFinish(m_currentTest);
115 | } else if (TAG_CLASS.equals(qName)) {
116 | m_className = null;
117 | } else if (TAG_TEST_METHOD.equals(qName)) {
118 | switch(m_currentTestResult.getResult()) {
119 | case ITestResult.SUCCESS:
120 | m_testListener.onTestSuccess(m_currentTestResult);
121 | break;
122 | case ITestResult.FAILURE:
123 | m_testListener.onTestFailure(m_currentTestResult);
124 | break;
125 | case ITestResult.SKIP:
126 | m_testListener.onTestSkipped(m_currentTestResult);
127 | break;
128 | default:
129 | p("Ignoring test status:" + m_currentTestResult.getResult());
130 | }
131 | }
132 | else if (TAG_PARAMS.equals(qName)) {
133 | String[] params = new String[m_params.size()];
134 | for (int i = 0; i < m_params.size(); i++) {
135 | // The parameters are encoded as type:value. Since we only care about the
136 | // value (and we don't receive the type anyway), use a dummy character in
137 | // its place
138 | params[i] = "@:" + m_params.get(i);
139 | }
140 | m_currentTestResult.setParameters(params);
141 | m_params = null;
142 | }
143 | }
144 |
145 | private static void p(String string) {
146 | if (false) {
147 | System.out.println("[ResultContentHandler] " + string);
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/remote/src/main/java/org/testng/xml/ResultXMLParser.java:
--------------------------------------------------------------------------------
1 | package org.testng.xml;
2 |
3 | import java.io.InputStream;
4 | import java.lang.reflect.Field;
5 | import java.lang.reflect.Method;
6 |
7 | import org.testng.TestNGException;
8 | import org.testng.remote.strprotocol.IRemoteSuiteListener;
9 | import org.testng.remote.strprotocol.IRemoteTestListener;
10 | import org.xml.sax.helpers.DefaultHandler;
11 |
12 | /**
13 | * Parses testng-result.xml.
14 | *
15 | * @see ResultContentHandler
16 | *
17 | * @author Cedric Beust
18 | */
19 | public class ResultXMLParser extends XMLParser