{"id":13601415,"url":"https://github.com/nicholasjackson/fake-service","last_synced_at":"2025-04-04T08:06:58.154Z","repository":{"id":38855134,"uuid":"198195566","full_name":"nicholasjackson/fake-service","owner":"nicholasjackson","description":"Simple service for testing upstream service communications","archived":false,"fork":false,"pushed_at":"2024-03-13T04:25:15.000Z","size":3807,"stargazers_count":400,"open_issues_count":8,"forks_count":77,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-28T07:05:21.687Z","etag":null,"topics":["golang","microservices","testing-tool"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicholasjackson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-07-22T09:54:48.000Z","updated_at":"2025-03-28T00:53:40.000Z","dependencies_parsed_at":"2024-01-04T14:29:41.257Z","dependency_job_id":"d31499b9-11e8-4972-8b4d-2cd3e879282f","html_url":"https://github.com/nicholasjackson/fake-service","commit_stats":null,"previous_names":["nicholasjackson/upstream-echo"],"tags_count":100,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholasjackson%2Ffake-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholasjackson%2Ffake-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholasjackson%2Ffake-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholasjackson%2Ffake-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicholasjackson","download_url":"https://codeload.github.com/nicholasjackson/fake-service/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142041,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","microservices","testing-tool"],"created_at":"2024-08-01T18:01:02.441Z","updated_at":"2025-04-04T08:06:58.125Z","avatar_url":"https://github.com/nicholasjackson.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Fake Service\nFake service that can handle both HTTP and gRPC traffic, for testing upstream service communications and testing service mesh and other scenarios.\n\nBinaries: [https://github.com/nicholasjackson/fake-service/releases/](https://github.com/nicholasjackson/fake-service/releases/)  \nDocker Images: [https://hub.docker.com/r/nicholasjackson/fake-service](https://hub.docker.com/r/nicholasjackson/fake-service)  \n\n## Basic usage\nTo run fake service, first download the correct version for your platform from the releases page. Then run the following command to start the service and bind it to \nall ip addresses on port 19090:\n\n```shell\nLISTEN_ADDR=0.0.0.0:19090 fake-service\n```\n\nYou will see the following output:\n\n```\n2021-12-26T14:57:19.222Z [INFO]  Using seed: seed=1640530639\n2021-12-26T14:57:19.222Z [INFO]  Adding handler for UI static files\n2021-12-26T14:57:19.223Z [INFO]  Settings CORS options: allow_creds=false allow_headers=Accept,Accept-Language,Content-Language,Origin,Content-Type allow_origins=*\n2021-12-26T14:57:19.223Z [INFO]  Started service: name=Code upstreamURIs= upstreamWorkers=1 listenAddress=0.0.0.0:19090\n```\n\nNext let's try to connect to the service using the curl:\n\n```shell\ncurl localhost:19090\n```\n\nFake service will respond with a json payload similar to the following:\n\n```shell\n{\n  \"name\": \"Code\",\n  \"uri\": \"/\",\n  \"type\": \"HTTP\",\n  \"ip_addresses\": [\n    \"172.21.166.161\"\n  ],\n  \"start_time\": \"2021-12-26T14:58:47.248837\",\n  \"end_time\": \"2021-12-26T14:58:47.249039\",\n  \"duration\": \"202.008µs\",\n  \"body\": \"Hello World\",\n  \"code\": 200\n}\n```\n\nYou could have also made this request using the browser based ui that is available at the following url: http://localhost:19090/ui\n\nLet's now see how you can make a gRPC request to fake service using [gRPCurl](https://github.com/fullstorydev/grpcurl)\n\n```shell\n grpcurl -plaintext localhost:19090 FakeService.Handle\n{\n  \"Message\": \"{\\n  \\\"name\\\": \\\"Code\\\",\\n  \\\"type\\\": \\\"gRPC\\\",\\n  \\\"ip_addresses\\\": [\\n    \\\"172.21.166.161\\\"\\n  ],\\n  \\\"start_time\\\": \\\"2021-12-26T15:03:27.384751\\\",\\n  \\\"end_time\\\": \\\"2021-12-26T15:03:27.384805\\\",\\n  \\\"duration\\\": \\\"53.961µs\\\",\\n  \\\"body\\\": \\\"Hello World\\\",\\n  \\\"code\\\": 0\\n}\\n\"\n}\n```\n\nThe gRPC endpoint returns a message with a single parameter that contains the same json payload that was returned by the HTTP endpoint. You can use `jq` to extract this message using the folowing command:\n\n```shell\n➜ grpcurl -plaintext localhost:19090 FakeService.Handle | jq -r .Message\n{\n  \"name\": \"Code\",\n  \"type\": \"gRPC\",\n  \"ip_addresses\": [\n    \"172.21.166.161\"\n  ],\n  \"start_time\": \"2021-12-26T15:05:30.281199\",\n  \"end_time\": \"2021-12-26T15:05:30.281257\",\n  \"duration\": \"57.889µs\",\n  \"body\": \"Hello World\",\n  \"code\": 0\n}\n```\n\nThere are a many more advance use cases from linking multiple services together or controlling the response duration or error threshold. These options \ncan be set using environment variables. \n\n## Configuration\nConfiguration values for fake service are set using environment variables, the following is a full list of permissable options:\n\n```\nConfiguration values are set using environment variables, for info please see the following list:\n\nEnvironment variables:\n  UPSTREAM_URIS  default: no default\n       Comma separated URIs of the upstream services to call\n  UPSTREAM_WORKERS  default: '1'\n       Number of parallel workers for calling upstream services, default is 1 which is sequential operation\n  UPSTREAM_REQUEST_BODY  default: no default\n       Request body to send to send with upstream requests, NOTE: UPSTREAM_REQUEST_SIZE and UPSTREAM_REQUEST_VARIANCE are ignored if this is set\n  UPSTREAM_REQUEST_SIZE  default: '0'\n       Size of the randomly generated request body to send with upstream requests\n  UPSTREAM_REQUEST_VARIANCE  default: '0'\n       Percentage variance of the randomly generated request body\n  MESSAGE  default: 'Hello World'\n       Message to be returned from service, can either be a string or valid JSON. To display content in the UI, valid HTML can be included in this variable.\n  NAME  default: 'Service'\n       Name of the service\n  LISTEN_ADDR  default: '0.0.0.0:9090'\n       IP address and port to bind service to\n  ALLOWED_ORIGINS  default: '*'\n       Comma separated list of allowed origins for CORS requests\n  ALLOWED_HEADERS  default: 'Accept,Accept-Language,Content-Language,Origin,Content-Type'\n       Comma separated list of allowed headers for CORS requests\n  ALLOW_CREDENTIALS  default: 'false'\n       Are credentials allowed for CORS requests\n  HTTP_SERVER_KEEP_ALIVES  default: 'false'\n       Enables the HTTP servers handling of keep alives.\n  HTTP_SERVER_READ_TIMEOUT  default: '5s'\n       Maximum duration for reading an entire HTTP request, if zero no read timeout is used.\n  HTTP_SERVER_READHEADER_TIMEOUT  default: '0s'\n       Maximum duration for reading the HTTP headers, if zero read timeout is used.\n  HTTP_SERVER_WRITE_TIMEOUT  default: '10s'\n       Maximum duration for writing HTTP body, if zero no write timeout is used.\n  HTTP_SERVER_IDLE_TIMEOUT  default: '30s'\n       Maximum duration to wait for next request when HTTP Keep alives are used.\n  HTTP_CLIENT_KEEP_ALIVES  default: 'false'\n       Enable HTTP connection keep alives for upstream calls\n  HTTP_CLIENT_REQUEST_TIMEOUT  default: '30s'\n       Maximum duration for upstream service requests\n  HTTP_CLIENT_APPEND_REQUEST  default: 'true'\n       When true the path, querystring, and any headers sent to the service will be appended to any upstream calls\n  TIMING_50_PERCENTILE  default: '0s'\n       Median duration for a request\n  TIMING_90_PERCENTILE  default: '0s'\n       90 percentile duration for a request, if no value is set, will use value from TIMING_50_PERCENTILE\n  TIMING_99_PERCENTILE  default: '0s'\n       99 percentile duration for a request, if no value is set, will use value from TIMING_90_PERCENTILE\n  TIMING_VARIANCE  default: '0'\n       Percentage variance for each request, every request will vary by a random amount to a maximum of a percentage of the total request time\n  ERROR_RATE  default: '0'\n       Decimal percentage of request where handler will report an error. e.g. 0.1 = 10% of all requests will result in an error\n  ERROR_TYPE  default: 'http_error'\n       Type of error [http_error, delay]\n  ERROR_CODE  default: '500'\n       Error code to return on error\n  ERROR_DELAY  default: '0s'\n       Error delay [1s,100ms]\n  RATE_LIMIT  default: '0'\n       Rate in req/second after which service will return an error code\n  RATE_LIMIT_CODE  default: '503'\n       Code to return when service call is rate limited\n  LOAD_CPU_CLOCK_SPEED  default: '1000'\n       MHz of a single logical core, default 1000Mhz\n  LOAD_CPU_CORES  default: '-1'\n       Number of logical cores to generate fake CPU load over, by default fake-service will use all cores\n  LOAD_CPU_PERCENTAGE  default: '0'\n       Percentage of CPU cores to consume as a percentage. I.e: 50, 50% load for LOAD_CPU_CORES. If LOAD_CPU_ALLOCATED \n       is not specified CPU percentage is based on the Total CPU available\n  LOAD_MEMORY_PER_REQUEST  default: '0'\n       Memory in bytes consumed per request\n  LOAD_MEMORY_VARIANCE  default: '0'\n       Percentage variance of the memory consumed per request, i.e with a value of 50 = 50%, and given a LOAD_MEMORY_PER_REQUEST of 1024 bytes, actual consumption per request would be in the range 516 - 1540 bytes\n  TRACING_ZIPKIN  default: no default\n       Location of Zipkin tracing collector\n  TRACING_DATADOG_HOST  default: no default\n       Hostname or IP for Datadog tracing collector\n  TRACING_DATADOG_PORT  default: '8126'\n       Port for Datadog tracing collector\n  METRICS_DATADOG_HOST  default: no default\n       Hostname or IP for Datadog metrics collector\n  METRICS_DATADOG_PORT  default: '8125'\n       Port for Datadog metrics collector\n  LOG_FORMAT  default: 'text'\n       Log file format. [text|json]\n  LOG_LEVEL  default: 'info'\n       Log level for output. [info|debug|trace|warn|error]\n  LOG_OUTPUT  default: 'stdout'\n       Location to write log output, default is stdout, e.g. /var/log/web.log\n  TLS_CERT_LOCATION  default: no default\n       Location of PEM encoded x.509 certificate for securing server\n  TLS_KEY_LOCATION  default: no default\n       Location of PEM encoded private key for securing server\n  HEALTH_CHECK_RESPONSE_CODE  default: '200'\n       Response code returned from the HTTP health check at /health\n  READY_CHECK_RESPONSE_SUCCESS_CODE  default: '200'\n       Response code returned from the HTTP readiness handler `/ready` after the response delay has elapsed\n  READY_CHECK_RESPONSE_FAILURE_CODE  default: '503'\n       Response code returned from the HTTP readiness handler `/ready` before the response delay has elapsed, this simulates the response code a service would return while starting\n  READY_CHECK_ROOT_PATH_WAIT_TILL_READY  default: 'false'\n       Should the main handler at path `/` or the gRPC method `FakeService` wait for the readiness check to pass before returning a response?\n  READY_CHECK_RESPONSE_DELAY  default: '0s'\n       Delay before the readyness check returns the READY_CHECK_RESPONSE_CODE\n  RAND_SEED  default: '1637512822'\n       A seed to initialize the random number generators\n  UI_PATH default: '/ui/'\n      The HTTP patht the UI is served from, must contain a trailing '/'\n```\n\n## Tracing\nWhen the `TRACING_ZIPKIN` environment variable is configured to point to a Zipkin compatible collector, Fake Service, will output\ntraces using the OpenTracing library. These can be viewed Jaeger Tracing or other tools which support OpenTracing.\n\n![](images/jaeger_tracing.png)\n\n## Examples\n\n### Docker Compose - examples/docker-compose\nThis example shows a multi-tier system running in docker compose consisting of 4 services which emit tracing data to Jaeger Tracing.\n\n```\nweb - type HTTP\n  |-- api (upstream calls to payments and cache in parallel) - type gRPC\n      |-- payments - type HTTP\n      |   |-- currency - type HTTP\n      |-- cache - type HTTP\n```\n\nTo run the example:\n```\n$ cd examples/docker-compose\n$ docker-compose up\nStarting docker-compose_currency_1 ... done\nStarting docker-compose_cache_1    ... done\nStarting docker-compose_api_1      ... done\nStarting docker-compose_payments_1 ... done\nStarting docker-compose_jaeger_1   ... done\nStarting docker-compose_web_1      ... done\nAttaching to docker-compose_payments_1, docker-compose_api_1, docker-compose_cache_1, docker-compose_web_1, docker-compose_currency_1, docker-compose_jaeger_1\npayments_1  | 2019-08-16T12:15:01.362Z [INFO]  Starting service: name=payments message=\"Payments response\" upstreamURIs=http://currency:9090 upstreamWorkers=1 listenAddress=0.0.0.0:9090 http_client_keep_alives=false zipkin_endpoint=http://jaeger:9411\ncache_1     | 2019-08-16T12:15:01.439Z [INFO]  Starting service: name=cache message=\"Cache response\" upstreamURIs= upstreamWorkers=1 listenAddress=0.0.0.0:9090 http_client_keep_alives=false zipkin_endpoint=http://jaeger:9411\n```\n\nThen curl the HTTP endpoint:\n```\n➜ curl -s localhost:9090 | jq\n{\n  \"name\": \"web\",\n  \"type\": \"HTTP\",\n  \"duration\": \"25.4975ms\",\n  \"body\": \"Hello World\",\n  \"upstream_calls\": [\n    {\n      \"name\": \"api\",\n      \"uri\": \"grpc://api:9090\",\n      \"type\": \"gRPC\",\n      \"duration\": \"20.8857ms\",\n      \"body\": \"API response\",\n      \"upstream_calls\": [\n        {\n          \"name\": \"payments\",\n          \"uri\": \"http://payments:9090\",\n          \"type\": \"HTTP\",\n          \"duration\": \"8.462ms\",\n          \"body\": \"Payments response\",\n          \"upstream_calls\": [\n            {\n              \"name\": \"currency\",\n              \"uri\": \"http://currency:9090/12434/jackson?auth=true\",\n              \"type\": \"HTTP\",\n              \"duration\": \"224.9µs\",\n              \"body\": \"Currency response\"\n            }\n          ]\n        },\n        {\n          \"name\": \"cache\",\n          \"uri\": \"http://cache:9090\",\n          \"type\": \"HTTP\",\n          \"duration\": \"500.5µs\",\n          \"body\": \"Cache response\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n\nTracing data can be seen using Jaeger which is running at `http://localhost:16686`.\n\n## Error Injection\nFake Service has the capability to simulate service errors, this feature can be used to test reliability patterns, particularly those which are externailized in a service mesh. The errors which Fake Service can simulate are:\n\n* Service Errors - gRPC and HTTP responses\n* Service Delays - Simulate sporadic delays to service execution\n* Rate Limiting - Simulate rate limiting of a service\n\nError Injection can be configured using the following environment variables:\n\n```\n  ERROR_RATE  default: '0'\n       Decimal percentage of request where handler will report an error. e.g. 0.1 = 10% of all requests will result in an error\n  ERROR_TYPE  default: 'http_error'\n       Type of error [http_error, delay]\n  ERROR_CODE  default: '500'\n       Error code to return on error\n  ERROR_DELAY  default: '0s'\n       Error delay [1s,100ms]\n  RATE_LIMIT  default: '0'\n       Rate in req/second after which service will return an error code\n  RATE_LIMIT_CODE  default: '503'\n       Code to return when service call is rate limited\n```\n\nAll features for Error Injection are available for HTTP and gRPC services.\n\n**NOTE:** gRPC calls do not return a message when an error is returned\n\n### Service Errors\nTo simulate a HTTP service which returns an Internal Server Error (Status Code 500) error 20% of the time, the following command can be used:\n\n```\n$ ERROR_RATE=0.2 ERROR_TYPE=http_error ERROR_CODE=500 fake-service\n```\n\nWhen called Fake Service will return an error 500 for every 2/10 requests:\n\n```\n➜ curl -i localhost:9090\nHTTP/1.1 500 Internal Server Error\nDate: Wed, 25 Sep 2019 09:36:45 GMT\nContent-Length: 129\nContent-Type: text/plain; charset=utf-8\n\n{\n  \"name\": \"web\",\n  \"type\": \"HTTP\",\n  \"body\": \"Hello World\",\n  \"code\": 500,\n  \"error\": \"Service error automatically injected\"\n}\n```\n\nTo simulate a gRPC service with the same error response, the following example can be used:\n\n```\n$ ERROR_RATE=0.2 ERROR_TYPE=http_error ERROR_CODE=13 SERVER_TYPE=grpc fake-service\n```\n\n### Service Delays\nService Delays give more granular control over the time take for a service to respond and can be used in combination with Service Timing. To simulate a execution delay which would result in a client timeout 20% of the time, the following command can be used:\n\n```\n$ ERROR_RATE=0.2 ERROR_TYPE=delay ERROR_DELAY=2m  fake-service\n\n➜ curl -i --max-time 0.5 localhost:9090\ncurl: (28) Operation timed out after 505 milliseconds with 0 bytes received\n```\n\n### Rate Limiting\nIt is possible to configure Fake Service to rate limit calls, rate limiting is applied before Service Errors or Service Delays and can be used in combination with these features. To simulate a service which only allows a rate of 1 request per second, the following example can be used:\n\n```\n$ RATE_LIMIT=1 RATE_LIMIT_CODE=429 fake-service\n```\n\nWhen the service is called quickly in succession the second calls with a rate limit error message:\n\n```\n➜ curl -i --max-time 0.5 localhost:9090\nHTTP/1.1 200 OK\nDate: Wed, 25 Sep 2019 09:59:01 GMT\nContent-Length: 109\nContent-Type: text/plain; charset=utf-8\n\n{\n  \"name\": \"Service\",\n  \"type\": \"HTTP\",\n  \"duration\": \"21.512µs\",\n  \"body\": \"Hello World\",\n  \"code\": 200\n}\n\n➜ curl -i --max-time 0.5 localhost:9090\nHTTP/1.1 429 Too Many Requests\nDate: Wed, 25 Sep 2019 09:59:02 GMT\nContent-Length: 124\nContent-Type: text/plain; charset=utf-8\n\n{\n  \"name\": \"Service\",\n  \"type\": \"HTTP\",\n  \"body\": \"Hello World\",\n  \"code\": 429,\n  \"error\": \"Service exceeded rate limit\"\n}\n```\n\n### Service Load\nFake Service can simulate load carried out during a service call by configuring the following variables.\n```\n  LOAD_CPU_CORES  default: '0'\n       Number of cores to generate fake CPU load over\n  LOAD_CPU_PERCENTAGE  default: '0'\n       Percentage of CPU cores to consume as a percentage. I.e: 50, 50% load for LOAD_CPU_CORES\n  LOAD_MEMORY_PER_REQUEST  default: '0'\n       Memory in bytes consumed per request\n  LOAD_MEMORY_VARIANCE  default: '0'\n       Percentage variance of the memory consumed per request, i.e with a value of 50 = 50%, and given a LOAD_MEMORY_PER_REQUEST of 1024 bytes, actual consumption per request would be in the range 516 - 1540 bytes\n```\n\nFor example to simulate a service call consuming 100% of 8 Cores you can run fake service with the following command:\n\n```\nLOAD_CPU_CORES=8 LOAD_CPU_PERCENTAGE=100 fake-service\n```\n\nTo simulate each service call consuming between 50MB and 150MB of memory\n\n```\nLOAD_MEMORY_PER_REQUEST=104857600 LOAD_MEMORY_VARIANCE=50 fake-service\n```\n\n### Health checks\n\nFake service implements both health checks and readyness checks. By default these are both configured to return a status 200 when called.\n\n* Readyness check path: \"/ready\"\n* Health check path: \"/health\"\n\nTo override the behaviour of the health check or the readyness checks the following environment varaibles can be set.\n\n```\n  HEALTH_CHECK_RESPONSE_CODE  default: '200'\n       Response code returned from the HTTP health check at /health\n  READY_CHECK_RESPONSE_SUCCESS_CODE  default: '200'\n       Response code returned from the HTTP readiness handler `/ready` after the response delay has elapsed\n  READY_CHECK_RESPONSE_FAILURE_CODE  default: '503'\n       Response code returned from the HTTP readiness handler `/ready` before the response delay has elapsed, this simulates the response code a service would return while starting\n  READY_CHECK_RESPONSE_DELAY  default: '0s'\n       Delay before the readyness check returns the READY_CHECK_RESPONSE_CODE\n```\n\n## UI\nFake Service also has a handy dandy UI which can be used to graphically represent the data which is returned as JSON when curling.\n\nThe API is accessible at the path `/ui` and under the covers just calls the main API endpoint.\n\n**NOTE:** The UI is only available when a service is configured as `HTTP`.\n\n### Example UI\n![](images/ui.png)\n\n### Example UI with errors\n![](images/ui-error.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicholasjackson%2Ffake-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicholasjackson%2Ffake-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicholasjackson%2Ffake-service/lists"}