Compare commits
89 commits
http-mock-
...
dev
Author | SHA1 | Date | |
---|---|---|---|
55ee22c3a1 | |||
65fba1eebc | |||
2a11dd9b10 | |||
ea16fa59d0 | |||
1c5909cf8d | |||
0884505a18 | |||
024bec4304 | |||
b2857d956b | |||
5ddcb87179 | |||
514064debc | |||
2fe3f2a67d | |||
36bc5dd14b | |||
|
afaab504da | ||
|
f9ae4a8003 | ||
|
a3a7c4f8dc | ||
|
e44c1de1a2 | ||
|
3413bfa0ad | ||
|
a825ad6fa2 | ||
|
374947847d | ||
|
8ba339b8a0 | ||
|
ab6345234f | ||
|
763f303a65 | ||
|
23bba7e713 | ||
|
82b22565d8 | ||
|
1a422fefca | ||
|
b314332228 | ||
|
f8f2cfb125 | ||
|
db93a99b9a | ||
|
8824634652 | ||
|
6d52f8bceb | ||
|
c5a9450e00 | ||
|
170fb58c99 | ||
|
6438c661da | ||
|
531daa0fbe | ||
|
c0188689f2 | ||
|
fe9ef89970 | ||
|
769199f5d4 | ||
|
aa3919dbd2 | ||
|
080516733a | ||
|
2cd84e3052 | ||
|
6044b3a275 | ||
|
79622a4177 | ||
|
fcd99cf61f | ||
|
c118365bbe | ||
|
4128b8b49d | ||
|
9c6afd599f | ||
|
579dd08d2f | ||
|
181f9dbcd9 | ||
|
0727ced422 | ||
|
f8e0cc44f9 | ||
|
6036bd2c3b | ||
|
dbc0410f52 | ||
|
5a3af95f0b | ||
|
ab2b3f9481 | ||
|
4bda860609 | ||
|
4fb0c9cfce | ||
|
2b57ba0806 | ||
|
3fcfec451a | ||
|
fca39a8355 | ||
|
3599300191 | ||
|
7a13cb2ce5 | ||
|
951a0f1b56 | ||
|
bfc547721e | ||
|
229f2d02d3 | ||
|
159f0a4987 | ||
|
d6b9abfe05 | ||
|
f110ffe8a9 | ||
|
23e2813e2b | ||
|
ba820bfcf2 | ||
|
da9cfc0ffb | ||
|
44f44ee392 | ||
|
c02e93edc3 | ||
|
d272f70141 | ||
|
493bb8fd91 | ||
|
261126d58b | ||
|
54739cff85 | ||
|
2b4ca48d79 | ||
|
631a651510 | ||
|
e17e20fadb | ||
|
e104672d83 | ||
|
6b90bbdc81 | ||
|
f4dde98f17 | ||
|
70c0f678ef | ||
|
1a5e0e5e17 | ||
|
3e695fcb78 | ||
|
faf8f8006a | ||
|
9a14f9bfab | ||
|
aabc9d75f2 | ||
|
0f45ccd82a |
55 changed files with 2954 additions and 802 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
*.iml
|
||||
target/
|
||||
.idea
|
||||
|
||||
.mvn/wrapper/maven-wrapper.jar
|
18
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
18
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
|
@ -1,5 +0,0 @@
|
|||
language: groovy
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
59
.woodpecker.yaml
Normal file
59
.woodpecker.yaml
Normal file
|
@ -0,0 +1,59 @@
|
|||
variables:
|
||||
&maven_image maven:3.9.6-eclipse-temurin-11-alpine
|
||||
|
||||
when:
|
||||
evaluate: 'not (CI_COMMIT_MESSAGE contains "Release")'
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: *maven_image
|
||||
commands:
|
||||
- mvn -B clean install -DskipTests -Dmaven.test.skip
|
||||
- name: test
|
||||
image: *maven_image
|
||||
commands:
|
||||
- mvn -B -pl :mockserver-tests verify
|
||||
- name: deploy to public
|
||||
image: *maven_image
|
||||
commands:
|
||||
- mvn -B jar:jar deploy:deploy
|
||||
secrets: [reposilite_user, reposilite_token]
|
||||
when:
|
||||
branch: [dev, master]
|
||||
- name: deploy to releases
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
base-url: https://git.ztsh.eu
|
||||
files:
|
||||
- "mockserver-client/target/mockserver-client*.jar"
|
||||
- "mockserver/target/mockserver-full.jar"
|
||||
api_key:
|
||||
from_secret: git_pat
|
||||
when:
|
||||
- event: tag
|
||||
- name: tag docker image
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
|
||||
repo: ztsheu/http-mock-server
|
||||
registry: docker.io
|
||||
tags: ${CI_COMMIT_TAG}
|
||||
username: ztsheu
|
||||
password:
|
||||
from_secret: docker_pat
|
||||
when:
|
||||
- event: tag
|
||||
- name: build docker image
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
|
||||
repo: ztsheu/http-mock-server
|
||||
registry: docker.io
|
||||
tags: latest
|
||||
username: ztsheu
|
||||
password:
|
||||
from_secret: docker_pat
|
||||
when:
|
||||
- event: tag
|
||||
- event: push
|
||||
branch: dev
|
10
Dockerfile
10
Dockerfile
|
@ -1,7 +1,11 @@
|
|||
FROM java:8
|
||||
FROM eclipse-temurin:11.0.22_7-jre-jammy
|
||||
|
||||
ADD mockserver/target/mockserver-1.1.1-SNAPSHOT-jar-with-dependencies.jar /mockserver.jar
|
||||
ADD mockserver/target/mockserver-full.jar /mockserver.jar
|
||||
|
||||
EXPOSE 9999
|
||||
|
||||
CMD java -jar /mockserver.jar
|
||||
RUN mkdir /externalSchema
|
||||
|
||||
VOLUME /externalSchema
|
||||
|
||||
CMD java -cp /mockserver.jar:/externalSchema eu.ztsh.mockserver.server.Main
|
||||
|
|
314
README.md
314
README.md
|
@ -1,20 +1,105 @@
|
|||
[](https://travis-ci.org/TouK/http-mock-server)
|
||||
|
||||
# HTTP MOCK SERVER
|
||||
HTTP MOCK SERVER
|
||||
================
|
||||
|
||||
## Create server jar (in mockserver directory)
|
||||
Http Mock Server allows to mock HTTP request using groovy closures.
|
||||
|
||||
Create server jar
|
||||
-----------------
|
||||
|
||||
```
|
||||
cd mockserver
|
||||
mvn clean package assembly:single
|
||||
```
|
||||
|
||||
## Start server on port (default 9999)
|
||||
Start server
|
||||
------------
|
||||
|
||||
### Native start
|
||||
|
||||
```
|
||||
java -jar mockserver-<VERSION>-jar-with-dependencies.jar [PORT]
|
||||
java -jar mockserver-full.jar [PORT] [CONFIGURATION_FILE]
|
||||
```
|
||||
|
||||
## Create mock on server via client
|
||||
Default port is 9999.
|
||||
|
||||
If configuration file is passed then port must be defined.
|
||||
|
||||
Configuration file is groovy configuration script e.g. :
|
||||
|
||||
```groovy
|
||||
testRest2 {
|
||||
port=9998
|
||||
response='{ req -> \'<response/>\' }'
|
||||
responseHeaders='{ _ -> [a: "b"] }'
|
||||
path='testEndpoint'
|
||||
predicate='{ req -> req.xml.name() == \'request1\'}'
|
||||
name='testRest2'
|
||||
}
|
||||
testRest4 {
|
||||
soap=true
|
||||
port=9999
|
||||
path='testEndpoint'
|
||||
name='testRest4'
|
||||
method='PUT'
|
||||
statusCode=204
|
||||
}
|
||||
testRest3 {
|
||||
port=9999
|
||||
path='testEndpoint2'
|
||||
name='testRest3'
|
||||
}
|
||||
testRest6 {
|
||||
port=9999
|
||||
path='testEndpoint2'
|
||||
name='testRest6'
|
||||
maxUses=1
|
||||
cyclic=true
|
||||
}
|
||||
testRest {
|
||||
imports {
|
||||
aaa='bbb'
|
||||
ccc='bla'
|
||||
}
|
||||
port=10001
|
||||
path='testEndpoint'
|
||||
name='testRest'
|
||||
}
|
||||
testHttps {
|
||||
soap=false
|
||||
port=10443
|
||||
path='testHttps'
|
||||
name='testHttps'
|
||||
method='GET'
|
||||
https={
|
||||
keystorePath='/tmp/keystore.jks'
|
||||
keystorePassword='keystorePass'
|
||||
keyPassword='keyPass'
|
||||
truststorePath='/tmp/truststore.jks'
|
||||
truststorePassword='truststorePass'
|
||||
requireClientAuth=true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Build with docker
|
||||
|
||||
Docker and docker-compose is needed.
|
||||
|
||||
```
|
||||
./buildImage.sh
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Docker repoository
|
||||
|
||||
Currently unavailable
|
||||
|
||||
Create mock on server
|
||||
---------------------
|
||||
|
||||
### Via client
|
||||
|
||||
```java
|
||||
RemoteMockServer remoteMockServer = new RemoteMockServer('localhost', <PORT>)
|
||||
|
@ -27,15 +112,27 @@ remoteMockServer.addMock(new AddMock(
|
|||
soap: ...,
|
||||
statusCode: ...,
|
||||
method: ...,
|
||||
responseHeaders: ...
|
||||
responseHeaders: ...,
|
||||
schema: ...,
|
||||
maxUses: ...,
|
||||
cyclic: ...,
|
||||
https: new Https(
|
||||
keystorePath: '/tmp/keystore.jks',
|
||||
keystorePassword: 'keystorePass',
|
||||
keyPassword: 'keyPass',
|
||||
truststorePath: '/tmp/truststore.jks',
|
||||
truststorePassword: 'truststorePass',
|
||||
requireClientAuth: true
|
||||
)
|
||||
))
|
||||
```
|
||||
|
||||
or via sending POST request to localhost:<PORT>/serverControl
|
||||
### Via HTTP
|
||||
|
||||
Send POST request to localhost:<PORT>/serverControl
|
||||
|
||||
```xml
|
||||
<addMock xmlns="http://touk.pl/mockserver/api/request">
|
||||
<addMock xmlns="http://ztsh.eu/mockserver/api/request">
|
||||
<name>...</name>
|
||||
<path>...</path>
|
||||
<port>...</port>
|
||||
|
@ -45,53 +142,90 @@ or via sending POST request to localhost:<PORT>/serverControl
|
|||
<statusCode>...</statusCode>
|
||||
<method>...</method>
|
||||
<responseHeaders>...</responseHeaders>
|
||||
<schema>...</schema>
|
||||
<imports alias="..." fullClassName="..."/>
|
||||
<maxUses>...</maxUses>
|
||||
<cyclic>...</cyclic>
|
||||
<https>
|
||||
<keystorePath>/tmp/keystore.jks</keystorePath>
|
||||
<keystorePassword>keystorePass</keystorePassword>
|
||||
<keyPassword>keyPass</keyPassword>
|
||||
<truststorePath>/tmp/truststore.jks</truststorePath>
|
||||
<truststorePassword>truststorePass</truststorePassword>
|
||||
<requireClientAuth>true</requireClientAuth>
|
||||
</https>
|
||||
</addMock>
|
||||
```
|
||||
|
||||
* name - name of mock, must be unique
|
||||
* path - path on which mock should be created
|
||||
* port - inteer, port on which mock should be created, cannot be the same as mock server port
|
||||
* predicate - groovy closure as string which must evaluate to true, when request object will be given to satisfy mock, optional, default {_ -> true}
|
||||
* response - groovy closure as string which must evaluate to string which will be response of mock when predicate is satisfied, optional, default { _ -> '' }
|
||||
* soap - true or false, is request and response should be wrapped in soap Envelope and Body elements, default false
|
||||
* statusCode - integer, status code of response when predicate is satisfied, default 200
|
||||
* method - POST|PUT|DELETE|GET|TRACE|OPTION|HEAD, expected http method of request, default POST
|
||||
* responseHeaders - groovyClosure as string which must evaluate to Map which will be added to response headers, default { _ -> [:] }
|
||||
### Parameters
|
||||
|
||||
- name - name of mock, must be unique
|
||||
- path - path on which mock should be created
|
||||
- port - inteer, port on which mock should be created, cannot be the same as mock server port
|
||||
- predicate - groovy closure as string which must evaluate to true, when request object will be given to satisfy mock, optional, default {_ -> true}
|
||||
- response - groovy closure as string which must evaluate to string which will be response of mock when predicate is satisfied, optional, default { _ -> '' }
|
||||
- soap - true or false, is request and response should be wrapped in soap Envelope and Body elements, default false
|
||||
- statusCode - integer, status code of response when predicate is satisfied, default 200
|
||||
- method - POST|PUT|DELETE|GET|TRACE|OPTION|HEAD|ANY_METHOD, expected http method of request, default `POST`, `ANY_METHOD` matches all HTTP methods
|
||||
- responseHeaders - groovyClosure as string which must evaluate to Map which will be added to response headers, default { _ -> \[:] }
|
||||
- schema - path to xsd schema file on mockserver classpath; default empty, so no vallidation of request is performed; if validation fails then response has got status 400 and response is raw message from validator
|
||||
- imports - list of imports for closures (each import is separate tag); `alias` is the name of `fullClassName` available in closure; `fullClassName` must be available on classpath of mock server
|
||||
- https - HTTPS configuration
|
||||
- maxUses - limit uses of mock to the specific number, after that mock is marked as ignored (any negative number means unlimited - default, cannot set value to 0), after this number of invocation mock history is still available, but mock does not apply to any request
|
||||
- cyclic - should mock be added after `maxUses` uses at the end of the mock list (by default false)
|
||||
|
||||
#### HTTPS configuration
|
||||
|
||||
- keystorePath - path to keystore in JKS format, keystore should contains only one privateKeyEntry
|
||||
- keystorePassword - keystore password
|
||||
- keyPassword - key password
|
||||
- truststorePath - path to truststore in JKS format
|
||||
- truststorePassword - truststore password
|
||||
- requireClientAuth - whether client auth is required (two-way SSL)
|
||||
|
||||
**HTTP** and **HTTPS** should be started on separated ports.
|
||||
|
||||
### Closures request properties
|
||||
|
||||
In closures input parameter (called req) contains properties:
|
||||
|
||||
|
||||
* text - request body as java.util.String
|
||||
* headers - java.util.Map with request headers
|
||||
* query - java.util.Map with query parameters
|
||||
* xml - groovy.util.slurpersupport.GPathResult created from request body (if request body is valid xml)
|
||||
* soap - groovy.util.slurpersupport.GPathResult created from request body without Envelope and Body elements (if request body is valid soap xml)
|
||||
* json - java.lang.Object created from request body (if request body is valid json)
|
||||
* path - java.util.List<String> with not empty parts of request path
|
||||
- text - request body as java.util.String
|
||||
- headers - java.util.Map with request headers
|
||||
- query - java.util.Map with query parameters
|
||||
- xml - groovy.util.slurpersupport.GPathResult created from request body (if request body is valid xml)
|
||||
- soap - groovy.util.slurpersupport.GPathResult created from request body without Envelope and Body elements (if request body is valid soap xml)
|
||||
- json - java.lang.Object created from request body (if request body is valid json)
|
||||
- path - java.util.List<String> with not empty parts of request path
|
||||
|
||||
Response if success:
|
||||
|
||||
```xml
|
||||
<mockAdded xmlns="http://touk.pl/mockserver/api/response"/>
|
||||
<mockAdded xmlns="http://ztsh.eu/mockserver/api/response"/>
|
||||
```
|
||||
|
||||
Response with error message if failure:
|
||||
|
||||
```xml
|
||||
<exceptionOccured xmlns="http://touk.pl/mockserver/api/response">...</exceptionOccured>
|
||||
<exceptionOccured xmlns="http://ztsh.eu/mockserver/api/response">...</exceptionOccured>
|
||||
```
|
||||
|
||||
## Mock could be peeked to get get report of its invocations.
|
||||
Via client:
|
||||
Peek mock
|
||||
---------
|
||||
|
||||
Mock could be peeked to get get report of its invocations.
|
||||
|
||||
### Via client
|
||||
|
||||
```java
|
||||
List<MockEvent> mockEvents = remoteMockServer.peekMock('...')
|
||||
```
|
||||
|
||||
Via sending POST request to localhost:<PORT>/serverControl
|
||||
### Via HTTP
|
||||
|
||||
Send POST request to localhost:<PORT>/serverControl
|
||||
|
||||
```xml
|
||||
<peekMock xmlns="http://touk.pl/mockserver/api/request">
|
||||
<peekMock xmlns="http://ztsh.eu/mockserver/api/request">
|
||||
<name>...</name>
|
||||
</peekMock>
|
||||
```
|
||||
|
@ -99,7 +233,7 @@ Via sending POST request to localhost:<PORT>/serverControl
|
|||
Response if success:
|
||||
|
||||
```xml
|
||||
<mockPeeked xmlns="http://touk.pl/mockserver/api/response">
|
||||
<mockPeeked xmlns="http://ztsh.eu/mockserver/api/response">
|
||||
<mockEvent>
|
||||
<request>
|
||||
<text>...</text>
|
||||
|
@ -131,20 +265,26 @@ Response if success:
|
|||
Response with error message if failure:
|
||||
|
||||
```xml
|
||||
<exceptionOccured xmlns="http://touk.pl/mockserver/api/response">...</exceptionOccured>
|
||||
<exceptionOccured xmlns="http://ztsh.eu/mockserver/api/response">...</exceptionOccured>
|
||||
```
|
||||
|
||||
## When mock was used it could be unregistered by name. It also optionally returns report of mock invocations if second parameter is true.
|
||||
Via client:
|
||||
Remove mock
|
||||
-----------
|
||||
|
||||
When mock was used it could be unregistered by name. It also optionally returns report of mock invocations if second parameter is true.
|
||||
|
||||
### Via client
|
||||
|
||||
```java
|
||||
List<MockEvent> mockEvents = remoteMockServer.removeMock('...', ...)
|
||||
```
|
||||
|
||||
Via sending POST request to localhost:<PORT>/serverControl
|
||||
### Via HTTP
|
||||
|
||||
Send POST request to localhost:<PORT>/serverControl
|
||||
|
||||
```xml
|
||||
<removeMock xmlns="http://touk.pl/mockserver/api/request">
|
||||
<removeMock xmlns="http://ztsh.eu/mockserver/api/request">
|
||||
<name>...</name>
|
||||
<skipReport>...</skipReport>
|
||||
</removeMock>
|
||||
|
@ -153,7 +293,7 @@ Via sending POST request to localhost:<PORT>/serverControl
|
|||
Response if success (and skipReport not given or equal false):
|
||||
|
||||
```xml
|
||||
<mockRemoved xmlns="http://touk.pl/mockserver/api/response">
|
||||
<mockRemoved xmlns="http://ztsh.eu/mockserver/api/response">
|
||||
<mockEvent>
|
||||
<request>
|
||||
<text>...</text>
|
||||
|
@ -185,25 +325,27 @@ Response if success (and skipReport not given or equal false):
|
|||
If skipReport is set to true then response will be:
|
||||
|
||||
```xml
|
||||
<mockRemoved xmlns="http://touk.pl/mockserver/api/response"/>
|
||||
<mockRemoved xmlns="http://ztsh.eu/mockserver/api/response"/>
|
||||
```
|
||||
|
||||
|
||||
Response with error message if failure:
|
||||
|
||||
```xml
|
||||
<exceptionOccured xmlns="http://touk.pl/mockserver/api/response">...</exceptionOccured>
|
||||
<exceptionOccured xmlns="http://ztsh.eu/mockserver/api/response">...</exceptionOccured>
|
||||
```
|
||||
|
||||
List mocks definitions
|
||||
----------------------
|
||||
|
||||
## List of current registered mocks could be retrieved:
|
||||
Via client:
|
||||
### Via client
|
||||
|
||||
```java
|
||||
List<RegisteredMock> mocks = remoteMockServer.listMocks()
|
||||
```
|
||||
|
||||
or via sending GET request to localhost:<PORT>/serverControl
|
||||
### Via HTTP
|
||||
|
||||
Send GET request to localhost:<PORT>/serverControl
|
||||
|
||||
Response:
|
||||
|
||||
|
@ -219,7 +361,91 @@ Response:
|
|||
<soap>...</soap>
|
||||
<method>...</method>
|
||||
<statusCode>...</statusCode>
|
||||
<imports alias="..." fullClassName="..."/>
|
||||
</mock>
|
||||
...
|
||||
</mocks>
|
||||
```
|
||||
|
||||
Get mocks configuration
|
||||
-----------------------
|
||||
|
||||
### Via client
|
||||
|
||||
```java
|
||||
ConfigObject mocks = remoteMockServer.getConfiguration()
|
||||
```
|
||||
|
||||
### Via HTTP
|
||||
|
||||
Send GET request to localhost:<PORT>/serverControl/configuration
|
||||
|
||||
Response:
|
||||
|
||||
```groovy
|
||||
testRest2 {
|
||||
port=9998
|
||||
response='{ req -> \'<response/>\' }'
|
||||
responseHeaders='{ _ -> [a: "b"] }'
|
||||
path='testEndpoint'
|
||||
predicate='{ req -> req.xml.name() == \'request1\'}'
|
||||
name='testRest2'
|
||||
}
|
||||
testRest4 {
|
||||
soap=true
|
||||
port=9999
|
||||
path='testEndpoint'
|
||||
name='testRest4'
|
||||
method='PUT'
|
||||
statusCode=204
|
||||
}
|
||||
testRest3 {
|
||||
port=9999
|
||||
path='testEndpoint2'
|
||||
name='testRest3'
|
||||
}
|
||||
testRest6 {
|
||||
port=9999
|
||||
path='testEndpoint2'
|
||||
name='testRest6'
|
||||
}
|
||||
testRest {
|
||||
imports {
|
||||
aaa='bbb'
|
||||
ccc='bla'
|
||||
}
|
||||
port=10001
|
||||
path='testEndpoint'
|
||||
name='testRest'
|
||||
}
|
||||
```
|
||||
|
||||
This response could be saved to file and passed as it is during mock server creation.
|
||||
|
||||
Remote repository
|
||||
-----------------
|
||||
|
||||
Mockserver is available at `philanthropist.ztsh.eu`.
|
||||
|
||||
Just add repository to maven pom:
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<repositories>
|
||||
...
|
||||
<repository>
|
||||
<id>touk</id>
|
||||
<url>https://philanthropist.ztsh.eu/nexus/content/repositories/releases</url>
|
||||
</repository>
|
||||
...
|
||||
</repositories>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
Q: *Can I have two mocks returning responses interchangeably for the same request?*
|
||||
A: Yes, you can. Just set two mocks with `maxUses: 1` and `cyclic: true`.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
mvn clean install
|
||||
mvn -f mockserver/pom.xml package assembly:single
|
||||
mvn -f mockserver/pom.xml clean package assembly:single
|
||||
|
||||
docker build -t mockserver .
|
||||
|
|
|
@ -2,3 +2,5 @@ mocks:
|
|||
image: mockserver
|
||||
ports:
|
||||
- "9999:9999"
|
||||
volumes:
|
||||
- /tmp:/externalSchema
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -18,19 +24,9 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
|
||||
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
|
||||
jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<jxb:bindings>
|
||||
<jxb:globalBindings>
|
||||
<bindings version="3.0"
|
||||
xmlns="https://jakarta.ee/xml/ns/jaxb"
|
||||
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
|
||||
|
||||
<globalBindings>
|
||||
<xjc:simple/>
|
||||
</jxb:globalBindings>
|
||||
</jxb:bindings>
|
||||
</jxb:bindings>
|
||||
</globalBindings>
|
||||
|
||||
</bindings>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema version="1.0" targetNamespace="http://ztsh.eu/mockserver/api/common" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="method">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="POST"/>
|
||||
<xs:enumeration value="GET"/>
|
||||
<xs:enumeration value="DELETE"/>
|
||||
<xs:enumeration value="PUT"/>
|
||||
<xs:enumeration value="TRACE"/>
|
||||
<xs:enumeration value="HEAD"/>
|
||||
<xs:enumeration value="OPTIONS"/>
|
||||
<xs:enumeration value="PATCH"/>
|
||||
<xs:enumeration value="ANY_METHOD" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="importAlias">
|
||||
<xs:attribute name="alias" type="xs:string"/>
|
||||
<xs:attribute name="fullClassName" type="xs:string"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="https">
|
||||
<xs:sequence>
|
||||
<xs:element name="keystorePath" type="xs:string" />
|
||||
<xs:element name="keystorePassword" type="xs:string" />
|
||||
<xs:element name="keyPassword" type="xs:string" />
|
||||
<xs:element name="truststorePath" type="xs:string" />
|
||||
<xs:element name="truststorePassword" type="xs:string" />
|
||||
<xs:element name="requireClientAuth" type="xs:boolean" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://ztsh.eu/mockserver/api/request" xmlns:tns="http://ztsh.eu/mockserver/api/request" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:common="http://ztsh.eu/mockserver/api/common">
|
||||
|
||||
<xs:import namespace="http://ztsh.eu/mockserver/api/common" schemaLocation="common.xsd"/>
|
||||
|
||||
<xs:element name="addMock" type="tns:AddMock"/>
|
||||
|
||||
<xs:element name="peekMock" type="tns:PeekMock"/>
|
||||
|
||||
<xs:element name="removeMock" type="tns:RemoveMock"/>
|
||||
|
||||
<xs:complexType name="AddMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest">
|
||||
<xs:sequence>
|
||||
<xs:element name="path" type="xs:string"/>
|
||||
<xs:element name="port" type="xs:int"/>
|
||||
<xs:element name="predicate" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="response" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="soap" type="xs:boolean" minOccurs="0"/>
|
||||
<xs:element name="statusCode" type="xs:int" minOccurs="0"/>
|
||||
<xs:element name="method" type="common:method" minOccurs="0"/>
|
||||
<xs:element name="https" type="common:https" minOccurs="0" />
|
||||
<xs:element name="responseHeaders" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="schema" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="preserveHistory" type="xs:boolean" minOccurs="0"/>
|
||||
<xs:element name="maxUses" type="xs:int" minOccurs="0" />
|
||||
<xs:element name="cyclic" type="xs:boolean" minOccurs="0" default="false" />
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockServerRequest" abstract="true">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="PeekMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="RemoveMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest">
|
||||
<xs:sequence>
|
||||
<xs:element name="skipReport" type="xs:boolean" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
137
mockserver-api/src/main/xsd/eu/ztsh/mockserver/api/response.xsd
Normal file
137
mockserver-api/src/main/xsd/eu/ztsh/mockserver/api/response.xsd
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://ztsh.eu/mockserver/api/response" xmlns:tns="http://ztsh.eu/mockserver/api/response" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:common="http://ztsh.eu/mockserver/api/common">
|
||||
|
||||
<xs:import namespace="http://ztsh.eu/mockserver/api/common" schemaLocation="common.xsd"/>
|
||||
|
||||
<xs:element name="exceptionOccured" type="tns:exceptionOccured"/>
|
||||
|
||||
<xs:element name="mockAdded" type="tns:mockAdded"/>
|
||||
|
||||
<xs:element name="mockPeeked" type="tns:mockPeeked"/>
|
||||
|
||||
<xs:element name="mockRemoved" type="tns:mockRemoved"/>
|
||||
|
||||
<xs:element name="mocks" type="tns:mockListing"/>
|
||||
|
||||
<xs:complexType name="exceptionOccured">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockAdded">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockServerResponse" abstract="true">
|
||||
<xs:sequence/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockEventReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="request" type="tns:mockRequestReport"/>
|
||||
<xs:element name="response" type="tns:mockResponseReport"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockRequestReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="text" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="headers" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="header" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="queryParams" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="queryParam" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="path" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="pathPart" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="parameter">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockResponseReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="statusCode" type="xs:int"/>
|
||||
<xs:element name="text" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="headers" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="header" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockListing">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mock" type="tns:mockReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="path" type="xs:string"/>
|
||||
<xs:element name="port" type="xs:int"/>
|
||||
<xs:element name="predicate" type="xs:string"/>
|
||||
<xs:element name="response" type="xs:string"/>
|
||||
<xs:element name="responseHeaders" type="xs:string"/>
|
||||
<xs:element name="soap" type="xs:boolean"/>
|
||||
<xs:element name="method" type="common:method"/>
|
||||
<xs:element name="statusCode" type="xs:int"/>
|
||||
<xs:element name="schema" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="preserveHistory" type="xs:boolean" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockPeeked">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mockEvent" type="tns:mockEventReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockRemoved">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mockEvent" type="tns:mockEventReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema version="1.0" targetNamespace="http://touk.pl/mockserver/api/common" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="method">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="POST"/>
|
||||
<xs:enumeration value="GET"/>
|
||||
<xs:enumeration value="DELETE"/>
|
||||
<xs:enumeration value="PUT"/>
|
||||
<xs:enumeration value="TRACE"/>
|
||||
<xs:enumeration value="HEAD"/>
|
||||
<xs:enumeration value="OPTIONS"/>
|
||||
<xs:enumeration value="PATCH"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://touk.pl/mockserver/api/request" xmlns:tns="http://touk.pl/mockserver/api/request" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:common="http://touk.pl/mockserver/api/common">
|
||||
|
||||
<xs:import namespace="http://touk.pl/mockserver/api/common" schemaLocation="common.xsd"/>
|
||||
|
||||
<xs:element name="addMock" type="tns:AddMock"/>
|
||||
|
||||
<xs:element name="peekMock" type="tns:PeekMock"/>
|
||||
|
||||
<xs:element name="removeMock" type="tns:RemoveMock"/>
|
||||
|
||||
<xs:complexType name="AddMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest">
|
||||
<xs:sequence>
|
||||
<xs:element name="path" type="xs:string"/>
|
||||
<xs:element name="port" type="xs:int"/>
|
||||
<xs:element name="predicate" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="response" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="soap" type="xs:boolean" minOccurs="0"/>
|
||||
<xs:element name="statusCode" type="xs:int" minOccurs="0"/>
|
||||
<xs:element name="method" type="common:method" minOccurs="0"/>
|
||||
<xs:element name="responseHeaders" type="xs:string" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockServerRequest" abstract="true">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="PeekMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="RemoveMock">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerRequest">
|
||||
<xs:sequence>
|
||||
<xs:element name="skipReport" type="xs:boolean" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://touk.pl/mockserver/api/response" xmlns:tns="http://touk.pl/mockserver/api/response" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:common="http://touk.pl/mockserver/api/common">
|
||||
|
||||
<xs:import namespace="http://touk.pl/mockserver/api/common" schemaLocation="common.xsd"/>
|
||||
|
||||
<xs:element name="exceptionOccured" type="tns:exceptionOccured"/>
|
||||
|
||||
<xs:element name="mockAdded" type="tns:mockAdded"/>
|
||||
|
||||
<xs:element name="mockPeeked" type="tns:mockPeeked"/>
|
||||
|
||||
<xs:element name="mockRemoved" type="tns:mockRemoved"/>
|
||||
|
||||
<xs:element name="mocks" type="tns:mockListing"/>
|
||||
|
||||
<xs:complexType name="exceptionOccured">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockAdded">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockServerResponse" abstract="true">
|
||||
<xs:sequence/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockEventReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="request" type="tns:mockRequestReport"/>
|
||||
<xs:element name="response" type="tns:mockResponseReport"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockRequestReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="text" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="headers" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="header" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="queryParams" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="queryParam" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="path" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="pathPart" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="parameter">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockResponseReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="statusCode" type="xs:int"/>
|
||||
<xs:element name="text" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="headers" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="header" type="tns:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockListing">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mock" type="tns:mockReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockReport">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="path" type="xs:string"/>
|
||||
<xs:element name="port" type="xs:int"/>
|
||||
<xs:element name="predicate" type="xs:string"/>
|
||||
<xs:element name="response" type="xs:string"/>
|
||||
<xs:element name="responseHeaders" type="xs:string"/>
|
||||
<xs:element name="soap" type="xs:boolean"/>
|
||||
<xs:element name="method" type="common:method"/>
|
||||
<xs:element name="statusCode" type="xs:int"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockPeeked">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mockEvent" type="tns:mockEventReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mockRemoved">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="tns:mockServerResponse">
|
||||
<xs:sequence>
|
||||
<xs:element name="mockEvent" type="tns:mockEventReport" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
|
@ -1,22 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mockserver-client</artifactId>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-xml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
|
@ -25,9 +47,15 @@
|
|||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.client
|
||||
package eu.ztsh.mockserver.client
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeChecked
|
|
@ -0,0 +1,9 @@
|
|||
package eu.ztsh.mockserver.client
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeChecked
|
||||
|
||||
@CompileStatic
|
||||
@TypeChecked
|
||||
class InvalidMockRequestSchema extends RuntimeException {
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.client
|
||||
package eu.ztsh.mockserver.client
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeChecked
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.client
|
||||
package eu.ztsh.mockserver.client
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeChecked
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.client
|
||||
package eu.ztsh.mockserver.client
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.client.methods.HttpGet
|
||||
|
@ -7,13 +7,17 @@ import org.apache.http.entity.ContentType
|
|||
import org.apache.http.entity.StringEntity
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClients
|
||||
import pl.touk.mockserver.api.request.AddMock
|
||||
import pl.touk.mockserver.api.request.MockServerRequest
|
||||
import pl.touk.mockserver.api.request.PeekMock
|
||||
import pl.touk.mockserver.api.request.RemoveMock
|
||||
import pl.touk.mockserver.api.response.*
|
||||
import eu.ztsh.mockserver.api.request.AddMock
|
||||
import eu.ztsh.mockserver.api.request.MockServerRequest
|
||||
import eu.ztsh.mockserver.api.request.PeekMock
|
||||
import eu.ztsh.mockserver.api.request.RemoveMock
|
||||
import eu.ztsh.mockserver.api.response.MockEventReport
|
||||
import eu.ztsh.mockserver.api.response.MockPeeked
|
||||
import eu.ztsh.mockserver.api.response.MockRemoved
|
||||
import eu.ztsh.mockserver.api.response.MockReport
|
||||
import eu.ztsh.mockserver.api.response.Mocks
|
||||
|
||||
import javax.xml.bind.JAXBContext
|
||||
import jakarta.xml.bind.JAXBContext
|
||||
|
||||
class RemoteMockServer {
|
||||
private final String address
|
||||
|
@ -47,6 +51,13 @@ class RemoteMockServer {
|
|||
return mockPeeked.mockEvents ?: []
|
||||
}
|
||||
|
||||
ConfigObject getConfiguration() {
|
||||
HttpGet get = new HttpGet(address + '/configuration')
|
||||
CloseableHttpResponse response = client.execute(get)
|
||||
String configuration = Util.extractStringResponse(response)
|
||||
return new ConfigSlurper().parse(configuration)
|
||||
}
|
||||
|
||||
private static StringEntity buildRemoveMockRequest(RemoveMock data) {
|
||||
return new StringEntity(marshallRequest(data), ContentType.create("text/xml", "UTF-8"))
|
||||
}
|
|
@ -1,17 +1,18 @@
|
|||
package pl.touk.mockserver.client
|
||||
package eu.ztsh.mockserver.client
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeChecked
|
||||
import groovy.util.slurpersupport.GPathResult
|
||||
import groovy.xml.XmlSlurper
|
||||
import groovy.xml.slurpersupport.GPathResult
|
||||
import org.apache.http.HttpEntity
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.util.EntityUtils
|
||||
import pl.touk.mockserver.api.response.ExceptionOccured
|
||||
import pl.touk.mockserver.api.response.MockAdded
|
||||
import pl.touk.mockserver.api.response.MockServerResponse
|
||||
import eu.ztsh.mockserver.api.response.ExceptionOccured
|
||||
import eu.ztsh.mockserver.api.response.MockAdded
|
||||
import eu.ztsh.mockserver.api.response.MockServerResponse
|
||||
|
||||
import javax.xml.bind.JAXBContext
|
||||
import jakarta.xml.bind.JAXBContext
|
||||
|
||||
@CompileStatic
|
||||
@TypeChecked
|
||||
|
@ -42,6 +43,9 @@ class Util {
|
|||
if (message == 'mock not registered') {
|
||||
throw new MockDoesNotExist()
|
||||
}
|
||||
if (message == 'mock request schema is invalid schema') {
|
||||
throw new InvalidMockRequestSchema()
|
||||
}
|
||||
throw new InvalidMockDefinition(message)
|
||||
}
|
||||
|
|
@ -1,49 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<version>2.0.0</version>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mockserver-tests</artifactId>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<artifactId>mockserver-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
package eu.ztsh.mockserver.tests
|
||||
|
||||
import eu.ztsh.mockserver.api.common.Https
|
||||
import eu.ztsh.mockserver.api.request.AddMock
|
||||
import eu.ztsh.mockserver.client.RemoteMockServer
|
||||
import eu.ztsh.mockserver.client.Util
|
||||
import eu.ztsh.mockserver.server.HttpMockServer
|
||||
import groovy.xml.slurpersupport.GPathResult
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.client.methods.HttpPost
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
|
||||
import org.apache.http.conn.ssl.SSLContexts
|
||||
import org.apache.http.entity.ContentType
|
||||
import org.apache.http.entity.StringEntity
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClients
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLHandshakeException
|
||||
import java.security.KeyStore
|
||||
|
||||
@Ignore
|
||||
class MockServerHttpsTest extends Specification {
|
||||
|
||||
RemoteMockServer remoteMockServer = new RemoteMockServer('localhost', 19000)
|
||||
|
||||
@AutoCleanup('stop')
|
||||
HttpMockServer httpMockServer = new HttpMockServer(19000)
|
||||
|
||||
@Shared
|
||||
SSLContext noClientAuthSslContext = SSLContexts.custom()
|
||||
.loadTrustMaterial(trustStore())
|
||||
.build()
|
||||
|
||||
@Shared
|
||||
SSLContext trustedCertificateSslContext = SSLContexts.custom()
|
||||
.loadKeyMaterial(trustedCertificateKeystore(), 'changeit'.toCharArray())
|
||||
.loadTrustMaterial(trustStore())
|
||||
.build()
|
||||
|
||||
@Shared
|
||||
SSLContext untrustedCertificateSslContext = SSLContexts.custom()
|
||||
.loadKeyMaterial(untrustedCertificateKeystore(), 'changeit'.toCharArray())
|
||||
.loadTrustMaterial(trustStore())
|
||||
.build()
|
||||
|
||||
@Ignore("TODO: SSL peer shut down incorrectly")
|
||||
def 'should handle HTTPS server' () {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testHttps',
|
||||
path: 'testEndpoint',
|
||||
port: 10443,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> "<goodResponse-${req.xml.name()}/>"}''',
|
||||
https: new Https(
|
||||
keyPassword: 'changeit',
|
||||
keystorePassword: 'changeit',
|
||||
keystorePath: MockServerHttpsTest.classLoader.getResource('keystore.jks').path
|
||||
),
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('https://localhost:10443/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client(noClientAuthSslContext).execute(restPost)
|
||||
then:
|
||||
GPathResult restPostResponse = Util.extractXmlResponse(response)
|
||||
restPostResponse.name() == 'goodResponse-request'
|
||||
}
|
||||
|
||||
@Ignore("TODO: SSL peer shut down incorrectly")
|
||||
def 'should handle HTTPS server with client auth' () {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testHttps',
|
||||
path: 'testEndpoint',
|
||||
port: 10443,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> "<goodResponse-${req.xml.name()}/>"}''',
|
||||
https: new Https(
|
||||
keyPassword: 'changeit',
|
||||
keystorePassword: 'changeit',
|
||||
keystorePath: MockServerHttpsTest.classLoader.getResource('keystore.jks').path,
|
||||
truststorePath: MockServerHttpsTest.classLoader.getResource('truststore.jks').path,
|
||||
truststorePassword: 'changeit',
|
||||
requireClientAuth: true
|
||||
),
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('https://localhost:10443/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client(trustedCertificateSslContext).execute(restPost)
|
||||
then:
|
||||
GPathResult restPostResponse = Util.extractXmlResponse(response)
|
||||
restPostResponse.name() == 'goodResponse-request'
|
||||
}
|
||||
|
||||
def 'should handle HTTPS server with wrong client auth' () {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testHttps',
|
||||
path: 'testEndpoint',
|
||||
port: 10443,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> "<goodResponse-${req.xml.name()}/>"}''',
|
||||
https: new Https(
|
||||
keyPassword: 'changeit',
|
||||
keystorePassword: 'changeit',
|
||||
keystorePath: MockServerHttpsTest.classLoader.getResource('keystore.jks').path,
|
||||
truststorePath: MockServerHttpsTest.classLoader.getResource('truststore.jks').path,
|
||||
truststorePassword: 'changeit',
|
||||
requireClientAuth: true
|
||||
),
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('https://localhost:10443/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
client(sslContext).execute(restPost)
|
||||
then:
|
||||
thrown(SSLHandshakeException)
|
||||
where:
|
||||
sslContext << [noClientAuthSslContext, untrustedCertificateSslContext]
|
||||
}
|
||||
|
||||
private CloseableHttpClient client(SSLContext sslContext) {
|
||||
return HttpClients.custom()
|
||||
.setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
|
||||
.setSslcontext(sslContext)
|
||||
.build()
|
||||
}
|
||||
|
||||
private KeyStore trustedCertificateKeystore() {
|
||||
return loadKeystore('trusted.jks')
|
||||
}
|
||||
|
||||
private KeyStore untrustedCertificateKeystore() {
|
||||
return loadKeystore('untrusted.jks')
|
||||
}
|
||||
|
||||
private KeyStore trustStore() {
|
||||
return loadKeystore('truststore.jks')
|
||||
}
|
||||
|
||||
private KeyStore loadKeystore(String fileName) {
|
||||
KeyStore truststore = KeyStore.getInstance(KeyStore.defaultType)
|
||||
truststore.load(new FileInputStream(MockServerHttpsTest.classLoader.getResource(fileName).path), "changeit".toCharArray());
|
||||
return truststore
|
||||
}
|
||||
}
|
|
@ -1,30 +1,43 @@
|
|||
package pl.touk.mockserver.tests
|
||||
package eu.ztsh.mockserver.tests
|
||||
|
||||
import groovy.util.slurpersupport.GPathResult
|
||||
import org.apache.http.client.methods.*
|
||||
import groovy.xml.slurpersupport.GPathResult
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.client.methods.HttpDelete
|
||||
import org.apache.http.client.methods.HttpGet
|
||||
import org.apache.http.client.methods.HttpHead
|
||||
import org.apache.http.client.methods.HttpOptions
|
||||
import org.apache.http.client.methods.HttpPatch
|
||||
import org.apache.http.client.methods.HttpPost
|
||||
import org.apache.http.client.methods.HttpPut
|
||||
import org.apache.http.client.methods.HttpTrace
|
||||
import org.apache.http.entity.ContentType
|
||||
import org.apache.http.entity.StringEntity
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClients
|
||||
import org.apache.http.util.EntityUtils
|
||||
import pl.touk.mockserver.api.request.AddMock
|
||||
import pl.touk.mockserver.api.common.Method
|
||||
import pl.touk.mockserver.api.response.MockEventReport
|
||||
import pl.touk.mockserver.api.response.MockReport
|
||||
import pl.touk.mockserver.api.response.Parameter
|
||||
import pl.touk.mockserver.client.*
|
||||
import pl.touk.mockserver.server.HttpMockServer
|
||||
import spock.lang.Shared
|
||||
import eu.ztsh.mockserver.api.common.ImportAlias
|
||||
import eu.ztsh.mockserver.api.common.Method
|
||||
import eu.ztsh.mockserver.api.request.AddMock
|
||||
import eu.ztsh.mockserver.api.response.MockEventReport
|
||||
import eu.ztsh.mockserver.api.response.MockReport
|
||||
import eu.ztsh.mockserver.client.InvalidMockDefinition
|
||||
import eu.ztsh.mockserver.client.InvalidMockRequestSchema
|
||||
import eu.ztsh.mockserver.client.MockAlreadyExists
|
||||
import eu.ztsh.mockserver.client.MockDoesNotExist
|
||||
import eu.ztsh.mockserver.client.RemoteMockServer
|
||||
import eu.ztsh.mockserver.client.Util
|
||||
import eu.ztsh.mockserver.server.HttpMockServer
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Unroll
|
||||
|
||||
class MockServerIntegrationTest extends Specification {
|
||||
|
||||
RemoteMockServer remoteMockServer
|
||||
|
||||
@AutoCleanup('stop')
|
||||
HttpMockServer httpMockServer
|
||||
|
||||
@Shared
|
||||
CloseableHttpClient client = HttpClients.createDefault()
|
||||
|
||||
def setup() {
|
||||
|
@ -32,10 +45,6 @@ class MockServerIntegrationTest extends Specification {
|
|||
remoteMockServer = new RemoteMockServer('localhost', 9000)
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
httpMockServer.stop()
|
||||
}
|
||||
|
||||
def "should add working rest mock on endpoint"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -57,6 +66,7 @@ class MockServerIntegrationTest extends Specification {
|
|||
remoteMockServer.removeMock('testRest')?.size() == 1
|
||||
}
|
||||
|
||||
@Ignore("TODO: restPostResponse.name()")
|
||||
def "should add working rest mock on endpoint with utf"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -146,6 +156,20 @@ class MockServerIntegrationTest extends Specification {
|
|||
thrown(MockAlreadyExists)
|
||||
}
|
||||
|
||||
def "should not add mock when schema does not exist"() {
|
||||
when:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'test',
|
||||
path: 'testEndpoint2',
|
||||
port: 9998,
|
||||
response: '''{req -> "<goodResponse/>"}''',
|
||||
soap: false,
|
||||
schema: 'ble.xsd'
|
||||
))
|
||||
then:
|
||||
thrown(InvalidMockRequestSchema)
|
||||
}
|
||||
|
||||
def "should not add mock with empty name"() {
|
||||
when:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -217,7 +241,6 @@ class MockServerIntegrationTest extends Specification {
|
|||
soapPostResponse.Body.'goodResponseSoap-request'.size() == 1
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "should dispatch rest mocks when second on #name"() {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -256,7 +279,6 @@ class MockServerIntegrationTest extends Specification {
|
|||
9998 | 'test2' | 'another port and path'
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "should dispatch rest mock with response code"() {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -598,7 +620,7 @@ class MockServerIntegrationTest extends Specification {
|
|||
restPostResponse.name == 'goodResponse-1'
|
||||
}
|
||||
|
||||
def "should get list mocks"() {
|
||||
def "should get list of mocks"() {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest2',
|
||||
|
@ -634,21 +656,24 @@ class MockServerIntegrationTest extends Specification {
|
|||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999
|
||||
port: 9999,
|
||||
schema: 'schema2.xsd',
|
||||
imports: [new ImportAlias(alias: 'aaa', fullClassName: 'bbb')]
|
||||
))
|
||||
remoteMockServer.removeMock('testRest5')
|
||||
when:
|
||||
List<MockReport> mockReport = remoteMockServer.listMocks()
|
||||
then:
|
||||
mockReport.size() == 5
|
||||
assertMockReport(mockReport[0], [name:'testRest', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
assertMockReport(mockReport[0], [name: 'testRest', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST, schema: 'schema2.xsd'])
|
||||
assertMockReport(mockReport[1], [name: 'testRest2', path: 'testEndpoint', port: 9998, predicate: '''{ req -> req.xml.name() == 'request1'}''', response: '''{ req -> '<response/>' }''', responseHeaders: '{ _ -> [a: "b"] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
assertMockReport(mockReport[2], [name: 'testRest3', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
assertMockReport(mockReport[3], [name: 'testRest4', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: true, statusCode: 204, method: Method.PUT])
|
||||
assertMockReport(mockReport[4], [name: 'testRest6', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
mockReport[0].imports.find { it.alias == 'aaa' }?.fullClassName == 'bbb'
|
||||
}
|
||||
|
||||
private void assertMockReport( MockReport mockReport, Map<String, Object> props) {
|
||||
private static void assertMockReport(MockReport mockReport, Map<String, Object> props) {
|
||||
props.each {
|
||||
assert mockReport."${it.key}" == it.value
|
||||
}
|
||||
|
@ -827,7 +852,6 @@ class MockServerIntegrationTest extends Specification {
|
|||
mockEvents2[0].response.statusCode == 202
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "should return mock report with #mockEvents events when deleting mock with flag skip mock = #skipReport"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -855,7 +879,6 @@ class MockServerIntegrationTest extends Specification {
|
|||
true | 0
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "should reject mock when it has System.exit in closure"() {
|
||||
when:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
|
@ -881,4 +904,280 @@ class MockServerIntegrationTest extends Specification {
|
|||
'''{req -> System.exit (-1); req.xml.name() == 'request'}'''
|
||||
]
|
||||
}
|
||||
|
||||
def "should validate request against multiple schema files"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
schema: 'schema1.xsd',
|
||||
response: '''{req -> '<goodResponseRest/>'}''',
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request xmlns="http://mockserver/test1"><id>15</id><value>unknown</value></request>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
response.statusLine.statusCode == 400
|
||||
Util.extractStringResponse(response).contains('''Value 'unknown' is not facet-valid with respect to enumeration '[test, prod, preprod]'.''')
|
||||
when:
|
||||
HttpPost restPost2 = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost2.entity = new StringEntity('<request xmlns="http://mockserver/test1"><id>15</id><value>test</value></request>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response2 = client.execute(restPost2)
|
||||
then:
|
||||
Util.consumeResponse(response2)
|
||||
response2.statusLine.statusCode == 200
|
||||
expect:
|
||||
remoteMockServer.removeMock('testRest')?.size() == 2
|
||||
}
|
||||
|
||||
def "should validate soap request"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testSoap',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
schema: 'schema1.xsd',
|
||||
response: '''{req -> '<goodResponse/>'}''',
|
||||
soap: true
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity(Util.soap('<request xmlns="http://mockserver/test1"><id>15</id><value>unknown</value></request>'), ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
response.statusLine.statusCode == 400
|
||||
Util.extractStringResponse(response).contains('''Value 'unknown' is not facet-valid with respect to enumeration '[test, prod, preprod]'.''')
|
||||
when:
|
||||
HttpPost restPost2 = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost2.entity = new StringEntity(Util.soap('<request xmlns="http://mockserver/test1"><id>15</id><value>test</value></request>'), ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response2 = client.execute(restPost2)
|
||||
then:
|
||||
Util.consumeResponse(response2)
|
||||
response2.statusLine.statusCode == 200
|
||||
expect:
|
||||
remoteMockServer.removeMock('testSoap')?.size() == 2
|
||||
}
|
||||
|
||||
def "should validate soap request with namespace in envelope"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testSoap',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
schema: 'schema1.xsd',
|
||||
response: '''{req -> '<goodResponse/>'}''',
|
||||
soap: true
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('''<soap-env:Envelope xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'
|
||||
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
|
||||
xmlns:req="http://mockserver/test1">
|
||||
<soap-env:Body>
|
||||
<req:request><req:id>15</req:id><req:value>unknown</req:value></req:request>
|
||||
</soap-env:Body>
|
||||
</soap-env:Envelope>''', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
response.statusLine.statusCode == 400
|
||||
Util.extractStringResponse(response).contains('''Value 'unknown' is not facet-valid with respect to enumeration '[test, prod, preprod]'.''')
|
||||
when:
|
||||
HttpPost restPost2 = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost2.entity = new StringEntity('''<soap-env:Envelope xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'
|
||||
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
|
||||
xmlns:req="http://mockserver/test1">
|
||||
<soap-env:Body>
|
||||
<req:request><req:id>15</req:id><req:value>test</req:value></req:request>
|
||||
</soap-env:Body>
|
||||
</soap-env:Envelope>''', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response2 = client.execute(restPost2)
|
||||
then:
|
||||
Util.consumeResponse(response2)
|
||||
response2.statusLine.statusCode == 200
|
||||
expect:
|
||||
remoteMockServer.removeMock('testSoap')?.size() == 2
|
||||
}
|
||||
|
||||
def "should add mock with alias"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> "<goodResponseRest-${AAA.XMLNS_ATTRIBUTE}/>"}''',
|
||||
soap: false,
|
||||
imports: [new ImportAlias(alias: 'AAA', fullClassName: 'javax.xml.XMLConstants')]
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
GPathResult restPostResponse = Util.extractXmlResponse(response)
|
||||
restPostResponse.name() == 'goodResponseRest-xmlns'
|
||||
expect:
|
||||
remoteMockServer.removeMock('testRest')?.size() == 1
|
||||
}
|
||||
|
||||
def "should get configuration of mocks and reconfigure new mock server based on it"() {
|
||||
given:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest2',
|
||||
path: 'testEndpoint',
|
||||
port: 9998,
|
||||
predicate: '''{ req -> req.xml.name() == 'request1'}''',
|
||||
response: '''{ req -> '<response/>' }''',
|
||||
responseHeaders: '{ _ -> [a: "b"] }'
|
||||
))
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest4',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
soap: true,
|
||||
statusCode: 204,
|
||||
method: Method.PUT
|
||||
))
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest3',
|
||||
path: 'testEndpoint2',
|
||||
port: 9999
|
||||
))
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest5',
|
||||
path: 'testEndpoint',
|
||||
port: 9999
|
||||
))
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest6',
|
||||
path: 'testEndpoint2',
|
||||
port: 9999
|
||||
))
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
schema: 'schema2.xsd',
|
||||
imports: [
|
||||
new ImportAlias(alias: 'aaa', fullClassName: 'bbb'),
|
||||
new ImportAlias(alias: 'ccc', fullClassName: 'bla')
|
||||
],
|
||||
preserveHistory: true
|
||||
))
|
||||
remoteMockServer.removeMock('testRest5')
|
||||
when:
|
||||
ConfigObject configObject = remoteMockServer.configuration
|
||||
httpMockServer.stop()
|
||||
httpMockServer = new HttpMockServer(9000, configObject)
|
||||
|
||||
then:
|
||||
List<MockReport> mockReport = remoteMockServer.listMocks()
|
||||
mockReport.size() == 5
|
||||
assertMockReport(mockReport[0], [name: 'testRest', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST, schema: 'schema2.xsd', preserveHistory: true])
|
||||
assertMockReport(mockReport[1], [name: 'testRest2', path: 'testEndpoint', port: 9998, predicate: '''{ req -> req.xml.name() == 'request1'}''', response: '''{ req -> '<response/>' }''', responseHeaders: '{ _ -> [a: "b"] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
assertMockReport(mockReport[2], [name: 'testRest3', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
assertMockReport(mockReport[3], [name: 'testRest4', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: true, statusCode: 204, method: Method.PUT])
|
||||
assertMockReport(mockReport[4], [name: 'testRest6', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
|
||||
mockReport[0].imports.find { it.alias == 'aaa' }?.fullClassName == 'bbb'
|
||||
mockReport[0].imports.find { it.alias == 'ccc' }?.fullClassName == 'bla'
|
||||
}
|
||||
|
||||
def "should add mock without history"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> "<goodResponseRest-${req.xml.name()}/>"}''',
|
||||
soap: false,
|
||||
preserveHistory: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
GPathResult restPostResponse = Util.extractXmlResponse(response)
|
||||
restPostResponse.name() == 'goodResponseRest-request'
|
||||
expect:
|
||||
remoteMockServer.removeMock('testRest')?.size() == 0
|
||||
}
|
||||
|
||||
def "should handle empty post"() {
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'testRest',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
statusCode: 201,
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
response.statusLine.statusCode == 201
|
||||
Util.consumeResponse(response)
|
||||
expect:
|
||||
remoteMockServer.removeMock('testRest')?.size() == 1
|
||||
}
|
||||
|
||||
def 'should handle leading slash'() {
|
||||
given:
|
||||
String name = "testRest-${UUID.randomUUID().toString()}"
|
||||
expect:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: name,
|
||||
path: mockPath,
|
||||
port: 9999,
|
||||
statusCode: 201,
|
||||
soap: false
|
||||
))
|
||||
when:
|
||||
HttpPost restPost = new HttpPost("http://localhost:9999/$urlPath")
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:
|
||||
response.statusLine.statusCode == 201
|
||||
Util.consumeResponse(response)
|
||||
expect:
|
||||
remoteMockServer.removeMock(name)?.size() == 1
|
||||
where:
|
||||
mockPath | urlPath
|
||||
'' | ''
|
||||
'/' | ''
|
||||
'test' | 'test'
|
||||
'/test' | 'test'
|
||||
'test/other' | 'test/other'
|
||||
'/test/other' | 'test/other'
|
||||
}
|
||||
|
||||
def 'should match any method'() {
|
||||
given:
|
||||
String name = "testRest-${UUID.randomUUID().toString()}"
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: name,
|
||||
path: 'any-method',
|
||||
port: 9999,
|
||||
statusCode: 201,
|
||||
soap: false,
|
||||
method: Method.ANY_METHOD
|
||||
))
|
||||
when:
|
||||
CloseableHttpResponse response = client.execute(req)
|
||||
then:
|
||||
response.statusLine.statusCode == 201
|
||||
Util.consumeResponse(response)
|
||||
cleanup:
|
||||
remoteMockServer.removeMock(name)
|
||||
where:
|
||||
req << [
|
||||
new HttpGet('http://localhost:9999/any-method'),
|
||||
new HttpPost('http://localhost:9999/any-method'),
|
||||
new HttpPatch('http://localhost:9999/any-method')
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
package eu.ztsh.mockserver.tests
|
||||
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.client.methods.HttpPost
|
||||
import org.apache.http.entity.ContentType
|
||||
import org.apache.http.entity.StringEntity
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClients
|
||||
import eu.ztsh.mockserver.api.request.AddMock
|
||||
import eu.ztsh.mockserver.client.RemoteMockServer
|
||||
import eu.ztsh.mockserver.server.HttpMockServer
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
|
||||
class MockServerMaxUsesTest extends Specification {
|
||||
|
||||
RemoteMockServer remoteMockServer
|
||||
|
||||
@AutoCleanup('stop')
|
||||
HttpMockServer httpMockServer
|
||||
|
||||
CloseableHttpClient client = HttpClients.createDefault()
|
||||
|
||||
def setup() {
|
||||
httpMockServer = new HttpMockServer(9000)
|
||||
remoteMockServer = new RemoteMockServer('localhost', 9000)
|
||||
}
|
||||
|
||||
def 'should return two mocks in order'() {
|
||||
given:'mock with predicate is given but for only one use'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock1'}''',
|
||||
maxUses: 1
|
||||
))
|
||||
and:'mock with the same predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock2',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock2'}''',
|
||||
))
|
||||
when:'we call the first time'
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:'first mock should be returned and expired'
|
||||
response.entity.content.text == 'mock1'
|
||||
when:'we call the second time using the same request'
|
||||
CloseableHttpResponse response2 = client.execute(restPost)
|
||||
then:'second mock should be returned'
|
||||
response2.entity.content.text == 'mock2'
|
||||
when:'we call the third time using the same request'
|
||||
CloseableHttpResponse response3 = client.execute(restPost)
|
||||
then:'second mock should be returned, because it has unlimited uses'
|
||||
response3.entity.content.text == 'mock2'
|
||||
}
|
||||
|
||||
def 'should return two mocks in order but only once'() {
|
||||
given:'mock with predicate is given but for only one use'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock1'}''',
|
||||
maxUses: 1
|
||||
))
|
||||
and:'mock with the same predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock2',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock2'}''',
|
||||
maxUses: 1,
|
||||
))
|
||||
when:'we call the first time'
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:'first mock should be returned and expired'
|
||||
response.entity.content.text == 'mock1'
|
||||
when:'we call the second time using the same request'
|
||||
CloseableHttpResponse response2 = client.execute(restPost)
|
||||
then:'second mock should be returned'
|
||||
response2.entity.content.text == 'mock2'
|
||||
when:'we call the third time using the same request'
|
||||
CloseableHttpResponse response3 = client.execute(restPost)
|
||||
then:'no mock should be found'
|
||||
response3.statusLine.statusCode == 404
|
||||
and:'mock should exist'
|
||||
remoteMockServer.listMocks().find { it.name == 'mock1' } != null
|
||||
}
|
||||
|
||||
def 'should return two mocks in cyclic order'() {
|
||||
given:'mock with predicate is given but for only one use'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock1'}''',
|
||||
maxUses: 1,
|
||||
cyclic: true,
|
||||
preserveHistory: true
|
||||
))
|
||||
and:'mock with the same predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock2',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock2'}''',
|
||||
maxUses: 1,
|
||||
cyclic: true
|
||||
))
|
||||
when:'we call the first time'
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:'first mock should be returned and expired'
|
||||
response.entity.content.text == 'mock1'
|
||||
when:'we call the second time using the same request'
|
||||
CloseableHttpResponse response2 = client.execute(restPost)
|
||||
then:'second mock should be returned and expired'
|
||||
response2.entity.content.text == 'mock2'
|
||||
when:'we call the third time using the same request'
|
||||
CloseableHttpResponse response3 = client.execute(restPost)
|
||||
then:'first mock should be returned, because these mocks are cyclic'
|
||||
response3.entity.content.text == 'mock1'
|
||||
when:'we call the fourth time using the same request'
|
||||
CloseableHttpResponse response4 = client.execute(restPost)
|
||||
then:'second mock should be returned, because these mocks are cyclic'
|
||||
response4.entity.content.text == 'mock2'
|
||||
and:
|
||||
remoteMockServer.peekMock('mock1').size() == 2
|
||||
}
|
||||
|
||||
def 'should return two mocks with the same request interjected by another'() {
|
||||
given:'mock with predicate is given but for only one use'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock1'}''',
|
||||
maxUses: 1,
|
||||
cyclic: true
|
||||
))
|
||||
and:'mock with the same predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock2',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock2'}''',
|
||||
maxUses: 1,
|
||||
cyclic: true
|
||||
))
|
||||
and:'mock with other predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'otherMock',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'otherRequest'}''',
|
||||
response: '''{req -> 'otherMock'}'''
|
||||
))
|
||||
when:'we call the first time'
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:'first mock should be returned and expired'
|
||||
response.entity.content.text == 'mock1'
|
||||
when:'we call other request'
|
||||
HttpPost otherRestPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
otherRestPost.entity = new StringEntity('<otherRequest/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse otherResponse = client.execute(otherRestPost)
|
||||
then:'other mock should be called'
|
||||
otherResponse.entity.content.text == 'otherMock'
|
||||
when:'we call the second time using the same request'
|
||||
CloseableHttpResponse response2 = client.execute(restPost)
|
||||
then:'second mock should be returned and expired'
|
||||
response2.entity.content.text == 'mock2'
|
||||
when:'we call the third time using the same request'
|
||||
CloseableHttpResponse response3 = client.execute(restPost)
|
||||
then:'first mock should be returned, because these mocks are cyclic'
|
||||
response3.entity.content.text == 'mock1'
|
||||
}
|
||||
|
||||
def 'should return first mock twice'() {
|
||||
given:'mock with predicate is given but for only one use'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock1'}''',
|
||||
maxUses: 2
|
||||
))
|
||||
and:'mock with the same predicate is given'
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock2',
|
||||
path: 'testEndpoint',
|
||||
port: 9999,
|
||||
predicate: '''{req -> req.xml.name() == 'request'}''',
|
||||
response: '''{req -> 'mock2'}''',
|
||||
))
|
||||
when:'we call the first time'
|
||||
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
|
||||
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
then:'first mock should be returned and expired'
|
||||
response.entity.content.text == 'mock1'
|
||||
when:'we call the second time using the same request'
|
||||
CloseableHttpResponse response2 = client.execute(restPost)
|
||||
then:'again first mock should be returned'
|
||||
response2.entity.content.text == 'mock1'
|
||||
when:'we call the third time using the same request'
|
||||
CloseableHttpResponse response3 = client.execute(restPost)
|
||||
then:'second mock should be returned'
|
||||
response3.entity.content.text == 'mock2'
|
||||
}
|
||||
|
||||
def 'should throw exception if adding mock with incorrect maxUses'() {
|
||||
when:
|
||||
remoteMockServer.addMock(new AddMock(
|
||||
name: 'mock1',
|
||||
maxUses: 0
|
||||
))
|
||||
then:
|
||||
thrown(RuntimeException)
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package pl.touk.mockserver.tests
|
||||
|
||||
import org.apache.http.client.HttpClient
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.client.methods.HttpPost
|
||||
import org.apache.http.entity.ContentType
|
||||
import org.apache.http.entity.StringEntity
|
||||
import org.apache.http.impl.client.HttpClients
|
||||
import pl.touk.mockserver.api.request.AddMock
|
||||
import pl.touk.mockserver.client.RemoteMockServer
|
||||
import pl.touk.mockserver.client.Util
|
||||
import pl.touk.mockserver.server.HttpMockServer
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ServerMockPT extends Specification {
|
||||
|
||||
@Timeout(value = 90)
|
||||
def "should handle many request simultaneously"() {
|
||||
given:
|
||||
HttpClient client = HttpClients.createDefault()
|
||||
HttpMockServer httpMockServer = new HttpMockServer()
|
||||
RemoteMockServer controlServerClient = new RemoteMockServer("localhost", 9999)
|
||||
int requestAmount = 1000
|
||||
String[] responses = new String[requestAmount]
|
||||
ExecutorService executorService = Executors.newCachedThreadPool()
|
||||
when:
|
||||
for (int i = 0; i < requestAmount; ++i) {
|
||||
int current = i
|
||||
executorService.submit {
|
||||
int endpointNumber = current % 10
|
||||
int port = 9000 + (current % 7)
|
||||
controlServerClient.addMock(new AddMock(
|
||||
name: "testRest$current",
|
||||
path: "testEndpoint$endpointNumber",
|
||||
port: port,
|
||||
predicate: """{req -> req.xml.name() == 'request$current'}""",
|
||||
response: """{req -> "<goodResponse$current/>"}"""
|
||||
))
|
||||
HttpPost restPost = new HttpPost("http://localhost:$port/testEndpoint$endpointNumber")
|
||||
restPost.entity = new StringEntity("<request$current/>", ContentType.create("text/xml", "UTF-8"))
|
||||
CloseableHttpResponse response = client.execute(restPost)
|
||||
responses[current] = Util.extractStringResponse(response)
|
||||
controlServerClient.removeMock("testRest$current", true)
|
||||
}
|
||||
}
|
||||
executorService.shutdown()
|
||||
executorService.awaitTermination(90, TimeUnit.SECONDS)
|
||||
then:
|
||||
responses.eachWithIndex { res, i -> assert res && new XmlSlurper().parseText(res).name() == "goodResponse$i" as String }
|
||||
cleanup:
|
||||
executorService.shutdown()
|
||||
httpMockServer.stop()
|
||||
}
|
||||
}
|
BIN
mockserver-tests/src/test/resources/keystore.jks
Normal file
BIN
mockserver-tests/src/test/resources/keystore.jks
Normal file
Binary file not shown.
19
mockserver-tests/src/test/resources/schema1.xsd
Normal file
19
mockserver-tests/src/test/resources/schema1.xsd
Normal file
|
@ -0,0 +1,19 @@
|
|||
<xs:schema elementFormDefault="qualified"
|
||||
version="1.0"
|
||||
targetNamespace="http://mockserver/test1"
|
||||
xmlns:tns="http://mockserver/test1"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:test2="http://mockserver/test2">
|
||||
|
||||
<xs:import namespace="http://mockserver/test2" schemaLocation="schema2.xsd"/>
|
||||
|
||||
<xs:element name="request" type="tns:Request"/>
|
||||
|
||||
<xs:complexType name="Request">
|
||||
<xs:sequence>
|
||||
<xs:element name="id" type="xs:int"/>
|
||||
<xs:element name="value" type="test2:Value"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
|
12
mockserver-tests/src/test/resources/schema2.xsd
Normal file
12
mockserver-tests/src/test/resources/schema2.xsd
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xs:schema version="1.0" targetNamespace="http://mockserver/test2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="Value">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="test"/>
|
||||
<xs:enumeration value="prod"/>
|
||||
<xs:enumeration value="preprod"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
|
BIN
mockserver-tests/src/test/resources/trusted.jks
Normal file
BIN
mockserver-tests/src/test/resources/trusted.jks
Normal file
Binary file not shown.
BIN
mockserver-tests/src/test/resources/truststore.jks
Normal file
BIN
mockserver-tests/src/test/resources/truststore.jks
Normal file
Binary file not shown.
BIN
mockserver-tests/src/test/resources/untrusted.jks
Normal file
BIN
mockserver-tests/src/test/resources/untrusted.jks
Normal file
Binary file not shown.
|
@ -1,53 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mockserver</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-xml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package assembly:single install</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>pl.touk.mockserver.server.Main</mainClass>
|
||||
<mainClass>eu.ztsh.mockserver.server.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<finalName>mockserver-full</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create-archive</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import eu.ztsh.mockserver.api.common.Method
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class ContextExecutor {
|
||||
private final HttpServerWrapper httpServerWrapper
|
||||
final String path
|
||||
private final List<Mock> mocks
|
||||
|
||||
ContextExecutor(HttpServerWrapper httpServerWrapper, Mock initialMock) {
|
||||
this.httpServerWrapper = httpServerWrapper
|
||||
this.path = "/${initialMock.path}"
|
||||
this.mocks = new CopyOnWriteArrayList<>([initialMock])
|
||||
httpServerWrapper.createContext(path) {
|
||||
HttpExchange ex ->
|
||||
try {
|
||||
applyMocks(ex)
|
||||
} catch (Exception e) {
|
||||
log.error("Exceptiony occured handling request", e)
|
||||
throw e
|
||||
} finally {
|
||||
ex.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyMocks(HttpExchange ex) {
|
||||
MockRequest request = new MockRequest(ex.requestBody.text, ex.requestHeaders, ex.requestURI)
|
||||
log.info('Mock received input')
|
||||
log.debug("Request: ${request.text}")
|
||||
for (Mock mock : mocks) {
|
||||
try {
|
||||
if (mock.match(Method.valueOf(ex.requestMethod), request)) {
|
||||
log.debug("Mock ${mock.name} match request ${request.text}")
|
||||
handleMaxUses(mock)
|
||||
MockResponse httpResponse = mock.apply(request)
|
||||
fillExchange(ex, httpResponse)
|
||||
log.trace("Mock ${mock.name} response with body ${httpResponse.text}")
|
||||
return
|
||||
}
|
||||
log.debug("Mock ${mock.name} does not match request")
|
||||
} catch (Exception e) {
|
||||
log.warn("An exception occured when matching or applying mock ${mock.name}", e)
|
||||
}
|
||||
}
|
||||
log.warn("Any mock does not match request ${request.text}")
|
||||
Util.createResponse(ex, request.text, 404)
|
||||
}
|
||||
|
||||
String getPath() {
|
||||
return path.substring(1)
|
||||
}
|
||||
|
||||
String getContextPath() {
|
||||
return path
|
||||
}
|
||||
|
||||
private static void fillExchange(HttpExchange httpExchange, MockResponse response) {
|
||||
response.headers.each {
|
||||
httpExchange.responseHeaders.add(it.key, it.value)
|
||||
}
|
||||
Util.createResponse(httpExchange, response.text, response.statusCode)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
Mock mock = mocks.find { it.name == name }
|
||||
if (mock) {
|
||||
mocks.remove(mock)
|
||||
return mock.history
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
Mock mock = mocks.find { it.name == name }
|
||||
if (mock) {
|
||||
return mock.history
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
mocks << mock
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return mocks
|
||||
}
|
||||
|
||||
private synchronized void handleMaxUses(Mock mock) {
|
||||
if (mock.hasLimitedUses()) {
|
||||
mock.decrementUses()
|
||||
resetIfNeeded(mock)
|
||||
log.debug("Uses left ${mock.usesLeft} of ${mock.maxUses} (is cyclic: ${mock.cyclic})")
|
||||
}
|
||||
}
|
||||
|
||||
private void resetIfNeeded(Mock mock) {
|
||||
if (mock.shouldUsesBeReset()) {
|
||||
mock.resetUses()
|
||||
mocks.remove(mock)
|
||||
mocks.add(mock)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +1,62 @@
|
|||
package pl.touk.mockserver.server
|
||||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange
|
||||
import groovy.util.logging.Slf4j
|
||||
import pl.touk.mockserver.api.request.AddMock
|
||||
import pl.touk.mockserver.api.request.MockServerRequest
|
||||
import pl.touk.mockserver.api.request.PeekMock
|
||||
import pl.touk.mockserver.api.request.RemoveMock
|
||||
import pl.touk.mockserver.api.response.*
|
||||
import eu.ztsh.mockserver.api.common.Https
|
||||
import eu.ztsh.mockserver.api.common.ImportAlias
|
||||
import eu.ztsh.mockserver.api.common.Method
|
||||
import eu.ztsh.mockserver.api.request.AddMock
|
||||
import eu.ztsh.mockserver.api.request.MockServerRequest
|
||||
import eu.ztsh.mockserver.api.request.PeekMock
|
||||
import eu.ztsh.mockserver.api.request.RemoveMock
|
||||
import eu.ztsh.mockserver.api.response.ExceptionOccured
|
||||
import eu.ztsh.mockserver.api.response.MockAdded
|
||||
import eu.ztsh.mockserver.api.response.MockEventReport
|
||||
import eu.ztsh.mockserver.api.response.MockPeeked
|
||||
import eu.ztsh.mockserver.api.response.MockRemoved
|
||||
import eu.ztsh.mockserver.api.response.MockReport
|
||||
import eu.ztsh.mockserver.api.response.MockRequestReport
|
||||
import eu.ztsh.mockserver.api.response.MockResponseReport
|
||||
import eu.ztsh.mockserver.api.response.Mocks
|
||||
import eu.ztsh.mockserver.api.response.Parameter
|
||||
|
||||
import javax.xml.bind.JAXBContext
|
||||
import jakarta.xml.bind.JAXBContext
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
import static pl.touk.mockserver.server.Util.createResponse
|
||||
import static eu.ztsh.mockserver.server.Util.createResponse
|
||||
|
||||
@Slf4j
|
||||
class HttpMockServer {
|
||||
|
||||
private final HttpServerWraper httpServerWraper
|
||||
private final Map<Integer, HttpServerWraper> childServers = new ConcurrentHashMap<>()
|
||||
private final HttpServerWrapper httpServerWrapper
|
||||
private final Map<Integer, HttpServerWrapper> childServers = new ConcurrentHashMap<>()
|
||||
private final Set<String> mockNames = new CopyOnWriteArraySet<>()
|
||||
private final ConfigObject configuration = new ConfigObject()
|
||||
private final Executor executor
|
||||
|
||||
private static
|
||||
final JAXBContext requestJaxbContext = JAXBContext.newInstance(AddMock.package.name, AddMock.classLoader)
|
||||
|
||||
HttpMockServer(int port = 9999) {
|
||||
httpServerWraper = new HttpServerWraper(port)
|
||||
HttpMockServer(int port = 9999, ConfigObject initialConfiguration = new ConfigObject(), int threads = 10) {
|
||||
executor = Executors.newFixedThreadPool(threads)
|
||||
httpServerWrapper = new HttpServerWrapper(port, executor)
|
||||
|
||||
httpServerWraper.createContext('/serverControl', {
|
||||
initialConfiguration.values()?.each { ConfigObject co ->
|
||||
addMock(co)
|
||||
}
|
||||
|
||||
httpServerWrapper.createContext('/serverControl', {
|
||||
HttpExchange ex ->
|
||||
try {
|
||||
if (ex.requestMethod == 'GET') {
|
||||
if (ex.requestURI.path == '/serverControl/configuration') {
|
||||
createResponse(ex, configuration.prettyPrint(), 200)
|
||||
} else {
|
||||
listMocks(ex)
|
||||
}
|
||||
} else if (ex.requestMethod == 'POST') {
|
||||
MockServerRequest request = requestJaxbContext.createUnmarshaller().unmarshal(ex.requestBody) as MockServerRequest
|
||||
if (request instanceof AddMock) {
|
||||
|
@ -64,7 +89,10 @@ class HttpMockServer {
|
|||
responseHeaders: it.responseHeadersClosureText,
|
||||
soap: it.soap,
|
||||
method: it.method,
|
||||
statusCode: it.statusCode as int
|
||||
statusCode: it.statusCode as int,
|
||||
schema: it.schema,
|
||||
imports: it.imports.collect { new ImportAlias(alias: it.key, fullClassName: it.value) },
|
||||
preserveHistory: it.preserveHistory
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -80,28 +108,97 @@ class HttpMockServer {
|
|||
if (name in mockNames) {
|
||||
throw new RuntimeException('mock already registered')
|
||||
}
|
||||
if (request.maxUses == 0) {
|
||||
throw new RuntimeException('cannot set maxUses to 0')
|
||||
}
|
||||
Mock mock = mockFromRequest(request)
|
||||
HttpServerWraper child = getOrCreateChildServer(mock.port)
|
||||
HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
|
||||
child.addMock(mock)
|
||||
saveConfiguration(request)
|
||||
mockNames << name
|
||||
createResponse(ex, new MockAdded(), 200)
|
||||
}
|
||||
|
||||
private void addMock(ConfigObject co) {
|
||||
String name = co.name
|
||||
if (name in mockNames) {
|
||||
throw new RuntimeException('mock already registered')
|
||||
}
|
||||
if (co.maxUses == 0) {
|
||||
throw new RuntimeException('cannot set maxUses to 0')
|
||||
}
|
||||
Mock mock = mockFromConfig(co)
|
||||
HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
|
||||
child.addMock(mock)
|
||||
configuration.put(name, co)
|
||||
mockNames << name
|
||||
}
|
||||
|
||||
private void saveConfiguration(AddMock request) {
|
||||
ConfigObject mockDefinition = new ConfigObject()
|
||||
request.metaPropertyValues.findAll { it.name != 'class' && it.value }.each {
|
||||
if (it.name == 'imports') {
|
||||
ConfigObject configObject = new ConfigObject()
|
||||
it.value.each { ImportAlias imp ->
|
||||
configObject.put(imp.alias, imp.fullClassName)
|
||||
}
|
||||
mockDefinition.put(it.name, configObject)
|
||||
} else if (it.name == 'method') {
|
||||
mockDefinition.put(it.name, it.value.name())
|
||||
} else {
|
||||
mockDefinition.put(it.name, it.value)
|
||||
}
|
||||
}
|
||||
configuration.put(request.name, mockDefinition)
|
||||
}
|
||||
|
||||
private static Mock mockFromRequest(AddMock request) {
|
||||
Mock mock = new Mock(request.name, request.path, request.port)
|
||||
mock.imports = request.imports?.collectEntries { [(it.alias): it.fullClassName] } ?: [:]
|
||||
mock.predicate = request.predicate
|
||||
mock.response = request.response
|
||||
mock.soap = request.soap
|
||||
mock.statusCode = request.statusCode
|
||||
mock.method = request.method
|
||||
mock.responseHeaders = request.responseHeaders
|
||||
mock.schema = request.schema
|
||||
mock.preserveHistory = request.preserveHistory != false
|
||||
mock.https = request.https
|
||||
mock.maxUses = request.maxUses
|
||||
mock.cyclic = request.cyclic
|
||||
return mock
|
||||
}
|
||||
|
||||
private HttpServerWraper getOrCreateChildServer(int mockPort) {
|
||||
HttpServerWraper child = childServers[mockPort]
|
||||
private static Mock mockFromConfig(ConfigObject co) {
|
||||
Mock mock = new Mock(co.name, co.path, co.port)
|
||||
mock.imports = co.imports
|
||||
mock.predicate = co.predicate ?: null
|
||||
mock.response = co.response ?: null
|
||||
mock.soap = co.soap ?: null
|
||||
mock.statusCode = co.statusCode ?: null
|
||||
mock.method = co.method ? Method.valueOf(co.method) : null
|
||||
mock.responseHeaders = co.responseHeaders ?: null
|
||||
mock.schema = co.schema ?: null
|
||||
mock.preserveHistory = co.preserveHistory != false
|
||||
if (co.https) {
|
||||
mock.https = new Https(
|
||||
keystorePath: co.https.keystorePath ?: null,
|
||||
keystorePassword: co.https.keystorePassword,
|
||||
keyPassword: co.https.keyPassword,
|
||||
truststorePath: co.https.truststorePath,
|
||||
truststorePassword: co.https.truststorePassword,
|
||||
requireClientAuth: co.https?.requireClientAuth?.asBoolean() ?: false
|
||||
)
|
||||
}
|
||||
mock.maxUses = co.maxUses ?: null
|
||||
mock.cyclic = co.cyclic ?: null
|
||||
return mock
|
||||
}
|
||||
|
||||
private HttpServerWrapper getOrCreateChildServer(int mockPort, Https https) {
|
||||
HttpServerWrapper child = childServers[mockPort]
|
||||
if (!child) {
|
||||
child = new HttpServerWraper(mockPort)
|
||||
child = new HttpServerWrapper(mockPort, executor, https)
|
||||
childServers.put(mockPort, child)
|
||||
}
|
||||
return child
|
||||
|
@ -118,6 +215,7 @@ class HttpMockServer {
|
|||
it.removeMock(name)
|
||||
}.flatten() as List<MockEvent>
|
||||
mockNames.remove(name)
|
||||
configuration.remove(name)
|
||||
MockRemoved mockRemoved = new MockRemoved(
|
||||
mockEvents: createMockEventReports(mockEvents)
|
||||
)
|
||||
|
@ -162,11 +260,12 @@ class HttpMockServer {
|
|||
}
|
||||
|
||||
private static void createErrorResponse(HttpExchange ex, Exception e) {
|
||||
log.warn('Exception occured', e)
|
||||
createResponse(ex, new ExceptionOccured(value: e.message), 400)
|
||||
}
|
||||
|
||||
void stop() {
|
||||
childServers.values().each { it.stop() }
|
||||
httpServerWraper.stop()
|
||||
httpServerWrapper.stop()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler
|
||||
import com.sun.net.httpserver.HttpServer
|
||||
import com.sun.net.httpserver.HttpsServer
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import eu.ztsh.mockserver.api.common.Https
|
||||
|
||||
import javax.net.ssl.KeyManager
|
||||
import javax.net.ssl.KeyManagerFactory
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManager
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import java.security.KeyStore
|
||||
import java.security.SecureRandom
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class HttpServerWrapper {
|
||||
private final HttpServer httpServer
|
||||
final int port
|
||||
|
||||
private List<ContextExecutor> executors = []
|
||||
|
||||
HttpServerWrapper(int port, Executor executor, Https https = null) {
|
||||
this.port = port
|
||||
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
|
||||
httpServer = buildServer(addr, https)
|
||||
httpServer.executor = executor
|
||||
log.info("Http server starting on port $port...")
|
||||
httpServer.start()
|
||||
log.info('Http server is started')
|
||||
}
|
||||
|
||||
private HttpServer buildServer(InetSocketAddress addr, Https https) {
|
||||
if (https) {
|
||||
HttpsServer httpsServer = HttpsServer.create(addr, 0)
|
||||
httpsServer.httpsConfigurator = new HttpsConfig(buildSslContext(https), https)
|
||||
return httpsServer
|
||||
} else {
|
||||
return HttpServer.create(addr, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private SSLContext buildSslContext(Https https) {
|
||||
KeyManager[] keyManagers = buildKeyManager(https)
|
||||
TrustManager[] trustManagers = buildTrustManager(https)
|
||||
|
||||
SSLContext ssl = SSLContext.getInstance('TLSv1')
|
||||
ssl.init(keyManagers, trustManagers, new SecureRandom())
|
||||
return ssl
|
||||
}
|
||||
|
||||
private KeyManager[] buildKeyManager(Https https) {
|
||||
KeyStore keyStore = KeyStore.getInstance('jks')
|
||||
keyStore.load(new FileInputStream(https.keystorePath), https.keystorePassword.toCharArray())
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.defaultAlgorithm)
|
||||
kmf.init(keyStore, https.keyPassword.toCharArray())
|
||||
return kmf.keyManagers
|
||||
}
|
||||
|
||||
private TrustManager[] buildTrustManager(Https https) {
|
||||
if (https.requireClientAuth) {
|
||||
KeyStore trustStore = KeyStore.getInstance('jks')
|
||||
trustStore.load(new FileInputStream(https.truststorePath), https.truststorePassword.toCharArray())
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.defaultAlgorithm)
|
||||
tmf.init(trustStore)
|
||||
return tmf.trustManagers
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
void createContext(String context, HttpHandler handler) {
|
||||
httpServer.createContext(context, handler)
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
ContextExecutor executor = executors.find { it.path == mock.path }
|
||||
if (executor) {
|
||||
executor.addMock(mock)
|
||||
} else {
|
||||
executors << new ContextExecutor(this, mock)
|
||||
}
|
||||
log.info("Added mock ${mock.name}")
|
||||
}
|
||||
|
||||
void stop() {
|
||||
executors.each { httpServer.removeContext(it.contextPath) }
|
||||
httpServer.stop(0)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
return executors.collect { it.removeMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
return executors.collect { it.peekMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return executors.collect { it.mocks }.flatten() as List<Mock>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpsConfigurator
|
||||
import com.sun.net.httpserver.HttpsParameters
|
||||
import groovy.transform.CompileStatic
|
||||
import eu.ztsh.mockserver.api.common.Https
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLParameters
|
||||
|
||||
@CompileStatic
|
||||
class HttpsConfig extends HttpsConfigurator {
|
||||
private final Https https
|
||||
|
||||
HttpsConfig(SSLContext sslContext, Https https) {
|
||||
super(sslContext)
|
||||
this.https = https
|
||||
}
|
||||
|
||||
@Override
|
||||
void configure(HttpsParameters httpsParameters) {
|
||||
SSLContext sslContext = getSSLContext()
|
||||
SSLParameters sslParameters = sslContext.defaultSSLParameters
|
||||
sslParameters.needClientAuth = https.requireClientAuth
|
||||
httpsParameters.needClientAuth = https.requireClientAuth
|
||||
httpsParameters.SSLParameters = sslParameters
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package eu.ztsh.mockserver.server
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
@Slf4j
|
||||
class Main {
|
||||
static void main(String[] args) {
|
||||
HttpMockServer httpMockServer = startMockServer(args)
|
||||
|
||||
Runtime.runtime.addShutdownHook(new Thread({
|
||||
log.info('Http server is stopping...')
|
||||
httpMockServer.stop()
|
||||
log.info('Http server is stopped')
|
||||
} as Runnable))
|
||||
|
||||
while (true) {
|
||||
Thread.sleep(10000)
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpMockServer startMockServer(String... args) {
|
||||
switch (args.length) {
|
||||
case 1:
|
||||
return new HttpMockServer(args[0] as int, new ConfigObject())
|
||||
case 2:
|
||||
return new HttpMockServer(args[0] as int, new ConfigSlurper().parse(new File(args[1]).toURI().toURL()))
|
||||
case 3:
|
||||
return new HttpMockServer(args[0] as int, new ConfigSlurper().parse(new File(args[1]).toURI().toURL()), args[2] as int)
|
||||
default:
|
||||
return new HttpMockServer()
|
||||
}
|
||||
}
|
||||
}
|
199
mockserver/src/main/groovy/eu/ztsh/mockserver/server/Mock.groovy
Normal file
199
mockserver/src/main/groovy/eu/ztsh/mockserver/server/Mock.groovy
Normal file
|
@ -0,0 +1,199 @@
|
|||
package eu.ztsh.mockserver.server
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
import eu.ztsh.mockserver.api.common.Https
|
||||
import eu.ztsh.mockserver.api.common.Method
|
||||
|
||||
import javax.xml.XMLConstants
|
||||
import javax.xml.transform.stream.StreamSource
|
||||
import javax.xml.validation.SchemaFactory
|
||||
import javax.xml.validation.Validator
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
@PackageScope
|
||||
@EqualsAndHashCode(excludes = ["counter"])
|
||||
@Slf4j
|
||||
class Mock implements Comparable<Mock> {
|
||||
final String name
|
||||
final String path
|
||||
final int port
|
||||
String predicateClosureText = '{ _ -> true }'
|
||||
String responseClosureText = '''{ _ -> '' }'''
|
||||
String responseHeadersClosureText = '{ _ -> [:] }'
|
||||
Closure predicate = toClosure(predicateClosureText)
|
||||
Closure response = toClosure(responseClosureText)
|
||||
Closure responseHeaders = toClosure(responseHeadersClosureText)
|
||||
boolean soap = false
|
||||
int statusCode = 200
|
||||
Method method = Method.POST
|
||||
int counter = 0
|
||||
final List<MockEvent> history = new CopyOnWriteArrayList<>()
|
||||
String schema
|
||||
private Validator validator
|
||||
Map<String, String> imports = [:]
|
||||
boolean preserveHistory = true
|
||||
Https https
|
||||
int maxUses = -1
|
||||
int usesLeft
|
||||
boolean cyclic
|
||||
|
||||
Mock(String name, String path, int port) {
|
||||
if (!(name)) {
|
||||
throw new RuntimeException("Mock name must be given")
|
||||
}
|
||||
this.name = name
|
||||
this.path = stripLeadingSlash(path)
|
||||
this.port = port
|
||||
}
|
||||
|
||||
private static String stripLeadingSlash(String path) {
|
||||
if (path?.startsWith('/')) {
|
||||
return path - '/'
|
||||
} else {
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
boolean match(Method method, MockRequest request) {
|
||||
boolean usesCondition = hasLimitedUses() ? usesLeft > 0 : true
|
||||
return usesCondition && (this.method == method || this.method == Method.ANY_METHOD) && predicate(request)
|
||||
}
|
||||
|
||||
MockResponse apply(MockRequest request) {
|
||||
log.debug("Mock $name invoked")
|
||||
if (validator) {
|
||||
try {
|
||||
log.debug('Validating...')
|
||||
if (soap) {
|
||||
validator.validate(new StreamSource(new StringReader(request.textWithoutSoap)))
|
||||
} else {
|
||||
validator.validate(new StreamSource(new StringReader(request.text)))
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MockResponse response = new MockResponse(400, e.message, [:])
|
||||
if(preserveHistory) {
|
||||
history << new MockEvent(request, response)
|
||||
}
|
||||
return response
|
||||
}
|
||||
}
|
||||
++counter
|
||||
String responseText = response(request)
|
||||
String response = soap ? wrapSoap(responseText) : responseText
|
||||
Map<String, String> headers = responseHeaders(request)
|
||||
MockResponse mockResponse = new MockResponse(statusCode, response, headers)
|
||||
if(preserveHistory) {
|
||||
history << new MockEvent(request, mockResponse)
|
||||
}
|
||||
return mockResponse
|
||||
}
|
||||
|
||||
private static String wrapSoap(String request) {
|
||||
"""<?xml version='1.0' encoding='UTF-8'?>
|
||||
<soap-env:Envelope xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/' xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
|
||||
<soap-env:Body>${request}</soap-env:Body>
|
||||
</soap-env:Envelope>"""
|
||||
}
|
||||
|
||||
void setPredicate(String predicate) {
|
||||
if (predicate) {
|
||||
this.predicateClosureText = predicate
|
||||
this.predicate = toClosure(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
private Closure toClosure(String predicate) {
|
||||
if (predicate ==~ /(?m).*System\s*\.\s*exit\s*\(.*/) {
|
||||
throw new RuntimeException('System.exit is forbidden')
|
||||
}
|
||||
CompilerConfiguration compilerConfiguration = new CompilerConfiguration()
|
||||
ImportCustomizer customizer = new ImportCustomizer()
|
||||
imports.each {
|
||||
customizer.addImport(it.key, it.value)
|
||||
}
|
||||
compilerConfiguration.addCompilationCustomizers(customizer)
|
||||
GroovyShell sh = new GroovyShell(this.class.classLoader, compilerConfiguration);
|
||||
Closure closure = sh.evaluate(predicate) as Closure
|
||||
sh.resetLoadedClasses()
|
||||
return closure
|
||||
}
|
||||
|
||||
void setResponse(String response) {
|
||||
if (response) {
|
||||
this.responseClosureText = response
|
||||
this.response = toClosure(response)
|
||||
}
|
||||
}
|
||||
|
||||
void setSoap(Boolean soap) {
|
||||
this.soap = soap ?: false
|
||||
}
|
||||
|
||||
void setStatusCode(String statusCode) {
|
||||
if (statusCode) {
|
||||
this.statusCode = Integer.valueOf(statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
void setMethod(Method method) {
|
||||
if (method) {
|
||||
this.method = method
|
||||
}
|
||||
}
|
||||
|
||||
void setResponseHeaders(String responseHeaders) {
|
||||
if (responseHeaders) {
|
||||
this.responseHeadersClosureText = responseHeaders
|
||||
this.responseHeaders = toClosure(responseHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
void setMaxUses(Integer maxUses) {
|
||||
if (maxUses > 0) {
|
||||
this.maxUses = maxUses
|
||||
this.usesLeft = maxUses
|
||||
}
|
||||
}
|
||||
|
||||
void setCyclic(Boolean cyclic) {
|
||||
this.cyclic = cyclic ?: false
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(Mock o) {
|
||||
return name.compareTo(o.name)
|
||||
}
|
||||
|
||||
void setSchema(String schema) {
|
||||
this.schema = schema
|
||||
if (schema) {
|
||||
try {
|
||||
validator = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
|
||||
.newSchema(this.class.getResource("/$schema"))
|
||||
.newValidator()
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException('mock request schema is invalid schema', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasLimitedUses() {
|
||||
return maxUses > 0
|
||||
}
|
||||
|
||||
void decrementUses() {
|
||||
usesLeft--
|
||||
}
|
||||
|
||||
boolean shouldUsesBeReset() {
|
||||
return hasLimitedUses() && usesLeft <= 0 && cyclic
|
||||
}
|
||||
|
||||
void resetUses() {
|
||||
setMaxUses(maxUses)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.server
|
||||
package eu.ztsh.mockserver.server
|
||||
|
||||
import groovy.transform.PackageScope
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package pl.touk.mockserver.server
|
||||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.Headers
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.slurpersupport.GPathResult
|
||||
import groovy.xml.XmlSlurper
|
||||
import groovy.xml.slurpersupport.GPathResult
|
||||
import groovy.xml.XmlUtil
|
||||
|
||||
@PackageScope
|
||||
class MockRequest {
|
||||
|
@ -26,6 +28,9 @@ class MockRequest {
|
|||
}
|
||||
|
||||
private static GPathResult inputToXml(String text) {
|
||||
if (!text.startsWith('<')) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return new XmlSlurper().parseText(text)
|
||||
} catch (Exception _) {
|
||||
|
@ -35,7 +40,7 @@ class MockRequest {
|
|||
|
||||
private static GPathResult inputToSoap(GPathResult xml) {
|
||||
try {
|
||||
if (xml.name() == 'Envelope' && xml.Body.size() > 0) {
|
||||
if (xml != null && xml.name() == 'Envelope' && xml.Body.size() > 0) {
|
||||
return getSoapBodyContent(xml)
|
||||
} else {
|
||||
return null
|
||||
|
@ -50,6 +55,9 @@ class MockRequest {
|
|||
}
|
||||
|
||||
private static Object inputToJson(String text) {
|
||||
if (!text.startsWith('[') && !text.startsWith('{')) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return new JsonSlurper().parseText(text)
|
||||
} catch (Exception _) {
|
||||
|
@ -69,4 +77,7 @@ class MockRequest {
|
|||
} as Map<String, String>
|
||||
}
|
||||
|
||||
String getTextWithoutSoap() {
|
||||
return XmlUtil.serialize(soap)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pl.touk.mockserver.server
|
||||
package eu.ztsh.mockserver.server
|
||||
|
||||
import groovy.transform.PackageScope
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package pl.touk.mockserver.server
|
||||
package eu.ztsh.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange
|
||||
import pl.touk.mockserver.api.response.MockAdded
|
||||
import eu.ztsh.mockserver.api.response.MockAdded
|
||||
|
||||
import javax.xml.bind.JAXBContext
|
||||
import jakarta.xml.bind.JAXBContext
|
||||
|
||||
class Util {
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import pl.touk.mockserver.api.common.Method
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class ContextExecutor {
|
||||
private final HttpServerWraper httpServerWraper
|
||||
final String path
|
||||
private final List<Mock> mocks
|
||||
|
||||
ContextExecutor(HttpServerWraper httpServerWraper, Mock initialMock) {
|
||||
this.httpServerWraper = httpServerWraper
|
||||
this.path = "/${initialMock.path}"
|
||||
this.mocks = new CopyOnWriteArrayList<>([initialMock])
|
||||
httpServerWraper.createContext(path) {
|
||||
HttpExchange ex ->
|
||||
MockRequest request = new MockRequest(ex.requestBody.text, ex.requestHeaders, ex.requestURI)
|
||||
log.info('Mock received input')
|
||||
log.debug("Request: ${request.text}")
|
||||
for (Mock mock : mocks) {
|
||||
try {
|
||||
if (mock.match(Method.valueOf(ex.requestMethod), request)) {
|
||||
log.debug("Mock ${mock.name} match request ${request.text}")
|
||||
MockResponse httpResponse = mock.apply(request)
|
||||
fillExchange(ex, httpResponse)
|
||||
log.trace("Mock ${mock.name} response with body ${httpResponse.text}")
|
||||
return
|
||||
}
|
||||
log.debug("Mock ${mock.name} does not match request")
|
||||
} catch (Exception e) {
|
||||
log.warn("An exception occured when matching or applying mock ${mock.name}", e)
|
||||
}
|
||||
}
|
||||
log.warn("Any mock does not match request ${request.text}")
|
||||
Util.createResponse(ex, request.text, 404)
|
||||
}
|
||||
}
|
||||
|
||||
String getPath() {
|
||||
return path.substring(1)
|
||||
}
|
||||
|
||||
String getContextPath() {
|
||||
return path
|
||||
}
|
||||
|
||||
private static void fillExchange(HttpExchange httpExchange, MockResponse response) {
|
||||
response.headers.each {
|
||||
httpExchange.responseHeaders.add(it.key, it.value)
|
||||
}
|
||||
Util.createResponse(httpExchange, response.text, response.statusCode)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
Mock mock = mocks.find { it.name == name }
|
||||
if (mock) {
|
||||
mocks.remove(mock)
|
||||
return mock.history
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
Mock mock = mocks.find { it.name == name }
|
||||
if (mock) {
|
||||
return mock.history
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
mocks << mock
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return mocks
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler
|
||||
import com.sun.net.httpserver.HttpServer
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class HttpServerWraper {
|
||||
private final HttpServer httpServer
|
||||
final int port
|
||||
|
||||
private List<ContextExecutor> executors = []
|
||||
|
||||
HttpServerWraper(int port) {
|
||||
this.port = port
|
||||
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
|
||||
httpServer = HttpServer.create(addr, 0)
|
||||
httpServer.executor = Executors.newWorkStealingPool()
|
||||
log.info("Http server starting on port $port...")
|
||||
httpServer.start()
|
||||
log.info('Http server is started')
|
||||
}
|
||||
|
||||
void createContext(String context, HttpHandler handler) {
|
||||
httpServer.createContext(context, handler)
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
ContextExecutor executor = executors.find { it.path == mock.path }
|
||||
if (executor) {
|
||||
executor.addMock(mock)
|
||||
} else {
|
||||
executors << new ContextExecutor(this, mock)
|
||||
}
|
||||
log.info("Added mock ${mock.name}")
|
||||
}
|
||||
|
||||
void stop() {
|
||||
executors.each { httpServer.removeContext(it.contextPath) }
|
||||
httpServer.stop(0)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
return executors.collect { it.removeMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
return executors.collect { it.peekMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return executors.collect { it.mocks }.flatten() as List<Mock>
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
@Slf4j
|
||||
class Main {
|
||||
static void main(String[] args) {
|
||||
HttpMockServer httpMockServer = args.length == 1 ? new HttpMockServer(args[0] as int) : new HttpMockServer()
|
||||
|
||||
Runtime.runtime.addShutdownHook(new Thread({
|
||||
log.info('Http server is stopping...')
|
||||
httpMockServer.stop()
|
||||
log.info('Http server is stopped')
|
||||
} as Runnable))
|
||||
|
||||
while (true) {
|
||||
Thread.sleep(10000)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import pl.touk.mockserver.api.common.Method
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
@PackageScope
|
||||
@EqualsAndHashCode(excludes = ["counter"])
|
||||
@Slf4j
|
||||
class Mock implements Comparable<Mock> {
|
||||
final String name
|
||||
final String path
|
||||
final int port
|
||||
String predicateClosureText = '{ _ -> true }'
|
||||
String responseClosureText = '''{ _ -> '' }'''
|
||||
String responseHeadersClosureText = '{ _ -> [:] }'
|
||||
Closure predicate = toClosure(predicateClosureText)
|
||||
Closure response = toClosure(responseClosureText)
|
||||
Closure responseHeaders = toClosure(responseHeadersClosureText)
|
||||
boolean soap = false
|
||||
int statusCode = 200
|
||||
Method method = Method.POST
|
||||
int counter = 0
|
||||
final List<MockEvent> history = new CopyOnWriteArrayList<>()
|
||||
|
||||
Mock(String name, String path, int port) {
|
||||
if (!(name)) {
|
||||
throw new RuntimeException("Mock name must be given")
|
||||
}
|
||||
this.name = name
|
||||
this.path = path
|
||||
this.port = port
|
||||
}
|
||||
|
||||
boolean match(Method method, MockRequest request) {
|
||||
return this.method == method && predicate(request)
|
||||
}
|
||||
|
||||
MockResponse apply(MockRequest request) {
|
||||
log.debug("Mock $name invoked")
|
||||
++counter
|
||||
String responseText = response(request)
|
||||
String response = soap ? wrapSoap(responseText) : responseText
|
||||
Map<String, String> headers = responseHeaders(request)
|
||||
MockResponse mockResponse = new MockResponse(statusCode, response, headers)
|
||||
history << new MockEvent(request, mockResponse)
|
||||
return mockResponse
|
||||
}
|
||||
|
||||
private static String wrapSoap(String request) {
|
||||
"""<?xml version='1.0' encoding='UTF-8'?>
|
||||
<soap-env:Envelope xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/' xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
|
||||
<soap-env:Body>${request}</soap-env:Body>
|
||||
</soap-env:Envelope>"""
|
||||
}
|
||||
|
||||
void setPredicate(String predicate) {
|
||||
if (predicate) {
|
||||
this.predicateClosureText = predicate
|
||||
this.predicate = toClosure(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
private Closure toClosure(String predicate) {
|
||||
if (predicate ==~ /(?m).*System\s*\.\s*exit\s*\(.*/) {
|
||||
throw new RuntimeException('System.exit is forbidden')
|
||||
}
|
||||
GroovyShell sh = new GroovyShell(this.class.classLoader);
|
||||
return sh.evaluate(predicate) as Closure
|
||||
}
|
||||
|
||||
void setResponse(String response) {
|
||||
if (response) {
|
||||
this.responseClosureText = response
|
||||
this.response = toClosure(response)
|
||||
}
|
||||
}
|
||||
|
||||
void setSoap(Boolean soap) {
|
||||
this.soap = soap ?: false
|
||||
}
|
||||
|
||||
void setStatusCode(String statusCode) {
|
||||
if (statusCode) {
|
||||
this.statusCode = Integer.valueOf(statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
void setMethod(Method method) {
|
||||
if (method) {
|
||||
this.method = method
|
||||
}
|
||||
}
|
||||
|
||||
void setResponseHeaders(String responseHeaders) {
|
||||
if (responseHeaders) {
|
||||
this.responseHeadersClosureText = responseHeaders
|
||||
this.responseHeaders = toClosure(responseHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(Mock o) {
|
||||
return name.compareTo(o.name)
|
||||
}
|
||||
}
|
308
mvnw
vendored
Executable file
308
mvnw
vendored
Executable file
|
@ -0,0 +1,308 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
fi
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
205
mvnw.cmd
vendored
Normal file
205
mvnw.cmd
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
SET WRAPPER_SHA_256_SUM=""
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
if ERRORLEVEL 1 goto error
|
||||
)
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
70
performance-tests/pom.xml
Normal file
70
performance-tests/pom.xml
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mockserver-performance-tests</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<exec-maven-plugin.version>1.4.0</exec-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>performance-test</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>${exec-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-benchmarks</id>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<classpathScope>test</classpathScope>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-classpath</argument>
|
||||
<classpath />
|
||||
<argument>org.openjdk.jmh.Main</argument>
|
||||
<argument>.*</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,82 @@
|
|||
package eu.ztsh.mockserver.client;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.TearDown;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
import org.openjdk.jmh.infra.ThreadParams;
|
||||
import eu.ztsh.mockserver.api.request.AddMock;
|
||||
import eu.ztsh.mockserver.server.HttpMockServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
public class MockserverTest {
|
||||
HttpMockServer httpMockServer;
|
||||
|
||||
int initialPort = 9000;
|
||||
|
||||
@Setup
|
||||
public void prepareMockServer() {
|
||||
httpMockServer = new HttpMockServer(9999);
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void stopMockServer() {
|
||||
httpMockServer.stop();
|
||||
}
|
||||
|
||||
@State(Scope.Thread)
|
||||
public static class TestState {
|
||||
RemoteMockServer remoteMockServer;
|
||||
HttpClient httpClient;
|
||||
int current;
|
||||
|
||||
@Setup
|
||||
public void prepareMockServer(ThreadParams params) {
|
||||
remoteMockServer = new RemoteMockServer("localhost", 9999);
|
||||
httpClient = HttpClients.createDefault();
|
||||
current = params.getThreadIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@Measurement(iterations = 20)
|
||||
@BenchmarkMode({Mode.AverageTime, Mode.Throughput, Mode.SampleTime})
|
||||
@Warmup(iterations = 10)
|
||||
public void shouldHandleManyRequestsSimultaneously(TestState testState, Blackhole bh) throws IOException {
|
||||
int current = testState.current;
|
||||
int endpointNumber = current % 10;
|
||||
int port = initialPort + (current % 7);
|
||||
AddMock addMock = new AddMock();
|
||||
addMock.setName("testRest" + current);
|
||||
addMock.setPath("testEndpoint" + endpointNumber);
|
||||
addMock.setPort(port);
|
||||
addMock.setPredicate("{req -> req.xml.name() == 'request" + current + "' }");
|
||||
addMock.setResponse("{req -> '<goodResponse" + current + "/>'}");
|
||||
testState.remoteMockServer.addMock(addMock);
|
||||
HttpPost restPost = new HttpPost("http://localhost:" + port + "/testEndpoint" + endpointNumber);
|
||||
restPost.setEntity(new StringEntity("<request" + current + "/>", ContentType.create("text/xml", "UTF-8")));
|
||||
CloseableHttpResponse response = (CloseableHttpResponse) testState.httpClient.execute(restPost);
|
||||
String stringResponse = Util.extractStringResponse(response);
|
||||
testState.remoteMockServer.removeMock("testRest" + current, true);
|
||||
assert stringResponse.equals("<goodResponse" + current + "/>");
|
||||
bh.consume(stringResponse);
|
||||
}
|
||||
|
||||
}
|
15
performance-tests/src/test/resources/logback.xml
Normal file
15
performance-tests/src/test/resources/logback.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<configuration>
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%highlight(%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n)</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder><pattern>%msg%n</pattern></encoder>
|
||||
</appender>
|
||||
|
||||
<root level="ERROR">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
139
pom.xml
139
pom.xml
|
@ -1,55 +1,90 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>http-mock-server</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>2.0.0</version>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
|
||||
<modules>
|
||||
<module>mockserver-client</module>
|
||||
<module>mockserver</module>
|
||||
<module>mockserver-tests</module>
|
||||
<module>mockserver-api</module>
|
||||
<module>performance-tests</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
|
||||
<groovy.version>2.4.1</groovy.version>
|
||||
<httpclient.version>4.3.5</httpclient.version>
|
||||
<spock-core.version>1.0-groovy-2.4</spock-core.version>
|
||||
<commons-lang3.version>3.3.2</commons-lang3.version>
|
||||
<slf4j-api.version>1.7.7</slf4j-api.version>
|
||||
<logback-classic.version>1.0.13</logback-classic.version>
|
||||
<lombok.version>1.16.6</lombok.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:ssh://gerrit.touk.pl:29418/integracja/http-mock-server</connection>
|
||||
<developerConnection>scm:git:ssh://gerrit.touk.pl:29418/integracja/http-mock-server</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<groovy.version>4.0.12</groovy.version>
|
||||
<httpclient.version>4.5.13</httpclient.version>
|
||||
<spock-core.version>2.2-groovy-4.0</spock-core.version>
|
||||
<commons-lang3.version>3.3.2</commons-lang3.version>
|
||||
<slf4j-api.version>1.7.30</slf4j-api.version>
|
||||
<logback.version>1.3.12</logback.version>
|
||||
<lombok.version>1.18.26</lombok.version>
|
||||
<jaxb.version>4.0.4</jaxb.version>
|
||||
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<jmh.version>1.37</jmh.version>
|
||||
<gmavenplus-plugin.version>3.0.2</gmavenplus-plugin.version>
|
||||
<jaxb2-maven-plugin.version>3.1.0</jaxb2-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.ztsh.mockserver</groupId>
|
||||
<artifactId>mockserver-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-bom</artifactId>
|
||||
<version>${jaxb.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-json</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-xml</artifactId>
|
||||
<version>${groovy.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<version>${spock-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
|
@ -60,54 +95,66 @@
|
|||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j-api.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback-classic.version}</version>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>pl.touk.mockserver</groupId>
|
||||
<artifactId>mockserver-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<version>${spock-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>${jaxb2-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>${gmavenplus-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>testCompile</goal>
|
||||
<goal>compileTests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>touk.nexus.release</id>
|
||||
<name>TouK Virtual Repository</name>
|
||||
<url>http://nexus.touk.pl/nexus/content/repositories/releases</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>touk.nexus.snapshots</id>
|
||||
<name>TouK Virtual Repository</name>
|
||||
<url>http://nexus.touk.pl/nexus/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
</project>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue