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

New feature request: Access to Owin pipeline #53

Closed
Rmkrs opened this issue Oct 13, 2017 · 11 comments
Closed

New feature request: Access to Owin pipeline #53

Rmkrs opened this issue Oct 13, 2017 · 11 comments

Comments

@Rmkrs
Copy link

Rmkrs commented Oct 13, 2017

Hey Stef,

We are looking into using WireMock.net for UI tests for one of our products. To give it some context, we have a single page Aurelia Frontend application talking to a backend using WebAPI2.

We serve the frontend files (/index, etc) but we also have /api/xxx where our backend responds.
And /api/signalr, where the signalr connection lives.
All on the same url:port.

We created a POC to provide fake api data to the frontend using WireMock and that works.

We had to do a little bit of "trickery" to be able to still host our frontend files, by making a "StaticResourceResponseProvider" that allows us to server files from disk based on the URI.
So all uri's now go to the StaticResourceResponseProvider, except for /api/, using the regex "^(?!/api/.$).*".

Per UI test we have different Given/RespondWith setups we do based on what /api/xxx calls we expect and require.

If we had access to the Owin pipeline you use inside WireMock.net we could hook this up a bit nicer (and without fonts breaking, due to always being sent as string, instead of bytes with encoding, courtesy of the string Body property in ResponseMessage).

But why we "really" need access to the Owin pipeline is because we also want to hook up SignalR. We cannot use Response.Create().WithProxy as that breaks the SignalR connection. So ideally I would want to register that on the IAppBuilder, such as:

public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}

We were looking at ways to accomplish this in WireMock.net, but found no readily available paths. One of the (least intrusive) solutions could be if IOwinSelfHost was public and it could be injected as an argument on the Start methods in FluentMockServer. Right now the private constructor there accepts settings and depending on the pragma NETSTANDARD, either AspNetCoreSelfHost or OwinSelfHost is spawned.

I could imagine creating my own implementation of OwinSelfHost where I can setup any Owin components I would like to use.

Or maybe you have a different/better idea, I am open to suggestions.

@Rmkrs
Copy link
Author

Rmkrs commented Oct 13, 2017

I did a POC of how this could work by changing some code in WireMock.net and export a new nuget package, but "least intrusive" might not be a correct term.

I had to make WireMockMiddlewareOptions, FluentMockServerSettings and IOwinSelfHost public.
I also had to copy some of the code now being done in the private constructor of the FluentMockServer to the outside where I start the FluentMockServer, like so:

            var middlewareOptions = new WireMockMiddlewareOptions();
            var settings = new FluentMockServerSettings();
            int port = settings.Port > 0 ? settings.Port.Value : PortUtil.FindFreeTcpPort();
            var urls = new[] { (settings.UseSSL == true ? "https" : "http") + ":https://localhost:" + port + "/" };
            settings.Urls = urls;
            this.server = FluentMockServer.Start(settings, new OwinSelfHost(middlewareOptions, urls), middlewareOptions);

Before this, the code looked like this:

this.server = FluentMockServer.Start(new FluentMockServerSettings());

And I had to add 2 optional arguments to the Start method I was using:

public static FluentMockServer Start(FluentMockServerSettings settings, IOwinSelfHost owinSelfHost = null, WireMockMiddlewareOptions options = null)

And of course pass these into the private constuctor and use them there:

private FluentMockServer(FluentMockServerSettings settings, IOwinSelfHost owinSelfHost = null, WireMockMiddlewareOptions options = null)
        {
            if (options != null)
            {
                _options = options;
            }

            if (settings.Urls != null)
            {
                Urls = settings.Urls;
            }
            else
            {
                int port = settings.Port > 0 ? settings.Port.Value : PortUtil.FindFreeTcpPort();
                Urls = new[] { (settings.UseSSL == true ? "https" : "http") + ":https://localhost:" + port + "/" };
            }

            if (owinSelfHost == null)
            {
#if NETSTANDARD
                _httpServer = new AspNetCoreSelfHost(_options, Urls);
#else
                _httpServer = new OwinSelfHost(_options, Urls);
#endif
            }
            else
            {
                this._httpServer = owinSelfHost;
            }

The OwinSelfHost that I created in my solution is a copy of your version, but I made some changes to the StartServer method to initialize SignalR. This is just quick and dirty, my "real" OwinSelfHost would probably be more configurable, instead of having a hardcoded URI in there:

        private void StartServers()
        {
            System.Console.WriteLine("WireMock.Net server using .net 4.5.x or .net 4.6.x");

            Action<IAppBuilder> startup = app =>
            {
                app.UseCors(CorsOptions.AllowAll);
                app.MapSignalR();
                app.Use<WireMockMiddleware>(_options);
            };

            var servers = new List<IDisposable>();
            servers.Add(WebApp.Start($"{Urls[0]}api/", startup));
            foreach (var url in Urls)
            {
                servers.Add(WebApp.Start(url, startup));
            }

            IsStarted = true;

            while (!_cts.IsCancellationRequested)
            {
                Thread.Sleep(30000);
            }

            IsStarted = false;

            foreach (var server in servers)
            {
                server.Dispose();
            }
        }

Not super happy about the resulting code changes... But at least I did get SignalR integrated into the solution I had and I could verify that that part would work in theory.

@StefH
Copy link
Collaborator

StefH commented Oct 13, 2017

1] and without fonts breaking, due to always being sent as string, instead of bytes with encoding, courtesy of the string Body property in ResponseMessage). --- This looks like a bug or a new feature

2] I will take a look at your poc code. And check if this can be build in a more easier way.

@Rmkrs
Copy link
Author

Rmkrs commented Oct 13, 2017

Thanks, I appreciate that. If you need any input from me, please don't hesitate.
Have a nice weekend.

@StefH
Copy link
Collaborator

StefH commented Oct 14, 2017

1] This issue has been fixed in the code by 07f0399
Do you want a new NuGet for this?

2] I still have to look into this.

3] Does the mocking work with SignalR, I'm surprised that mocking works? Can you maybe provide a POC client or unit-test to test this ?

@Rmkrs
Copy link
Author

Rmkrs commented Oct 14, 2017

Nice fix. I do not require a nuget package for this right now. I can wait with that for item 2.

For 3, I am not really "faking" SignalR itself, but rather create a real signalr hub with the same name as the original. Here I can expose the same methods that I have on the real one, but the data these methods will expose will be fake. So instead of faking the mechanism itself, I just expose fake data with it if that makes sense,

I actually fell today and had to get to the ER (hence my late reply) so I am typing (very slowly) with one hand and cannot easily create a POC right now, but once I heal up a bit I will see what I can do.

@StefH
Copy link
Collaborator

StefH commented Oct 17, 2017

That really unfortunately, get well soon!

@StefH
Copy link
Collaborator

StefH commented Oct 17, 2017

Hello @Rmkrs

I did add some code which should make it possible to do additional pre and post setup based on the IAppBuilder.

See this code 37244d5#diff-e13c7e694283c3ed3636ff01623747c4R64 at a new branch.

Would this be a solution to your problem ?

@Rmkrs
Copy link
Author

Rmkrs commented Oct 18, 2017

@StefH, that would definately solve the challenges we are having with the SignalR wireup.

@StefH
Copy link
Collaborator

StefH commented Oct 18, 2017

@Rmkrs I've merged that code into the main branch so you can use it from there.

@StefH
Copy link
Collaborator

StefH commented Oct 30, 2017

New NuGet is added which includes this functionality.

I'm closing this issue for now, if you need more details, please open a new one.

@StefH StefH closed this as completed Oct 30, 2017
@StefH
Copy link
Collaborator

StefH commented Jan 10, 2018

@Rmkrs
Just a question:
Did you succeed in running WireMock as a webjob in Azure?

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