This is a web mock CLI that can be used in order to create self-defined local endpoints for testing within seconds.
- Clone this project.
cd pygmalion
.gradlew build
.- Add the
run
folder to your PATH.
Running Pygmalion (and hence the unit tests as well) will require either the deprecated Nashorn engine or the Graaljs engine to be included in your Java Runtime Environment. This means that from JDK 15 onwards you will need to use GraalVM instead of the regular JDK for testing and running. (If none of those engines is present, jRuby is used as a fallback, which obviously changes the execution semantics of your scripts.)
pygmalion
> when get /hallo-welt then 'Hallo Welt'
Then open your browser and navigate to http://localhost/hallo-welt
.
(Note that you can use single quotes for escaping.)
There are quite a lot of useful Pygmalion commands. One of the most powerful ones is the restTemplate
command. Its syntax is:
> restTemplate /cookies --key=flavour
This will create the usual GET, POST, PUT, DELETE endpoints for /cookies.
It expects them to be json objects using the property specified in the argument as key (defaults to id
).
Hence the following calls would work as expected after the command above:
POST http://localhost/cookies {"flavour":"chocolate"} -> 201 CREATED | "chocolate"
PUT http://localhost/cookies/chocolate {"flavour":"chocolate", "goesWith": "coffee"} -> 200 OK
GET http://localhost/cookies -> 200 OK | [{"flavour":"chocolate", "goesWith": "coffee"}]
DELETE http://localhost/cookies/chocolate -> 200 OK
GET http://localhost/cookies/chocolate -> 404 NOT FOUND
Note that the resources can even be initialized from a JSON array stored in a file:
> restTemplate /cookies from cookies.txt --key=flavour
If you add the --persistent
flag, your data will be stored in a local database and hence still be present when restarting Pygmalion.
If you want to make sure that your databases for different pygmalion configurations do not get mixed, you can provide a name for the database like this:
database db1
> port 8080
> when get /test then 'This is served on port 8080.'
Then check http://localhost:8080/test
.
> when get /test then from index.html
> static .
This will serve from the specified directory statically. (.
is for current, you can use absolute path as well.)
> apply script.txt
This will apply every line found in the provided file as if it had been entered in the CLI. (Lines starting with #
or //
are considered to be comments.)
> when post /test then ${body}
> when post /test then ${JSON.parse(body).name}
> when get / then forward https://google.com
> when get /test then 'Works' status 200
> when post /test then '${queryParams.number + 3}'
In general, expressions within ${}
are evaluated using the JSR-223 Java Scripting Extension (defaulting to the Nashorn and GraalJS engines), i.e. valid JavaScript expressions can be used.
It is also possible to configure the type of the engine itself via the engine
command, e.g.:
engine jruby
The following properties are injected by Pygmalion via bindings and can be accessed from within the expressions:
Property | Description |
---|---|
body | Request body |
cookies | Map of all cookies sent with the request |
counter | How many times this endpoint has been called |
headers | Map of all request headers |
queryParams | Map of all queryParams |
params | Map of all "params", i.e. pathVariables |
request | JSON string representing the whole request |
timestamp | Current timestamp (ms since the epoch) |
uri | The request's URI |
restTemplates | Map of JSON objects representing the current state of all configured restTemplates (i.e. the resources themselves) |
The JavaScript expression can also be put into a file instead, like that:
> when post /test then eval test.js
Another common use case is to create a mapping using a path variable and then using that variable in the return value expression:
> when get /:pathvariable then '${"Your variable is: " + params[":pathvariable"]}'
It is possible to create websocket endpoints like this:
> websocket /test1
> websocket /test2
> websocket start
(Due to the underlying framework it is only possible to create websockets before every other request mapping.)
After setting up the endpoints messages can be sent to the websocket's clients:
> websocket /test
> websocket start
> websocket /test message 'Hello'
It is also possible to schedule recurring websocket messages like this:
> websocket /test recurring 'PING' 5000
This will send the message 'PING' to all clients connected to the /test
websocket every 5 seconds.
Also, it is possible to configure a response to incoming messages:
> websocket /test respond ${message}
This will simply echo the incoming message.
> openapi spec.yml
Assuming you have a json or yaml specification in OpenAPI format, you can use pygmalion to spawn a test server.
Also it is possible to export your current Pygmalion request configuration to OpenAPI:
> openapi-export exportFile.yaml
For resource templates Pygmalion will observe the entities you create and infer their schema for OpenAPI export.
> oauth /oauth
You can use Pygmalion to spawn an OAuth2 test server. The above command creates routes GET /oauth/authorize
and POST /oauth/token
to allow for the Authorization Code Grant Flow (see https://tools.ietf.org/html/rfc6749#section-4.1).
The authorization endpoint simply redirects to the specified redirect_uri
providing an (expiring) authorization code and the original state
. The token endpoint validates the authorization code and issues JWTs that can be verified using the public key in src/main/resources
. (Obviously, this key pair is not a secret at all..)
> chaosmonkey 42
This will fail about 42% of all requests with a status of 503.
pygmalion
> help
This project is powered by the awesome Spark-Java project (i.e. its Kotlin version). Please see: https://github.com/perwendel/spark
Copyright by Christopher Rudoll, 2018-. This is Free Software and published under the GPL 3.0 License.