Skip to content

Commit 0adb501

Browse files
authored
Initial commit (#1)
Initial commit
1 parent 9dda71a commit 0adb501

37 files changed

+7230
-1
lines changed

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request: ~
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
javaversion: ["8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"]
14+
steps:
15+
- uses: actions/checkout@v3
16+
- name: Set up Java ${{ matrix.javaversion }}
17+
uses: actions/setup-java@v3
18+
with:
19+
distribution: "zulu"
20+
java-version: ${{ matrix.javaversion }}
21+
- name: Build and test with Maven
22+
run: mvn --batch-mode install -Dgpg.skip=true -Dcheckstyle.skip=true
23+
lint:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v3
27+
- name: Run CheckStyle checks
28+
uses: nikitasavinov/[email protected]
29+
with:
30+
level: error
31+
fail_on_error: true
32+
checkstyle_config: easypost_java_style.xml
33+
tool_name: "style_enforcer"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121

2222
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
2323
hs_err_pid*
24+
/target/

README.md

Lines changed: 248 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,248 @@
1-
# easyvcr-java
1+
# EasyVCR
2+
3+
[![CI](https://github.com/EasyPost/easyvcr-java/workflows/CI/badge.svg)](https://github.com/EasyPost/easyvcr-java/actions?query=workflow%3ACI)
4+
5+
EasyVCR is a library for recording and replaying HTTP interactions in your test suite.
6+
7+
This can be useful for speeding up your test suite, or for running your tests on a CI server which doesn't have connectivity to the HTTP endpoints you need to interact with.
8+
9+
## Supported HTTP Clients
10+
11+
- Java 8's [HttpUrlConnection](https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html)
12+
13+
## How to use EasyVCR
14+
15+
#### Step 1.
16+
17+
Run your test suite locally against a real HTTP endpoint in recording mode
18+
19+
```java
20+
import com.easypost.easyvcr;
21+
import com.easypost.easyvcr.Cassette;
22+
import com.easypost.easyvcr.Mode;
23+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
24+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
25+
26+
public class Example {
27+
public static void main(String[] args) {
28+
29+
// Create a cassette to handle HTTP interactions
30+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
31+
32+
// create a RecordableURL using the cassette
33+
RecordableURL recordableURL = new RecordableURL("https://www.example.com", cassette, Mode.Record);
34+
35+
// open the connection to get a Http(s)URLConnection
36+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
37+
38+
// A RecordableHttp(s)URLConnection extends a normal Http(s)URLConnection, so you can use it as you would a normal Http(s)URLConnection
39+
connection.setConnectTimeout(1000);
40+
connection.connect();
41+
int responseCode = connection.getResponseCode();
42+
}
43+
}
44+
```
45+
46+
Real HTTP calls will be made and recorded to the cassette file.
47+
48+
#### Step 2.
49+
50+
Switch to replay mode:
51+
52+
```java
53+
import com.easypost.easyvcr;
54+
import com.easypost.easyvcr.Cassette;
55+
import com.easypost.easyvcr.Mode;
56+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
57+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
58+
59+
public class Example {
60+
public static void main(String[] args) {
61+
62+
// Create a cassette to handle HTTP interactions
63+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
64+
65+
// create a RecordableURL using the cassette
66+
RecordableURL recordableURL = new RecordableURL("https://www.example.com", cassette, Mode.Replay);
67+
68+
// open the connection to get a Http(s)URLConnection
69+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
70+
71+
// A RecordableHttp(s)URLConnection extends a normal Http(s)URLConnection, so you can use it as you would a normal Http(s)URLConnection
72+
int responseCode = connection.getResponseCode();
73+
}
74+
}
75+
```
76+
Now when tests are run, no real HTTP calls will be made. Instead, the HTTP responses will be replayed from the cassette file.
77+
78+
### Available modes
79+
80+
- `Mode.Auto`: Play back a request if it has been recorded before, or record a new one if not. (default mode for `VCR`)
81+
- `Mode.Record`: Record a request, including overwriting any existing matching recording.
82+
- `Mode.Replay`: Replay a request. Throws an exception if no matching recording is found.
83+
- `Mode.Bypass`: Do not record or replay any requests (client will behave like a normal HttpClient).
84+
85+
## Features
86+
87+
`EasyVCR` comes with a number of features, many of which can be customized via the `AdvancedOptions` class.
88+
89+
### Censoring
90+
91+
Censor sensitive data in the request and response bodies and headers, such as API keys and auth tokens.
92+
93+
**Default**: *Disabled*
94+
95+
```java
96+
import com.easypost.easyvcr;
97+
import com.easypost.easyvcr.AdvancedSettings;
98+
import com.easypost.easyvcr.Cassette;
99+
import com.easypost.easyvcr.Censors;
100+
import com.easypost.easyvcr.Mode;
101+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
102+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
103+
104+
public class Example {
105+
public static void main(String[] args) {
106+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
107+
108+
AdvancedSettings advancedSettings = new AdvancedSettings();
109+
advancedSettings.censors = new Censors().hideHeader("Authorization"); // Hide the Authorization header
110+
// or
111+
advancedSettings.censors = Censors.strict(); // use the built-in strict censoring mode (hides common sensitive data)
112+
113+
RecordableURL recordableURL =
114+
new RecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
115+
116+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
117+
}
118+
}
119+
```
120+
121+
### Delay
122+
123+
Simulate a delay when replaying a recorded request, either using a specified delay or the original request duration.
124+
125+
**Default**: *No delay*
126+
127+
```java
128+
import com.easypost.easyvcr;
129+
import com.easypost.easyvcr.AdvancedSettings;
130+
import com.easypost.easyvcr.Cassette;
131+
import com.easypost.easyvcr.Mode;
132+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
133+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
134+
135+
public class Example {
136+
public static void main(String[] args) {
137+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
138+
139+
AdvancedSettings advancedSettings = new AdvancedSettings();
140+
advancedSettings.manualDelay = 1000; // Simulate a delay of 1000 milliseconds when replaying
141+
advancedSettings.simulateDelay = true; // Simulate a delay of the original request duration when replaying (overrides manualDelay)
142+
143+
RecordableURL recordableURL = new RecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
144+
145+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
146+
}
147+
}
148+
```
149+
150+
### Matching
151+
152+
Customize how a recorded request is determined to be a match to the current request.
153+
154+
**Default**: *Method and full URL must match*
155+
156+
```java
157+
import com.easypost.easyvcr;
158+
import com.easypost.easyvcr.AdvancedSettings;
159+
import com.easypost.easyvcr.Cassette;
160+
import com.easypost.easyvcr.MatchRules;
161+
import com.easypost.easyvcr.Mode;
162+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
163+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
164+
165+
public class Example {
166+
public static void main(String[] args) {
167+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
168+
169+
AdvancedSettings advancedSettings = new AdvancedSettings();
170+
advancedSettings.matchRules = new MatchRules().byBody().byHeader("X-My-Header"); // Match recorded requests by request body (i.e. POST data) and a specific header
171+
// or
172+
advancedSettings.matchRules = MatchRules.strict(); // use the built-in strict matching mode (matches by method, full URL and request body; useful for POST/PATCH/PUT requests)
173+
174+
RecordableURL recordableURL =
175+
new RecordableURL("https://www.example.com", cassette, Mode.Replay, advancedSettings);
176+
177+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
178+
}
179+
}
180+
```
181+
182+
## VCR
183+
184+
In addition to individual recordable HttpClient instances, `EasyVCR` also offers a built-in VCR, which can be used to easily switch between multiple cassettes and/or modes. Any advanced settings applied to the VCR will be applied on every request made using the VCR's HTTP client.
185+
186+
```java
187+
import com.easypost.easyvcr;
188+
import com.easypost.easyvcr.AdvancedSettings;
189+
import com.easypost.easyvcr.Cassette;
190+
import com.easypost.easyvcr.Censors;
191+
import com.easypost.easyvcr.Mode;
192+
import com.easypost.easyvcr.VCR;
193+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableHttpsURLConnection;
194+
import com.easypost.easyvcr.clients.httpurlconnection.RecordableURL;
195+
196+
public class Example {
197+
public static void main(String[] args) {
198+
AdvancedSettings advancedSettings = new AdvancedSettings();
199+
advancedSettings.censors = new Censors().hideQueryParameter("api_key"); // hide the api_key query parameter
200+
201+
// Create a VCR with the advanced settings applied
202+
VCR vcr = new VCR(advancedSettings);
203+
204+
// Create a cassette and add it to the VCR
205+
Cassette cassette = new Cassette("path/to/cassettes", "my_cassette");
206+
vcr.insert(cassette);
207+
208+
// Set the VCR to record mode
209+
vcr.record();
210+
211+
// Get a RecordableURL instance from the VCR
212+
RecordableURL recordableURL = vcr.getHttpUrlConnection("https://www.example.com");
213+
214+
// Use the client as you would normally.
215+
RecordableHttpsURLConnection connection = recordableURL.openConnectionSecure();
216+
connection.connect();
217+
218+
// Remove the cassette from the VCR
219+
vcr.eject();
220+
}
221+
}
222+
```
223+
224+
## Development
225+
226+
### Tests
227+
228+
```bash
229+
# Build project
230+
mvn clean install -DskipTests -Dgpg.skip
231+
232+
# Run tests
233+
mvn clean test -B
234+
235+
# Run tests with coverage
236+
mvn clean test -B jacoco:report
237+
```
238+
239+
### Testing
240+
241+
The test suite in this project was specifically built to produce consistent results on every run, regardless of when they run or who is running them.
242+
243+
The cassettes used in the test suite are stored in a "cassettes" directory in the project root. Most of the cassettes produced by the test suite are erased and recreated on each run. Nevertheless, the test suite may complain if the cassettes are not present, so please do not delete them manually.
244+
245+
#### Credit
246+
247+
- [C# EasyVCR](https://github.com/EasyPost/easyvcr-csharp), upon which this library is based
248+
- [Scotch by Martin Leech](https://github.com/mleech/scotch), whose core functionality inspired the C# version of EasyVCR

0 commit comments

Comments
 (0)