Giter VIP home page Giter VIP logo

natenho / mockaco Goto Github PK

View Code? Open in Web Editor NEW
321.0 13.0 34.0 2 MB

๐Ÿต HTTP mock server, useful to stub services and simulate dynamic API responses, leveraging ASP.NET Core features, built-in fake data generation and pure C# scripting

Home Page: https://natenho.github.io/Mockaco/

License: Other

C# 92.09% Dockerfile 0.58% PowerShell 0.42% JavaScript 4.71% CSS 2.20%
csharp mock-server roslyn faker mocks-generator aspnet mocks engine dotnet-core aspnet-core

mockaco's People

Contributors

alieniasty avatar atyminski avatar dependabot[bot] avatar fossabot avatar glassespi avatar gomete avatar jonasgiehl avatar leandrodasilvaalves avatar marcothz avatar natenho avatar pmorelli92 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mockaco's Issues

NullReferenceException when the callback "headers" are not set in template

Describe the bug

NullReferenceException when the callback "headers" are not set in template.

[16:30:03 ERR] 0HM0SC3R6B3US:00000005 Callback error
System.NullReferenceException: Object reference not set to an instance of an object.
at Mockaco.CallbackMiddleware.PrepareHttpRequest(CallbackTemplate callbackTemplate, MockacoOptions options) in C:\projects\mockaco\src\Mockaco\Middlewares\CallbackMiddleware.cs:line 93
at Mockaco.CallbackMiddleware.PerformCallback(HttpContext httpContext, IMockacoContext mockacoContext, IScriptContext scriptContext, ITemplateTransformer templateTransformer, MockacoOptions options) in C:\projects\mockaco\src\Mockaco\Middlewares\CallbackMiddleware.cs:line 62

To Reproduce
Use this mock to reproduce the scenario:

{
  "request": {
	"method": "GET"
  },
  "response": {
	"status": "OK",
	"body": {
	  "currentTime": "<#= DateTime.Now.ToString() #>"
	}
  },
  "callback": {
	"method": "POST",
	"timeout": 2000,	
	"body": {
		"message": "The response was <#= Response.Body["currentTime"]?.ToString() #>"
	},
	"url": "https://postman-echo.com/post",
	"delay": 5000
  }
}

Expected behavior
No error

Support multiple callbacks

Is your feature request related to a problem? Please describe.
Sometimes you would need to callback multiple services to properly mock a behavior.

Describe the solution you'd like
Include callbacks attribute to the mock template so it would be compatible with the current mock template implementation and also support multiple calls. It would be great to have a condition that could be evaluated as well.

Describe alternatives you've considered

  • To modify the current callback attribute in order to support multiple callbacks. However, it would introduce a breaking change to the mock template scheme, which seems not to be a good idea.

Improve performance

Roslyn usage must be reviewed or some kind of caching should do the job.
The current version compiles code for every request.

Error when removing template files on the fly

Describe the bug
[19:29:01 INF] File change detected
[19:29:01 DBG] Cache invalidated because of TokenExpired
Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'C:\Code\github\natenho\Mockaco\src\Mockaco\Mocks\Claro-M4U-Thundercats\11963641040\ProductsIdGet-200-R$30.json'. at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle) at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at System.IO.File.Open(String path, FileMode mode, FileAccess access, FileShare share) at Mockaco.TemplateFileProvider.<>c__DisplayClass16_1.<LoadTemplatesFromDirectory>b__1() in C:\Code\github\natenho\Mockaco\src\Mockaco\Templating\Providers\TemplateFileProvider.cs:line 105 at Polly.Policy.<>c__DisplayClass108_0.<Execute>b__0(Context ctx, CancellationToken ct) at Polly.Policy.<>c__DisplayClass138_0.<Implementation>b__0(Context ctx, CancellationToken token) at Polly.Retry.RetryEngine.Implementation[TResult](Func3 action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldRetryExceptionPredicates, ResultPredicates1 shouldRetryResultPredicates, Action4 onRetry, Int32 permittedRetryCount, IEnumerable1 sleepDurationsEnumerable, Func4 sleepDurationProvider)
at Polly.Retry.RetryPolicy.Implementation[TResult](Func3 action, Context context, CancellationToken cancellationToken) at Polly.Policy.Implementation(Action2 action, Context context, CancellationToken cancellationToken)
at Polly.Policy.Execute(Action2 action, Context context, CancellationToken cancellationToken) at Mockaco.TemplateFileProvider.LoadTemplatesFromDirectory()+MoveNext() in C:\Code\github\natenho\Mockaco\src\Mockaco\Templating\Providers\TemplateFileProvider.cs:line 103 at Mockaco.MockProvider.WarmUp() in C:\Code\github\natenho\Mockaco\src\Mockaco\MockProvider.cs:line 67 at Mockaco.MockProvider.TemplateProviderChange(Object sender, EventArgs e) in C:\Code\github\natenho\Mockaco\src\Mockaco\MockProvider.cs:line 42 at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown --- at System.Threading.ThreadPoolWorkQueue.Dispatch()

