Giter Club home page Giter Club logo

kestrelmock's Introduction

Kestrel Mock

A .NET HTTP mock server.

badge Unit Tests docker Nuget version License: MIT

Example Nuget Reference Usage (RunAsync)

For direct use in a test project you can add the KestralMock nuget package and RunAsync. This will startup the webserver and return so your tests can use the mock API's configured in appsettings.json. See example appsetting.json below. By default, the mock endpoints will use http://localhost:60000.

var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();

KestrelMock.RunAsync(config);

Example Nuget Reference Usage (CreateWebHostBuilder)

For direct use in a test project you can add the KestralMock nuget package and call CreateWebHostBuilder. CreateWebHostBuilder will return the web host so you can controll the start and stop of the mock server.

webHost = KestrelMock.CreateWebHostBuilder(new string[] { YourUrl }, YourConfigurationRoot).Build();
webHost.Start();

Example Server Usage (Run)

Server will run and not return until the process shuts down. See KestrelMockServer project as an example.

var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();

KestrelMock.Run(config);

Install

dotnet add package KestrelMock

Example Mocks setup via appsettings.json

{
   "MockSettings":[
      {
         "Request":{
            "Methods":[
               "GET"
            ],
            "PathStartsWith":"/starts/with"
         },
         "Response":{
            "Status":200,
            "Headers":[
               {
                  "Content-Type":"application/json"
               }
            ],
            "Body":"{\"banana_x\": 8000}"
         }
      },
      {
         "Request": {
            "Methods": [ "GET" ],
            "PathMatchesRegex": ".+\\d{4}.+"
         },
         "Response": {
            "Status": 200,
            "Headers": [
               {
                  "Content-Type": "application/json"
               }
            ],
            "Body": "{\"banana_x\": 8000}"
         }
      },
      {
         "Request":{
            "Methods":[
               "POST",
               "GET"
            ],
            "Path":"/hello/world"
         },
         "Response":{
            "Status":200,
            "Headers":[
               {
                  "Content-Type":"application/json"
               }
            ],
            "Body":"{\"hello\": \"world\"}"
         }
      },
      {
         "Request":{
            "Methods":[
               "POST"
            ],
            "Path":"/api/estimate",
            "BodyContains":"00000"
         },
         "Response":{
            "Status":200,
            "Headers":[
               {
                  "Content-Type":"application/json"
               }
            ],
            "Body":"BodyContains Works!"
         }
      },
      {
         "Request":{
            "Methods":[
               "POST"
            ],
            "Path":"/api/estimate",
            "BodyDoesNotContain":"00000"
         },
         "Response":{
            "Status":200,
            "Headers":[
               {
                  "Content-Type":"application/json"
               }
            ],
            "Body":"BodyDoesNotContain works!!"
         }
      },
      {
         "Request":{
            "Methods":[
               "POST",
               "GET"
            ],
            "Path":"/api/fromfile"
         },
         "Response":{
            "Status":200,
            "Headers":[
               {
                  "Content-Type":"application/json"
               }
            ],
            "BodyFromFilePath":"./TestData/body.txt"
         }
      }
   ]
}

Example Mocks setup via admin endpoint

admin endpoint '/kestrelmock/mocks'

GET - returns list of mock settings objects.

POST - body is expected to be HttpMockSetting and adds new mock

DELETE - '/kestrelmock/mocks/YOURID' will delete by HttpMockSetting Id.

Watch requests using observe endpoint

observe endpoint '/kestrelmock/observe/[Watch id]'

When adding the "Watch" object to your mock settings, an observe endpoint will be created to retrieve request data. The watch id can be added directly or retrieved via response of mock creation.

### Example post request to create mock with "Watch" object

POST https://localhost:44391/kestrelmock/mocks
Content-Type: application/json

{
   "Request": {
      "Methods": [ "PUT" ],
      "PathStartsWith": "/api/supplier"
   },
   "Response": {
      "Status": 200,
      "Headers": [
         {
         "Content-Type": "application/json"
         }
      ],
      "Body": "{\"hello\":\"test\"}",
      "BodyFromFilePath":null,
      "Replace": null
   },
   "Watch": {
      "RequestLogLimit": 10,
      "Id": "c3f57f2c-b989-46eb-93a3-247a6caebe6d"
   }
}

