cjstehno / ersatz Goto Github PK
View Code? Open in Web Editor NEW๐ค A simulated HTTP server for testing client code with configurable responses.
Home Page: https://cjstehno.github.io/ersatz
License: Apache License 2.0
๐ค A simulated HTTP server for testing client code with configurable responses.
Home Page: https://cjstehno.github.io/ersatz
License: Apache License 2.0
Add a ServerFeature
to support DIGEST authentication. Undertow seems to support it already so this should be similar to the BASIC auth feature as far as implementation goes.
When posting multipart file content, the logged body is way too big... truncate the to-string on that down to like 1k or something manageable.
Groovy 2.5 is coming out soon - it would be nice to know how things work before it's released.
Not sure we would want to upgrade right away but it would be good to have a test (shell) and some docs around using it - if there is any difference - I would think it would just work without any notes.
Will the new Java 8 lambda integration make the extra Groovy vs Java methods obsolete?
Come up with a support timeline for 2.5 - hopefully it will just work with both until I start using new features.
If not really necessary it would be nice if Ersatz server is compatible with Undertow 1.3.x (namely 1.3.15.Final) which is used by various spring boot related libraries (https://mvnrepository.com/artifact/io.undertow/undertow-core/1.3.25.Final/usages). This disqualifies from using Ersatz with Spring Boot or Grails 3. The construct offending the compatibility is currently server.listenerInfo
:
actualHttpPort = (server.listenerInfo[0].address as InetSocketAddress).port
if (httpsEnabled) {
actualHttpsPort = (server.listenerInfo[1].address as InetSocketAddress).port
}
Add support for multi-part upload handling either in the core or as a feature.
Explore how Ersatz may be used from Kotlin.
Let's get the latest versions of spock, groovy and gradle.
It would be invaluable if the actual and expected requests were logged in more detail and if possible, identify where they didn't match. I think mock-server does this and prints out which part of the request did not match (whether it was the method, body, headers etc).
Also consider making the output Spock and/or JUnit friendly so that IDEs (esp IntelliJ) can show a diff.
Configure project artifacts to be published in maven central repository as well as Jcenter.
Java 9 is out and it's not pretty. I upgraded, tried to build the project only to fail with odd errors... I then did a similar pattern on my other projects and got the same result. I then downgraded back to Java 8.
At this point, I don't have a Java 9 upgrade plan. My original understanding was that the modularization was an optional piece of functionality - it appears that it is not and that it also seems to break pretty much everything.
If you are comfortable with Java 9 and want to take a whack and getting Ersatz to compile and work, feel free to submit a Pull Request. If not for that, it might be a while unless I get a lot of outside pressure.
The only mention of hamcrest is one line in the user guide - some examples would be nice.
TBD
Currently the encoders/decoders are configured on a per-request/response basis. While a shared collection of them may be injected, it would be better to allow for global configuration of the desired defaults at the server or expectations
configuration level.
Also ensure that there is a set of reusable common encoders/decoders for standard scenarios.
It seems that request with multiple value headers are not matched. Below is the expectation.
server.expectations {
get('/api/hello') {
called 1
header 'Accept', 'application/json'
header 'Accept', 'application/vnd.company+json'
responder {
code 200
content 'msg': 'World', 'application/vnd.company+json'
}
}
}
However, this does not seem to match. Looking at the code it appears that only the first value is compared:
static RequestMatcher header(final String name, final Matcher<String> m) {
new RequestMatcher(m, { ClientRequest cr -> cr.headers.getFirst(name) })
}
public String getFirst(String headerName) {
HeaderValues headerValues = getEntry(headerName);
if (headerValues == null) return null;
return headerValues.getFirst();
}
Can this be fixed, or would you prefer I send a PR ?
Thanks
Consider/investigate request/response recording such that you can use Ersatz as a proxy in front of a live server, run a test or other requests against it and record the request/response captured as expectations.
Add the grails guide link:
to the docs somewhere and attribute it to the author
The tests are a bit of a hodge podge right now. There is good coverage but things could be cleaner and better organized.
The pattern of:
ersatzServer.expectations {
// expectation code..
}.start()
is common enough that it might be useful to provide a means of auto-starting after calling one of the expectation configuration methods (maybe a global config):
def ersatzServer = new ErsatzServer({
autoStart true
})
Should still be false
by default, and it should not cause errors if its enabled and start()
is called - it should just be ignored in this case.
This will allow for cleaner code.
The JavaMail API is a bit more generic in its Multipart implementation - let's use it instead.
Make sure it works for both request and response multipart content.
Document how to use it in both cases.
At this point there is just a quick cross-section of unit testing... finish this and then finish the integration testing in the HttpBuilder-NG project.
It would be nice if a Closure<Boolean>
could be used as an alternative to a Hamcrest matcher where they are allowed... I guess a Supplier<Boolean>
could also be allowed.
Either adjust the interfaces to allow this or make a ClosureMatcher
and a ConsumerMatcher
implementation of the Matcher
interface.
Related to http-builder-ng/http-builder-ng#162 found in HttpBuilder-NG the path matcher does not account for encoded parts of a path, such as:
/api/v4/projects/myteam%2Fmyrepo/repository/files/myfile.json
It will automatically decode it to:
/api/v4/projects/myteam/myrepo/repository/files/myfile.json
Figure out how to support these encoded paths.
It would be interesting and helpful to provide a distribution version of the library as a shadow jar as an alternate dependency to the standard. This would keep the dependencies of this project from affecting the using project.
Currently, the request and response headers are simply String
s... HTTP headers can be more complicated. Consider adding support for more types of headers - is this even needed or will Strings work well enough?
The Java example is weak in the Getting Started section. Expand it to a full Java JUnit test example as the Groovy Spock example.
Also add simple Java example to the site landing page.
The Request.body
content matcher methods allow for Hamcrest matchers as values, but not for content types. It would be useful (especially in multipart matching) to allow for Hamcrest matchers in the content type fields. So that you could have something like:
expectations {
post('/foo').body( any(), startsWith('text/') ).responds().code(201)
}
Undertow should already support this but I need to figure out how to enable and expose as an option.
I think this project is nearing the point for a true 1.0 release - use this issue to gather a list of features required for 1.0.
Add support for some sort of OAUTH - could probably use pac4j or something similar.
Currently expecations are additive. Add support for clearing them and investigate possibility of having a test share a server for all test methods without rebuilding it, but only clearing the expectations.
The BASIC and DIGEST authentication support should be converted to config properties rather than "features"
Add something like:
def server = new ErsatzServer({
basicAuthentication true
digestAuthentication true
})
Currently the HTTPS support for the proxy server is not implemented. There is an issue in Undertow that needs to be resolved first:
The multipart content matcher configuration has content types as strings, provide overrides with the ContentType object.
It might be useful to have the ability to timeout or delay the response for testing how the client handles this.
expectations {
get('/foo').responds {
delay '1 min'
code 200
}
get('/bar').responds {
delay 3600 // ms
code 200
}
}
Use the time duration parsing from Vanilla for rich string times or just allow ms (maybe TimeCategory too).
This would slow down tests that use it, but I could see this being something a client would want to test.
Rework the user guide to have better organization and more details and examples about each feature.
Make the point that this is not really a mock server but a server simulator... might make things more clear.
Add reference to my recent blog post about REST development.
Also note the kotlin version of the project as an example of using with kotlin
Documentation needs to be written:
It would be useful to add an any
request matcher such that it would match any request method - with the ability to refine the match with the rest of the configuration (query, headers, etc).
server.expectations {
any('/foo').responds().body('ok', TEXT_PLAIN)
}
so that GET /foo
and POST /foo
would both be matched by this expectation.
Make sure that the uploading and downloading support specifications support very large files in some manner.
The proxy support added to HttpBuilder-NG has exposed the need for a more realistic yet still simple embedded proxy server. Undertow can be used as a proxy server so it would be nice to provide a simple interface for setting up a small embedded testing proxy server outside of the Ersatz server itself.
Should be able to support simulation of web socket request/response.
Add support for configuring HTTPS endpoints either via extension or other means.
Need to add support for OPTIONS and TRACE request matching.
It might be useful to add a means of writing a matcher directly against a request, something like:
server.expectations {
match( matcher ).responds().body('ok', TEXT_PLAIN)
}
where matcher
would be a hamcrest matcher given the ClientRequest
object to match against. This would allow another level of flexibility in match configuration.
Note: that the match
method would be generic to handle whatever the matcher matches, including the request method.
Need to make sure that gzip, deflate compression are both supported.
If we try to encode a Map instance using the response encoder, the encoder chain logic fails to resolve it.
static final def JSON_ENCODER = { Object object ->
toJson(object)
} as Function
def server = new ErsatzServer({
encoder 'application/json', LinkedHashMap, JSON_ENCODER
})
I believe this is because in the ErsatzResponse
class the getContent
method tries to evaluate content.class
but if content
is a Map, Groovy thinks class
is a key of the Map rather than a property accessor for getClass
method.
@Override
String getContent() {
if (content != null) {
return encoderChain.resolve(contentType, content.class)?.apply(content) ?: (content as String)
}
return ''
}
The proposed solution is to use the method accessor rather than property shorthand in this instance.
return encoderChain.resolve(contentType, content.getClass())?.apply(content) ?: (content as String)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.