Project

holoserve

0.0
No commit activity in last 3 years
No release in over 3 years
This tool can be used to fake webservice APIs for testing proposals.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
>= 0
>= 0
>= 0

Runtime

 Project Readme

Holoserve - Simple faking of HTTP APIs¶ ↑

This tool can be used to fake HTTP web APIs. It’s meant to be used in a testing environment, to make the test suite run faster and be independent from other API and network problems.

Concept¶ ↑

HoloServe runs a Goliath application server, that matches any incoming request to a list of request/response pairs. If a match is found, the corresponding response is returned. To do that the response is assembeled by a selection of responses. The selection is made by conditions on the current state. The name of the matched request/response pair is saved in a request history. If no match is found, a 404 is returned and the request data is stored in the bucket for unhandeled requests. These informations can be used to extend the server layout with missing request handlers.

To avoid too much duplication in the definition of the request/response-pairs, it is possible reference some fixture data that is shared between all pair definitions.

The pairs, state, history and bucket can be accessed via control routes, which are described below.

Installation¶ ↑

Assuming that ruby and gem are installed, simply type…

gem install holoserve

Run from the command line¶ ↑

To start up an empty Holoserve instance, type…

holoserve

To load the server with a couple of pairs, fixtures and define a state during start up, use these parameters.

holoserve -f 'path/to/fixtures/*.yaml' -p 'path/to/pairs/*.yaml' -s user_one=missing -s car_one=existing

Notice, that the files must have either the .yaml or the .json extension.

A full description of all options can be displayed with holoserve --help

-P, --port PORT                  The port holoserve should listen to.
-f, --fixture-files PATTERN      Load the specified fixture files on startup.
-p, --pair-files PATTERN         Load the specified pair files on startup.
-s, --state SETTING              Set a specific state. Use the pattern key=value. Can be applied multiple times.
-h, --help                       Shows the help message.

Control routes¶ ↑

If you’re using Ruby, you can control Holoserve via the Holoserve Connector gem.

GET /_control/pairs¶ ↑

Returns all pair definitions.

GET /_control/pairs/:id¶ ↑

Returns the specified pair definition.

PUT /_control/state¶ ↑

Sets the current state with the transmitted parameters.

GET /_control/state¶ ↑

Returns the current state.

Response example¶ ↑

{
  "user_one": "missing",
  "car_one": "existing"
}

GET /_control/bucket¶ ↑

Returns a list of all requests that has been received, but couldn’t be handled.

Response example¶ ↑

[
  {
    "method": "GET",
    "path": "/test",
    "headers": {
      "SERVER_SOFTWARE": "Goliath",
      "SERVER_NAME": "localhost",
      "SERVER_PORT": "4250",
      "REMOTE_ADDR": "127.0.0.1",
      "HTTP_ACCEPT": "*/*",
      "HTTP_USER_AGENT": "Ruby",
      "HTTP_HOST": "localhost:4250",
      "HTTP_VERSION": "1.1",
      "SCRIPT_NAME": "/test"
    }
  }
]

GET /_control/history¶ ↑

Returns a list of hashes, which include the names/id of pairs that has been triggered, with a request variant and a list of response variants.

Response example¶ ↑

[{"id":"test_request","request_variant":"default","response_variants":["default","alternative"]}]

DELETE /_control/history¶ ↑

Removes all entries from the history.

Pair file format¶ ↑

The request/response pair file should have the following format.

requests:
  default:
    imports:
      - path: "test_fixtures.users.0"
        as: "parameters"
        only: [ "username", "password" ]
    method: "POST"
    path: "/session"
    headers:
      HTTP_USER_AGENT: "Ruby"
    oauth:
      oauth_token: "12345"
responses:
  default:
    status: 200
  found:
    condition: "username == :existing"
    imports:
      - path: "test_fixtures.users.0"
        as: "json.user"
    transitions:
      session_one: "existing"
  not_found:
    condition: "username == :missing"
    json:
      message: "user not found"

The fixture data where this example pair definition relies on, could look like the following.

users:
  - email: "one@test.com"
    username: "one"
    password: "valid"

This example defines a request/response pair situation. It uses username=one and password=valid as parameters.

If the state includes condition: "user_one == :existing", the response would return the complete user object encoded as json. If the state includes user_one == :missing, the request would be replied with the message “user not found”.

The transitions part of the response allows you set the successor state. If a response is selected, the corresponding transitions will be evaluated.

requests:
  default:
    imports:
      - path: "test_fixtures.users.0.email"
        as: "parameters"
    method: "POST"
    path: "/valid_email"
responses:
  default:
    status: 200
  found:
    condition: "email == :existing"
    imports:
      - path: "test_fixtures.users.0.username"
        as: "json.user.username"
    transitions:
      session_one: "existing"
  not_found:
    condition: "email == :missing"
    json:
      message: "email address not found"

This example relies on the same fixture file used above.

This time it uses email=one@test.com as a parameter. If the state includes condition: "email == :existing", the response would return a username of the email address owner as json.

If the state includes email == :missing, the response would be a message “email address not found” in json.