Example of mock creation response from request above

{"Message":"Dynamic mock added with observability, call /kestrelmock/observe/c3f57f2c-b989-46eb-93a3-247a6caebe6d","Watch":{"Id":"c3f57f2c-b989-46eb-93a3-247a6caebe6d","RequestLogLimit":10}}

If you send the following request to a mocked endpoint which has a watch.

### Send request to mocked endpoint with body data to test

PUT https://localhost:44391/api/supplier
Content-Type: application/json

{
   "Test" : "foo"
}

Then you can call the observe endpoint to see that request body from previous requests up to the limit. The request to the observe endpoint will clear all current data from the watch queue.

### See your requests using observe endpoint

GET https://localhost:44391/kestrelmock/observe/c3f57f2c-b989-46eb-93a3-247a6caebe6d
Content-Type: application/json

The observe endpoint will give you back the body. Example respons:

[{"Path":"/api/supplier","Body":"{\r\n   \"Test\" : \"foo\"\r\n}","Method":"PUT"}]

Dynamic Mock

Some advanced dynamic mocking capabilities are provided for Json body data responses

Simple body replace

{
   "Request": {
      "Methods": [ "GET" ],
      "PathStartsWith": "/api/persons/carl"
   },
   "Response": {
      "Status": 200,
      "Headers": [
         {
         "Content-Type": "application/json"
         }
      ],
      "Body": "./data/person.json",
      "Replace": {
         "BodyReplacements": {
         "year": "1987",
         "name" : "carl"
         }
      }
   }
}

From Uri : Regex

{
   "Request": {
      "Methods": [ "GET" ],
      "PathStartsWith": "/api/cars"
   },
   "Response": {
      "Status": 200,
      "Headers": [
         {
         "Content-Type": "application/json"
         }
      ],
      "Body": "./my/generic/response.json",
      "Replace": {
          "RegexUriReplacements": {
            "car": "cars/([\\w\\d]+)/.+",
            "color": "/([\\w\\d]+)$"
          }
        }
   }
}

From Uri: Uri template

UriPathReplacements is in the format bodyValue:uriValue

{
      "Request": {
        "Methods": [ "GET" ],
        "PathStartsWith": "/api/wines"
      },
      "Response": {
        "Status": 200,
        "Headers": [
          {
            "Content-Type": "application/json"
          }
        ],
        "Body": "{\"wine\":\"W\",\"color\":\"C\",\"year\":\"Y\"}",
        "Replace": {
          "UriTemplate": "wines/{wine}/{color}?year={year}",
          "BodyReplacements": {
            "year": "1987"
          },
          "UriPathReplacements": {
            "wine": "{wine}",
            "color": "{color}",
            "year":"{year}"
          }
        }
      }
}

DOCKER

you can just run kestrel mock default template configuration with

docker run -p 5006:5000 -e ASPNETCORE_URLS=http://*:5000 jasonrowe/kestrelmock

If you want you can create your own image, and then add a custom appsetting.json and responses folder

docker build --no-cache -t kestrelmock:latest -f .\KestrelMockServerInstance\Dockerfile .

docker run -it --rm -p 5000:80 --name myapp kestrelmock:latest

Keep in mind that within the container you can modify the behaviour changing: /app/appsettings.json and /app/responses .
Via docker cp command on a local container you can apply custom settings and mock response files

cd mySettingsFolder

docker cp appsettings.json myapp:/app/appsettings.json

docker cp .\resp\ciao.json myapp:/app/responses/ciao.json

If you prefer build your custom image in CI/CD pipelines, you can append this to the docker file. Else just push to a private image registry, and use that as a starting image

FROM jasonrowe/kestrelmock as KestrelMockServerBase
WORKDIR /app
COPY ["responses","responses"]
COPY ["appsettings.json", "appsettings.json"]
ENTRYPOINT ["dotnet", "KestrelMockServerInstance.dll"]

kestrelmock's People

Contributors

jasonrowe avatar jkone27 avatar magicweasel avatar bryanprotolabs avatar

Stargazers

