-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add advanced filtering: When running tests where multiple request types are used, it if quite difficult to set up proper filtering. To help this, made it possible to chain multiple filters and check URL and method. Furthermore the URL can now be modified. For future-proofing the Request and Response structs can now be extended with more stuff without breaking compatibility.
- Loading branch information
Showing
14 changed files
with
1,220 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"math/rand" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/seborama/govcr" | ||
) | ||
|
||
const example6CassetteName = "MyCassette6" | ||
|
||
// Example6 is an example use of govcr. | ||
// This will show how to do conditional rewrites. | ||
// For example, your request has a "/order/{random}" path | ||
// and we want to rewrite it to /order/1234 so we can match it later. | ||
// We change the response status code. | ||
// We add headers based on request method. | ||
func Example6() { | ||
cfg := govcr.VCRConfig{ | ||
Logging: true, | ||
} | ||
|
||
// The filter will neutralize a value in the URL. | ||
// In this case we rewrite /order/{random} to /order/1234 | ||
replacePath := govcr.RequestFilter(func(req govcr.Request) govcr.Request { | ||
// Replace path with a predictable one. | ||
req.URL.Path = "/order/1234" | ||
return req | ||
}) | ||
// Only execute when we match path. | ||
replacePath = replacePath.OnPath(`example\.com\/order\/`) | ||
|
||
// Add to request filters. | ||
cfg.RequestFilters.Add(replacePath) | ||
cfg.RequestFilters.Add(govcr.RequestDeleteHeaderKeys("X-Transaction-Id")) | ||
|
||
// Add filters | ||
cfg.ResponseFilters.Add( | ||
// Always transfer 'X-Transaction-Id' as in example 5. | ||
govcr.ResponseTransferHeaderKeys("X-Transaction-Id"), | ||
|
||
// Change status 404 to 202. | ||
func(resp govcr.Response) govcr.Response { | ||
if resp.StatusCode == http.StatusNotFound { | ||
resp.StatusCode = http.StatusAccepted | ||
} | ||
return resp | ||
}, | ||
|
||
// Add header if method was "GET" | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
resp.Header.Add("method-was-get", "true") | ||
return resp | ||
}).OnMethod(http.MethodGet), | ||
|
||
// Add header if method was "POST" | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
resp.Header.Add("method-was-post", "true") | ||
return resp | ||
}).OnMethod(http.MethodPost), | ||
|
||
// Add actual request URL to header. | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
url := resp.Request().URL | ||
resp.Header.Add("get-url", url.String()) | ||
return resp | ||
}).OnMethod(http.MethodGet), | ||
) | ||
|
||
orderID := fmt.Sprint(rand.Int63()) | ||
vcr := govcr.NewVCR(example6CassetteName, &cfg) | ||
|
||
// create a request with our custom header and a random url part. | ||
req, err := http.NewRequest("POST", "http://www.example.com/order/"+orderID, nil) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
runRequest(req, vcr) | ||
|
||
// create a request with our custom header and a random url part. | ||
req, err = http.NewRequest("GET", "http://www.example.com/order/"+orderID, nil) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
runRequest(req, vcr) | ||
|
||
} | ||
|
||
func runRequest(req *http.Request, vcr *govcr.VCRControlPanel) { | ||
req.Header.Add("X-Transaction-Id", time.Now().String()) | ||
// run the request | ||
resp, err := vcr.Client.Do(req) | ||
if err != nil { | ||
fmt.Println(err) | ||
return | ||
} | ||
// verify outcome | ||
if req.Header.Get("X-Transaction-Id") != resp.Header.Get("X-Transaction-Id") { | ||
fmt.Println("Header transaction Id verification failed - this would be the live request!") | ||
} else { | ||
fmt.Println("Header transaction Id verification passed - this would be the replayed track!") | ||
} | ||
|
||
// print outcome. | ||
fmt.Println("Status code:", resp.StatusCode, " (should be 404 on real and 202 on replay)") | ||
fmt.Println("method-was-get:", resp.Header.Get("method-was-get"), "(should never be true on GET)") | ||
fmt.Println("method-was-post:", resp.Header.Get("method-was-post"), "(should be true on replay on POST)") | ||
fmt.Println("get-url:", resp.Header.Get("get-url"), "(actual url of the request, not of the track)") | ||
fmt.Printf("%+v\n", vcr.Stats()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"math/rand" | ||
"net/http" | ||
"net/http/httptest" | ||
"regexp" | ||
|
||
"github.com/seborama/govcr" | ||
) | ||
|
||
const example7CassetteName = "MyCassette7" | ||
|
||
// Order is out example body we want to modify. | ||
type Order struct { | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
} | ||
|
||
// Example7 is an example use of govcr. | ||
// This will show how bodies can be rewritten. | ||
// We will take a varying ID from the request URL, neutralize it and also change the ID in the body of the response. | ||
func Example7() { | ||
cfg := govcr.VCRConfig{ | ||
Logging: true, | ||
} | ||
|
||
// Regex to extract the ID from the URL. | ||
reOrderID := regexp.MustCompile(`/order/([^/]+)`) | ||
|
||
// Create a local test server that serves out responses. | ||
handler := func(w http.ResponseWriter, r *http.Request) { | ||
id := reOrderID.FindStringSubmatch(r.URL.String()) | ||
if len(id) < 2 { | ||
w.WriteHeader(404) | ||
return | ||
} | ||
|
||
w.WriteHeader(200) | ||
b, err := json.Marshal(Order{ | ||
ID: id[1], | ||
Name: "Test Order", | ||
}) | ||
if err != nil { | ||
w.WriteHeader(500) | ||
return | ||
} | ||
w.Header().Add("Content-Type", "application/json") | ||
w.WriteHeader(200) | ||
w.Write(b) | ||
} | ||
server := httptest.NewServer(http.HandlerFunc(handler)) | ||
defer server.Close() | ||
|
||
// The filter will neutralize a value in the URL. | ||
// In this case we rewrite /order/{random} to /order/1234 | ||
// and replacing the host so it doesn't depend on the random port number. | ||
replacePath := govcr.RequestFilter(func(req govcr.Request) govcr.Request { | ||
req.URL.Path = "/order/1234" | ||
req.URL.Host = "127.0.0.1" | ||
return req | ||
}) | ||
|
||
// Only execute when we match path. | ||
cfg.RequestFilters.Add(replacePath.OnPath(`/order/`)) | ||
|
||
cfg.ResponseFilters.Add( | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
req := resp.Request() | ||
|
||
// Find the requested ID: | ||
orderID := reOrderID.FindStringSubmatch(req.URL.String()) | ||
|
||
// Unmarshal body. | ||
var o Order | ||
err := json.Unmarshal(resp.Body, &o) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Change the ID | ||
o.ID = orderID[1] | ||
|
||
// Replace the body. | ||
resp.Body, err = json.Marshal(o) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return resp | ||
}).OnStatus(200), | ||
) | ||
|
||
orderID := fmt.Sprint(rand.Int63()) | ||
vcr := govcr.NewVCR(example7CassetteName, &cfg) | ||
|
||
// create a request with our custom header and a random url part. | ||
req, err := http.NewRequest("GET", server.URL+"/order/"+orderID, nil) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
fmt.Println("GET", req.URL.String()) | ||
|
||
// run the request | ||
resp, err := vcr.Client.Do(req) | ||
if err != nil { | ||
fmt.Println("Error:", err) | ||
return | ||
} | ||
// print outcome. | ||
fmt.Println("Status code:", resp.StatusCode) | ||
body, _ := ioutil.ReadAll(resp.Body) | ||
fmt.Println("Returned Body:", string(body)) | ||
fmt.Printf("%+v\n", vcr.Stats()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.