To Reproduce
Delete template files. It is not reproducible all the times.

Expected behavior
To not generate errors when deleting templates.

Prioritize templates containing conditions over those with empty condition

Although template files are usually loaded in alphabetical order, currently there is no guaranteed order.
Besides that, the order the templates are loaded is the same they are evaluated.
Because of that, if there are multiple templates targeting the same HTTP method and path and the first loaded is the one with empty condition, the others will never be reached.

Scripting doesn't work for file template

Describe the bug
When sending response from external file (f.e. html file) containing script, the script is not evaluated

To Reproduce
Using these mocks:

{
    "request": {
        "route": "login",
        "method": "GET"
    },
    "response": {
        "headers": {
            "Content-Type": "text/html; charset=UTF-8"
        },
        "status": "OK",
        "file": "Mocks/login.html" 
    } 
}

and

{
    "request": {
        "route": "login",
        "method": "POST"
    },
    "response": {
        "headers": {
            "Content-Type": "text/html; charset=UTF-8"
        },
        "status": "OK",
        "file": "Mocks/login.html" 
    } 
}

And this's html file

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
<form method="post">
    <label for="username">Username</label>: 
    <input type="text" name="username" id="username" value="<#= Request.Body["username"]?.ToString() #>"/>
</form>
</body>
</html>

Expected behavior
The script is evaluated

Screenshots
mockaco-scripting

Support loading response body from a file

To avoid the need to correctly escape body contents (like in XML), it would be useful to load raw data from a file.

It could be useful to mock file downloading as well.

XML Example:

{
  "request": {
    "method": "GET",
    "route": "ping"
  },
  "response": {
    "status": "OK",
    "headers": {
      "Content-Type": "application/xml"
    },
    "file": "foo-bar-response.xml"
  }
}

Binary Download Example:

{
  "request": {
    "method": "GET",
    "route": "ping"
  },
  "response": {
    "status": "OK",
    "headers": {
      "Content-Type": "application/octet-stream",
      "Content-Disposition": "attachment; filename=\"xpto.bin\""
    },
    "file": "xpto.bin"
  }
}

Append git sha to version number

Mockaco executable files do not have an easy way to track back to source control. Appending the git sha to the version metadata can help with that.

Unexpected successful response when the request is malformed

Describe the bug
When a malformed request is sent and there is a condition analyzing values from the request, Mockaco is ignoring the condition and returning the mock as if it was evaluated to "True". It seems that when a condition is evaluated with a runtime error, the mock is being returned anyway.

To Reproduce

Use the mock bellow:

{
	"request": {
		"method": "POST",
		"route": "/bug",
		"condition": "<#=Request.Body["expectedProperty"]?.ToString() == "expectedValue" #>"
	},
	"response": {
		"status": 200,
		"body": "This should not be returned"
	}	
}

Send any malformed request that cannot be evaluated as a JSON or XML object, accessed through Request.Body["xxx"]:

$ curl --location --request POST 'http://localhost:5000/bug' --header 'Content-Type: application/xml' --data-raw 'foo' -w "\n\n"

Results:

"This should not be returned"

Expected behavior
Mockaco should not return mocks when it was not able to evaluate its condition property.

Additional context
The log:

[04:29:31 INF] 0HM4THLDIDBKQ:00000001 Request starting HTTP/1.1 POST http://localhost:5000/bug application/xml 3
[04:29:31 INF] 0HM4THLDIDBKQ:00000001 Incoming request from ::ffff:172.17.0.1
[04:29:31 DBG] 0HM4THLDIDBKQ:00000001 Headers: {
  "Content-Type": [
    "application/xml"
  ],
  "Accept": [
    "*/*"
  ],
  "Host": [
    "localhost:5000"
  ],
  "User-Agent": [
    "curl/7.58.0"
  ],
  "Content-Length": [
    "3"
  ]
}
[04:29:31 DBG] 0HM4THLDIDBKQ:00000001 Body: foo
[04:29:31 ERR] 0HM4THLDIDBKQ:00000001 Processed script Request.Body["inexistentProperty"]?.ToString() == "anything"  with error
System.NullReferenceException: Object reference not set to an instance of an object.
   at Submission#0.<<Initialize>>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)
   at Mockaco.TemplateTransformer.Run(String code, IScriptContext scriptContext) in /src/Templating/TemplateTransformer.cs:line 102
[04:29:32 INF] 0HM4THLDIDBKQ:00000001 Incoming request matched POST /bug (mock.json)
[04:29:32 ERR] 0HM4THLDIDBKQ:00000001 Processed script Request.Body["inexistentProperty"]?.ToString() == "anything"  with error
System.NullReferenceException: Object reference not set to an instance of an object.
   at Submission#0.<<Initialize>>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)
   at Mockaco.TemplateTransformer.Run(String code, IScriptContext scriptContext) in /src/Templating/TemplateTransformer.cs:line 102
[04:29:32 INF] 0HM4THLDIDBKQ:00000001 Request finished in 177.9192ms 200 application/json

Consider YAML as template format

Is your feature request related to a problem? Please describe.
To use the scripting engine on mock templates, most of times there is a need to write an invalid JSON structure, like this:

{
  "request": {
	"method": "PUT",
	"route": "customers/{id}"
  },
  "response": {
	"status": "OK",
	"body": {
	  "url": "<#= Request.Url?.ToString() #>",
	  "customerId": "<#= Request.Route["id"]?.ToString() #>",
	  "acceptHeader": "<#= Request.Header["Content-Type"]?.ToString() #>",
	  "queryString": "<#= Request.Query["dummy"]?.ToString() #>",
	  "requestBodyAttribute": "<#= Request.Body["address"]?[0]?.ToString() #>"
	},
        "indented": false
  }
}

Describe the solution you'd like
YAML seems to be suitable alternative to write templates with C# scripts, as it is more permissive on content, like the example bellow, which is a completely valid YAML:

---
request:
  method: PUT
  route: customers/{id}
  
response:
  status: OK
  body: |
    {
      "url": "<#= Request.Url?.ToString() #>",
      "customerId": "<#= Request.Route["id"]?.ToString() #>",
      "acceptHeader": "<#= Request.Header["Content-Type"]?.ToString() #>",
      "queryString": "<#= Request.Query["dummy"]?.ToString() #>",
      "requestBodyAttribute": "<#= Request.Body["address"]?[0]?.ToString() #>"
    }
  indented: false

There is a C# implementation: YamlDotNet

Describe alternatives you've considered
To use mustache or handlebars templating alternatives would require a DSL to be created. This alternative is not suitable for Mockaco as its proposal is to reduce the learning curve, keeping C# as the scripting language.

Additional context
There are some disadvantages using YAML:

  • It's not so easy to find a YAML formatter (this one is good)
  • You can't use tabs to indent the file (๐Ÿ˜”)
  • YAML syntax has more nuances than JSON
  • There is no C# project implementing YAML 1.2 spec

Improve logging

Include date/time, request id and other relevant information
Get rid of default logging infrastructure (Serilog?)

Include custom template directory setting

Is your feature request related to a problem? Please describe.
Currently, there is no way to setup a different directory, all mocks must be under "Mocks" directory. Sometimes it can be useful to have mocks in another folder.

Describe the solution you'd like
Include a setting to define mocks folder, otherwise use the default "Mocks" dir.

Publish as dotnet tool

Describe the solution you'd like
Dotnet has its own ecosystem for publishing its executable binary. Dotnet tool is suitable choice because we can install and update the binary easily.

Describe alternatives you've considered
The tool should be able to be installed as dotnet tool. Therefor, we don't care where the binary is located. When running the tool, we should be able to configure where required files/folder:

  • Mocks
  • Logs
  • appSettings.json

This flexibility will allows us to run the tool with different mock configuration

Improve startup performance

Is your feature request related to a problem? Please describe.
As the number of templates increase, Mockaco startup time considerably increases.

Describe the solution you'd like
The startup time could be reduced performing paralell warm up of templates.

Support stateful mock behavior

The current Mockaco implementation only allow static mocks, i.e. the same request will always return the content based on the same matching response template.

It would be nice to have a way to dinamically choose different response templates depending on previous calls, so one could setup mocks to support this scenario:

  1. Call GET /customers/foobar for the first time returns 404 Not Found
  2. Call POST /customers to add the foobar customer then returns 201 Created
  3. Another call to GET/customers/foobar returns 200 OK with the created customer

Routing constraints are not working

Is your feature request related to a problem? Please describe.
Earlier versions of Mockaco used to fully parse AspNet Core Routing constraints like {field:int} or package/{operation:regex(^track|create$)}/{id:int}.

In an attempt to simplify the routing decision process, the feature was lost, so it's not considering the routing constraints anymore, basically because TemplateMatcher class does not compute constraints.

The example route template
package/{operation:regex(^track|create$)}/{id:int} matches routes like package/foo/bar, ignoring the regex and int constraints:

Describe the solution you'd like
The best solution so far is to reimplement the first approach of using full asp net routing infrastructure instead of just using the TemplateMatcher.

Describe alternatives you've considered
Another approach is to find the proper classes to compute routing constraints, but it would end up bringing complexity to the code.

Log to file

Is your feature request related to a problem? Please describe.
When running directly from the command line, the log is not persisted. Running hosted on IIS, stdout can be configured to be written in a file via web.config

Describe the solution you'd like
Enable the possibility to log to file. The project uses Serilog, so it's a matter of adding the proper sink,

Resolve relative path

Describe the bug
The response.file configuration should be able to resolve relative path instead of absolute path to app root. It's useful when we try to restructure the mocks folder and move the mock files often.

To Reproduce
Create this mock under [app]/Mocks folder

{
  "request": {
    "method": "GET",
    "route": "signin"
  },
  "response": {
    "headers": {
      "Content-Type": "text/html; charset=UTF-8"
    },
    "file": "Mocks/signin.html"
  }
}

Assuming signin.html file requires many resource files (images, javascript, css, etc), I grab those from HAR file. Because this page requires many files, so let's structure the folder and create SignIn folder under Mocks folder and move this mock file along with other mocks. Updating from Mocks/signin.html to Mocks/SignIn/signin.html is easy. But updating the rest of the mocks takes time.

Expected behavior
Introduce relative path strategy, i.e. ./ or ../ let's assume it's relative to the mock (.json) file

Screenshots

