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

Run Hoverfly in simulate mode as web server #202

Closed
mogronalol opened this issue Jun 1, 2016 · 4 comments
Closed

Run Hoverfly in simulate mode as web server #202

mogronalol opened this issue Jun 1, 2016 · 4 comments

Comments

@mogronalol
Copy link
Contributor

The proposition would be to configure Hoverfly as a web server as opposed to a proxy when using it in a development. The reason behind this is it's a property change for applications to point to a new web server, as opposed to proxy configuration. The applications are the left untouched and behave in the same way (ie, not talking via a proxy). My instincts tell me this would only make sense when simulating - during capture seems like it would be easier to remain as a proxy. I'd be interested to get some input.

@JohnFDavenport
Copy link
Contributor

I've been thinking about such a change. A developer is likely to use Hoverfly in capture mode on existing services for short periods (hours) but is likely to want to use Hoverfly in simulation mode in testing and development for much longer (days). Having to have proxy settings set to use Hoverfly permanently could be an imposition.

@nicholasjackson
Copy link

nicholasjackson commented Jun 5, 2016

For me there are two real use cases:

  1. To record traffic of an existing API
  2. To simulate the contract of an API which is yet to be written

When it comes to testing my preferred approach is to mock out any HTTP calls in my unit tests and only hit a real endpoint during integration tests. For integration testing I prefer to use cucumber so I would write a test something like this...

@dataapi
Feature: Data API
    In order to ensure my service integrates correctly
    As a developer
    I want to be able to test the service handles requests to the data api

Background:
    Given hoverfly is running and using the recording 'data_api.json'

Scenario: Requesting data fetches the data from the data API
    Given I make a request to '/data/34'
    Then the service should make an upstream request to the data api # validates call to hoverfly
    And the service should return the correct data # check response from my api

Scenario: When the upstream returns no data return not found
    Given I make a request to '/data/badrequest'
    Then the service should make an upstream request to the data api # validates call to hoverfly
    And the service should return status code 404 # check response from my api

This is obviously quite a simplified example but it allows me to spin up a stack including the system under test with docker and then execute an integration suite written BDD style.

I have been playing round this morning and wrote a little application which sits in front of hoverfly as a mock api which proxies all requests to hoverfly. This enables me to make requests to http://myserver/myurl without the requirement for setting an http_proxy.

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "os"
)

var (
    proxyURL    string
    simulateURL string
)

func main() {
    proxyURL = os.Args[1]
    simulateURL = os.Args[2]

    fmt.Println("running on port 9000")

    http.HandleFunc("/", rootHandler)

    fmt.Println("Listening for connections on port", 9000)
    http.ListenAndServe(fmt.Sprintf(":%v", 9000), nil)
}

func rootHandler(w http.ResponseWriter, req *http.Request) {

    proxyURL, _ := url.Parse(proxyURL)
    client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}}

    defer req.Body.Close()

    path := fmt.Sprintf("%v%v", simulateURL, req.URL.Path)
    fmt.Printf("Making request for: %v\n", path)

    request, err := http.NewRequest(req.Method, path, req.Body)
    for k, v := range req.Header {
        if k != "Content-Length" {
            request.Header.Set(k, v[0])
        }
    }

    if err != nil {
        http.Error(w, "Unable to create request", http.StatusInternalServerError)
    }

    resp, err := client.Do(request)
    if err != nil {
        http.Error(w, "Unable to execute request", http.StatusInternalServerError)
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        http.Error(w, "Unable to read body", http.StatusInternalServerError)
    }

    w.WriteHeader(resp.StatusCode)
    w.Write(body)
}

@nicholasjackson
Copy link

One other thing I would add is that given I have a request like this...

"request": {
                "path": "/events/v1/register",
                "method": "POST",
                "destination": "dev.acet.io",
                "scheme": "http",
                "query": "",
                "body": "{\"event_name\":\"test\", \"callback_url\":\"http://test\"}"
            }

it would be good to be able to specify regex in the request options such as...

```json
"request": {
                "path": "/events/v1/register",
                "method": "POST",
                "destination": "dev.acet.io",
                "scheme": "http",
                "query": "",
                "body": "{\"event_name\":\"regex(.*)\", \"callback_url\":\"http://regex(.*)\"}"
            }

@benjih
Copy link
Contributor

benjih commented Jul 12, 2016

As of v0.7.0 (9bf0b1f), Hoverfly can be ran as a webserver with support for simulate mode. The use case we imagine is that you use the proxy to capture simulation data and then would then deploy Hoverfly with the data as a webserver along side their application in a test environment.

@benjih benjih closed this as completed Jul 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants