├── .github
└── workflows
│ ├── main.yml
│ └── test.yml
├── .gitignore
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── settings.gradle
└── src
├── main
├── java
│ └── io
│ │ └── reqover
│ │ ├── Reqover.java
│ │ ├── core
│ │ ├── ReqoverResultsWriter.java
│ │ └── model
│ │ │ └── coverage
│ │ │ ├── CoverageInfo.java
│ │ │ ├── Parameter.java
│ │ │ └── UrlPath.java
│ │ └── rest
│ │ └── assured
│ │ ├── CoverageFilter.java
│ │ └── SwaggerCoverage.java
└── resources
│ └── logback.xml
└── test
└── java
└── io
└── reqover
└── test
├── TestCoverage.java
└── TestOpenApiV3.java
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Github Registry on Tag
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | publish:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: Set up JDK 11
14 | uses: actions/setup-java@v1
15 | with:
16 | java-version: 11
17 | - name: Build with Gradle
18 | run: ./gradlew build -x test
19 |
20 | - name: Publish to Github registry
21 | env:
22 | GH_USER: ${{ secrets.GH_USER }}
23 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 | run: ./gradlew publish
25 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Github Registry on Tag
2 |
3 | on:
4 | push:
5 | push:
6 | branches: [ "main" ]
7 |
8 | jobs:
9 | publish:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: Set up JDK 11
14 | uses: actions/setup-java@v1
15 | with:
16 | java-version: 11
17 |
18 | - name: Start recorder
19 | run: |
20 | docker run -d -p 8080:3000 \
21 | -v $PWD:/reqover --name reqover reqover/reqover-cli record -t https://petstore.swagger.io
22 |
23 | - name: Show containers
24 | run: docker run reqover/reqover-cli --version && docker logs reqover
25 |
26 | - name: Build with Gradle
27 | run: ./gradlew test
28 |
29 | - name: Generate coverage report
30 | run: |
31 | docker run -v $PWD:/reqover \
32 | -v $PWD/reqover-results:/tmp/data \
33 | -v $PWD/swagger.json:/tmp/swagger.json \
34 | reqover/reqover-cli generate -f /tmp/swagger.json -d /tmp/data -p /v2 --html
35 |
36 | - uses: actions/upload-artifact@v3
37 | with:
38 | name: reqover-report
39 | path: .reqover/report
40 |
41 | - name: Deploy 🚀
42 | uses: JamesIves/github-pages-deploy-action@v4
43 | with:
44 | folder: .reqover/report
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .gradle/
3 | build/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Reqover java
2 |
3 | [](https://jitpack.io/#reqover/reqover-java)
4 |
5 | Add dependency:
6 |
7 | ```
8 |
9 |
10 | jitpack.io
11 | https://jitpack.io
12 |
13 |
14 |
15 |
16 | com.github.reqover
17 | reqover-java
18 | v0.2.8
19 |
20 | ```
21 |
22 | Add RestAssured filter:
23 |
24 | ```
25 | import io.reqover.rest.assured.SwaggerCoverage;
26 |
27 | RestAssured.given()
28 | .filter(new SwaggerCoverage());
29 | ```
30 |
31 | Generate html report:
32 |
33 | ```
34 | docker run -v $PWD:/reqover \
35 | -v $PWD/.reqover:/tmp/data \
36 | -v $PWD/swagger.json:/tmp/swagger.json \
37 | reqover/reqover-cli generate -f /tmp/swagger.json -d /tmp/data/reqover-results -p /v2 --html
38 | ```
39 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'maven-publish'
4 | }
5 |
6 | repositories {
7 | mavenCentral()
8 | }
9 |
10 | dependencies {
11 | implementation group: 'io.rest-assured', name: 'rest-assured', version: '5.1.0'
12 | implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.3'
13 |
14 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
15 | testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
16 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
17 | }
18 |
19 | test {
20 | useJUnitPlatform()
21 | ignoreFailures = true
22 | }
23 |
24 | publishing {
25 | publications {
26 | mavenJava(MavenPublication) {
27 | groupId = 'io.reqover'
28 | artifactId = 'reqover-java'
29 | version = '0.3.0'
30 |
31 | from components.java
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reqover/reqover-java/381b9120a1c0d06cfcff26d64d610e1034bceb4f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - sdk install java 11.0.10-open
3 | - sdk use java 11.0.10-open
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'reqover-java'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/Reqover.java:
--------------------------------------------------------------------------------
1 | package io.reqover;
2 |
3 | import io.reqover.core.ReqoverResultsWriter;
4 |
5 | import java.io.File;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.net.MalformedURLException;
10 | import java.net.URL;
11 | import java.nio.channels.Channels;
12 | import java.nio.channels.ReadableByteChannel;
13 | import java.nio.file.Path;
14 |
15 | public class Reqover {
16 |
17 | public static final String REQOVER_ROOT = ".reqover";
18 |
19 | public static void dumpSpec(String url) {
20 | try {
21 | ReqoverResultsWriter.createDirectories(Path.of(REQOVER_ROOT));
22 | download(url, REQOVER_ROOT + File.separator + "spec.yml");
23 | } catch (IOException e) {
24 | throw new RuntimeException(e);
25 | }
26 | }
27 |
28 | private static void download(String urlStr, String file) throws IOException {
29 | URL url = new URL(urlStr);
30 | ReadableByteChannel rbc = Channels.newChannel(url.openStream());
31 | FileOutputStream fos = new FileOutputStream(file);
32 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
33 | fos.close();
34 | rbc.close();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/core/ReqoverResultsWriter.java:
--------------------------------------------------------------------------------
1 | package io.reqover.core;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import io.reqover.core.model.coverage.CoverageInfo;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.nio.file.Files;
10 | import java.nio.file.Path;
11 | import java.util.UUID;
12 |
13 | import static java.nio.file.StandardOpenOption.CREATE_NEW;
14 |
15 | public class ReqoverResultsWriter {
16 |
17 | public static final String COVERAGE_OUTPUT_FILE_SUFFIX = "-coverage.json";
18 | private final Path outputDirectory;
19 |
20 | public ReqoverResultsWriter(String resultsDir) {
21 | this.outputDirectory = Path.of(resultsDir);
22 | }
23 |
24 | private String generateCoverageOutputName() {
25 | return UUID.randomUUID() + COVERAGE_OUTPUT_FILE_SUFFIX;
26 | }
27 |
28 | public static void createDirectories(final Path directory) {
29 | try {
30 | Files.createDirectories(directory);
31 | } catch (IOException e) {
32 | throw new RuntimeException("");
33 | }
34 | }
35 |
36 | public void write(CoverageInfo info) {
37 | final String swaggerResultName = generateCoverageOutputName();
38 | createDirectories(outputDirectory);
39 | Path file = outputDirectory.resolve(swaggerResultName);
40 |
41 | ObjectMapper mapper = new ObjectMapper();
42 |
43 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
44 | try (OutputStream os = Files.newOutputStream(file, CREATE_NEW)) {
45 | mapper.writeValue(os, info);
46 | } catch (IOException e) {
47 | throw new RuntimeException("Could not write Swagger", e);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/core/model/coverage/CoverageInfo.java:
--------------------------------------------------------------------------------
1 | package io.reqover.core.model.coverage;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 |
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.UUID;
8 |
9 | @JsonInclude(JsonInclude.Include.NON_NULL)
10 | public class CoverageInfo {
11 | private String uuid = UUID.randomUUID().toString();
12 | private UrlPath urlPath;
13 | private String method;
14 | private String statusCode;
15 | private List parameters;
16 | private Object body;
17 | private String basePath;
18 | private String path;
19 | private String uri;
20 | private Map response;
21 |
22 | public CoverageInfo() {
23 |
24 | }
25 |
26 | public String getUri() {
27 | return uri;
28 | }
29 |
30 | public void setUri(String uri) {
31 | this.uri = uri;
32 | }
33 |
34 | public String getBasePath() {
35 | return basePath;
36 | }
37 |
38 | public void setBasePath(String basePath) {
39 | this.basePath = basePath;
40 | }
41 |
42 | public Map getResponse() {
43 | return response;
44 | }
45 |
46 | public void setResponse(Map response) {
47 | this.response = response;
48 | }
49 |
50 | public String getUuid() {
51 | return uuid;
52 | }
53 |
54 | public void setUuid(String uuid) {
55 | this.uuid = uuid;
56 | }
57 |
58 | public UrlPath getUrlPath() {
59 | return urlPath;
60 | }
61 |
62 | public void setUrlPath(UrlPath urlPath) {
63 | this.urlPath = urlPath;
64 | }
65 |
66 | public String getMethod() {
67 | return method;
68 | }
69 |
70 | public void setMethod(String method) {
71 |
72 | this.method = method;
73 | }
74 |
75 | public String getStatusCode() {
76 | return statusCode;
77 | }
78 |
79 | public void setStatusCode(String statusCode) {
80 |
81 | this.statusCode = statusCode;
82 | }
83 |
84 | public List getParameters() {
85 | return parameters;
86 | }
87 |
88 | public void setParameters(List parameters) {
89 | this.parameters = parameters;
90 | }
91 |
92 | public Object getBody() {
93 | return body;
94 | }
95 |
96 | public void setBody(Object body) {
97 |
98 | this.body = body;
99 | }
100 |
101 | public String getPath() {
102 | return path;
103 | }
104 |
105 | public void setPath(String path) {
106 | this.path = path;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/core/model/coverage/Parameter.java:
--------------------------------------------------------------------------------
1 | package io.reqover.core.model.coverage;
2 |
3 | public class Parameter {
4 | private String name;
5 | private String value;
6 |
7 | public Parameter(String name, String value) {
8 | this.name = name;
9 | this.value = value;
10 | }
11 |
12 | public String getName() {
13 | return name;
14 | }
15 |
16 | public void setName(String name) {
17 | this.name = name;
18 | }
19 |
20 | public String getValue() {
21 | return value;
22 | }
23 |
24 | public void setValue(String value) {
25 | this.value = value;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/core/model/coverage/UrlPath.java:
--------------------------------------------------------------------------------
1 | package io.reqover.core.model.coverage;
2 |
3 | import java.util.Map;
4 |
5 | public class UrlPath {
6 |
7 | public static String getPath(String path, Map params) {
8 | String result = path;
9 | for (Map.Entry entry : params.entrySet()) {
10 | result = result.replace("{" + entry.getKey() + "}", entry.getValue());
11 | }
12 | return result;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/rest/assured/CoverageFilter.java:
--------------------------------------------------------------------------------
1 | package io.reqover.rest.assured;
2 |
3 | import io.reqover.core.model.coverage.CoverageInfo;
4 | import io.reqover.core.model.coverage.Parameter;
5 | import io.reqover.core.model.coverage.UrlPath;
6 | import io.restassured.filter.OrderedFilter;
7 | import io.restassured.response.Response;
8 | import io.restassured.specification.FilterableRequestSpecification;
9 | import org.apache.commons.lang3.StringUtils;
10 |
11 | import java.net.URI;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.Objects;
15 | import java.util.stream.Collectors;
16 |
17 | public abstract class CoverageFilter implements OrderedFilter {
18 |
19 | protected CoverageInfo collectCoverageInfo(FilterableRequestSpecification requestSpec, Response response) {
20 | Integer statusCode = response.statusCode();
21 | Map unnamedPathParams = requestSpec.getUnnamedPathParams();
22 | URI requestURI = convertUriStringToURI(requestSpec.getURI());
23 |
24 | String uri = removeHostFromUri(Objects.requireNonNull(requestURI));
25 | String basePath = requestSpec.getBasePath();
26 | String path = requestURI.getPath();
27 |
28 | String method = requestSpec.getMethod();
29 |
30 | Map queryParams = requestSpec.getQueryParams();
31 | Map requestParams = requestSpec.getRequestParams();
32 |
33 | List queryParameters = queryParams.entrySet()
34 | .stream().map(it -> new Parameter(it.getKey(), it.getValue()))
35 | .collect(Collectors.toList());
36 |
37 | List requestParameters = requestParams.entrySet()
38 | .stream().map(it -> new Parameter(it.getKey(), it.getValue()))
39 | .collect(Collectors.toList());
40 |
41 | queryParameters.addAll(requestParameters);
42 |
43 | Object body = requestSpec.getBody();
44 | Object responseBody = null;
45 | try {
46 | responseBody = response.getBody().as(Object.class);
47 | } catch (Exception e) {
48 | //System.err.println("Error parsing response body "+e);
49 | }
50 |
51 | CoverageInfo coverageInfo = new CoverageInfo();
52 | coverageInfo.setUri(uri);
53 | coverageInfo.setBasePath(basePath);
54 | coverageInfo.setPath(path);
55 | coverageInfo.setStatusCode(String.valueOf(statusCode));
56 | coverageInfo.setMethod(method);
57 | coverageInfo.setParameters(queryParameters);
58 | coverageInfo.setBody(body);
59 | if (responseBody != null) {
60 | coverageInfo.setResponse(Map.of("statusCode", statusCode, "body", responseBody));
61 | }
62 |
63 | return coverageInfo;
64 | }
65 |
66 | private URI convertUriStringToURI(String uri) {
67 | try {
68 | return new URI(uri);
69 | } catch (Exception e) {
70 | throw new RuntimeException("Can not parse URI " + uri + " " + e);
71 | }
72 | }
73 |
74 | private String removeHostFromUri(URI uri) {
75 | String query = uri.getQuery();
76 | String path = uri.getPath();
77 | if (StringUtils.isBlank(query)) {
78 | return path;
79 | }
80 | return path + "?" + query;
81 | }
82 |
83 | @Override
84 | public int getOrder() {
85 | return Integer.MAX_VALUE;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/io/reqover/rest/assured/SwaggerCoverage.java:
--------------------------------------------------------------------------------
1 | package io.reqover.rest.assured;
2 |
3 | import io.reqover.Reqover;
4 | import io.reqover.core.ReqoverResultsWriter;
5 | import io.reqover.core.model.coverage.CoverageInfo;
6 | import io.restassured.filter.FilterContext;
7 | import io.restassured.response.Response;
8 | import io.restassured.specification.FilterableRequestSpecification;
9 | import io.restassured.specification.FilterableResponseSpecification;
10 |
11 | import java.io.File;
12 |
13 | public class SwaggerCoverage extends CoverageFilter {
14 |
15 | public static final String OUTPUT_DIRECTORY = Reqover.REQOVER_ROOT + File.separator + "reqover-results";
16 |
17 | private final ReqoverResultsWriter writer;
18 |
19 | public SwaggerCoverage() {
20 | this(OUTPUT_DIRECTORY);
21 | }
22 |
23 | public SwaggerCoverage(String resultsDir) {
24 | this.writer = new ReqoverResultsWriter(resultsDir);
25 | }
26 |
27 | @Override
28 | public Response filter(FilterableRequestSpecification requestSpec,
29 | FilterableResponseSpecification responseSpec,
30 | FilterContext ctx) {
31 | final Response response = ctx.next(requestSpec, responseSpec);
32 | CoverageInfo coverageInfo = collectCoverageInfo(requestSpec, response);
33 | writer.write(coverageInfo);
34 | return response;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %green(%msg%n)
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/test/java/io/reqover/test/TestCoverage.java:
--------------------------------------------------------------------------------
1 | package io.reqover.test;
2 |
3 | import io.reqover.Reqover;
4 | import io.reqover.rest.assured.SwaggerCoverage;
5 | import io.restassured.RestAssured;
6 | import io.restassured.filter.log.RequestLoggingFilter;
7 | import io.restassured.http.ContentType;
8 | import io.restassured.specification.RequestSpecification;
9 | import org.junit.jupiter.api.BeforeAll;
10 | import org.junit.jupiter.api.Test;
11 | import org.junit.jupiter.params.ParameterizedTest;
12 | import org.junit.jupiter.params.provider.ValueSource;
13 |
14 | import java.util.Map;
15 |
16 | // Code of service https://github.com/swagger-api/swagger-petstore/blob/master/src/main/java/io/swagger/petstore/controller/PetController.java
17 | public class TestCoverage {
18 |
19 | private final SwaggerCoverage swaggerCoverage = new SwaggerCoverage();
20 |
21 | @BeforeAll
22 | public static void setUp() {
23 | RestAssured.baseURI = "https://petstore.swagger.io";
24 | RestAssured.basePath = "/v2";
25 | Reqover.dumpSpec("https://petstore.swagger.io/v2/swagger.json");
26 | }
27 |
28 | private RequestSpecification setup() {
29 | return RestAssured.given()
30 | .filter(new RequestLoggingFilter())
31 | .filter(swaggerCoverage);
32 | }
33 |
34 | @ParameterizedTest
35 | @ValueSource(ints = {1, Integer.MIN_VALUE, Integer.MAX_VALUE})
36 | void testGetPet(int value) {
37 | setup()
38 | .get("/pet/{petId}", value);
39 | }
40 |
41 | @Test
42 | void testGetPetWithNull() {
43 | setup()
44 | .get("/pet/{petId}", "null");
45 | }
46 |
47 |
48 | @Test
49 | void testDeletePet() {
50 | setup()
51 | .delete("/pet/{petId}", 1);
52 | }
53 |
54 | @Test
55 | void testDeletePetByNull() {
56 | setup()
57 | .delete("/pet/{petId}", "null");
58 | }
59 |
60 | @Test
61 | void testCanGetPetByStatus() {
62 | setup()
63 | .queryParam("status", "sold")
64 | .get("/pet/findByStatus");
65 | }
66 |
67 | @Test
68 | void testCanGetPetByStatusAvailable() {
69 | setup()
70 | .queryParam("status", "available")
71 | .get("/pet/findByStatus");
72 | }
73 |
74 | @Test
75 | void testCanGetPetByStatusEmpty() {
76 | setup()
77 | .get("/pet/findByStatus");
78 | }
79 |
80 | @Test
81 | void testCanCreatePet() {
82 | setup()
83 | .body("{\"name\": \"doggie\"}")
84 | .post("/pet");
85 | }
86 |
87 | @Test
88 | void testCanCreatePetWithEmptyBody() {
89 | setup()
90 | .contentType(ContentType.JSON)
91 | .body("{}")
92 | .post("/pet");
93 | }
94 |
95 | @Test
96 | void testCreatePetThrows400() {
97 | setup()
98 | .contentType(ContentType.JSON)
99 | .body("''")
100 | .post("/pet");
101 | }
102 |
103 | @Test
104 | void testCanLogUserWithQueryParams() {
105 | setup().contentType(ContentType.JSON)
106 | .queryParams(Map.of("username", "admin", "password", "admin"))
107 | .get("/user/login");
108 | }
109 |
110 | @Test
111 | void testCanLogUserWithParams() {
112 | setup().contentType(ContentType.JSON)
113 | .params(Map.of("username", "demo", "password", "demo"))
114 | .get("/user/login");
115 | }
116 |
117 | @Test
118 | void testCanGetInventory() {
119 | setup().contentType(ContentType.JSON)
120 | .get("/store/inventory");
121 | }
122 | }
123 |
124 |
125 |
--------------------------------------------------------------------------------
/src/test/java/io/reqover/test/TestOpenApiV3.java:
--------------------------------------------------------------------------------
1 | package io.reqover.test;
2 |
3 | import io.reqover.rest.assured.SwaggerCoverage;
4 | import io.restassured.RestAssured;
5 | import io.restassured.filter.log.RequestLoggingFilter;
6 | import io.restassured.specification.RequestSpecification;
7 | import org.junit.jupiter.api.BeforeAll;
8 | import org.junit.jupiter.api.Test;
9 |
10 | public class TestOpenApiV3 {
11 | private final SwaggerCoverage swaggerCoverage = new SwaggerCoverage("build/reqover-results");
12 |
13 | @BeforeAll
14 | public static void setUp() {
15 | RestAssured.baseURI = "https://canada-holidays.ca/api/v1";
16 | }
17 |
18 | private RequestSpecification setup() {
19 | return RestAssured.given()
20 | .filter(new RequestLoggingFilter())
21 | .filter(swaggerCoverage);
22 | }
23 |
24 | @Test
25 | void testGetPet() {
26 | setup()
27 | .get("/holidays/{holidayId}?year=2023&optional=false", 2);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------