[10:11:33 ERR] 0HM6407H0SUU4:00000011 Error generating mocked response
System.IO.FileNotFoundException: Could not find file 'C:\Application\Mockaco\signin-1.html'.
File name: 'C:\Application\Mockaco\signin.html'
   at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
   at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at System.IO.File.ReadAllBytesAsync(String path, CancellationToken cancellationToken)
   at Mockaco.BinaryResponseBodyStrategy.GetFileBytes(String path)
   at Mockaco.BinaryResponseBodyStrategy.GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate)
   at Mockaco.ResponseMockingMiddleware.PrepareResponse(HttpResponse httpResponse, Template transformedTemplate, IResponseBodyFactory responseBodyFactory, MockacoOptions options)
   at Mockaco.ResponseMockingMiddleware.Invoke(HttpContext httpContext, IMockacoContext mockacoContext, IScriptContext scriptContext, IResponseBodyFactory responseBodyFactory, IOptionsSnapshot`1 options)
   at Mockaco.RequestMatchingMiddleware.Invoke(HttpContext httpContext, IMockacoContext mockacoContext, IScriptContext scriptContext, IMockProvider mockProvider, ITemplateTransformer templateTransformer, IEnumerable`1 requestMatchers)
   at Mockaco.ResponseDelayMiddleware.Invoke(HttpContext httpContext, IMockacoContext mockacoContext, ILogger`1 logger)
   at Mockaco.ErrorHandlingMiddleware.Invoke(HttpContext httpContext, IMockacoContext mockacoContext, IOptionsSnapshot`1 statusCodeOptions, IMockProvider mockProvider, ILogger`1 logger)

Request template matching precedence engine

Some request template matching rules may be ambigous and the application should have a way to deal with them, by deciding which template overcomes the other in some kind of priority or precedence engine.

Another idea is to simply throw an exception in case of ambiguitty.

The current mechanism just evaluate template request starting from the biggest condition length to the the smaller and the first match wins.

Variables reutilization support

Some generated variables are useful to be repeatedly used inside the template body.

The feature could include "environment" or "global" variables, available to all templates and "scope" variables, available only to a given template.

Arrays not working in scripts

The example bellow does not work anymore after implementation of #3 :

{
 "brand": "${Faker.PickRandom(new[] {\"VISA\",\"MASTERCARD\",\"DINERS\",\"ELO\",\"HIPER\",\"AMEX\"}) }",
}
fail: Mockore.TemplateProcessor[0]
      Processed script Faker.PickRandom(new[] {"VISA","MASTERCARD","DINERS","ELO","HIPER","AMEX" with result Microsoft.CodeAnalysis.Scripting.CompilationErrorException: (1,74): error CS1513: } esperada
         at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.ThrowIfAnyCompilationErrors(DiagnosticBag diagnostics, DiagnosticFormatter formatter) in /_/src/Scripting/Core/ScriptBuilder.cs:line 104
         at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.CreateExecutor[T](ScriptCompiler compiler, Compilation compilation, Boolean emitDebugInformation, CancellationToken cancellationToken) in /_/src/Scripting/Core/ScriptBuilder.cs:line 82
         at Microsoft.CodeAnalysis.Scripting.Script`1.GetExecutor(CancellationToken cancellationToken) in /_/src/Scripting/Core/Script.cs:line 359
         at Microsoft.CodeAnalysis.Scripting.Script`1.CreateDelegate(CancellationToken cancellationToken)
         at Mockore.ScriptRunnerFactory.CreateRunner[TContext,TResult](String code, ScriptRunner`1& runner) in C:\Code\github\natenho\Mockaco\src\Mockaco\Processors\ScriptRunnerFactory.cs:line 66
         at Mockore.ScriptRunnerFactory.GetOrCreateRunner[TContext,TResult](String code) in C:\Code\github\natenho\Mockaco\src\Mockaco\Processors\ScriptRunnerFactory.cs:line 38
         at Mockore.ScriptRunnerFactory.Invoke[TContext,TResult](TContext context, String code) in C:\Code\github\natenho\Mockaco\src\Mockaco\Processors\ScriptRunnerFactory.cs:line 24
         at Mockore.TemplateProcessor.Run(String code, ScriptContext scriptContext) in C:\Code\github\natenho\Mockaco\src\Mockaco\Processors\TemplateProcessor.cs:line 154

Add support to http2/grpc templating.

Is your feature request related to a problem? Please describe.
Currently there's a mix in applications running soap/rest/grpc.
It would be good to support grpc when mocking requests and responses.

Describe the solution you'd like
It would be good to support grpc when mocking requests and responses by using proto files describing the request and responses.

Document request template matching strategy

Is your feature request related to a problem? Please describe.
The current strategy to prioritize multiple mocks matching the same request are not described in documentation.

Describe the solution you'd like
To add a topic to the documentation describing the actual behavior

Support for fake data file

Indeed to paste a JSON on the mock file, can have a folder with all the responses and on the mock definition select the file to send a response. And if you want to use the same endpoint with a little change in the response only have to change the selected file.

CORS support

Im using Mockaco to mock an angular app and Im issuing some problems with CORS. It could be useful to add some cors support, using appsettings to setup allowed origins (for ex).

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.