猪肉荣 avatar  avatar  avatar  avatar  avatar Vicente González avatar Dmitry Eydinov avatar xboo avatar dzmitry-lahoda avatar LambertWu avatar  avatar  avatar HiST avatar HenryHuang avatar 问道老王 avatar Sagilio avatar 朱利戈 avatar Bingfeng Liu avatar vzeng avatar Jeffrey Hu avatar 机灵小不懂 avatar ConanYao avatar pidan avatar geffzhang avatar Ruben Pahino avatar  avatar  avatar Jay avatar Debashish Pal avatar Sérgio Silveira avatar Steven T. Cramer avatar Renato Burton avatar David Vedvick avatar  avatar

Watchers

 avatar Jeff Byboth avatar James Cloos avatar  avatar  avatar Jon De Long avatar

kestrelmock's Issues

implement HTTP verb

a resource accepts different http verb, seems we are providing verbs but they are not actually used for resources, e.g. the verb is ignore (both GET, DELETE or PUT will work the same)

the verb is already in the configuration object, but does not currently seem to work as expected,
also for different verbs on a same resource/path

Graceful shutdown

shutdown does not seems to be graceful in the current setup, seems necessary to force shutdown

Make it easier to add to a test project

Early on it as very easy to call the "run" command in a test project and the library would run in a background thread for you. We should add back in that behavior for folks who want to the library more inline instead of a server.

At this point it might be easier to change .Run to do what the old default behavior was and create a new on for the server behavior?

// Would run and return
KestrelMock.Run(config);

// Would run the server
KestrelMock.RunServer(config)

Thoughts?

Add new admin endpoint to view recent requests to mocked endpoints

Give a way to view recent requests and the data that was sent to enable more advanced mocking flows.

Original Request:
"With kestrel mock, we've got a use case where our service receives a message, translates and then PUTs to another service ...

So we'd set up a Kestrel Mock to return 200 on the PUT ...

but ideally we want to see that translated data that was made to the PUT ...

Is there a way in Kestrel Mocks to see was was sent to mocked API please?"

published docker image issue

tired to pull and run from dockerhub the image we published, seems to have some problems. couldn't not get the mocked responses. (tried both localhost and 127.0.0.1)

image

docker run -p 5006:5000 -e ASPNETCORE_URLS=http://127.0.0.1:5000 jasonrowe/kestrelmock

i also tried inspect the image and required configuration files seems to be there (responses folder and appsetting.json),
and server "starts listening to 5000 correctly". Not sure what's wrong

Hosting environment: Production

Content root path: /app

Now listening on: http://127.0.0.1:5000

Application started. Press Ctrl+C to shut down.

Support for a sequence of requests

Given a developer configures a sequence of body results and http status.
When a request to a mock endpoint matches that result for a 'n' number of times.
Then the nth result from the sequence body and status is returned for the request.

Eventually we could replace this feature with the ability to have control over the full response but keeping this simple for now.

Pseudo implementation:

Update the' Response' class to have list of responses something like 'SequenceBodies' and 'SequenceHttpStatus'

public List<string> SequenceBodies { get; set; }

public List<string> SequenceStatus { get; set; }

Then add a counter property to the' Response' class that is incremented when a response is used.

 public int SequenceUsageCount { get; set; }

Then use a new method to figure out the correct body and status sequence to use from the list.

public string GetStatus()
{
 //TODO similar to GetBody below
}

 public string GetBody()
        {
            if ( SequenceBodies != null && SequenceBodies.Any())
            {
                int total = SequenceBodies.Count();
                var index = SequenceUsageCount;

                if (index < total)
                {
                    return SequenceBodies[index];
                }
                else
                {
                    return SequenceBodies[index % total];
                }
            }
            else
            {
                return Body;
            }
        }

Feature: add aspnetcore integration testing capabilities

Would be nice to easilly configure the mock for aspnetcore integration testing, either using only the TestServer somehow, or else providing a way to configure it easilly

using var mock = new MockServer(5001); //or other fluent configuration ways
//from here mock-server is listening on a TestServer (or if not possible real loopback server) on port 5001, with all configured mocks listening in appsetting.json

using var client = new HttpClient();
var response = await client.GetAsync("http://localhost:5001/api/mocked");

Figure out a good way to run tests via github actions

