mock-server / mockserver

MockServer enables easy mocking of any system you integrate with via HTTP or HTTPS with clients written in Java, JavaScript and Ruby. MockServer also includes a proxy that introspects all proxied traffic including encrypted SSL traffic and supports Port Forwarding, Web Proxying (i.e. HTTP proxy), HTTPS Tunneling Proxying (using HTTP CONNECT) and SOCKS Proxying (i.e. dynamic port forwarding).
http://mock-server.com
Apache License 2.0
4.58k stars 1.07k forks source link

overriding unlimited response gives old response for few times #280

Closed janonymus closed 6 years ago

janonymus commented 8 years ago

Imagine that I'm setting up an unlimited response for /test to say message "A" then overriding the same path with message "B"

for the first few times calling that path, I receive message "A" for the first few times. Only after calling the same path a few times I'm able to get the overridden message "B"

Is there any workaround for this?

jamesdbloom commented 7 years ago

As it currently stands it is not possible to override an expectation that has already been setup, by design. The expectations are evaluated in the order they are setup so if two expectations match exact then the first one will always be matched. However if the first expectation is only valid for a limited number of matches once it has completed the specified number of matches the second matching expectation will be matched. As follows:

  1. setup expectation one
{
    "httpRequest": {
        "method": "GET", 
        "path": "/simple"
    }, 
    "httpResponse": {
        "statusCode": 200, 
        "body": "some response - one"
    }, 
    "times": {
        "remainingTimes": 3, 
        "unlimited": false
    }
}
  1. setup expectation two
{
    "httpRequest": {
        "method": "GET", 
        "path": "/simple"
    }, 
    "httpResponse": {
        "statusCode": 200, 
        "body": "some response - two"
    }, 
    "times": {
        "remainingTimes": 1, 
        "unlimited": true
    }
}
  1. make requests to /simple and get the following sequence of response
some response - one
some response - one
some response - one
some response - two
some response - two
some response - two
some response - two
...

I have just re-tested this manually and it works as expected. There are also multiple tests covering these cases, such as org.mockserver.mock.MockServerMatcherSequentialResponsesTest and org.mockserver.mock.MockServerMatcherOverlappingRequestsTest.

Perhaps you could provide some code examples so that I can better understand what the issue is.

janonymus commented 7 years ago

Thanks for your response!

Imagine that you have a "button" which you press would change the state of the server, but until it's not pressed the state should be always "A" and after pressed the state should be always "B".

Setup for "state A" { "httpRequest": { "method": "GET", "path": "/simple" }, "httpResponse": { "statusCode": 200, "body": "state - A" }, "times": { "remainingTimes": 3, "unlimited": false } } After the button is "pressed" we run the set up for state B Setup for "state A" { "httpRequest": { "method": "GET", "path": "/simple" }, "httpResponse": { "statusCode": 200, "body": "state - B" }, "times": { "remainingTimes": 3, "unlimited": false } }

In this case we want this result: state - A state - A state - A "button pressed, setup for state B is executed" state - B state - B state - B

What we usually get is like this: In this case we want this result: state - A state - A state - A "button pressed, setup for state B is executed" state - A state - B state - B

jamesdbloom commented 7 years ago

Have you thought of mocking each request one by one?

The other option is you might need to wait until I have finished the websocket callback logic, this is complete but still needs a couple more integration tests and the javascript client, see branch websocket_callbacks. This would allow you to dynamically define a response using a local callback method in the test. For example:

mockServerClient
        .when(request().withPath("/object_callback"))
        .callback(
                new ExpectationCallback() {
                    @Override
                    public HttpResponse handle(HttpRequest httpRequest) {
                        return response()
                                .withStatusCode(HttpStatusCode.ACCEPTED_202.code())
                                .withHeaders(
                                        header("x-object-callback", "test_object_callback_header")
                                )
                                .withBody("an_object_callback_response");
                    }
                }
        );

In Java 7 with lambas this code would look much nicer as follows:

mockServerClient
        .when(request().withPath("/object_callback"))
        .callback(
                httpRequest -> response()
                        .withStatusCode(HttpStatusCode.ACCEPTED_202.code())
                        .withHeaders(
                                header("x-object-callback", "test_object_callback_header")
                        )
                        .withBody("an_object_callback_response")
        );

Under the hood a websocket is opened between the MockServerClient and MockServer so that when MockServer receives a matching request the MockServer communicates back to the MockServerClient using the websocket to retrieve the response that should be returned.

I would expect this to be in the next release in one to two weeks from now.

kleinron commented 7 years ago

Hi,

Great work on this project!

About this specific question, I'll try to add my scenario: I'm trying to set the "right" expectation for my http client, and it's always an unlimited in count. This kind of process is trial and error, mostly since I'm trying to figure out the best response. So the matching is always the same, but the response might change during the process.

In my experience, if I change the expectation, then the previous one is still there, for a single request.

But I want to completely override the current expectation with the new one, as documented.

Is it possible to change the behavior of mock-server to override the exact previously configured expectations?

jamesdbloom commented 6 years ago

The easiest way to do this would be to clear the previously configured expectations, then create a new expectation.

I am going to close this ticket as the documentation has been update (90% completed).

dhouhamaa commented 1 year ago

Hi ,

I'm looking for a way to match unknown number of requests within 60 seconds then remove expectation I have the following in expectation : "times": { "unlimited": false }, "timeToLive" : { "timeUnit" : "SECONDS", "timeToLive" : 60, "unlimited" : false }

But this results in matching the expectation only once and then it is removed without waiting for the 60 seconds to finish. if I change it to : "times": { "unlimited": true }, "timeToLive" : { "timeUnit" : "SECONDS", "timeToLive" : 60, "unlimited" : false }

Then the expectation won't be removed even after 60 seconds Any idea ? Thanks