├── .editorconfig
├── .github
├── maven-cd-settings.xml
├── maven-ci-settings.xml
└── workflows
│ ├── ci-4.x.yml
│ ├── ci-5.x-stable.yml
│ ├── ci-5.x.yml
│ ├── ci-matrix-5.x.yml
│ ├── ci.yml
│ └── deploy.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── asciidoc
│ └── index.adoc
├── java
│ ├── examples
│ │ ├── Examples.java
│ │ ├── LifecycleExampleTest.java
│ │ ├── RunTestOnContextExampleTest.java
│ │ └── package-info.java
│ ├── io
│ │ └── vertx
│ │ │ └── junit5
│ │ │ ├── Checkpoint.java
│ │ │ ├── CountingCheckpoint.java
│ │ │ ├── ParameterClosingConsumer.java
│ │ │ ├── RunTestOnContext.java
│ │ │ ├── ScopedObject.java
│ │ │ ├── Timeout.java
│ │ │ ├── VertxExtension.java
│ │ │ ├── VertxExtensionParameterProvider.java
│ │ │ ├── VertxParameterProvider.java
│ │ │ ├── VertxTestContext.java
│ │ │ ├── VertxTestContextParameterProvider.java
│ │ │ └── package-info.java
│ └── module-info.java
└── resources
│ └── META-INF
│ └── services
│ └── io.vertx.junit5.VertxExtensionParameterProvider
└── test
└── java
├── io
└── vertx
│ └── junit5
│ └── tests
│ ├── AbstractTest.java
│ ├── AsyncBeforeAllTest.java
│ ├── AsyncBeforeCombinedTest.java
│ ├── AsyncBeforeEachTest.java
│ ├── ConcreteTest.java
│ ├── CountingCheckpointTest.java
│ ├── CustomizedRunOnContextExtensionTest.java
│ ├── IntegrationTest.java
│ ├── RunOnContextExtensionTest.java
│ ├── StaticRunOnContextExtensionTest.java
│ ├── VertxExtensionCompleteLifecycleInjectionTest.java
│ ├── VertxExtensionTest.java
│ ├── VertxParameterProviderTest.java
│ └── VertxTestContextTest.java
└── module-info.java
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | trim_trailing_whitespace = true
8 | end_of_line = lf
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.github/maven-cd-settings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | false
20 |
21 |
22 |
23 | vertx-snapshots-repository
24 | ${env.VERTX_NEXUS_USERNAME}
25 | ${env.VERTX_NEXUS_PASSWORD}
26 |
27 |
28 |
29 |
30 |
31 | google-mirror
32 |
33 | true
34 |
35 |
36 |
37 | google-maven-central
38 | GCS Maven Central mirror EU
39 | https://maven-central.storage-download.googleapis.com/maven2/
40 |
41 | true
42 |
43 |
44 | false
45 |
46 |
47 |
48 |
49 |
50 | google-maven-central
51 | GCS Maven Central mirror
52 | https://maven-central.storage-download.googleapis.com/maven2/
53 |
54 | true
55 |
56 |
57 | false
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/.github/maven-ci-settings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | false
20 |
21 |
22 |
23 | google-mirror
24 |
25 | true
26 |
27 |
28 |
29 | google-maven-central
30 | GCS Maven Central mirror EU
31 | https://maven-central.storage-download.googleapis.com/maven2/
32 |
33 | true
34 |
35 |
36 | false
37 |
38 |
39 |
40 |
41 |
42 | google-maven-central
43 | GCS Maven Central mirror
44 | https://maven-central.storage-download.googleapis.com/maven2/
45 |
46 | true
47 |
48 |
49 | false
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/.github/workflows/ci-4.x.yml:
--------------------------------------------------------------------------------
1 | name: vertx-junit5 (4.x)
2 | on:
3 | schedule:
4 | - cron: '0 4 * * *'
5 | jobs:
6 | CI:
7 | strategy:
8 | matrix:
9 | include:
10 | - os: ubuntu-latest
11 | jdk: 8
12 | - os: ubuntu-latest
13 | jdk: 17
14 | uses: ./.github/workflows/ci.yml
15 | with:
16 | branch: 4.x
17 | jdk: ${{ matrix.jdk }}
18 | os: ${{ matrix.os }}
19 | secrets: inherit
20 | Deploy:
21 | if: ${{ github.repository_owner == 'eclipse-vertx' && (github.event_name == 'push' || github.event_name == 'schedule') }}
22 | needs: CI
23 | uses: ./.github/workflows/deploy.yml
24 | with:
25 | branch: 4.x
26 | jdk: 8
27 | secrets: inherit
28 |
--------------------------------------------------------------------------------
/.github/workflows/ci-5.x-stable.yml:
--------------------------------------------------------------------------------
1 | name: vertx-junit5 (5.x-stable)
2 | on:
3 | push:
4 | branches:
5 | - '5.[0-9]+'
6 | pull_request:
7 | branches:
8 | - '5.[0-9]+'
9 | schedule:
10 | - cron: '0 6 * * *'
11 | jobs:
12 | CI-CD:
13 | uses: ./.github/workflows/ci-matrix-5.x.yml
14 | secrets: inherit
15 | with:
16 | branch: ${{ github.event_name == 'schedule' && vars.VERTX_5_STABLE_BRANCH || github.event.pull_request.head.sha || github.ref_name }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci-5.x.yml:
--------------------------------------------------------------------------------
1 | name: vertx-junit5 (5.x)
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - master
9 | schedule:
10 | - cron: '0 5 * * *'
11 | jobs:
12 | CI-CD:
13 | uses: ./.github/workflows/ci-matrix-5.x.yml
14 | secrets: inherit
15 | with:
16 | branch: ${{ github.event.pull_request.head.sha || github.ref_name }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci-matrix-5.x.yml:
--------------------------------------------------------------------------------
1 | name: CI matrix (5.x)
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jobs:
9 | CI:
10 | strategy:
11 | matrix:
12 | include:
13 | - os: ubuntu-latest
14 | jdk: 11
15 | - os: ubuntu-latest
16 | jdk: 21
17 | uses: ./.github/workflows/ci.yml
18 | with:
19 | branch: ${{ inputs.branch }}
20 | jdk: ${{ matrix.jdk }}
21 | os: ${{ matrix.os }}
22 | secrets: inherit
23 | Deploy:
24 | if: ${{ github.repository_owner == 'eclipse-vertx' && (github.event_name == 'push' || github.event_name == 'schedule') }}
25 | needs: CI
26 | uses: ./.github/workflows/deploy.yml
27 | with:
28 | branch: ${{ inputs.branch }}
29 | jdk: 11
30 | secrets: inherit
31 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jdk:
9 | default: 8
10 | type: string
11 | os:
12 | default: ubuntu-latest
13 | type: string
14 | jobs:
15 | Test:
16 | name: Run tests
17 | runs-on: ${{ inputs.os }}
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | ref: ${{ inputs.branch }}
23 | - name: Install JDK
24 | uses: actions/setup-java@v2
25 | with:
26 | java-version: ${{ inputs.jdk }}
27 | distribution: temurin
28 | - name: Run tests
29 | run: mvn -s .github/maven-ci-settings.xml -q clean verify -B
30 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 | on:
3 | workflow_call:
4 | inputs:
5 | branch:
6 | required: true
7 | type: string
8 | jdk:
9 | default: 8
10 | type: string
11 | jobs:
12 | Deploy:
13 | name: Deploy to OSSRH
14 | runs-on: ubuntu-latest
15 | env:
16 | VERTX_NEXUS_USERNAME: ${{ secrets.VERTX_NEXUS_USERNAME }}
17 | VERTX_NEXUS_PASSWORD: ${{ secrets.VERTX_NEXUS_PASSWORD }}
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | ref: ${{ inputs.branch }}
23 | - name: Install JDK
24 | uses: actions/setup-java@v2
25 | with:
26 | java-version: ${{ inputs.jdk }}
27 | distribution: temurin
28 | - name: Get project version
29 | run: echo "PROJECT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -q -DforceStdout | grep -v '\[')" >> $GITHUB_ENV
30 | - name: Maven deploy
31 | if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
32 | run: mvn deploy -s .github/maven-cd-settings.xml -DskipTests -B
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 | *.iml
4 | .DS_Store
5 | .classpath
6 | .project
7 | .settings/
8 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-vertx/vertx-junit5/c9b97c8497e53ff65da831cf3e3b75464b7963e1/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/eclipse-vertx/vertx-junit5/actions/workflows/ci-5.x.yml)
2 | [](https://github.com/eclipse-vertx/vertx-codegen/actions/workflows/ci-4.x.yml)
3 |
4 | # Vert.x JUnit 5 integration
5 |
6 | This module offers integration and support for writing Vert.x tests with JUnit 5.
7 |
8 | ## Documentation
9 |
10 | * [Manual](https://vertx.io/docs/vertx-junit5/java/)
11 | * [API](https://vertx.io/docs/apidocs/)
12 |
13 | ## License
14 |
15 | Copyright (c) 2018 Red Hat, Inc.
16 |
17 | Licensed under the Apache License, Version 2.0 (the "License");
18 | you may not use this file except in compliance with the License.
19 | You may obtain a copy of the License at
20 |
21 | http://www.apache.org/licenses/LICENSE-2.0
22 |
23 | Unless required by applicable law or agreed to in writing, software
24 | distributed under the License is distributed on an "AS IS" BASIS,
25 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 | See the License for the specific language governing permissions and
27 | limitations under the License.
28 |
29 | Originally written by [Julien Ponge](https://julien.ponge.org/).
30 |
--------------------------------------------------------------------------------
/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 | # Maven2 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 /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | if [ "$MVNW_VERBOSE" = true ]; then
205 | echo $MAVEN_PROJECTBASEDIR
206 | fi
207 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
208 |
209 | # For Cygwin, switch paths to Windows format before running java
210 | if $cygwin; then
211 | [ -n "$M2_HOME" ] &&
212 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
213 | [ -n "$JAVA_HOME" ] &&
214 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
215 | [ -n "$CLASSPATH" ] &&
216 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
217 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
218 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
219 | fi
220 |
221 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
222 |
223 | exec "$JAVACMD" \
224 | $MAVEN_OPTS \
225 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
226 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
227 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
228 |
--------------------------------------------------------------------------------
/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 Maven2 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 key stroke 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 my 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 "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\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 |
121 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
123 |
124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
125 | if ERRORLEVEL 1 goto error
126 | goto end
127 |
128 | :error
129 | set ERROR_CODE=1
130 |
131 | :end
132 | @endlocal & set ERROR_CODE=%ERROR_CODE%
133 |
134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
138 | :skipRcPost
139 |
140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
142 |
143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
144 |
145 | exit /B %ERROR_CODE%
146 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 | 4.0.0
18 | jar
19 |
20 |
21 | io.vertx
22 | vertx5-parent
23 | 12
24 |
25 |
26 | vertx-junit5
27 | 5.1.0-SNAPSHOT
28 |
29 | Vert.x JUnit 5 support :: Core
30 |
31 |
32 | scm:git:git@github.com:eclipse-vertx/vertx-junit5.git
33 | scm:git:git@github.com:eclipse-vertx/vertx-junit5.git
34 | git@github.com:eclipse-vertx/vertx-junit5.git
35 |
36 |
37 |
38 | 5.9.3
39 | 1.0.0
40 | 3.24.2
41 | 1.2.1
42 |
43 |
44 |
45 |
46 |
47 | io.vertx
48 | vertx-dependencies
49 | ${project.version}
50 | pom
51 | import
52 |
53 |
54 | org.junit
55 | junit-bom
56 | ${junit-jupiter.version}
57 | pom
58 | import
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | io.vertx
67 | vertx-codegen-api
68 | true
69 |
70 |
71 | io.vertx
72 | vertx-codegen-json
73 | true
74 |
75 |
76 | io.vertx
77 | vertx-docgen-api
78 | true
79 |
80 |
81 |
82 | io.vertx
83 | vertx-core
84 |
85 |
86 |
87 | org.junit.jupiter
88 | junit-jupiter-api
89 | compile
90 |
91 |
92 | org.junit.jupiter
93 | junit-jupiter-params
94 | compile
95 |
96 |
97 | org.junit.jupiter
98 | junit-jupiter-engine
99 | runtime
100 |
101 |
102 |
103 | org.junit.jupiter
104 | junit-jupiter
105 | test
106 |
107 |
108 | org.junit.platform
109 | junit-platform-launcher
110 | test
111 |
112 |
113 |
114 | com.github.stefanbirkner
115 | system-lambda
116 | ${system-lamda.version}
117 | test
118 |
119 |
120 |
121 | org.assertj
122 | assertj-core
123 | ${assertj-core.version}
124 | provided
125 | true
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | maven-compiler-plugin
134 |
135 |
136 | default-compile
137 |
138 |
139 |
140 | io.vertx
141 | vertx-codegen
142 | processor
143 |
144 |
145 | io.vertx
146 | vertx-docgen-processor
147 | processor
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | maven-surefire-plugin
156 |
157 |
158 | --add-opens java.base/java.util=system.lambda
159 | programmatic
160 |
161 |
162 |
163 |
164 |
165 |
166 | maven-assembly-plugin
167 |
168 |
169 | package-docs
170 |
171 | single
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | java17-running-test-with-strong-encapsulation
182 |
183 | 17
184 |
185 |
186 |
187 |
188 | org.apache.maven.plugins
189 | maven-surefire-plugin
190 |
191 | programmatic
192 | --add-opens=java.base/java.util=ALL-UNNAMED
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/src/main/asciidoc/index.adoc:
--------------------------------------------------------------------------------
1 | = Vert.x JUnit 5 integration
2 |
3 | This module offers integration and support for writing Vert.x tests with JUnit 5.
4 |
5 | == Use it in your build
6 |
7 | To use this component, add the following dependency to the dependencies section of your build descriptor:
8 |
9 | * Maven (in your `pom.xml`):
10 |
11 | [source,xml,subs="+attributes"]
12 | ----
13 |
14 | io.vertx
15 | vertx-junit5
16 | ${maven.version}
17 |
18 | ----
19 |
20 | * Gradle (in your `build.gradle` file):
21 |
22 | [source,groovy,subs="+attributes"]
23 | ----
24 | compile io.vertx:vertx-junit5:${maven.version}
25 | ----
26 |
27 | == Why testing asynchronous code is different
28 |
29 | Testing asynchronous operations requires more tools than what a test harness like JUnit provides.
30 | Let us consider a typical Vert.x creation of a HTTP server, and put it into a JUnit test:
31 |
32 | [source,java]
33 | ----
34 | {@link examples.Examples.ATest}
35 | ----
36 |
37 | There are issues here since `listen` does not block as it tries to start a HTTP server asynchronously.
38 | We cannot simply assume that the server has properly started upon a `listen` invocation return.
39 | Also:
40 |
41 | 1. the callback passed to `listen` will be executed from a Vert.x event loop thread, which is different from the thread that runs the JUnit test, and
42 | 2. right after calling `listen`, the test exits and is being considered to be passed, while the HTTP server may not even have finished starting, and
43 | 3. since the `listen` callback executes on a different thread than the one executing the test, then any exception such as one thrown by a failed assertion cannot be capture by the JUnit runner.
44 |
45 | == A test context for asynchronous executions
46 |
47 | The first contribution of this module is a {@link io.vertx.junit5.VertxTestContext} object that:
48 |
49 | 1. allows waiting for operations in other threads to notify of completion, and
50 | 2. supports assertion failures to be received to mark a test as failed.
51 |
52 | Here is a very basic usage:
53 |
54 | [source,java]
55 | ----
56 | {@link examples.Examples.BTest}
57 | ----
58 |
59 | <1> {@link io.vertx.junit5.VertxTestContext#succeedingThenComplete} returns an asynchronous result handler that is expected to succeed and then make the test context pass.
60 | <2> {@link io.vertx.junit5.VertxTestContext#awaitCompletion} has the semantics of a `java.util.concurrent.CountDownLatch`, and returns `false` if the waiting delay expired before the test passed.
61 | <3> If the context captures a (potentially asynchronous) error, then after completion we must throw the failure exception to make the test fail.
62 |
63 | == Use any assertion library
64 |
65 | This module does not make any assumption on the assertion library that you should be using.
66 | You can use plain JUnit assertions, http://joel-costigliola.github.io/assertj/[AssertJ], etc.
67 |
68 | To make assertions in asynchronous code and make sure that {@link io.vertx.junit5.VertxTestContext} is notified of potential failures, you need to wrap them with a call to {@link io.vertx.junit5.VertxTestContext#verify}, {@link io.vertx.junit5.VertxTestContext#succeeding(io.vertx.core.Handler)}, or {@link io.vertx.junit5.VertxTestContext#failing(io.vertx.core.Handler)}:
69 |
70 | [source,java]
71 | ----
72 | {@link examples.Examples#usingVerify}
73 | ----
74 |
75 | The useful methods in {@link io.vertx.junit5.VertxTestContext} are the following:
76 |
77 | * {@link io.vertx.junit5.VertxTestContext#completeNow} and {@link io.vertx.junit5.VertxTestContext#failNow} to notify of a success or failure
78 | * {@link io.vertx.junit5.VertxTestContext#succeedingThenComplete} to provide `Handler>` handlers that expect a success and then completes the test context
79 | * {@link io.vertx.junit5.VertxTestContext#failingThenComplete} to provide `Handler>` handlers that expect a failure and then completes the test context
80 | * {@link io.vertx.junit5.VertxTestContext#succeeding} to provide `Handler>` handlers that expect a success and pass the result to another callback, any exception thrown from the callback is considered as a test failure
81 | * {@link io.vertx.junit5.VertxTestContext#failing} to provide `Handler>` handlers that expect a failure and pass the exception to another callback, any exception thrown from the callback is considered as a test failure
82 | * {@link io.vertx.junit5.VertxTestContext#verify} to perform assertions, any exception thrown from the code block is considered as a test failure.
83 |
84 | WARNING: Unlike `succeedingThenComplete` and `failingThenComplete`, calling `succeeding` and `failing` methods can only make a test fail (e.g., `succeeding` gets a failed asynchronous result).
85 | To make a test pass you still need to call `completeNow`, or use checkpoints as explained below.
86 |
87 | == Checkpoint when there are multiple success conditions
88 |
89 | Many tests can be marked as passed by simply calling {@link io.vertx.junit5.VertxTestContext#completeNow} at some point of the execution.
90 | That being said there are also many cases where the success of a test depends on different asynchronous parts to be validated.
91 |
92 | You can use checkpoints to flag some execution points to be passed.
93 | A {@link io.vertx.junit5.Checkpoint} can require a single flagging, or multiple flags.
94 | When all checkpoints have been flagged, then the corresponding {@link io.vertx.junit5.VertxTestContext} makes the test pass.
95 |
96 | Here is an example with checkpoints on the HTTP server being started, 10 HTTP requests having being responded, and 10 HTTP client requests having been made:
97 |
98 | [source,java]
99 | ----
100 | {@link examples.Examples#checkpointing}
101 | ----
102 |
103 | TIP: Checkpoints should be created only from the test case main thread, not from Vert.x asynchronous event callbacks.
104 |
105 | == Integration with JUnit 5
106 |
107 | JUnit 5 provides a different model compared to the previous versions.
108 |
109 | === Test methods
110 |
111 | The Vert.x integration is primarily done using the {@link io.vertx.junit5.VertxExtension} class, and using test parameter injection of `Vertx` and `VertxTestContext` instances:
112 |
113 | [source,java]
114 | ----
115 | {@link examples.Examples.CTest.SomeTest}
116 | ----
117 |
118 | NOTE: The `Vertx` instance is not clustered and has the default configuration.
119 | If you need something else then just don't use injection on that parameter and prepare a `Vertx` object by yourself.
120 |
121 | The test is automatically wrapped around the {@link io.vertx.junit5.VertxTestContext} instance lifecycle, so you don't need to insert {@link io.vertx.junit5.VertxTestContext#awaitCompletion} calls yourself:
122 |
123 | [source,java]
124 | ----
125 | {@link examples.Examples.DTest.SomeTest}
126 | ----
127 |
128 | You can use it with standard JUnit annotations such as `@RepeatedTest` or lifecycle callbacks annotations:
129 |
130 | [source,java]
131 | ----
132 | {@link examples.Examples.ETest.SomeTest}
133 | ----
134 |
135 | It is also possible to customize the default {@link io.vertx.junit5.VertxTestContext} timeout using the {@link io.vertx.junit5.Timeout} annotation either on test classes or methods:
136 |
137 | [source,java]
138 | ----
139 | {@link examples.Examples.FTest.SomeTest}
140 | ----
141 |
142 | === Lifecycle methods
143 |
144 | JUnit 5 provides several user-defined lifecycle methods annotated with `@BeforeAll`, `@BeforeEach`, `@AfterEach` and `@AfterAll`.
145 |
146 | These methods can request the injection of `Vertx` instances.
147 | By doing so, they are likely to perform asynchronous operations with the `Vertx` instance, so they can request the injection of a `VertxTestContext` instance to ensure that the JUnit runner waits for them to complete, and report possible errors.
148 |
149 | Here is an example:
150 |
151 | [source,java]
152 | ----
153 | {@link examples.LifecycleExampleTest}
154 | ----
155 |
156 | ==== Scope of `VertxTestContext` objects
157 |
158 | Since these objects help waiting for asynchronous operations to complete, a new instance is created for any `@Test`, `@BeforeAll`, `@BeforeEach`, `@AfterEach` and `@AfterAll` method.
159 |
160 | ==== Scope of `Vertx` objects
161 |
162 | The scope of a `Vertx` object depends on which lifecycle method in the http://junit.org/junit5/docs/current/user-guide/#extensions-execution-order[JUnit relative execution order] first required a new instance to be created.
163 | Generally-speaking, we respect the JUnit extension scoping rules, but here are the specifications.
164 |
165 | 1. If a parent test context already had a `Vertx` instance, it is being reused in children extension test contexts.
166 | 2. Injecting in a `@BeforeAll` method creates a new instance that is being shared for injection in all subsequent test and lifecycle methods.
167 | 3. Injecting in a `@BeforeEach` with no parent context or previous `@BeforeAll` injection creates a new instance shared with the corresponding test and `AfterEach` method(s).
168 | 4. When no instance exists before running a test method, an instance is created for that test (and only for that test).
169 |
170 | ==== Configuring `Vertx` instances
171 |
172 | By default, the `Vertx` objects get created with `Vertx.vertx()`, using the default settings for `Vertx`.
173 | However, you have the ability to configure `VertxOptions` to suit your needs.
174 | A typical use case would be "extending blocking timeout warning for debugging".
175 | To configure the `Vertx` object you must:
176 |
177 | 1. create a json file with the `VertxOptions` in https://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html#VertxOptions-io.vertx.core.json.JsonObject-[json format]
178 | 2. create an environment variable `VERTX_PARAMETER_FILENAME`, or a system property `vertx.parameter.filename`, pointing to that file
179 |
180 | TIP: The environment variable value takes precedence over the system property value, if both are present.
181 |
182 | Example file content for extended timeouts:
183 |
184 | [source,json]
185 | {
186 | "blockedThreadCheckInterval" : 5,
187 | "blockedThreadCheckIntervalUnit" : "MINUTES",
188 | "maxEventLoopExecuteTime" : 360,
189 | "maxEventLoopExecuteTimeUnit" : "SECONDS"
190 | }
191 |
192 | With these conditions met, the `Vertx` object will be created with the configured options
193 |
194 | ==== Closing and removal of `Vertx` objects
195 |
196 | Injected `Vertx` objects are being automatically closed and removed from their corresponding scopes.
197 |
198 | For instance if a `Vertx` object is created for the scope of a test method, it is being closed after the test completes.
199 | Similarly, when it is being created by a `@BeforeEach` method, it is being closed after possible `@AfterEach` methods have completed.
200 |
201 | == Support for additional parameter types
202 |
203 | The Vert.x JUnit 5 extension is extensible: you can add more types through the
204 | {@link io.vertx.junit5.VertxExtensionParameterProvider} service provider interface.
205 |
206 | If you use RxJava, instead of `io.vertx.core.Vertx` you can inject:
207 |
208 | * `io.vertx.rxjava3.core.Vertx`, or
209 | * `io.vertx.reactivex.core.Vertx`, or
210 | * `io.vertx.rxjava.core.Vertx`.
211 |
212 | To do so, add the corresponding library to your project:
213 |
214 | * `io.vertx:vertx-junit5-rx-java3`, or
215 | * `io.vertx:vertx-junit5-rx-java2`, or
216 | * `io.vertx:vertx-junit5-rx-java`.
217 |
218 | On Reactiverse you can find a growing collection of extensions for `vertx-junit5` that integrates with Vert.x stack in the `reactiverse-junit5-extensions` project:
219 | https://github.com/reactiverse/reactiverse-junit5-extensions.
220 |
221 | == Parameter ordering
222 |
223 | It may be the case that a parameter type has to be placed before another parameter.
224 | For instance the Web Client support in the `reactiverse-junit5-extensions` project requires that the `Vertx` argument is before the `WebClient` argument.
225 | This is because the `Vertx` instance needs to exist to create the `WebClient`.
226 |
227 | It is expected that parameter providers throw meaningful exceptions to let users know of possible ordering constraints.
228 |
229 | In any case it is a good idea to have the `Vertx` parameter first, and the next parameters in the order of what you'd need to create them manually.
230 |
231 | == Parameterized tests with `@MethodSource`
232 |
233 | You can use parameterized tests with `@MethodSource` with vertx-junit5. Therefore you need to declare the method source parameters before the vertx test parameters in the method definition.
234 |
235 | [source,java]
236 | ----
237 | {@link examples.Examples.PTest.SomeTest}
238 | ----
239 |
240 | The same holds for the other `ArgumentSources`.
241 | See the section `Formal Parameter List` in the API doc of
242 | https://junit.org/junit5/docs/current/api/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html[ParameterizedTest]
243 |
244 | == Running tests on a Vert.x context
245 |
246 | By default the thread invoking the test methods is the JUnit thread.
247 | The {@link io.vertx.junit5.RunTestOnContext} extension can be used to alter this behavior by running test methods on a Vert.x event-loop thread.
248 |
249 | CAUTION: Keep in mind that you must not block the event loop when using this extension.
250 |
251 | For this purpose, the extension needs a {@link io.vertx.core.Vertx} instance.
252 | By default, it creates one automatically but you can provide options for configuration or a supplier method.
253 |
254 | The {@link io.vertx.core.Vertx} instance can be retrieved when the test is running.
255 |
256 | [source,java]
257 | ----
258 | {@link examples.RunTestOnContextExampleTest}
259 | ----
260 |
261 | When used as a `@RegisterExtension` instance field, a new {@link io.vertx.core.Vertx} object and {@link io.vertx.core.Context} are created for each tested method.
262 | `@BeforeEach` and `@AfterEach` methods are executed on this context.
263 |
264 | When used as a `@RegisterExtension` static field, a single {@link io.vertx.core.Vertx} object and {@link io.vertx.core.Context} are created for all the tested methods.
265 | `@BeforeAll` and `@AfterAll` methods are executed on this context too.
266 |
--------------------------------------------------------------------------------
/src/main/java/examples/Examples.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package examples;
18 |
19 | import io.vertx.core.VerticleBase;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.core.http.HttpClient;
22 | import io.vertx.core.http.HttpClientResponse;
23 | import io.vertx.core.http.HttpMethod;
24 | import io.vertx.junit5.Checkpoint;
25 | import io.vertx.junit5.Timeout;
26 | import io.vertx.junit5.VertxExtension;
27 | import io.vertx.junit5.VertxTestContext;
28 | import org.junit.jupiter.api.BeforeEach;
29 | import org.junit.jupiter.api.Nested;
30 | import org.junit.jupiter.api.RepeatedTest;
31 | import org.junit.jupiter.api.Test;
32 | import org.junit.jupiter.api.extension.ExtendWith;
33 | import org.junit.jupiter.params.ParameterizedTest;
34 | import org.junit.jupiter.params.provider.Arguments;
35 | import org.junit.jupiter.params.provider.MethodSource;
36 |
37 | import java.util.concurrent.TimeUnit;
38 | import java.util.stream.Stream;
39 |
40 | import static org.assertj.core.api.Assertions.assertThat;
41 |
42 | /**
43 | * @author Julien Ponge
44 | */
45 | @ExtendWith(VertxExtension.class)
46 | public class Examples {
47 |
48 | HttpClient client;
49 |
50 | class ATest {
51 | Vertx vertx = Vertx.vertx();
52 |
53 | @Test
54 | void start_server() {
55 | vertx.createHttpServer()
56 | .requestHandler(req -> req.response().end("Ok"))
57 | .listen(16969).onComplete(ar -> {
58 | // (we can check here if the server started or not)
59 | });
60 | }
61 | }
62 |
63 | @Nested
64 | class ATestNested extends ATest {
65 | @BeforeEach
66 | void setVertx(Vertx vertx) {
67 | this.vertx = vertx;
68 | }
69 | }
70 |
71 | class BTest {
72 | Vertx vertx = Vertx.vertx();
73 |
74 | @Test
75 | void start_http_server() throws Throwable {
76 | VertxTestContext testContext = new VertxTestContext();
77 |
78 | vertx.createHttpServer()
79 | .requestHandler(req -> req.response().end())
80 | .listen(16969)
81 | .onComplete(testContext.succeedingThenComplete()); // <1>
82 |
83 | assertThat(testContext.awaitCompletion(5, TimeUnit.SECONDS)).isTrue(); // <2>
84 | if (testContext.failed()) { // <3>
85 | throw testContext.causeOfFailure();
86 | }
87 | }
88 | }
89 |
90 | @Nested
91 | class BTestNested extends BTest {
92 | @BeforeEach
93 | void setVertx(Vertx vertx) {
94 | this.vertx = vertx;
95 | }
96 | }
97 |
98 | @BeforeEach
99 | void startPlopServer(Vertx vertx, VertxTestContext testContext) {
100 | vertx.createHttpServer()
101 | .requestHandler(request -> request.response().end("Plop"))
102 | .listen(8080).onComplete(testContext.succeedingThenComplete());
103 | }
104 |
105 | @Test
106 | public void usingVerify(Vertx vertx, VertxTestContext testContext) {
107 | client = vertx.createHttpClient();
108 |
109 | client.request(HttpMethod.GET, 8080, "localhost", "/")
110 | .compose(req -> req.send().compose(HttpClientResponse::body))
111 | .onComplete(testContext.succeeding(buffer -> testContext.verify(() -> {
112 | assertThat(buffer.toString()).isEqualTo("Plop");
113 | testContext.completeNow();
114 | })));
115 | }
116 |
117 | @Test
118 | public void checkpointing(Vertx vertx, VertxTestContext testContext) {
119 | Checkpoint serverStarted = testContext.checkpoint();
120 | Checkpoint requestsServed = testContext.checkpoint(10);
121 | Checkpoint responsesReceived = testContext.checkpoint(10);
122 |
123 | vertx.createHttpServer()
124 | .requestHandler(req -> {
125 | req.response().end("Ok");
126 | requestsServed.flag();
127 | })
128 | .listen(8888)
129 | .onComplete(testContext.succeeding(httpServer -> {
130 | serverStarted.flag();
131 |
132 | client = vertx.createHttpClient();
133 | for (int i = 0; i < 10; i++) {
134 | client.request(HttpMethod.GET, 8888, "localhost", "/")
135 | .compose(req -> req.send().compose(HttpClientResponse::body))
136 | .onComplete(testContext.succeeding(buffer -> testContext.verify(() -> {
137 | assertThat(buffer.toString()).isEqualTo("Ok");
138 | responsesReceived.flag();
139 | })));
140 | }
141 | }));
142 | }
143 |
144 | class CTest {
145 |
146 | @ExtendWith(VertxExtension.class)
147 | class SomeTest {
148 |
149 | @Test
150 | void some_test(Vertx vertx, VertxTestContext testContext) {
151 | // (...)
152 | }
153 | }
154 | }
155 |
156 | class HttpServerVerticle extends VerticleBase {
157 | }
158 |
159 | class DTest {
160 |
161 | @ExtendWith(VertxExtension.class)
162 | class SomeTest {
163 |
164 | HttpClient client;
165 |
166 | @Test
167 | void http_server_check_response(Vertx vertx, VertxTestContext testContext) {
168 | vertx.deployVerticle(new HttpServerVerticle()).onComplete(testContext.succeeding(id -> {
169 | client = vertx.createHttpClient();
170 | client.request(HttpMethod.GET, 8080, "localhost", "/")
171 | .compose(req -> req.send().compose(HttpClientResponse::body))
172 | .onComplete(testContext.succeeding(buffer -> testContext.verify(() -> {
173 | assertThat(buffer.toString()).isEqualTo("Plop");
174 | testContext.completeNow();
175 | })));
176 | }));
177 | }
178 | }
179 | }
180 |
181 | @Nested
182 | class DTestNested extends DTest {
183 | @Nested
184 | class SomeTestNested extends DTest.SomeTest {
185 | }
186 | }
187 |
188 | class ETest {
189 |
190 | @ExtendWith(VertxExtension.class)
191 | class SomeTest {
192 |
193 | // Deploy the verticle and execute the test methods when the verticle
194 | // is successfully deployed
195 | @BeforeEach
196 | void deploy_verticle(Vertx vertx, VertxTestContext testContext) {
197 | vertx.deployVerticle(new HttpServerVerticle()).onComplete(testContext.succeedingThenComplete());
198 | }
199 |
200 | HttpClient client;
201 |
202 | // Repeat this test 3 times
203 | @RepeatedTest(3)
204 | void http_server_check_response(Vertx vertx, VertxTestContext testContext) {
205 | client = vertx.createHttpClient();
206 | client.request(HttpMethod.GET, 8080, "localhost", "/")
207 | .compose(req -> req.send().compose(HttpClientResponse::body))
208 | .onComplete(testContext.succeeding(buffer -> testContext.verify(() -> {
209 | assertThat(buffer.toString()).isEqualTo("Plop");
210 | testContext.completeNow();
211 | })));
212 | }
213 | }
214 | }
215 |
216 | @Nested
217 | class ETestNested extends ETest {
218 | @Nested
219 | class SomeTestNested extends ETest.SomeTest {
220 | }
221 | }
222 |
223 | class FTest {
224 |
225 | @ExtendWith(VertxExtension.class)
226 | class SomeTest {
227 |
228 | @Test
229 | @Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
230 | void some_test(Vertx vertx, VertxTestContext context) {
231 | // (...)
232 | }
233 | }
234 | }
235 |
236 | static class PTest {
237 |
238 | @ExtendWith(VertxExtension.class)
239 | static class SomeTest {
240 |
241 | static Stream testData() {
242 | return Stream.of(
243 | Arguments.of("complex object1", 4),
244 | Arguments.of("complex object2", 0)
245 | );
246 | }
247 |
248 | @ParameterizedTest
249 | @MethodSource("testData")
250 | void test2(String obj, int count, Vertx vertx, VertxTestContext testContext) {
251 | // your test code
252 | testContext.completeNow();
253 | }
254 | }
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/src/main/java/examples/LifecycleExampleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package examples;
18 |
19 | import io.vertx.core.VerticleBase;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.junit5.VertxExtension;
22 | import io.vertx.junit5.VertxTestContext;
23 | import org.junit.jupiter.api.AfterEach;
24 | import org.junit.jupiter.api.BeforeEach;
25 | import org.junit.jupiter.api.DisplayName;
26 | import org.junit.jupiter.api.Test;
27 | import org.junit.jupiter.api.extension.ExtendWith;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | /**
32 | * @author Julien Ponge
33 | */
34 | @ExtendWith(VertxExtension.class)
35 | class LifecycleExampleTest {
36 |
37 | @BeforeEach
38 | @DisplayName("Deploy a verticle")
39 | void prepare(Vertx vertx, VertxTestContext testContext) {
40 | vertx.deployVerticle(new SomeVerticle()).onComplete(testContext.succeedingThenComplete());
41 | }
42 |
43 | @Test
44 | @DisplayName("A first test")
45 | void foo(Vertx vertx, VertxTestContext testContext) {
46 | // (...)
47 | testContext.completeNow();
48 | }
49 |
50 | @Test
51 | @DisplayName("A second test")
52 | void bar(Vertx vertx, VertxTestContext testContext) {
53 | // (...)
54 | testContext.completeNow();
55 | }
56 |
57 | @AfterEach
58 | @DisplayName("Check that the verticle is still there")
59 | void lastChecks(Vertx vertx) {
60 | assertThat(vertx.deploymentIDs())
61 | .isNotEmpty()
62 | .hasSize(1);
63 | }
64 | }
65 |
66 | class SomeVerticle extends VerticleBase {
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/examples/RunTestOnContextExampleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package examples;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.junit5.RunTestOnContext;
21 | import io.vertx.junit5.VertxExtension;
22 | import io.vertx.junit5.VertxTestContext;
23 | import org.junit.jupiter.api.AfterEach;
24 | import org.junit.jupiter.api.BeforeEach;
25 | import org.junit.jupiter.api.Test;
26 | import org.junit.jupiter.api.extension.ExtendWith;
27 | import org.junit.jupiter.api.extension.RegisterExtension;
28 |
29 | @ExtendWith(VertxExtension.class)
30 | class RunTestOnContextExampleTest {
31 |
32 | @RegisterExtension
33 | RunTestOnContext rtoc = new RunTestOnContext();
34 |
35 | Vertx vertx;
36 |
37 | @BeforeEach
38 | void prepare(VertxTestContext testContext) {
39 | vertx = rtoc.vertx();
40 | // Prepare something on a Vert.x event-loop thread
41 | // The thread changes with each test instance
42 | testContext.completeNow();
43 | }
44 |
45 | @Test
46 | void foo(VertxTestContext testContext) {
47 | // Test something on the same Vert.x event-loop thread
48 | // that called prepare
49 | testContext.completeNow();
50 | }
51 |
52 | @AfterEach
53 | void cleanUp(VertxTestContext testContext) {
54 | // Clean things up on the same Vert.x event-loop thread
55 | // that called prepare and foo
56 | testContext.completeNow();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/examples/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * @author Julien Ponge
19 | */
20 | @Source
21 | package examples;
22 |
23 | import io.vertx.docgen.Source;
24 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/Checkpoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | /**
20 | * A test completion checkpoint, flagging it advances towards the test context completion.
21 | *
22 | * @author Julien Ponge
23 | * @see VertxTestContext
24 | */
25 | public interface Checkpoint {
26 |
27 | /**
28 | * Flags the checkpoint.
29 | */
30 | void flag();
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/CountingCheckpoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import java.util.Objects;
20 | import java.util.function.Consumer;
21 |
22 | /**
23 | * Checkpoints that count the number of flag invocations.
24 | *
25 | * @author Julien Ponge
26 | */
27 | public final class CountingCheckpoint implements Checkpoint {
28 |
29 | private final Consumer satisfactionTrigger;
30 | private final Consumer overuseTrigger;
31 | private final int requiredNumberOfPasses;
32 | private final StackTraceElement creationCallSite;
33 |
34 | private int numberOfPasses = 0;
35 | private boolean satisfied = false;
36 |
37 | public static CountingCheckpoint laxCountingCheckpoint(Consumer satisfactionTrigger, int requiredNumberOfPasses) {
38 | return new CountingCheckpoint(satisfactionTrigger, null, requiredNumberOfPasses);
39 | }
40 |
41 | public static CountingCheckpoint strictCountingCheckpoint(Consumer satisfactionTrigger, Consumer overuseTrigger, int requiredNumberOfPasses) {
42 | Objects.requireNonNull(overuseTrigger);
43 | return new CountingCheckpoint(satisfactionTrigger, overuseTrigger, requiredNumberOfPasses);
44 | }
45 |
46 | private CountingCheckpoint(Consumer satisfactionTrigger, Consumer overuseTrigger, int requiredNumberOfPasses) {
47 | Objects.requireNonNull(satisfactionTrigger);
48 | if (requiredNumberOfPasses <= 0) {
49 | throw new IllegalArgumentException("A checkpoint needs at least 1 pass");
50 | }
51 | this.creationCallSite = findCallSite();
52 | this.satisfactionTrigger = satisfactionTrigger;
53 | this.overuseTrigger = overuseTrigger;
54 | this.requiredNumberOfPasses = requiredNumberOfPasses;
55 | }
56 |
57 | private StackTraceElement findCallSite() {
58 | StackTraceElement[] stackTrace = new Exception().getStackTrace();
59 | for (int i = stackTrace.length - 1; i >= 0; i--) {
60 | if (stackTrace[i].getClassName().equals(VertxTestContext.class.getName())) {
61 | return stackTrace[i + 1];
62 | }
63 | }
64 | return stackTrace[1]; // This can only happen from direct usage of CountingCheckpoint in tests, so the value is irrelevant
65 | }
66 |
67 | @Override
68 | public void flag() {
69 | boolean callSatisfactionTrigger = false;
70 | boolean callOveruseTrigger = false;
71 | synchronized (this) {
72 | if (satisfied) {
73 | callOveruseTrigger = true;
74 | } else {
75 | numberOfPasses = numberOfPasses + 1;
76 | if (numberOfPasses == requiredNumberOfPasses) {
77 | callSatisfactionTrigger = true;
78 | satisfied = true;
79 | }
80 | }
81 | }
82 | if (callSatisfactionTrigger) {
83 | satisfactionTrigger.accept(this);
84 | } else if (callOveruseTrigger && overuseTrigger != null) {
85 | overuseTrigger.accept(new IllegalStateException("Strict checkpoint flagged too many times"));
86 | }
87 | }
88 |
89 | public boolean satisfied() {
90 | return this.satisfied;
91 | }
92 |
93 | public StackTraceElement creationCallSite() {
94 | return creationCallSite;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/ParameterClosingConsumer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | /**
20 | * A consumer to close extension parameters, like closing a Vert.x context, a web client, etc.
21 | *
22 | * This is useful for parameter providers.
23 | *
24 | * @param Parameter type
25 | * @author Julien Ponge
26 | */
27 | @FunctionalInterface
28 | public interface ParameterClosingConsumer {
29 | void accept(T obj) throws Exception;
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/RunTestOnContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import io.vertx.core.*;
20 | import io.vertx.core.internal.VertxInternal;
21 | import org.junit.jupiter.api.extension.*;
22 |
23 | import java.lang.reflect.Method;
24 | import java.util.concurrent.CompletableFuture;
25 | import java.util.concurrent.ExecutionException;
26 | import java.util.function.Function;
27 | import java.util.function.Supplier;
28 |
29 | /**
30 | * An extension that runs tests on a Vert.x context.
31 | *
32 | * When used as a {@link RegisterExtension} instance field, a new {@link Vertx} object and {@link Context} are created for each tested method.
33 | * {@link org.junit.jupiter.api.BeforeEach} and {@link org.junit.jupiter.api.AfterEach} methods are executed on this context.
34 | *
35 | * When used as a {@link RegisterExtension} static field, a single {@link Vertx} object and {@link Context} are created for all the tested methods.
36 | * {@link org.junit.jupiter.api.BeforeAll} and {@link org.junit.jupiter.api.AfterAll} methods are executed on this context too.
37 | */
38 | public class RunTestOnContext implements BeforeAllCallback, InvocationInterceptor, AfterEachCallback, AfterAllCallback {
39 |
40 | private volatile boolean staticExtension;
41 |
42 | private volatile Vertx vertx;
43 | private volatile Context context;
44 |
45 | private final Supplier> supplier;
46 | private final Function> shutdown;
47 |
48 | /**
49 | * Create an instance of this extension that builds a {@link Vertx} object using default options.
50 | */
51 | public RunTestOnContext() {
52 | this(new VertxOptions(), false);
53 | }
54 |
55 | /**
56 | * Create an instance of this extension that builds a {@link Vertx} object using the specified {@code options}.
57 | *
58 | * When the options hold a {@link io.vertx.core.spi.cluster.ClusterManager} instance, a clustered {@link Vertx} object is created.
59 | *
60 | * @param options the vertx options
61 | */
62 | public RunTestOnContext(VertxOptions options, boolean clustered) {
63 | this(() -> clustered ? Vertx.clusteredVertx(options) : Future.succeededFuture(Vertx.vertx(options)));
64 | }
65 |
66 | /**
67 | * Create an instance of this extension that gets a {@link Vertx} object using the specified asynchronous {@code supplier}.
68 | *
69 | * @param supplier the asynchronous supplier
70 | */
71 | public RunTestOnContext(Supplier> supplier) {
72 | this(supplier, Vertx::close);
73 | }
74 |
75 | /**
76 | * Create an instance of this extension that gets a {@link Vertx} object using the specified asynchronous {@code supplier}.
77 | * The asynchronous {@code shutdown} function is invoked when the {@link Vertx} object is no longer needed.
78 | *
79 | * @param supplier the asynchronous supplier
80 | * @param shutdown the asynchronous shutdown function
81 | */
82 | public RunTestOnContext(Supplier> supplier, Function> shutdown) {
83 | this.supplier = supplier;
84 | this.shutdown = shutdown;
85 | }
86 |
87 | /**
88 | * @return the current Vert.x instance
89 | */
90 | public Vertx vertx() {
91 | return vertx;
92 | }
93 |
94 | @Override
95 | public void beforeAll(ExtensionContext context) {
96 | staticExtension = true;
97 | }
98 |
99 | @Override
100 | public void interceptBeforeAllMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
101 | runOnContext(invocation);
102 | }
103 |
104 | @Override
105 | public void interceptBeforeEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
106 | runOnContext(invocation);
107 | }
108 |
109 | @Override
110 | public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
111 | runOnContext(invocation);
112 | }
113 |
114 | @Override
115 | public T interceptTestFactoryMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
116 | return runOnContext(invocation);
117 | }
118 |
119 | @Override
120 | public void interceptTestTemplateMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
121 | runOnContext(invocation);
122 | }
123 |
124 | @Override
125 | public void interceptDynamicTest(Invocation invocation, ExtensionContext extensionContext) throws Throwable {
126 | runOnContext(invocation);
127 | }
128 |
129 | @Override
130 | public void interceptAfterEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
131 | runOnContext(invocation);
132 | }
133 |
134 | @Override
135 | public void interceptAfterAllMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
136 | runOnContext(invocation);
137 | }
138 |
139 | private T runOnContext(Invocation invocation) throws Throwable {
140 | Future vertxFuture;
141 | if (vertx != null) {
142 | vertxFuture = Future.succeededFuture(vertx);
143 | } else {
144 | vertxFuture = supplier.get().onSuccess(vertx -> {
145 | this.vertx = vertx;
146 | context = ((VertxInternal) vertx).createEventLoopContext();
147 | });
148 | }
149 | CompletableFuture cf = vertxFuture
150 | .compose(ignore -> {
151 | Promise promise = Promise.promise();
152 | context.runOnContext(v -> {
153 | try {
154 | promise.complete(invocation.proceed());
155 | } catch (Throwable e) {
156 | promise.fail(e);
157 | }
158 | });
159 | return promise.future();
160 | })
161 | .toCompletionStage()
162 | .toCompletableFuture();
163 | try {
164 | return cf.get();
165 | } catch (InterruptedException e) {
166 | Thread.currentThread().interrupt();
167 | throw e;
168 | } catch (ExecutionException e) {
169 | throw e.getCause();
170 | }
171 | }
172 |
173 | @Override
174 | public void afterEach(ExtensionContext context) throws Exception {
175 | if (staticExtension) {
176 | return;
177 | }
178 | cleanUp();
179 | }
180 |
181 | private void cleanUp() throws Exception {
182 | context = null;
183 | if (vertx == null) {
184 | return;
185 | }
186 | Future closeFuture = shutdown.apply(vertx);
187 | vertx = null;
188 | try {
189 | closeFuture.toCompletionStage().toCompletableFuture().get();
190 | } catch (InterruptedException e) {
191 | Thread.currentThread().interrupt();
192 | throw e;
193 | } catch (ExecutionException e) {
194 | Throwable cause = e.getCause();
195 | if (cause instanceof Error) {
196 | throw (Error) cause;
197 | }
198 | if (cause instanceof Exception) {
199 | throw (Exception) cause;
200 | }
201 | throw new RuntimeException(cause);
202 | }
203 | }
204 |
205 | @Override
206 | public void afterAll(ExtensionContext context) throws Exception {
207 | cleanUp();
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/ScopedObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import org.junit.jupiter.api.extension.ExtensionContext;
20 |
21 | import java.util.Objects;
22 | import java.util.function.Supplier;
23 |
24 | /**
25 | * A parameter as an object with a scope and that can be closed when the scope exits.
26 | *
27 | * This is useful for parameter providers.
28 | *
29 | * @param Parameter type
30 | * @author Julien Ponge
31 | */
32 | public class ScopedObject implements Supplier, ExtensionContext.Store.CloseableResource {
33 |
34 | private T object;
35 | private final ParameterClosingConsumer cleaner;
36 |
37 | ScopedObject(T object, ParameterClosingConsumer cleaner) {
38 | Objects.requireNonNull(object, "The object cannot be null");
39 | this.object = object;
40 | this.cleaner = cleaner;
41 | }
42 |
43 | @Override
44 | public void close() throws Throwable {
45 | cleaner.accept(object);
46 | }
47 |
48 | @Override
49 | public T get() {
50 | return object;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/Timeout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import java.lang.annotation.ElementType;
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.RetentionPolicy;
22 | import java.lang.annotation.Target;
23 | import java.util.concurrent.TimeUnit;
24 |
25 | /**
26 | * Specify how long {@link VertxTestContext#awaitCompletion(long, TimeUnit)} waits before timing out.
27 | *
28 | * This annotation works on both test methods and test classes.
29 | *
30 | * @author Julien Ponge
31 | * @see VertxTestContext
32 | * @see org.junit.jupiter.api.Test
33 | * @see org.junit.jupiter.api.extension.ExtendWith
34 | */
35 | @Retention(RetentionPolicy.RUNTIME)
36 | @Target({ElementType.METHOD, ElementType.TYPE})
37 | public @interface Timeout {
38 | int value();
39 |
40 | TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/VertxExtension.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License 2.0 which is available at
6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8 | *
9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10 | */
11 |
12 | package io.vertx.junit5;
13 |
14 | import io.vertx.core.Vertx;
15 | import org.junit.jupiter.api.Nested;
16 | import org.junit.jupiter.api.extension.*;
17 | import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
18 | import org.junit.jupiter.api.extension.ExtensionContext.Store;
19 |
20 | import java.lang.reflect.Method;
21 | import java.util.ArrayList;
22 | import java.util.HashMap;
23 | import java.util.Optional;
24 | import java.util.ServiceLoader;
25 | import java.util.concurrent.TimeUnit;
26 | import java.util.concurrent.TimeoutException;
27 | import java.util.function.Supplier;
28 | import java.util.stream.Collectors;
29 |
30 | /**
31 | * JUnit 5 Vert.x extension that allows parameter injection as well as an automatic lifecycle on the {@link VertxTestContext} instance.
32 | *
33 | * The following types can be injected:
34 | *
35 | *
{@link Vertx}
36 | *
{@link VertxTestContext}
37 | *
{@code io.vertx.rxjava.core.Vertx}
38 | *
{@code io.vertx.reactivex.core.Vertx}
39 | *
{@code io.vertx.rxjava3.core.Vertx}
40 | *
41 | *
42 | * @author Julien Ponge
43 | */
44 | public final class VertxExtension implements ParameterResolver, InvocationInterceptor {
45 |
46 | /**
47 | * Default timeout.
48 | */
49 | public static final int DEFAULT_TIMEOUT_DURATION = 30;
50 |
51 | /**
52 | * Default timeout unit.
53 | */
54 | public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;
55 |
56 | /**
57 | * Key for all {@link Vertx} instances, including what shims like RxJava should use.
58 | */
59 | public static final String VERTX_INSTANCE_KEY = "Vertx";
60 |
61 | private static final String TEST_CONTEXT_KEY = "VertxTestContext";
62 |
63 | private static class ContextList extends ArrayList {
64 | /*
65 | * There may be concurrent test contexts to join at a point of time because it is allowed to have several
66 | * user-defined lifecycle event handles (e.g., @BeforeEach, etc).
67 | */
68 | }
69 |
70 | private final HashMap, VertxExtensionParameterProvider>> parameterProviders = new HashMap<>();
71 |
72 | public VertxExtension() {
73 | for (VertxExtensionParameterProvider> parameterProvider : ServiceLoader.load(VertxExtensionParameterProvider.class)) {
74 | parameterProviders.put(parameterProvider.type(), parameterProvider);
75 | }
76 | }
77 |
78 | @Override
79 | public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
80 | return parameterProviders.containsKey(parameterType(parameterContext));
81 | }
82 |
83 | private Class> parameterType(ParameterContext parameterContext) {
84 | return parameterContext.getParameter().getType();
85 | }
86 |
87 | @Override
88 | public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
89 | Class> type = parameterType(parameterContext);
90 | VertxExtensionParameterProvider> parameterProvider = parameterProviders.get(type);
91 |
92 | if (type.equals(VertxTestContext.class)) {
93 | return newTestContext(extensionContext);
94 | }
95 |
96 | if (extensionContext.getParent().isPresent()) {
97 | Store parentStore = store(extensionContext.getParent().get());
98 | if (parentStore.get(parameterProvider.key()) != null) {
99 | return unpack(parentStore.get(parameterProvider.key()));
100 | }
101 | }
102 |
103 | Store store = store(extensionContext);
104 | return unpack(store.getOrComputeIfAbsent(parameterProvider.key(), key -> new ScopedObject(
105 | parameterProvider.newInstance(extensionContext, parameterContext),
106 | parameterProvider.parameterClosingConsumer())));
107 | }
108 |
109 | private static Object unpack(Object object) {
110 | if (object instanceof Supplier>) {
111 | return ((Supplier>) object).get();
112 | }
113 | return object;
114 | }
115 |
116 | private VertxTestContext newTestContext(ExtensionContext extensionContext) {
117 | Store store = store(extensionContext);
118 | ContextList contexts = (ContextList) store.getOrComputeIfAbsent(TEST_CONTEXT_KEY, key -> new ContextList());
119 | VertxTestContext newTestContext = new VertxTestContext();
120 | contexts.add(newTestContext);
121 | return newTestContext;
122 | }
123 |
124 | private Store store(ExtensionContext extensionContext) {
125 | return extensionContext.getStore(Namespace.GLOBAL);
126 | }
127 |
128 | @Override
129 | public void interceptBeforeAllMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
130 | invocation.proceed();
131 | joinActiveTestContexts(extensionContext);
132 | }
133 |
134 | @Override
135 | public void interceptAfterAllMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
136 | invocation.proceed();
137 | joinActiveTestContexts(extensionContext);
138 | }
139 |
140 | @Override
141 | public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
142 | invocation.proceed();
143 | joinActiveTestContexts(extensionContext);
144 | }
145 |
146 | @Override
147 | public void interceptBeforeEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
148 | invocation.proceed();
149 | joinActiveTestContexts(extensionContext);
150 | }
151 |
152 | @Override
153 | public void interceptTestTemplateMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
154 | invocation.proceed();
155 | joinActiveTestContexts(extensionContext);
156 | }
157 |
158 | @Override
159 | public void interceptDynamicTest(Invocation invocation, DynamicTestInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
160 | invocation.proceed();
161 | joinActiveTestContexts(extensionContext);
162 | }
163 |
164 | @Override
165 | public void interceptAfterEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable {
166 | invocation.proceed();
167 | joinActiveTestContexts(extensionContext);
168 | }
169 |
170 | private void joinActiveTestContexts(ExtensionContext extensionContext) throws Exception {
171 | if (extensionContext.getExecutionException().isPresent()) {
172 | return;
173 | }
174 |
175 | ContextList currentContexts = store(extensionContext).remove(TEST_CONTEXT_KEY, ContextList.class);
176 | if (currentContexts != null) {
177 | for (VertxTestContext context : currentContexts) {
178 | int timeoutDuration = DEFAULT_TIMEOUT_DURATION;
179 | TimeUnit timeoutUnit = DEFAULT_TIMEOUT_UNIT;
180 | Optional testMethod = extensionContext.getTestMethod();
181 | if (testMethod.isPresent() && testMethod.get().isAnnotationPresent(Timeout.class)) {
182 | Timeout annotation = extensionContext.getRequiredTestMethod().getAnnotation(Timeout.class);
183 | timeoutDuration = annotation.value();
184 | timeoutUnit = annotation.timeUnit();
185 | } else {
186 | for (
187 | Class> testClass = extensionContext.getRequiredTestClass();
188 | testClass != null;
189 | testClass = testClass.isAnnotationPresent(Nested.class) ? testClass.getEnclosingClass() : null
190 | ) {
191 | if (testClass.isAnnotationPresent(Timeout.class)) {
192 | Timeout annotation = testClass.getAnnotation(Timeout.class);
193 | timeoutDuration = annotation.value();
194 | timeoutUnit = annotation.timeUnit();
195 | break;
196 | }
197 | }
198 | }
199 | if (context.awaitCompletion(timeoutDuration, timeoutUnit)) {
200 | if (context.failed()) {
201 | Throwable throwable = context.causeOfFailure();
202 | if (throwable instanceof Exception) {
203 | throw (Exception) throwable;
204 | } else {
205 | throw new AssertionError(throwable);
206 | }
207 | }
208 | } else {
209 | String message = "The test execution timed out. Make sure your asynchronous code "
210 | + "includes calls to either VertxTestContext#completeNow(), VertxTestContext#failNow() "
211 | + "or Checkpoint#flag()";
212 | message = message + context.unsatisfiedCheckpointCallSites()
213 | .stream()
214 | .map(element -> String.format("-> checkpoint at %s", element))
215 | .collect(Collectors.joining("\n", "\n\nUnsatisfied checkpoints diagnostics:\n", ""));
216 | throw new TimeoutException(message);
217 | }
218 | }
219 | }
220 |
221 | if (extensionContext.getParent().isPresent()) {
222 | joinActiveTestContexts(extensionContext.getParent().get());
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/VertxExtensionParameterProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import org.junit.jupiter.api.extension.ExtensionContext;
20 | import org.junit.jupiter.api.extension.ParameterContext;
21 |
22 | /**
23 | * A {@link VertxExtension} test method parameter provider service provider interface.
24 | *
25 | * You can register new providers by pointing to implementations in the
26 | * {@code META-INF/services/io.vertx.junit5.VertxExtensionParameterProvider} resource.
27 | *
28 | * @param Parameter type
29 | * @author Julien Ponge
30 | */
31 | public interface VertxExtensionParameterProvider {
32 |
33 | /**
34 | * The parameter type.
35 | *
36 | * @return the parameter type
37 | */
38 | Class type();
39 |
40 | /**
41 | * A string to identify the parameter in an extension context.
42 | *
43 | * In most cases it should be a constant.
44 | *
45 | * @return the identifier
46 | */
47 | String key();
48 |
49 | /**
50 | * Provide a new parameter instance.
51 | *
52 | * @param extensionContext the extension context
53 | * @param parameterContext the parameter context
54 | * @return the new instance
55 | */
56 | T newInstance(ExtensionContext extensionContext, ParameterContext parameterContext);
57 |
58 | /**
59 | * A consumer to close the resource.
60 | *
61 | * @return the consumer
62 | */
63 | ParameterClosingConsumer parameterClosingConsumer();
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/VertxParameterProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.core.VertxException;
21 | import io.vertx.core.VertxOptions;
22 | import io.vertx.core.buffer.Buffer;
23 | import io.vertx.core.internal.logging.Logger;
24 | import io.vertx.core.internal.logging.LoggerFactory;
25 | import io.vertx.core.json.JsonObject;
26 | import org.junit.jupiter.api.extension.ExtensionContext;
27 | import org.junit.jupiter.api.extension.ParameterContext;
28 |
29 | import java.nio.file.Files;
30 | import java.nio.file.Path;
31 | import java.nio.file.Paths;
32 | import java.util.concurrent.CountDownLatch;
33 | import java.util.concurrent.TimeoutException;
34 | import java.util.concurrent.atomic.AtomicReference;
35 |
36 | import static io.vertx.junit5.VertxExtension.*;
37 |
38 | public class VertxParameterProvider implements VertxExtensionParameterProvider {
39 |
40 | private static final Logger LOG = LoggerFactory.getLogger(VertxParameterProvider.class);
41 |
42 | // Visible for testing
43 | public static final String VERTX_PARAMETER_FILENAME = "vertx.parameter.filename";
44 | public static final String VERTX_PARAMETER_FILENAME_ENV_VAR = "VERTX_PARAMETER_FILENAME";
45 | public static final String VERTX_PARAMETER_FILENAME_SYS_PROP = "vertx.parameter.filename";
46 |
47 | private static final String DEPRECATION_WARNING = String.format(
48 | "'%s' environment variable is deprecated and will be removed in a future version, use '%s' instead",
49 | VERTX_PARAMETER_FILENAME,
50 | VERTX_PARAMETER_FILENAME_ENV_VAR
51 | );
52 |
53 | @Override
54 | public Class type() {
55 | return Vertx.class;
56 | }
57 |
58 | @Override
59 | public String key() {
60 | return VertxExtension.VERTX_INSTANCE_KEY;
61 | }
62 |
63 | @Override
64 | public Vertx newInstance(ExtensionContext extensionContext, ParameterContext parameterContext) {
65 |
66 | final JsonObject parameters = this.getVertxOptions();
67 | final VertxOptions options = new VertxOptions(parameters);
68 | return Vertx.vertx(options);
69 | }
70 |
71 | @Override
72 | public ParameterClosingConsumer parameterClosingConsumer() {
73 | return vertx -> {
74 | CountDownLatch latch = new CountDownLatch(1);
75 | AtomicReference errorBox = new AtomicReference<>();
76 | vertx.close().onComplete(ar -> {
77 | if (ar.failed()) {
78 | errorBox.set(ar.cause());
79 | }
80 | latch.countDown();
81 | });
82 | if (!latch.await(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT)) {
83 | throw new TimeoutException("Closing the Vertx context timed out");
84 | }
85 | Throwable throwable = errorBox.get();
86 | if (throwable != null) {
87 | if (throwable instanceof Exception) {
88 | throw (Exception) throwable;
89 | } else {
90 | throw new VertxException(throwable);
91 | }
92 | }
93 | };
94 | }
95 |
96 | public JsonObject getVertxOptions() {
97 | String optionFileName = System.getenv(VERTX_PARAMETER_FILENAME_ENV_VAR);
98 | if (optionFileName == null) {
99 | optionFileName = System.getProperty(VERTX_PARAMETER_FILENAME_SYS_PROP);
100 | if (optionFileName == null) {
101 | optionFileName = System.getenv(VERTX_PARAMETER_FILENAME);
102 | if (optionFileName != null) {
103 | LOG.warn(DEPRECATION_WARNING);
104 | } else {
105 | return new JsonObject();
106 | }
107 | }
108 | }
109 | try {
110 | Path path = Paths.get(optionFileName);
111 | Buffer content = Buffer.buffer(Files.readAllBytes(path));
112 | return new JsonObject(content);
113 | } catch (Exception e) {
114 | LOG.warn("Failure when reading Vert.x options file, will use default options", e);
115 | return new JsonObject();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/VertxTestContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import io.vertx.core.*;
20 |
21 | import java.util.HashSet;
22 | import java.util.Objects;
23 | import java.util.Set;
24 | import java.util.concurrent.CountDownLatch;
25 | import java.util.concurrent.TimeUnit;
26 | import java.util.stream.Collectors;
27 |
28 | /**
29 | * A test context to wait on the outcomes of asynchronous operations.
30 | *
31 | * @author Julien Ponge
32 | */
33 | public final class VertxTestContext {
34 |
35 | /**
36 | * Interface for an executable block of assertion code.
37 | *
38 | * @see #verify(ExecutionBlock)
39 | */
40 | @FunctionalInterface
41 | public interface ExecutionBlock {
42 |
43 | void apply() throws Throwable;
44 | }
45 |
46 | // ........................................................................................... //
47 |
48 | private Throwable throwableReference = null;
49 | private boolean done = false;
50 | private final CountDownLatch releaseLatch = new CountDownLatch(1);
51 | private final HashSet checkpoints = new HashSet<>();
52 |
53 | // ........................................................................................... //
54 |
55 | /**
56 | * Check if the context has been marked has failed or not.
57 | *
58 | * @return {@code true} if the context has failed, {@code false} otherwise.
59 | */
60 | public synchronized boolean failed() {
61 | return throwableReference != null;
62 | }
63 |
64 | /**
65 | * Give the cause of failure.
66 | *
67 | * @return the cause of failure, or {@code null} if the test context hasn't failed.
68 | */
69 | public synchronized Throwable causeOfFailure() {
70 | return throwableReference;
71 | }
72 |
73 | /**
74 | * Check if the context has completed.
75 | *
76 | * @return {@code true} if the context has completed, {@code false} otherwise.
77 | */
78 | public synchronized boolean completed() {
79 | return !failed() && (done || releaseLatch.getCount() == 0);
80 | }
81 |
82 | /**
83 | * Gives the call sites of all unsatisfied checkpoints.
84 | *
85 | * @return a set of {@link StackTraceElement} references pointing to the unsatisfied checkpoint call sites.
86 | */
87 | public Set unsatisfiedCheckpointCallSites() {
88 | return checkpoints
89 | .stream()
90 | .filter(checkpoint -> !checkpoint.satisfied())
91 | .map(CountingCheckpoint::creationCallSite)
92 | .collect(Collectors.toSet());
93 | }
94 |
95 | // ........................................................................................... //
96 |
97 | /**
98 | * Complete the test context immediately, making the corresponding test pass.
99 | */
100 | public synchronized void completeNow() {
101 | done = true;
102 | releaseLatch.countDown();
103 | }
104 |
105 | /**
106 | * Make the test context fail immediately, making the corresponding test fail.
107 | *
108 | * @param t the cause of failure.
109 | */
110 | public synchronized void failNow(Throwable t) {
111 | Objects.requireNonNull(t, "The exception cannot be null");
112 | if (throwableReference == null) {
113 | throwableReference = t;
114 | releaseLatch.countDown();
115 | }
116 | }
117 |
118 | /**
119 | * Calls {@link #failNow(Throwable)} with the {@code message}.
120 | *
121 | * @param message the cause of failure
122 | */
123 | public synchronized void failNow(String message) {
124 | failNow(VertxException.noStackTrace(message));
125 | }
126 |
127 | // ........................................................................................... //
128 |
129 | private synchronized void checkpointSatisfied(Checkpoint checkpoint) {
130 | checkpoints.remove(checkpoint);
131 | if (checkpoints.isEmpty()) {
132 | completeNow();
133 | }
134 | }
135 |
136 | /**
137 | * Create a lax checkpoint.
138 | *
139 | * @return a checkpoint that requires 1 pass; more passes are allowed and ignored.
140 | */
141 | public Checkpoint laxCheckpoint() {
142 | return laxCheckpoint(1);
143 | }
144 |
145 | /**
146 | * Create a lax checkpoint.
147 | *
148 | * @param requiredNumberOfPasses the required number of passes to validate the checkpoint.
149 | * @return a checkpoint that requires several passes; more passes than the required number are allowed and ignored.
150 | */
151 | public synchronized Checkpoint laxCheckpoint(int requiredNumberOfPasses) {
152 | if (done) {
153 | throw new IllegalStateException("Context has already been completed");
154 | }
155 | CountingCheckpoint checkpoint = CountingCheckpoint.laxCountingCheckpoint(this::checkpointSatisfied, requiredNumberOfPasses);
156 | checkpoints.add(checkpoint);
157 | return checkpoint;
158 | }
159 |
160 | /**
161 | * Create a strict checkpoint.
162 | *
163 | * @return a checkpoint that requires 1 pass, and makes the context fail if it is called more than once.
164 | */
165 | public Checkpoint checkpoint() {
166 | return checkpoint(1);
167 | }
168 |
169 | /**
170 | * Create a strict checkpoint.
171 | *
172 | * @param requiredNumberOfPasses the required number of passes to validate the checkpoint.
173 | * @return a checkpoint that requires several passes, but no more, or it fails the context.
174 | */
175 | public synchronized Checkpoint checkpoint(int requiredNumberOfPasses) {
176 | if (done) {
177 | throw new IllegalStateException("Context has already been completed");
178 | }
179 | CountingCheckpoint checkpoint = CountingCheckpoint.strictCountingCheckpoint(this::checkpointSatisfied, this::failNow, requiredNumberOfPasses);
180 | checkpoints.add(checkpoint);
181 | return checkpoint;
182 | }
183 |
184 | // ........................................................................................... //
185 |
186 | /**
187 | * Create an asynchronous result handler that expects a success, and passes the value to another handler.
188 | *
189 | * @param nextHandler the value handler to call on success that is expected not to throw a {@link Throwable}.
190 | * @param the asynchronous result type.
191 | * @return the handler.
192 | */
193 | public Handler> succeeding(Handler nextHandler) {
194 | Objects.requireNonNull(nextHandler, "The handler cannot be null");
195 | return ar -> {
196 | if (ar.failed()) {
197 | failNow(ar.cause());
198 | return;
199 | }
200 | try {
201 | nextHandler.handle(ar.result());
202 | } catch (Throwable e) {
203 | failNow(e);
204 | }
205 | };
206 | }
207 |
208 | /**
209 | * Create an asynchronous result handler that expects a failure.
210 | *
211 | * @param the asynchronous result type.
212 | * @return the handler.
213 | * @deprecated Use {@link #failingThenComplete()} or {@link #failing(Handler)}, for example
214 | * failing(e -> checkpoint.flag()), failing(e -> { more testing code }), or
215 | * failing(e -> {}).
216 | */
217 | @Deprecated
218 | public Handler> failing() {
219 | return ar -> {
220 | if (ar.succeeded()) {
221 | failNow(new AssertionError("The asynchronous result was expected to have failed"));
222 | }
223 | };
224 | }
225 |
226 | /**
227 | * Create an asynchronous result handler that expects a failure, and passes the exception to another handler.
228 | *
229 | * @param nextHandler the exception handler to call on failure that is expected not to throw a {@link Throwable}.
230 | * @param the asynchronous result type.
231 | * @return the handler.
232 | */
233 | public Handler> failing(Handler nextHandler) {
234 | Objects.requireNonNull(nextHandler, "The handler cannot be null");
235 | return ar -> {
236 | if (ar.succeeded()) {
237 | failNow(new AssertionError("The asynchronous result was expected to have failed"));
238 | return;
239 | }
240 | try {
241 | nextHandler.handle(ar.cause());
242 | } catch (Throwable e) {
243 | failNow(e);
244 | }
245 | };
246 | }
247 |
248 | /**
249 | * Create an asynchronous result handler that expects a success to then complete the test context.
250 | *
251 | * @param the asynchronous result type.
252 | * @return the handler.
253 | */
254 | public Handler> succeedingThenComplete() {
255 | return ar -> {
256 | if (ar.succeeded()) {
257 | completeNow();
258 | } else {
259 | failNow(ar.cause());
260 | }
261 | };
262 | }
263 |
264 | /**
265 | * Create an asynchronous result handler that expects a success to then complete the test context.
266 | *
267 | * @param the asynchronous result type.
268 | * @return the handler.
269 | * @see #failingThenComplete()
270 | * @deprecated Use {@link #succeedingThenComplete()} instead.
271 | */
272 | @Deprecated
273 | public Handler> completing() {
274 | return succeedingThenComplete();
275 | }
276 |
277 | /**
278 | * Create an asynchronous result handler that expects a failure to then complete the test context.
279 | *
280 | * @param the asynchronous result type.
281 | * @return the handler.
282 | */
283 | public Handler> failingThenComplete() {
284 | return ar -> {
285 | if (ar.succeeded()) {
286 | failNow(new AssertionError("The asynchronous result was expected to have failed"));
287 | return;
288 | }
289 | completeNow();
290 | };
291 | }
292 |
293 | // ........................................................................................... //
294 |
295 | /**
296 | * This method allows you to check if a future is completed.
297 | * It internally creates a checkpoint.
298 | * You can use it in a chain of `Future`.
299 | *
300 | * @param fut The future to assert success
301 | * @return a future with completion result
302 | */
303 | public Future assertComplete(Future fut) {
304 | Promise newPromise = Promise.promise();
305 | fut.onComplete(ar -> {
306 | if (ar.succeeded()) {
307 | newPromise.complete(ar.result());
308 | } else {
309 | Throwable ex = new AssertionError("Future failed with exception: " + ar.cause().getMessage(), ar.cause());
310 | this.failNow(ex);
311 | newPromise.fail(ex);
312 | }
313 | });
314 | return newPromise.future();
315 | }
316 |
317 | /**
318 | * This method allows you to check if a future is failed.
319 | * It internally creates a checkpoint.
320 | * You can use it in a chain of `Future`.
321 | *
322 | * @param fut The future to assert failure
323 | * @return a future with failure result
324 | */
325 | public Future assertFailure(Future fut) {
326 | Promise newPromise = Promise.promise();
327 | fut.onComplete(ar -> {
328 | if (ar.succeeded()) {
329 | Throwable ex = new AssertionError("Future completed with value: " + ar.result());
330 | this.failNow(ex);
331 | newPromise.fail(ex);
332 | } else {
333 | newPromise.fail(ar.cause());
334 | }
335 | });
336 | return newPromise.future();
337 | }
338 |
339 | // ........................................................................................... //
340 |
341 | /**
342 | * Allow verifications and assertions to be made.
343 | *
344 | * This method allows any assertion API to be used.
345 | * The semantic is that the verification is successful when no exception is being thrown upon calling {@code block},
346 | * otherwise the context fails with that exception.
347 | *
348 | * @param block a block of code to execute.
349 | * @return this context.
350 | */
351 | public VertxTestContext verify(ExecutionBlock block) {
352 | Objects.requireNonNull(block, "The block cannot be null");
353 | try {
354 | block.apply();
355 | } catch (Throwable t) {
356 | failNow(t);
357 | }
358 | return this;
359 | }
360 |
361 | // ........................................................................................... //
362 |
363 | /**
364 | * Wait for the completion of the test context.
365 | *
366 | * This method is automatically called by the {@link VertxExtension} when using parameter injection of {@link VertxTestContext}.
367 | * You should only call it when you instantiate this class manually.
368 | *
369 | * @param timeout the timeout.
370 | * @param unit the timeout unit.
371 | * @return {@code true} if the completion or failure happens before the timeout has been reached, {@code false} otherwise.
372 | * @throws InterruptedException when the thread has been interrupted.
373 | */
374 | public boolean awaitCompletion(long timeout, TimeUnit unit) throws InterruptedException {
375 | return failed() || releaseLatch.await(timeout, unit);
376 | }
377 |
378 | // ........................................................................................... //
379 | }
380 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/VertxTestContextParameterProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5;
18 |
19 | import org.junit.jupiter.api.extension.ExtensionContext;
20 | import org.junit.jupiter.api.extension.ParameterContext;
21 |
22 | /**
23 | * Vert.x test context parameter provider holder class.
24 | *
25 | * The implementation does not do anything since that type is a built-in special case, but we need it for the injection
26 | * mechanism to operate.
27 | *
28 | * @author Julien Ponge
29 | */
30 | public class VertxTestContextParameterProvider implements VertxExtensionParameterProvider {
31 |
32 | @Override
33 | public Class type() {
34 | return VertxTestContext.class;
35 | }
36 |
37 | @Override
38 | public String key() {
39 | doNotCallMe();
40 | return null;
41 | }
42 |
43 | @Override
44 | public VertxTestContext newInstance(ExtensionContext extensionContext, ParameterContext parameterContext) {
45 | doNotCallMe();
46 | return null;
47 | }
48 |
49 | @Override
50 | public ParameterClosingConsumer parameterClosingConsumer() {
51 | doNotCallMe();
52 | return null;
53 | }
54 |
55 | private ParameterClosingConsumer doNotCallMe() {
56 | throw new UnsupportedOperationException("VertxTestContext is a built-in special case");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/junit5/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * This module offers support for writing Vert.x tests with JUnit 5.
19 | *
20 | * @author Julien Ponge
21 | */
22 | package io.vertx.junit5;
23 |
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | import org.junit.jupiter.api.extension.ParameterResolver;
2 |
3 | module io.vertx.testing.junit5 {
4 |
5 | requires static io.vertx.docgen;
6 |
7 | requires static org.assertj.core; // Examples
8 |
9 | requires io.vertx.core;
10 | requires io.vertx.core.logging;
11 | requires org.junit.jupiter.params;
12 |
13 | exports io.vertx.junit5;
14 |
15 | uses io.vertx.junit5.VertxExtensionParameterProvider;
16 |
17 | provides ParameterResolver with io.vertx.junit5.VertxExtension;
18 | provides io.vertx.junit5.VertxExtensionParameterProvider with io.vertx.junit5.VertxParameterProvider, io.vertx.junit5.VertxTestContextParameterProvider;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.vertx.junit5.VertxExtensionParameterProvider:
--------------------------------------------------------------------------------
1 | io.vertx.junit5.VertxParameterProvider
2 | io.vertx.junit5.VertxTestContextParameterProvider
3 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/AbstractTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License 2.0 which is available at
6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8 | *
9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10 | */
11 |
12 | package io.vertx.junit5.tests;
13 |
14 | import io.vertx.core.Vertx;
15 | import io.vertx.junit5.VertxTestContext;
16 | import org.junit.jupiter.api.BeforeAll;
17 | import org.junit.jupiter.api.BeforeEach;
18 |
19 | import java.util.concurrent.atomic.AtomicInteger;
20 |
21 | import static org.junit.jupiter.api.Assertions.assertEquals;
22 | import static org.junit.jupiter.api.Assertions.assertTrue;
23 |
24 | public abstract class AbstractTest {
25 |
26 | public static final AtomicInteger counter = new AtomicInteger();
27 |
28 | @BeforeAll
29 | static void superBeforeAll(Vertx vertx, VertxTestContext testContext) {
30 | testContext.verify(() -> expectations(vertx, testContext, 0));
31 | }
32 |
33 | @BeforeEach
34 | void superBeforeEach(Vertx vertx, VertxTestContext testContext) {
35 | testContext.verify(() -> expectations(vertx, testContext, 2));
36 | }
37 |
38 | protected static void expectations(Vertx vertx, VertxTestContext testContext, int expected) {
39 | assertEquals(expected, counter.get());
40 | vertx.setTimer(20, l -> {
41 | testContext.verify(() -> {
42 | assertTrue(counter.compareAndSet(expected, expected + 1));
43 | testContext.completeNow();
44 | });
45 | });
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/AsyncBeforeAllTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License 2.0 which is available at
6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8 | *
9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10 | */
11 | package io.vertx.junit5.tests;
12 |
13 | import io.vertx.core.Vertx;
14 | import io.vertx.junit5.Checkpoint;
15 | import io.vertx.junit5.VertxExtension;
16 | import io.vertx.junit5.VertxTestContext;
17 | import org.junit.jupiter.api.BeforeAll;
18 | import org.junit.jupiter.api.DisplayName;
19 | import org.junit.jupiter.api.Test;
20 | import org.junit.jupiter.api.extension.ExtendWith;
21 |
22 | import java.util.concurrent.atomic.AtomicBoolean;
23 | import java.util.concurrent.atomic.AtomicInteger;
24 |
25 | import static org.junit.jupiter.api.Assertions.*;
26 |
27 | @ExtendWith(VertxExtension.class)
28 | @DisplayName("Test multiple @BeforeAll methods")
29 | class AsyncBeforeAllTest {
30 |
31 | private static final AtomicBoolean started1 = new AtomicBoolean();
32 | private static final AtomicBoolean started2 = new AtomicBoolean();
33 | private static final AtomicInteger count = new AtomicInteger();
34 |
35 | @BeforeAll
36 | static void before1(VertxTestContext context, Vertx vertx) {
37 | checkBeforeMethod(context, vertx, started1, started2);
38 | }
39 |
40 | @BeforeAll
41 | static void before2(VertxTestContext context, Vertx vertx) {
42 | checkBeforeMethod(context, vertx, started2, started1);
43 | }
44 |
45 | private static void checkBeforeMethod(VertxTestContext context, Vertx vertx, AtomicBoolean mine, AtomicBoolean other) {
46 | int c = count.get();
47 | if (c == 0) {
48 | assertFalse(mine.get());
49 | assertFalse(other.get());
50 | } else if (c == 1) {
51 | assertFalse(mine.get());
52 | assertTrue(other.get());
53 | }
54 | Checkpoint checkpoint = context.checkpoint();
55 | vertx.setTimer(20, id -> {
56 | mine.set(true);
57 | count.incrementAndGet();
58 | checkpoint.flag();
59 | });
60 | }
61 |
62 | @Test
63 | void check_async_before_completed() {
64 | assertEquals(2, count.get());
65 | assertTrue(started1.get());
66 | assertTrue(started2.get());
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/AsyncBeforeCombinedTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.vertx.junit5.tests;
17 |
18 | import io.vertx.core.Vertx;
19 | import io.vertx.junit5.Checkpoint;
20 | import io.vertx.junit5.VertxExtension;
21 | import io.vertx.junit5.VertxTestContext;
22 | import org.junit.jupiter.api.BeforeAll;
23 | import org.junit.jupiter.api.BeforeEach;
24 | import org.junit.jupiter.api.DisplayName;
25 | import org.junit.jupiter.api.Test;
26 | import org.junit.jupiter.api.extension.ExtendWith;
27 |
28 | import static org.junit.jupiter.api.Assertions.assertEquals;
29 |
30 | @ExtendWith(VertxExtension.class)
31 | @DisplayName("Test @BeforeEach and @BeforeAll methods")
32 | class AsyncBeforeCombinedTest {
33 |
34 | private static volatile int step;
35 |
36 | @BeforeAll
37 | static void before_all(VertxTestContext context, Vertx vertx) {
38 | assertEquals(0, step);
39 | Checkpoint checkpoint = context.checkpoint();
40 | vertx.setTimer(200, id -> {
41 | step = 1;
42 | checkpoint.flag();
43 | });
44 | }
45 |
46 | @BeforeEach
47 | void before_each(VertxTestContext context, Vertx vertx) {
48 | assertEquals(1, step);
49 | Checkpoint checkpoint = context.checkpoint();
50 | vertx.setTimer(200, id -> {
51 | step = 2;
52 | checkpoint.flag();
53 | });
54 | }
55 |
56 | @Test
57 | void check_async_before_completed() {
58 | assertEquals(2, step);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/AsyncBeforeEachTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License 2.0 which is available at
6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8 | *
9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10 | */
11 | package io.vertx.junit5.tests;
12 |
13 | import io.vertx.core.Vertx;
14 | import io.vertx.junit5.Checkpoint;
15 | import io.vertx.junit5.VertxExtension;
16 | import io.vertx.junit5.VertxTestContext;
17 | import org.junit.jupiter.api.BeforeEach;
18 | import org.junit.jupiter.api.DisplayName;
19 | import org.junit.jupiter.api.RepeatedTest;
20 | import org.junit.jupiter.api.extension.ExtendWith;
21 |
22 | import java.util.concurrent.atomic.AtomicBoolean;
23 | import java.util.concurrent.atomic.AtomicInteger;
24 |
25 | import static org.junit.jupiter.api.Assertions.*;
26 |
27 | @ExtendWith(VertxExtension.class)
28 | @DisplayName("Test multiple @BeforeEach methods")
29 | class AsyncBeforeEachTest {
30 |
31 | private final AtomicBoolean started1 = new AtomicBoolean();
32 | private final AtomicBoolean started2 = new AtomicBoolean();
33 | private final AtomicInteger count = new AtomicInteger();
34 |
35 | @BeforeEach
36 | void before1(VertxTestContext context, Vertx vertx) {
37 | checkBeforeMethod(context, vertx, started1, started2);
38 | }
39 |
40 | @BeforeEach
41 | void before2(VertxTestContext context, Vertx vertx) {
42 | checkBeforeMethod(context, vertx, started2, started1);
43 | }
44 |
45 | private void checkBeforeMethod(VertxTestContext context, Vertx vertx, AtomicBoolean mine, AtomicBoolean other) {
46 | int c = count.get();
47 | if (c == 0) {
48 | assertFalse(mine.get());
49 | assertFalse(other.get());
50 | } else if (c == 1) {
51 | assertFalse(mine.get());
52 | assertTrue(other.get());
53 | }
54 | Checkpoint checkpoint = context.checkpoint();
55 | vertx.setTimer(20, id -> {
56 | mine.set(true);
57 | count.incrementAndGet();
58 | checkpoint.flag();
59 | });
60 | }
61 |
62 | @RepeatedTest(10)
63 | void check_async_before_completed() {
64 | assertEquals(2, count.get());
65 | assertTrue(started1.get());
66 | assertTrue(started2.get());
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/ConcreteTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2023 Contributors to the Eclipse Foundation
3 | *
4 | * This program and the accompanying materials are made available under the
5 | * terms of the Eclipse Public License 2.0 which is available at
6 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8 | *
9 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10 | */
11 |
12 | package io.vertx.junit5.tests;
13 |
14 | import io.vertx.core.Vertx;
15 | import io.vertx.junit5.VertxExtension;
16 | import io.vertx.junit5.VertxTestContext;
17 | import org.junit.jupiter.api.BeforeAll;
18 | import org.junit.jupiter.api.BeforeEach;
19 | import org.junit.jupiter.api.Test;
20 | import org.junit.jupiter.api.extension.ExtendWith;
21 |
22 | @ExtendWith(VertxExtension.class)
23 | public class ConcreteTest extends AbstractTest {
24 |
25 | @BeforeAll
26 | static void beforeAll(Vertx vertx, VertxTestContext testContext) {
27 | testContext.verify(() -> expectations(vertx, testContext, 1));
28 | }
29 |
30 | @BeforeEach
31 | void beforeEach(Vertx vertx, VertxTestContext testContext) {
32 | testContext.verify(() -> expectations(vertx, testContext, 3));
33 | }
34 |
35 | @Test
36 | void testMethod(Vertx vertx, VertxTestContext testContext) {
37 | testContext.verify(() -> expectations(vertx, testContext, 4));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/CountingCheckpointTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.junit5.Checkpoint;
20 | import io.vertx.junit5.CountingCheckpoint;
21 | import org.junit.jupiter.api.DisplayName;
22 | import org.junit.jupiter.api.Test;
23 |
24 | import java.util.concurrent.atomic.AtomicBoolean;
25 | import java.util.concurrent.atomic.AtomicReference;
26 | import java.util.function.Consumer;
27 |
28 | import static org.assertj.core.api.Assertions.assertThat;
29 | import static org.junit.jupiter.api.Assertions.assertThrows;
30 |
31 | /**
32 | * @author Julien Ponge
33 | */
34 | @DisplayName("Unit test for CountingCheckpoint")
35 | class CountingCheckpointTest {
36 |
37 | @Test
38 | @DisplayName("Smoke tests")
39 | void smoke_test() {
40 | AtomicBoolean success = new AtomicBoolean(false);
41 | AtomicReference witness = new AtomicReference<>();
42 | Consumer consumer = c -> {
43 | success.set(true);
44 | witness.set(c);
45 | };
46 | CountingCheckpoint checkpoint = CountingCheckpoint.laxCountingCheckpoint(consumer, 3);
47 |
48 | checkpoint.flag();
49 | assertThat(success).isFalse();
50 | assertThat(witness).hasValue(null);
51 | assertThat(checkpoint.satisfied()).isFalse();
52 |
53 | checkpoint.flag();
54 | assertThat(success).isFalse();
55 | assertThat(witness).hasValue(null);
56 | assertThat(checkpoint.satisfied()).isFalse();
57 |
58 | checkpoint.flag();
59 | assertThat(success).isTrue();
60 | assertThat(witness).hasValue(checkpoint);
61 | assertThat(checkpoint.satisfied()).isTrue();
62 | }
63 |
64 | private static final Consumer NOOP = c -> {
65 | };
66 |
67 | @Test
68 | @DisplayName("Refuse null triggers")
69 | void refuse_null_triggers() {
70 | assertThrows(NullPointerException.class, () -> CountingCheckpoint.laxCountingCheckpoint(null, 1));
71 | assertThrows(NullPointerException.class, () -> CountingCheckpoint.strictCountingCheckpoint(v -> {
72 | }, null, 1));
73 | }
74 |
75 | @Test
76 | @DisplayName("Refuse having 0 expected passes")
77 | void refuse_zero_passes() {
78 | assertThrows(IllegalArgumentException.class, () -> CountingCheckpoint.laxCountingCheckpoint(NOOP, 0));
79 | }
80 |
81 | @Test
82 | @DisplayName("Refuse having negative expected passes")
83 | void refuse_negative_passes() {
84 | assertThrows(IllegalArgumentException.class, () -> CountingCheckpoint.laxCountingCheckpoint(NOOP, -1));
85 | }
86 |
87 | @Test
88 | @DisplayName("Check of a lax checkpoint")
89 | void check_lax_checkpoint() {
90 | CountingCheckpoint checkpoint = CountingCheckpoint.laxCountingCheckpoint(NOOP, 1);
91 | checkpoint.flag();
92 | checkpoint.flag();
93 | }
94 |
95 | @Test
96 | @DisplayName("Check of a strict checkpoint")
97 | void check_strict_checkpoint() {
98 | AtomicReference box = new AtomicReference<>();
99 | CountingCheckpoint checkpoint = CountingCheckpoint.strictCountingCheckpoint(NOOP, box::set, 1);
100 |
101 | assertThat(checkpoint.satisfied()).isFalse();
102 | checkpoint.flag();
103 | assertThat(box).hasValue(null);
104 | assertThat(checkpoint.satisfied()).isTrue();
105 |
106 | checkpoint.flag();
107 | assertThat(box.get())
108 | .isNotNull()
109 | .isInstanceOf(IllegalStateException.class)
110 | .hasMessage("Strict checkpoint flagged too many times");
111 | assertThat(checkpoint.satisfied()).isTrue();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/CustomizedRunOnContextExtensionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.Context;
20 | import io.vertx.core.Future;
21 | import io.vertx.core.Vertx;
22 | import io.vertx.junit5.RunTestOnContext;
23 | import org.junit.jupiter.api.AfterAll;
24 | import org.junit.jupiter.api.AfterEach;
25 | import org.junit.jupiter.api.BeforeEach;
26 | import org.junit.jupiter.api.Test;
27 | import org.junit.jupiter.api.extension.RegisterExtension;
28 |
29 | import java.util.concurrent.atomic.AtomicInteger;
30 |
31 | import static org.junit.jupiter.api.Assertions.*;
32 |
33 | public class CustomizedRunOnContextExtensionTest {
34 |
35 | static AtomicInteger destroyMethodInvocations = new AtomicInteger();
36 | Vertx expectedVertx;
37 |
38 | @RegisterExtension
39 | RunTestOnContext testOnContext = new RunTestOnContext(() -> {
40 | expectedVertx = Vertx.vertx();
41 | return Future.succeededFuture(expectedVertx);
42 | }, vertx -> {
43 | destroyMethodInvocations.incrementAndGet();
44 | assertSame(expectedVertx, vertx);
45 | return vertx.close();
46 | });
47 |
48 | @BeforeEach
49 | void beforeTest() {
50 | Context ctx = Vertx.currentContext();
51 | assertNotNull(ctx);
52 | assertSame(expectedVertx, ctx.owner());
53 | }
54 |
55 | @Test
56 | void testMethod1() {
57 | Context ctx = Vertx.currentContext();
58 | assertNotNull(ctx);
59 | assertSame(expectedVertx, ctx.owner());
60 | }
61 |
62 | @Test
63 | void testMethod2() {
64 | Context ctx = Vertx.currentContext();
65 | assertNotNull(ctx);
66 | assertSame(expectedVertx, ctx.owner());
67 | }
68 |
69 | @AfterEach
70 | void tearDown() {
71 | Context ctx = Vertx.currentContext();
72 | assertNotNull(ctx);
73 | assertSame(expectedVertx, ctx.owner());
74 | }
75 |
76 | @AfterAll
77 | static void afterAll() {
78 | assertEquals(2, destroyMethodInvocations.get());
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/IntegrationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.*;
20 | import io.vertx.core.http.HttpClient;
21 | import io.vertx.core.http.HttpClientResponse;
22 | import io.vertx.core.http.HttpMethod;
23 | import io.vertx.junit5.Checkpoint;
24 | import io.vertx.junit5.Timeout;
25 | import io.vertx.junit5.VertxExtension;
26 | import io.vertx.junit5.VertxTestContext;
27 | import org.junit.jupiter.api.DisplayName;
28 | import org.junit.jupiter.api.Nested;
29 | import org.junit.jupiter.api.Test;
30 | import org.junit.jupiter.api.extension.ExtendWith;
31 |
32 | import java.util.concurrent.CountDownLatch;
33 | import java.util.concurrent.TimeUnit;
34 |
35 | import static org.assertj.core.api.Assertions.assertThat;
36 |
37 | /**
38 | * @author Julien Ponge
39 | */
40 | @DisplayName("Integration tests")
41 | class IntegrationTest {
42 |
43 | static class HttpServerVerticle extends VerticleBase {
44 |
45 | @Override
46 | public Future> start() throws Exception {
47 | return vertx
48 | .createHttpServer()
49 | .requestHandler(request -> request.response().end("Plop"))
50 | .listen(8080);
51 | }
52 | }
53 |
54 | @Nested
55 | @DisplayName("Tests without parameter injection and explicit Vertx and VertxTestContext instances")
56 | class Naked {
57 |
58 | @Test
59 | @DisplayName("Start a HTTP server")
60 | void start_http_server() throws InterruptedException {
61 | VertxTestContext testContext = new VertxTestContext();
62 |
63 | Vertx vertx = Vertx.vertx();
64 | vertx.createHttpServer()
65 | .requestHandler(req -> req.response().end())
66 | .listen(16969).onComplete(testContext.succeeding(ar -> testContext.completeNow()));
67 |
68 | assertThat(testContext.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
69 | closeVertx(vertx);
70 | }
71 |
72 | @Test
73 | @DisplayName("Start a HTTP server, then issue a HTTP client request and check the response")
74 | void vertx_check_http_server_response() throws InterruptedException {
75 | Vertx vertx = Vertx.vertx();
76 | VertxTestContext testContext = new VertxTestContext();
77 |
78 | vertx.deployVerticle(new HttpServerVerticle()).onComplete(testContext.succeeding(id -> {
79 | HttpClient client = vertx.createHttpClient();
80 | client.request(HttpMethod.GET, 8080, "localhost", "/")
81 | .flatMap(req -> req.send().compose(HttpClientResponse::body))
82 | .onFailure(testContext::failNow)
83 | .onSuccess(buffer -> testContext.verify(() -> {
84 | assertThat(buffer.toString()).isEqualTo("Plop");
85 | testContext.completeNow();
86 | }));
87 | }));
88 |
89 | assertThat(testContext.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
90 | closeVertx(vertx);
91 | }
92 |
93 | private void closeVertx(Vertx vertx) throws InterruptedException {
94 | CountDownLatch latch = new CountDownLatch(1);
95 | vertx.close().onComplete(ar -> latch.countDown());
96 | assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
97 | }
98 | }
99 |
100 | @Nested
101 | @ExtendWith(VertxExtension.class)
102 | @DisplayName("Tests with parameter injection")
103 | class WithExtension {
104 |
105 | private HttpClient client;
106 |
107 | @Test
108 | @Timeout(10_000)
109 | @DisplayName("Start a HTTP server, make 10 client requests, and use several checkpoints")
110 | void start_and_request_http_server_with_checkpoints(Vertx vertx, VertxTestContext testContext) {
111 | Checkpoint serverStarted = testContext.checkpoint();
112 | Checkpoint requestsServed = testContext.checkpoint(10);
113 | Checkpoint responsesReceived = testContext.checkpoint(10);
114 |
115 | vertx.createHttpServer()
116 | .requestHandler(serverRequest -> {
117 | serverRequest.response().end("Ok");
118 | requestsServed.flag();
119 | })
120 | .listen(8080).onComplete(ar -> {
121 | if (ar.failed()) {
122 | testContext.failNow(ar.cause());
123 | } else {
124 | serverStarted.flag();
125 | client = vertx.createHttpClient();
126 | for (int i = 0; i < 10; i++) {
127 | client.request(HttpMethod.GET, 8080, "localhost", "/")
128 | .flatMap(clientRequest -> clientRequest.send().compose(HttpClientResponse::body))
129 | .onFailure(testContext::failNow)
130 | .onSuccess(buffer -> {
131 | testContext.verify(() -> assertThat(buffer.toString()).isEqualTo("Ok"));
132 | responsesReceived.flag();
133 | });
134 | }
135 | }
136 | });
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/RunOnContextExtensionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.Context;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.junit5.RunTestOnContext;
22 | import org.junit.jupiter.api.*;
23 | import org.junit.jupiter.api.extension.RegisterExtension;
24 |
25 | import java.util.concurrent.atomic.AtomicReference;
26 |
27 | import static io.vertx.junit5.tests.StaticRunOnContextExtensionTest.checkContext;
28 | import static org.junit.jupiter.api.Assertions.*;
29 |
30 | public class RunOnContextExtensionTest {
31 |
32 | @RegisterExtension
33 | RunTestOnContext testOnContext = new RunTestOnContext();
34 |
35 | AtomicReference ctxRef = new AtomicReference<>();
36 |
37 | @BeforeAll
38 | static void beforeAll() {
39 | assertNull(Vertx.currentContext());
40 | }
41 |
42 | public RunOnContextExtensionTest() {
43 | assertNull(Vertx.currentContext());
44 | }
45 |
46 | @BeforeEach
47 | void beforeTest() {
48 | Context ctx = Vertx.currentContext();
49 | assertNotNull(ctx);
50 | assertSame(ctx.owner(), testOnContext.vertx());
51 | assertNotSame(ctx, ctxRef.getAndSet(ctx));
52 | }
53 |
54 | @Test
55 | void testMethod1() {
56 | checkContext(testOnContext.vertx(), ctxRef.get());
57 | }
58 |
59 | @Test
60 | void testMethod2() {
61 | checkContext(testOnContext.vertx(), ctxRef.get());
62 | }
63 |
64 | @AfterEach
65 | void tearDown() {
66 | checkContext(testOnContext.vertx(), ctxRef.get());
67 | }
68 |
69 | @AfterAll
70 | static void afterAll() {
71 | assertNull(Vertx.currentContext());
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/StaticRunOnContextExtensionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.Context;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.junit5.RunTestOnContext;
22 | import io.vertx.junit5.VertxExtension;
23 | import org.junit.jupiter.api.*;
24 | import org.junit.jupiter.api.extension.ExtendWith;
25 | import org.junit.jupiter.api.extension.RegisterExtension;
26 |
27 | import java.util.concurrent.atomic.AtomicReference;
28 |
29 | import static org.junit.jupiter.api.Assertions.*;
30 |
31 | @ExtendWith({VertxExtension.class})
32 | public class StaticRunOnContextExtensionTest {
33 |
34 | @RegisterExtension
35 | static RunTestOnContext testOnContext = new RunTestOnContext();
36 |
37 | static AtomicReference ctxRef = new AtomicReference<>();
38 |
39 | @BeforeAll
40 | static void beforeAll() {
41 | Context ctx = Vertx.currentContext();
42 | assertNotNull(ctx);
43 | assertSame(ctx.owner(), testOnContext.vertx());
44 | ctxRef.set(ctx);
45 | }
46 |
47 | public StaticRunOnContextExtensionTest() {
48 | assertNull(Vertx.currentContext());
49 | }
50 |
51 | @BeforeEach
52 | void beforeTest() {
53 | checkContext(testOnContext.vertx(), ctxRef.get());
54 | }
55 |
56 | @Test
57 | void testMethod1() {
58 | checkContext(testOnContext.vertx(), ctxRef.get());
59 | }
60 |
61 | @Test
62 | void testMethod2() {
63 | checkContext(testOnContext.vertx(), ctxRef.get());
64 | }
65 |
66 | @AfterEach
67 | void tearDown() {
68 | checkContext(testOnContext.vertx(), ctxRef.get());
69 | }
70 |
71 | @AfterAll
72 | static void afterAll() {
73 | checkContext(testOnContext.vertx(), ctxRef.get());
74 | }
75 |
76 | static void checkContext(Vertx expectedVertx, Context expectedContext) {
77 | Context ctx = Vertx.currentContext();
78 | assertNotNull(ctx);
79 | assertSame(expectedVertx, ctx.owner());
80 | assertSame(expectedContext, ctx);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/VertxExtensionCompleteLifecycleInjectionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.junit5.VertxExtension;
21 | import io.vertx.junit5.VertxTestContext;
22 | import org.junit.jupiter.api.*;
23 | import org.junit.jupiter.api.extension.ExtendWith;
24 |
25 | import static org.assertj.core.api.Assertions.assertThat;
26 |
27 | /**
28 | * @author Julien Ponge
29 | */
30 | @DisplayName("Test the injection in a complete lifecycle (esp., with @BeforeEach)")
31 | @ExtendWith(VertxExtension.class)
32 | class VertxExtensionCompleteLifecycleInjectionTest {
33 |
34 | static Vertx daVertx;
35 | static VertxTestContext daContext;
36 |
37 | @BeforeAll
38 | static void inTheBeginning(Vertx vertx, VertxTestContext testContext) {
39 | daVertx = vertx;
40 | daContext = testContext;
41 | testContext.completeNow();
42 | }
43 |
44 | @BeforeEach
45 | void rightBefore(Vertx vertx, VertxTestContext testContext) {
46 | assertThat(vertx).isSameAs(daVertx);
47 | assertThat(testContext).isNotSameAs(daContext);
48 | testContext.completeNow();
49 | }
50 |
51 | @Test
52 | @DisplayName("Check that the Vertx instance is shared and that VertxTestContext is fresh")
53 | void test1(Vertx vertx, VertxTestContext testContext) {
54 | assertThat(vertx).isSameAs(daVertx);
55 | assertThat(testContext).isNotSameAs(daContext);
56 | testContext.completeNow();
57 | }
58 |
59 | @Test
60 | @DisplayName("Same test, same assumptions")
61 | void test2(Vertx vertx, VertxTestContext testContext) {
62 | assertThat(vertx).isSameAs(daVertx);
63 | assertThat(testContext).isNotSameAs(daContext);
64 | testContext.completeNow();
65 | }
66 |
67 | @AfterEach
68 | void rightAfter(Vertx vertx, VertxTestContext testContext) {
69 | assertThat(vertx).isSameAs(daVertx);
70 | assertThat(testContext).isNotSameAs(daContext);
71 | testContext.completeNow();
72 | }
73 |
74 | @AfterAll
75 | static void inTheEnd(Vertx vertx, VertxTestContext testContext) {
76 | assertThat(vertx).isSameAs(daVertx);
77 | assertThat(testContext).isNotSameAs(daContext);
78 | testContext.completeNow();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/VertxExtensionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.VerticleBase;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.junit5.Checkpoint;
22 | import io.vertx.junit5.Timeout;
23 | import io.vertx.junit5.VertxExtension;
24 | import io.vertx.junit5.VertxTestContext;
25 | import org.junit.jupiter.api.*;
26 | import org.junit.jupiter.api.extension.ExtendWith;
27 | import org.junit.platform.launcher.Launcher;
28 | import org.junit.platform.launcher.LauncherDiscoveryRequest;
29 | import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
30 | import org.junit.platform.launcher.core.LauncherFactory;
31 | import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
32 | import org.junit.platform.launcher.listeners.TestExecutionSummary;
33 |
34 | import java.util.concurrent.TimeUnit;
35 | import java.util.concurrent.TimeoutException;
36 |
37 | import static org.assertj.core.api.Assertions.assertThat;
38 | import static org.junit.jupiter.api.Assertions.*;
39 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
40 |
41 | /**
42 | * @author Julien Ponge
43 | */
44 | @DisplayName("Tests of VertxExtension")
45 | class VertxExtensionTest {
46 |
47 | @Nested
48 | @ExtendWith(VertxExtension.class)
49 | @DisplayName("Basic test-level parameter injection smoke tests")
50 | class Injection {
51 |
52 | @Test
53 | @DisplayName("Inject a Vertx instance")
54 | void gimme_vertx(Vertx vertx) {
55 | assertNotNull(vertx);
56 | }
57 |
58 | @Test
59 | @DisplayName("Inject a VertxTestContext instance")
60 | void gimme_vertx_test_context(VertxTestContext context) {
61 | assertNotNull(context);
62 | context.completeNow();
63 | }
64 |
65 | @Test
66 | @DisplayName("Inject Vertx and VertxTestContext instances")
67 | void gimme_everything(Vertx vertx, VertxTestContext context) {
68 | assertNotNull(vertx);
69 | assertNotNull(context);
70 | context.completeNow();
71 | }
72 |
73 | @Test
74 | @DisplayName("Inject 2 Vertx instances and check they are the same")
75 | void gimme_2_vertx(Vertx vertx1, Vertx vertx2) {
76 | assertSame(vertx1, vertx2);
77 | }
78 |
79 | @Test
80 | @DisplayName("Inject 2 VertxTestContext instances and check they are different")
81 | void gimme_2_vertx(VertxTestContext context1, VertxTestContext context2) {
82 | assertNotSame(context1, context2);
83 | context1.completeNow();
84 | context2.completeNow();
85 | }
86 | }
87 |
88 | @Nested
89 | @ExtendWith(VertxExtension.class)
90 | @io.vertx.junit5.Timeout(4500)
91 | @DisplayName("Specify timeouts")
92 | class SpecifyTimeout {
93 |
94 | @Test
95 | @DisplayName("Override a class-level timeout")
96 | @io.vertx.junit5.Timeout(value = 5, timeUnit = TimeUnit.SECONDS)
97 | void a(VertxTestContext context) throws InterruptedException {
98 | Thread.sleep(50);
99 | context.completeNow();
100 | }
101 |
102 | @Test
103 | @DisplayName("Use the class-level timeout")
104 | void b(VertxTestContext context) throws InterruptedException {
105 | Thread.sleep(50);
106 | context.completeNow();
107 | }
108 | }
109 |
110 | @Nested
111 | @DisplayName("Tests that require embedding a JUnit launcher")
112 | class EmbeddedWithARunner {
113 |
114 | @Test
115 | @DisplayName("⚙️ Check a test failure")
116 | void checkFailureTest() {
117 | LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
118 | .selectors(selectClass(FailureTest.class))
119 | .build();
120 | Launcher launcher = LauncherFactory.create();
121 | SummaryGeneratingListener listener = new SummaryGeneratingListener();
122 | launcher.registerTestExecutionListeners(listener);
123 | launcher.execute(request);
124 | TestExecutionSummary summary = listener.getSummary();
125 | assertThat(summary.getTestsStartedCount()).isEqualTo(1);
126 | assertThat(summary.getTestsFailedCount()).isEqualTo(1);
127 | assertThat(summary.getFailures().get(0).getException()).isInstanceOf(AssertionError.class);
128 | }
129 |
130 | @Nested
131 | @ExtendWith(VertxExtension.class)
132 | @DisplayName("🚫")
133 | class FailureTest {
134 |
135 | @Test
136 | @Tag("programmatic")
137 | void thisMustFail(Vertx vertx, VertxTestContext testContext) {
138 | testContext.verify(() -> {
139 | assertTrue(false);
140 | });
141 | }
142 | }
143 |
144 | @Test
145 | @DisplayName("⚙️ Check a failure in the test method body rather than in a callback")
146 | void checkDirectFailure() {
147 | LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
148 | .selectors(selectClass(DirectFailureTest.class))
149 | .build();
150 | Launcher launcher = LauncherFactory.create();
151 | SummaryGeneratingListener listener = new SummaryGeneratingListener();
152 | launcher.registerTestExecutionListeners(listener);
153 | launcher.execute(request);
154 | TestExecutionSummary summary = listener.getSummary();
155 | assertThat(summary.getTestsStartedCount()).isEqualTo(1);
156 | assertThat(summary.getTestsFailedCount()).isEqualTo(1);
157 | assertThat(summary.getFailures().get(0).getException()).isInstanceOf(RuntimeException.class);
158 | }
159 |
160 | @Nested
161 | @ExtendWith(VertxExtension.class)
162 | @DisplayName("🚫")
163 | class DirectFailureTest {
164 |
165 | @Test
166 | @Tag("programmatic")
167 | @io.vertx.junit5.Timeout(value = 1, timeUnit = TimeUnit.SECONDS)
168 | void thisMustFail(VertxTestContext testContext) {
169 | throw new RuntimeException("YOLO");
170 | }
171 | }
172 |
173 | @Test
174 | @DisplayName("⚙️ Check a test failure with an intermediate async result verifier")
175 | void checkFailureTestWithIntermediateAsyncVerifier() {
176 | LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
177 | .selectors(selectClass(FailureWithIntermediateAsyncVerifierTest.class))
178 | .build();
179 | Launcher launcher = LauncherFactory.create();
180 | SummaryGeneratingListener listener = new SummaryGeneratingListener();
181 | launcher.registerTestExecutionListeners(listener);
182 | launcher.execute(request);
183 | TestExecutionSummary summary = listener.getSummary();
184 | assertThat(summary.getTestsStartedCount()).isEqualTo(1);
185 | assertThat(summary.getTestsFailedCount()).isEqualTo(1);
186 | assertThat(summary.getFailures().get(0).getException()).isInstanceOf(AssertionError.class);
187 | }
188 |
189 | @Nested
190 | @ExtendWith(VertxExtension.class)
191 | @DisplayName("🚫")
192 | class FailureWithIntermediateAsyncVerifierTest {
193 |
194 | @Test
195 | @Tag("programmatic")
196 | void thisMustAlsoFail(Vertx vertx, VertxTestContext testContext) {
197 | vertx.executeBlocking(() -> {
198 | try {
199 | Thread.sleep(500);
200 | } catch (InterruptedException e) {
201 | e.printStackTrace();
202 | }
203 | return 69;
204 | }).onComplete(testContext.succeeding(i -> testContext.verify(() -> assertEquals(58, i))));
205 | }
206 | }
207 |
208 | @Nested
209 | @ExtendWith(VertxExtension.class)
210 | @DisplayName("🚫")
211 | class TimingOut {
212 |
213 | @Test
214 | @Tag("programmatic")
215 | @Timeout(value = 2, timeUnit = TimeUnit.SECONDS)
216 | void doNothing(VertxTestContext testContext) {
217 | testContext.checkpoint();
218 | }
219 | }
220 |
221 | @Nested
222 | @ExtendWith(VertxExtension.class)
223 | @DisplayName("🚫")
224 | class TooMuchFlagging {
225 |
226 | @Test
227 | @Tag("programmatic")
228 | void flagTooMuch(VertxTestContext testContext) {
229 | Checkpoint checkpoint = testContext.checkpoint(3);
230 | for (int i = 0; i < 10; i++) {
231 | checkpoint.flag();
232 | }
233 | }
234 | }
235 |
236 | @Test
237 | @DisplayName("⚙️ Check that too much flagging fails tests")
238 | void checkTooMuchFlaggingFails() {
239 | LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
240 | .selectors(selectClass(EmbeddedWithARunner.TooMuchFlagging.class))
241 | .build();
242 | Launcher launcher = LauncherFactory.create();
243 | SummaryGeneratingListener listener = new SummaryGeneratingListener();
244 | launcher.registerTestExecutionListeners(listener);
245 | launcher.execute(request);
246 | TestExecutionSummary summary = listener.getSummary();
247 | assertThat(summary.getTestsStartedCount()).isEqualTo(1);
248 | assertThat(summary.getTestsFailedCount()).isEqualTo(1);
249 | Throwable exception = summary.getFailures().get(0).getException();
250 | assertThat(exception)
251 | .isInstanceOf(IllegalStateException.class)
252 | .hasMessage("Strict checkpoint flagged too many times");
253 | }
254 |
255 | @Test
256 | @DisplayName("⚙️ Check a timeout diagnosis")
257 | void checkTimeoutFailureTestWithIntermediateAsyncVerifier() {
258 | LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
259 | .selectors(selectClass(EmbeddedWithARunner.TimingOut.class))
260 | .build();
261 | Launcher launcher = LauncherFactory.create();
262 | SummaryGeneratingListener listener = new SummaryGeneratingListener();
263 | launcher.registerTestExecutionListeners(listener);
264 | launcher.execute(request);
265 | TestExecutionSummary summary = listener.getSummary();
266 | assertThat(summary.getTestsStartedCount()).isEqualTo(1);
267 | assertThat(summary.getTestsFailedCount()).isEqualTo(1);
268 | Throwable exception = summary.getFailures().get(0).getException();
269 | assertThat(exception)
270 | .isInstanceOf(TimeoutException.class)
271 | .hasMessageContaining("checkpoint at io.vertx.testing.junit5.tests/io.vertx.junit5.tests.VertxExtensionTest$EmbeddedWithARunner$TimingOut");
272 | }
273 | }
274 |
275 | private static class UselessVerticle extends VerticleBase {
276 | }
277 |
278 | @Nested
279 | @ExtendWith(VertxExtension.class)
280 | @DisplayName("Test parameter injection at various (non-static) levels")
281 | class VertxInjectionTest {
282 |
283 | Vertx currentVertx;
284 | VertxTestContext previousTestContext;
285 |
286 | @BeforeEach
287 | void prepare(Vertx vertx, VertxTestContext testContext) {
288 | assertThat(testContext).isNotSameAs(previousTestContext);
289 | previousTestContext = testContext;
290 | assertThat(currentVertx).isNotSameAs(vertx);
291 | currentVertx = vertx;
292 | vertx.deployVerticle(new UselessVerticle()).onComplete(testContext.succeeding(id -> testContext.completeNow()));
293 | }
294 |
295 | @AfterEach
296 | void cleanup(Vertx vertx, VertxTestContext testContext) {
297 | assertThat(testContext).isNotSameAs(previousTestContext);
298 | previousTestContext = testContext;
299 | assertThat(vertx.deploymentIDs()).isNotEmpty().hasSize(1);
300 | vertx.close().onComplete(testContext.succeeding(v -> testContext.completeNow()));
301 | }
302 |
303 | @RepeatedTest(10)
304 | @DisplayName("Test the validity of references and scoping")
305 | void checkDeployments(Vertx vertx, VertxTestContext testContext) {
306 | assertThat(testContext).isNotSameAs(previousTestContext);
307 | previousTestContext = testContext;
308 | assertThat(vertx).isSameAs(currentVertx);
309 | assertThat(vertx.deploymentIDs()).isNotEmpty().hasSize(1);
310 | testContext.completeNow();
311 | }
312 |
313 | @Nested
314 | @DisplayName("A nested test")
315 | class NestedTest {
316 |
317 | @RepeatedTest(10)
318 | @DisplayName("Test the validity of references and scoping")
319 | void checkDeployments(Vertx vertx, VertxTestContext testContext) {
320 | assertThat(testContext).isNotSameAs(previousTestContext);
321 | previousTestContext = testContext;
322 | assertThat(vertx).isSameAs(currentVertx);
323 | assertThat(vertx.deploymentIDs()).isNotEmpty().hasSize(1);
324 | testContext.completeNow();
325 | }
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/VertxParameterProviderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.json.JsonObject;
20 | import io.vertx.junit5.VertxParameterProvider;
21 | import org.junit.jupiter.api.DisplayName;
22 | import org.junit.jupiter.api.Test;
23 | import org.junit.jupiter.api.condition.DisabledForJreRange;
24 | import org.junit.jupiter.api.condition.EnabledOnJre;
25 | import org.junit.jupiter.api.condition.JRE;
26 | import org.junit.jupiter.api.io.TempDir;
27 |
28 | import java.nio.file.Files;
29 | import java.nio.file.Path;
30 |
31 | import static com.github.stefanbirkner.systemlambda.SystemLambda.*;
32 | import static io.vertx.junit5.VertxParameterProvider.*;
33 | import static org.junit.jupiter.api.Assertions.*;
34 |
35 | /**
36 | * @author Stephan Wisssel
37 | */
38 | @DisplayName("Test of VertxParameterProvider")
39 | @EnabledOnJre(value = JRE.JAVA_11)
40 | public class VertxParameterProviderTest {
41 |
42 | VertxParameterProvider provider = new VertxParameterProvider();
43 | JsonObject expected = new JsonObject();
44 | JsonObject actual = new JsonObject();
45 |
46 | @Test
47 | @DisplayName("Default case - empty VertxOptions")
48 | void default_empty_options() {
49 | actual.mergeIn(provider.getVertxOptions());
50 | assertEquals(expected.encode(), actual.encode(), "Options should be equally empty but are not");
51 | }
52 |
53 | @Test
54 | @DisplayName("Failed retrieval of options - env var")
55 | void failed_retrieval_of_options_env_var() throws Exception {
56 | failure(true, false);
57 | }
58 |
59 | @Test
60 | @DisplayName("Failed retrieval of options - old env var")
61 | void failed_retrieval_of_options_old_env_var() throws Exception {
62 | failure(true, true);
63 | }
64 |
65 | @Test
66 | @DisplayName("Failed retrieval of options - sys prop")
67 | void failed_retrieval_of_options_sys_prop() throws Exception {
68 | failure(false, false);
69 | }
70 |
71 | private void failure(boolean useEnv, boolean oldEnv) throws Exception {
72 | String doesNotExist = "something.that.does.not.exist.json";
73 | if (useEnv) {
74 | String var = oldEnv ? VERTX_PARAMETER_FILENAME : VERTX_PARAMETER_FILENAME_ENV_VAR;
75 | withEnvironmentVariable(var, doesNotExist).execute(() -> {
76 | actual.mergeIn(provider.getVertxOptions());
77 | });
78 | } else {
79 | restoreSystemProperties(() -> {
80 | System.setProperty(VertxParameterProvider.VERTX_PARAMETER_FILENAME_SYS_PROP, doesNotExist);
81 | actual.mergeIn(provider.getVertxOptions());
82 | });
83 | }
84 | assertEquals(expected.encode(), actual.encode(), "Options retrieval failure not handled");
85 | }
86 |
87 | @Test
88 | @DisplayName("Retrieval of options - env var")
89 | void retrieval_of_options_env_var(@TempDir Path tempDir) throws Exception {
90 | success(tempDir, true, false);
91 | }
92 |
93 | @Test
94 | @DisplayName("Retrieval of options - old env var")
95 | void retrieval_of_options_old_env_var(@TempDir Path tempDir) throws Exception {
96 | success(tempDir, true, true);
97 | }
98 |
99 | @Test
100 | @DisplayName("Retrieval of options - sys prop")
101 | void retrieval_of_options_sys_prop(@TempDir Path tempDir) throws Exception {
102 | success(tempDir, false, false);
103 | }
104 |
105 | private void success(Path tempDir, boolean useEnv, boolean oldEnv) throws Exception {
106 | expected.mergeIn(new JsonObject()
107 | .put("BlockedThreadCheckInterval", 120)
108 | .put("MaxWorkerExecuteTime", 42));
109 |
110 | // Create a temp file and populate it with our expected values
111 | Path tempOptionFile = tempDir.resolve("VertxOptions.json").toAbsolutePath();
112 | Files.write(tempOptionFile, expected.toBuffer().getBytes());
113 |
114 | if (useEnv) {
115 | String var = oldEnv ? VERTX_PARAMETER_FILENAME : VERTX_PARAMETER_FILENAME_ENV_VAR;
116 | withEnvironmentVariable(var, tempOptionFile.toString()).execute(() -> {
117 | actual.mergeIn(provider.getVertxOptions());
118 | });
119 | } else {
120 | restoreSystemProperties(() -> {
121 | System.setProperty(VERTX_PARAMETER_FILENAME_SYS_PROP, tempOptionFile.toString());
122 | actual.mergeIn(provider.getVertxOptions());
123 | });
124 | }
125 |
126 | assertEquals(expected.encode(), actual.encode(), "Options retrieval failed");
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/junit5/tests/VertxTestContextTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Red Hat, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.vertx.junit5.tests;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.Handler;
21 | import io.vertx.junit5.Checkpoint;
22 | import io.vertx.junit5.VertxTestContext;
23 | import org.junit.jupiter.api.DisplayName;
24 | import org.junit.jupiter.api.Test;
25 |
26 | import java.util.concurrent.TimeUnit;
27 | import java.util.concurrent.atomic.AtomicBoolean;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 | import static org.assertj.core.api.Assertions.assertThatThrownBy;
31 |
32 | /**
33 | * @author Julien Ponge
34 | */
35 | @DisplayName("Unit tests for VertxTestContext")
36 | class VertxTestContextTest {
37 |
38 | @Test
39 | @DisplayName("Check that failing with a null exception is forbidden")
40 | void fail_with_null() {
41 | VertxTestContext context = new VertxTestContext();
42 | assertThatThrownBy(() -> context.failNow((Throwable) null))
43 | .isInstanceOf(NullPointerException.class)
44 | .hasMessage("The exception cannot be null");
45 | }
46 |
47 | @Test
48 | @DisplayName("Check the behavior of failing()")
49 | void check_async_assert_fail() throws InterruptedException {
50 | VertxTestContext context = new VertxTestContext();
51 | context.failing().handle(Future.failedFuture("Bam"));
52 | context.awaitCompletion(1, TimeUnit.MILLISECONDS);
53 | assertThat(context.failed()).isFalse();
54 |
55 | context = new VertxTestContext();
56 | context.failing().handle(Future.succeededFuture());
57 | context.awaitCompletion(1, TimeUnit.MILLISECONDS);
58 | assertThat(context.failed()).isTrue();
59 | assertThat(context.causeOfFailure()).hasMessage("The asynchronous result was expected to have failed");
60 | }
61 |
62 | @Test
63 | @DisplayName("Check the behavior of succeeding(callback)")
64 | void check_async_assert_with_handler() throws InterruptedException {
65 | AtomicBoolean checker = new AtomicBoolean(false);
66 | VertxTestContext context = new VertxTestContext();
67 |
68 | VertxTestContext finalContext = context;
69 | Handler