TODO:

  • 1. Fix up test that uses body.txt to work on windows and Linux or something else
  • 2. look into critical error logs about port binding and see if we can avoid those.
- name: Test
      run: dotnet test --no-restore --verbosity normal

Feature request: json path or similar way of specifying specific field in body re-write

would be nice to be able to specify json path for body rewrites, so that body rewrite can be precise ,
or a similar mechanism

https://jsonpath.com/

https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm

sample body response

{
  'Stores': [
    'Lambton Quay',
    'Willis Street'
  ],
  'Manufacturers': [
    {
      'Name': 'Acme Co',
      'Products': [
        {
          'Name': 'Anvil',
          'Price': 50
        }
      ]
    },
    {
      'Name': 'Contoso',
      'Products': [
        {
          'Name': 'Elbow Grease',
          'Price': 99.95
        },
        {
          'Name': 'Headlight Fluid',
          'Price': 4
        }
      ]
    }
  ]
}

and e.g. in the mock settings have

"Replace": {
          "UriTemplate": "test/{store}/{productName}",
          "UriJsonPathReplacements": {
            "$.Stores[0]": "{store}", //bodyValue: uriValue
            "$.Manufacturers[1].Products[0].Name": "{productName}"
          }
        }

Fix up .Run to make it easier for integrated testing

Early on it as very easy to call the "run" command in a test project and the library would run in a background thread for you. We should add back in that behavior for folks who want to the library more inline instead of a server.

At this point it might be easier to change .Run to do what the old default behavior was and create a new on for the server behavior?

// Would run and return
KestrelMock.Run(config);

// Would run the server
KestrelMock.RunServer(config)

Thoughts?

Add API endpoints to create, remove, and view mocks.

Setup API that can be used to add or remove a mocks. This will allow mocks to be setup and removed on the fly during testing. This will give another option for how people can configure tests.

  • Remove mock endpoint should take an id to lookup and remove the mock.
  • Add mock endpoint should take a HttpMockSetting and return a id.
  • View mock endpoint should return a list of mocks and ids.

This will require us to add ids to our HttpMockSetting object during creation. If we don't find an id in the appsetting we can auto create one.

Issue with stream ?

Might be this lines actually close the stream in some context and dont allow further middleware to re-read the stream again eventually

if (context.Request.Body != null)
{
using StreamReader reader = new StreamReader(context.Request.Body);
body = await reader.ReadToEndAsync();
}

we might neet to "reqind it" or re-seek to zero or somehow manage to make it readeable again
--> #46.

docker run throws error

The following command fails

docker run -p 5006:5000 -e ASPNETCORE_URLS=http://*:5000 jasonrowe/kestrelmock

Cannot use file stream for [/app/KestrelMockServer.deps.json]: No such file or directory
A fatal error was encountered. The library 'libhostpolicy.so' required to execute the application was not found in '/app/'.
Failed to run as a self-contained app.

  • The application was run as a self-contained app because '/app/KestrelMockServer.runtimeconfig.json' was not found.
  • If this should be a framework-dependent app, add the '/app/KestrelMockServer.runtimeconfig.json' file and specify the appropriate framework.

Microsoft.AspNetCore 2.2.0, Microsoft.AspNetCore.Server.IIS Vulnerability Report

JFrog Xray alerted me to the following second-order vulnerabilities in my solution based on my use of KestrelMock for testing:

Severity Direct Dependency Direct Dependency Version Impacted Dependency Name Impacted Dependency Version Fixed Versions CVE
High KestrelMock 0.4.0 Microsoft.AspNetCore 2.2.0 3.1.15, 5.0.6 CVE-2021-31204
Medium KestrelMock 0.4.0 Microsoft.AspNetCore.Server.IIS 2.2.0 2.2.6 CVE-2019-1075

KestralMock not working with Refit

In my application, i call various Rest endpoints using a third party framework called Refit
https://github.com/reactiveui/refit

When i try to mock that api using KestralMock , Upon execution the api call remains in the
Result = "Not Yet Computed" and status "WaitingForActivation" state
and hence the code throws an exception when trying to retrieve the response data.

Where as if i try to create an HttpClient similar to samples given in your code it works .

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.