rr_test.go
Overview
rr_test.go is a test source file dedicated to verifying the correctness, robustness, and error handling of the HTTP record and replay functionality implemented in the httprr package. This package facilitates recording HTTP client-server interactions to a file and replaying them later for testing or caching purposes. The test file exercises different scenarios including:
Recording and replaying HTTP requests and responses.
Scrubbing sensitive information from requests and responses.
Handling various HTTP methods and headers.
Testing error cases such as corrupt trace files, transport errors, and failures during request/response processing.
The file contains comprehensive test cases validating the integrity and security of the recorded data, and the behavior of the record/replay client under normal and exceptional conditions.
Key Functions and Methods
handler(w http.ResponseWriter, r *http.Request)
Purpose: A HTTP handler function used to simulate server behavior in tests.
Functionality:
Returns a 304 status with message
"redirect me!"if the request URL path ends with/redirect.For
GETrequests, checks for a"Secret"header with value"key". If missing or incorrect, responds with status code 666.For POST requests, reads the request body and verifies it contains the string
"my Secret". If missing, responds with status code 667.
Usage: Used as a test server handler to validate client requests and responses during record and replay.
always555(w http.ResponseWriter, r *http.Request)
Purpose: A HTTP handler that always responds with status code 555 and an error message.
Usage: Simulates a server that should not be contacted during replay, indicating unexpected HTTP requests.
Scrubbing Functions
These functions modify requests or responses to remove or alter sensitive data before recording or replaying.
dropPort(r *http.Request) error
Removes the port portion from the request URL host and theHostheader if any port is present.dropSecretHeader(r *http.Request) error
Deletes the"Secret"header from the request.hideSecretBody(r *http.Request) error
Replaces the request body content with the string "redacted" if the body is non-nil.doNothing(b *bytes.Buffer) error
No-op scrubbing function that returns immediately without modifying the response buffer.doRefresh(b *bytes.Buffer) error
Refreshes the response buffer by resetting and rewriting the same content, effectively a no-op with a buffer reset.
TestRecordReplay(t *testing.T)
Purpose: End-to-end test validating the record and replay lifecycle of HTTP interactions.
Test Workflow:
Creates a temporary directory and file for storing HTTP records.
Runs four test passes:
Create a new recording.
Open existing recording for replay.
Open recording with
"r+"mode allowing recording and replay.Open recording in default mode (replay).
For each pass:
Initializes the record/replay (
rr) client using eithercreateorOpenfunction.Sets up scrubbing functions to sanitize requests and responses.
Creates an HTTP test server using either
handleroralways555.Sends various HTTP requests (
GETand POST) with specific headers and bodies.Validates expected response status codes (200, 304, or error).
Ensures recorded data does not contain sensitive strings such as
"Secret".Closes the record/replay client.
Key Validations:
Ensures proper recording and replaying of requests.
Confirms scrubbing functions effectively remove sensitive data.
Validates error handling on unexpected requests in replay mode.
TestErrors(t *testing.T)
Purpose: Tests error handling paths and robustness of the record/replay mechanism.
Test Scenarios Covered:
Invalid
-httprecordflag values causing parse errors.Opening invalid or corrupt HTTP record files.
Creating record files with invalid filenames.
Reading non-existent files.
Handling read errors from request bodies.
Errors during request and response scrubbing operations.
Failures in writing request/response data to the record file.
Transport layer errors simulated via custom
errTransportandbadRespTransport.Failures in the RoundTrip method or during response body reading.
Closing the record/replay client after failures.
Usage: Ensures the package gracefully reports issues and does not silently fail.
Supporting Types and Transports
errTransport
Implements http.RoundTripper interface that always returns an error on RoundTrip.badRespTransport
Implements http.RoundTripper interface that returns a response whose body always errors on read, simulating transport failures.
Important Implementation Details
The tests simulate both server and client sides to verify integration.
The httptest.NewServer utility creates an ephemeral HTTP server using the defined handlers.
Scrubbing functions are chained to sanitize sensitive information from requests before recording and from responses before replaying.
The record/replay client (
rr) supports modes including creation of new recordings and replaying from existing traces.Error tests use temporary files in isolated directories to avoid side effects.
Multiple layers of error injection test robustness: corrupted files, transport errors, scrubbing errors, and closed file errors.
The test file verifies that sensitive information such as
"Secret"does not appear in stored record files.The file exercises the API methods
create,Open,ScrubReq,ScrubResp,Client(), andClose()which are part of the main httprr package (defined elsewhere).
Interaction with Other Parts of the System
Relies on the httprr package’s record and replay client API, specifically the functions
create,Open, and methods on the returnedrrobject such asScrubReq,ScrubResp,Client(), andClose().Uses the
net/httpstandard library for HTTP client and server simulation.Uses
httptestpackage to instantiate test HTTP servers.Interacts with the filesystem for temporary storage and reading/writing HTTP trace files.
Employs the testing package for test execution and assertions.
Utilizes
testing/iotestfor simulating I/O errors in request bodies and response bodies.The scrubbing functions demonstrate the package's extensibility for modifying requests and responses during record/replay phases.
Diagram: Function Interaction and Test Workflow
flowchart TD
subgraph Server Side
handler["handler()"]
always555["always555()"]
end
subgraph Scrubbing Functions
dropPort["dropPort()"]
dropSecretHeader["dropSecretHeader()"]
hideSecretBody["hideSecretBody()"]
doNothing["doNothing()"]
doRefresh["doRefresh()"]
end
subgraph Test Cases
TestRecordReplay["TestRecordReplay()"]
TestErrors["TestErrors()"]
end
subgraph Transports
errTransport["errTransport"]
badRespTransport["badRespTransport"]
end
TestRecordReplay --> |Uses| handler
TestRecordReplay --> |Uses| always555
TestRecordReplay --> |Applies| dropPort
TestRecordReplay --> |Applies| dropSecretHeader
TestRecordReplay --> |Applies| hideSecretBody
TestRecordReplay --> |Applies| doNothing
TestRecordReplay --> |Applies| doRefresh
TestErrors --> |Uses| errTransport
TestErrors --> |Uses| badRespTransport
TestErrors --> |Exercises Errors in| TestRecordReplay
Usage Examples Extracted from TestRecordReplay
Creating a new record/replay client (record mode):
rr, err := create(file, http.DefaultTransport)
if err != nil {
t.Fatal(err)
}
Opening an existing record file for replay:
rr, err := Open(file, http.DefaultTransport)
if err != nil {
t.Fatal(err)
}
Scrubbing sensitive request headers and body before recording:
rr.ScrubReq(dropPort, dropSecretHeader)
rr.ScrubReq(hideSecretBody)
Scrubbing response bodies before replay:
rr.ScrubResp(doNothing, doRefresh)
Making an HTTP request with the record/replay client:
req, err := http.NewRequest("GET", srv.URL+"/myrequest", nil)
req.Header.Set("Secret", "key")
resp, err := rr.Client().Do(req)
Closing the record/replay client to flush and release resources:
if err := rr.Close(); err != nil {
t.Fatal(err)
}
This file serves as a critical validation layer ensuring the HTTP record and replay mechanism works correctly, securely, and resiliently under a variety of normal and error conditions. It demonstrates practical usage patterns and validates the scrubbing capabilities to protect sensitive data during HTTP interaction recording.