Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use the "add stub" API on an existing imposter #106

Closed
mabead opened this issue Nov 2, 2022 · 8 comments
Closed

How to use the "add stub" API on an existing imposter #106

mabead opened this issue Nov 2, 2022 · 8 comments

Comments

@mabead
Copy link
Contributor

mabead commented Nov 2, 2022

I have an existing http imposter that is already running in mountebank. I would like to add stub to this imposter by calling the "add stub" API: http://www.mbtest.org/docs/api/overview#add-stub.

I looked in the code of MbDotNet but I couldn't find a way to just add a stub to an existing imposter. I just found way to either create or update the imposter.

Could you please tell me if I looked in the wrong place or I could call this "add stub" API if this feature exists?

@mattherman
Copy link
Owner

MbDotNet does not support the add stub feature currently. You may be able to accomplish your goals with the UpdateImposterAsync client method.

imposter.AddStub().Returns(...);
client.SubmitImposter(imposter);
...
imposter.AddStub().Returns(...);
client.UpdateImposter(imposter);

That will result in an imposter with both stubs. This won't work for you if you need to maintain the state of the original stubs (ex. recorded requests) since they'll be replaced. It also won't be helpful if you're trying to add stubs to an imposter that was not created with MbDotNet (ex. saved imposters restored when you started mountebank).

@mattherman
Copy link
Owner

I just noticed you mentioned it was an existing imposter. The UpdateImposterAsync method will not work then for the reasons I mentioned in my previous reply.

Unfortunately, I don't know of any way to accomplish what you are trying to do without updating MbDotNet to support that operation.

@mabead
Copy link
Contributor Author

mabead commented Nov 7, 2022

Ok, that's what I figured out. I will try to open a pull request if you are willing to accept that feature. Would you be opened to such a PR?

In terms of implementation, given that the AddStub method already exists on the imposter class, I am just not sure of how to clearly expose the new feature. The option that I see with the least chances of creating breaking changes would be to add a new method like AddStubToExistingImposter. That would make sure that all existing calls to AddStub would be unaffected.

What do you think about this? Do you have a better option in mind?

@mattherman
Copy link
Owner

The AddStub method is just a factory method for creating a stub of the appropriate type (HttpStub, TcpStub, etc.) and adding it to the imposter model so I'm not sure that's the best place to put this.

This should be a new MountebankClient method alongside UpdateImposterAsync (which implements the "change stubs" API). I would expect it to be something like this:

public async Task AddToExistingImposter(Imposter imposter, StubBase newStub, int? index, CancellationToken cancellationToken = default) { ... }

The one thing I don't like about that is that Imposter and StubBase are not "typed" to the appropriate imposter that you're updating. Similar to the GetXYZImposterAsync client methods we may want to have a method per type for this API as well:

AddToExistingHttpImposter(HttpImposter imposter, HttpStub newStub, ....)
AddToExistingHttpsImposter(HttpsImposter imposter, HttpStub newStub, ...)
AddToExistingTpcImposter(TcpImposter imposter, TcpStub newStub, ...)
AddToExistingSmtpImposter(SmtpImposter imposter, SmtpStub newStub, ...)

We'll also need a new model to represent the request object:

internal class AddStubRequest
{
    [JsonProperty("index", NullValueHandling = NullValueHandling.Ignore)]
    public int? Index { get; set; }

    [JsonProperty("stub", NullValueHandling = NullValueHandling.Ignore)]
    public StubBase Stub { get; set; }
}

The client methods will be responsible for creating this request object with the inputs. That way we still get the typing on the public API but can avoid duplicating this model four times.

I think the client methods would also call imposter.AddStub(newStub) on the imposter that's passed in. This would ensure the Stubs collection is up to date with the changes. It's definitely a little weird though - I've repeatedly ran into issues like this since I'm trying to maintain the state of the imposter, but the real source of truth is the mountebank process itself. Still, I think it is better than not adding the stub to the imposter object.

Finally, the client methods will pass the necessary data along to a new method on HttpRequestProxy that calls the API.

Let me know if you have any questions or feedback.

@mabead
Copy link
Contributor Author

mabead commented Nov 8, 2022

Thanks for the detailed guidance. I agree with your suggestion. I will try to add this in the next few weeks.

@mattherman
Copy link
Owner

I added support for this in #117. It will be included in the v5 package when I publish it in a few days.

@mabead
Copy link
Contributor Author

mabead commented Apr 5, 2023

Thank you so much @mattherman . I was feeling guilty everyday that I saw my post-it reminder to submit such a PR.

@mattherman
Copy link
Owner

No worries. The v5 package with that functionality has been published:
https://github.com/mattherman/MbDotNet/releases/tag/v5.0.0

The implementation changed a little bit from what we had discussed. To add a stub to an existing imposter you would do something like this:

var stub = new HttpStub()
	.OnMethodEquals(Method.Get)
	.ReturnsStatus(HttpStatusCode.BadRequest);

await _client.AddHttpImposterStubAsync(port, stub);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants