http_decoy 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/CHANGELOG.md +11 -11
- data/CONTRIBUTING.md +6 -6
- data/README.md +25 -25
- data/lib/{httpfake → http_decoy}/configuration.rb +1 -1
- data/lib/{httpfake → http_decoy}/handler_context.rb +4 -4
- data/lib/{httpfake → http_decoy}/request_log.rb +1 -1
- data/lib/{httpfake → http_decoy}/route.rb +1 -1
- data/lib/{httpfake → http_decoy}/route_map.rb +1 -1
- data/lib/{httpfake → http_decoy}/router.rb +1 -1
- data/lib/{httpfake → http_decoy}/rspec.rb +18 -18
- data/lib/{httpfake → http_decoy}/server.rb +2 -2
- data/lib/http_decoy/version.rb +5 -0
- data/lib/{httpfake → http_decoy}/webmock_integration.rb +4 -4
- data/lib/{httpfake.rb → http_decoy.rb} +13 -13
- metadata +20 -20
- data/lib/httpfake/version.rb +0 -5
- /data/sig/{httpfake.rbs → http_decoy.rbs} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 975527fe6fe58ce43dc77b5a0889d359d3cc55c120e04b5f93de51783e12d71d
|
|
4
|
+
data.tar.gz: 5d2bd7cc5c51adb9a65f3af5768c892b410b4973b9498d6b378f2efd261cd4f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f12507d96e3dc4d2a2d54a2067cc06c7da17a20d1d2460dd89738d2d166efb8f470399d51a56c7980f154589aee9304f528b27e1d65331686cc44e79446032d
|
|
7
|
+
data.tar.gz: 613d2362f5fdaa48632fb90dafe49ed81172df3cb62d0f53b7fd8bc93dda10835fc08bba1c23d5ac2246ffb573606b352df292c695a988c3b98ec5069299c8bf
|
data/.rubocop.yml
CHANGED
|
@@ -53,7 +53,7 @@ Metrics/BlockLength:
|
|
|
53
53
|
Max: 60
|
|
54
54
|
Exclude:
|
|
55
55
|
- "spec/**/*"
|
|
56
|
-
- "
|
|
56
|
+
- "http_decoy.gemspec"
|
|
57
57
|
|
|
58
58
|
Metrics/AbcSize:
|
|
59
59
|
Max: 40
|
|
@@ -68,7 +68,7 @@ Metrics/PerceivedComplexity:
|
|
|
68
68
|
Max: 12
|
|
69
69
|
|
|
70
70
|
# ── RuboCop-RSpec path convention ──────────────────────────────────────────
|
|
71
|
-
# Our module is
|
|
71
|
+
# Our module is HttpDecoy but the gem/dir is http_decoy (no underscore).
|
|
72
72
|
# RSpec/SpecFilePathFormat expects http_fake/ — disable it.
|
|
73
73
|
RSpec/SpecFilePathFormat:
|
|
74
74
|
Enabled: false
|
|
@@ -78,7 +78,7 @@ RSpec/SpecFilePathFormat:
|
|
|
78
78
|
# matcher (e.g. RSpec matchers, Ranges, Regexps all respond to ===).
|
|
79
79
|
Style/CaseEquality:
|
|
80
80
|
Exclude:
|
|
81
|
-
- "lib/
|
|
81
|
+
- "lib/http_decoy/rspec.rb"
|
|
82
82
|
|
|
83
83
|
# Entry uses :http_method not :method, so this is moot — kept for awareness.
|
|
84
84
|
Lint/StructNewOverride:
|
data/CHANGELOG.md
CHANGED
|
@@ -11,12 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
### Added
|
|
13
13
|
|
|
14
|
-
- `
|
|
15
|
-
- `
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
14
|
+
- `HttpDecoy.define` — declare a named fake service with a DSL block
|
|
15
|
+
- `HttpDecoy::RouteMap` — route definition DSL (`get`, `post`, `put`, `patch`, `delete`)
|
|
16
|
+
- `HttpDecoy::Router` — path matching with `:param` template segments
|
|
17
|
+
- `HttpDecoy::Server` — real WEBrick HTTP server on OS-assigned port (port 0); starts in a background thread, stops cleanly
|
|
18
|
+
- `HttpDecoy::RequestLog` — thread-safe store of every received request; powers assertion helpers
|
|
19
|
+
- `HttpDecoy::HandlerContext` — `instance_eval` DSL surface inside handler blocks:
|
|
20
20
|
- `respond(status, json:, text:, headers:)` — build a response
|
|
21
21
|
- `respond_sequence(*entries)` — return different responses on successive calls
|
|
22
22
|
- `requires_body(*keys)` — assert required fields are present; raises `ContractError` with descriptive message if not
|
|
@@ -25,15 +25,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
25
25
|
- `body`, `path_params`, `query_params` — request data accessors
|
|
26
26
|
- Lambdas in JSON response values are resolved at request time (`-> { body[:amount] }`)
|
|
27
27
|
- `fake_server(name) { ... }` — class-level RSpec macro; starts a fresh server per example, tears it down after
|
|
28
|
-
- `
|
|
28
|
+
- `HttpDecoy.define(:name) { ... }.rspec_helpers` — suite-wide helper module pattern
|
|
29
29
|
- `with_scenario(:name) { ... }` — activate a named failure/alternate scenario in a test block
|
|
30
30
|
- `have_received_request(method, path)` — RSpec matcher with `.once`, `.twice`, `.times(n)`, `.with(body:)` chains
|
|
31
|
-
- WebMock auto-detection: if WebMock is loaded and `base_url` is declared, requests are intercepted automatically; teardown removes only
|
|
32
|
-
- `
|
|
31
|
+
- WebMock auto-detection: if WebMock is loaded and `base_url` is declared, requests are intercepted automatically; teardown removes only http_decoy's stub
|
|
32
|
+
- `HttpDecoy.configure { |c| c.auto_intercept = false }` — opt out of automatic WebMock interception
|
|
33
33
|
- Supports `application/json`, `application/x-www-form-urlencoded`, and raw bodies
|
|
34
34
|
- Compatible with Rack 2.x and Rack 3.x
|
|
35
35
|
- Ruby 3.1+ support
|
|
36
36
|
- 92% test coverage (SimpleCov), 66 examples
|
|
37
37
|
|
|
38
|
-
[Unreleased]: https://github.com/jibranusman/
|
|
39
|
-
[0.1.0]: https://github.com/jibranusman/
|
|
38
|
+
[Unreleased]: https://github.com/jibranusman/http_decoy/compare/v0.1.0...HEAD
|
|
39
|
+
[0.1.0]: https://github.com/jibranusman/http_decoy/releases/tag/v0.1.0
|
data/CONTRIBUTING.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# Contributing to
|
|
1
|
+
# Contributing to http_decoy
|
|
2
2
|
|
|
3
3
|
Thanks for taking the time. Bug reports, documentation improvements, and feature proposals are all welcome.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
git clone https://github.com/jibranusman/
|
|
9
|
-
cd
|
|
8
|
+
git clone https://github.com/jibranusman/http_decoy
|
|
9
|
+
cd http_decoy
|
|
10
10
|
bundle install
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ bundle install
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
bundle exec rspec # full suite
|
|
17
|
-
bundle exec rspec spec/
|
|
17
|
+
bundle exec rspec spec/http_decoy/server_spec.rb # single file
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Linting
|
|
@@ -45,7 +45,7 @@ Both must be green before a PR can be merged. CI enforces this on every push.
|
|
|
45
45
|
|
|
46
46
|
## Good first issues
|
|
47
47
|
|
|
48
|
-
Check the [`good first issue`](https://github.com/jibranusman/
|
|
48
|
+
Check the [`good first issue`](https://github.com/jibranusman/http_decoy/issues?q=label%3A%22good+first+issue%22) label for beginner-friendly tasks.
|
|
49
49
|
|
|
50
50
|
## Code style
|
|
51
51
|
|
|
@@ -58,7 +58,7 @@ Check the [`good first issue`](https://github.com/jibranusman/httpfake/issues?q=
|
|
|
58
58
|
|
|
59
59
|
Open a GitHub issue with:
|
|
60
60
|
- Ruby version (`ruby --version`)
|
|
61
|
-
-
|
|
61
|
+
- http_decoy version
|
|
62
62
|
- Minimal reproduction case (ideally a failing RSpec example)
|
|
63
63
|
- What you expected vs what happened
|
|
64
64
|
|
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# http_decoy
|
|
2
2
|
|
|
3
3
|
**A real fake HTTP server. For real tests.**
|
|
4
4
|
|
|
5
|
-
[](https://github.com/jibranusman/http_decoy/actions)
|
|
6
|
+
[](https://badge.fury.io/rb/http_decoy)
|
|
7
|
+
[](https://rubygems.org/gems/http_decoy)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
|
|
10
10
|
---
|
|
@@ -13,7 +13,7 @@ Your WebMock stubs are lying to you.
|
|
|
13
13
|
|
|
14
14
|
They test that your code constructs the right HTTP call. Not that the API would accept it. Not that the response shape matches what your code expects. Not that you haven't been sending a stale request format for six months while production quietly breaks.
|
|
15
15
|
|
|
16
|
-
**
|
|
16
|
+
**http_decoy spins up a real Rack server inside your tests** — one that validates incoming request contracts, computes dynamic responses from real inputs, and fails loudly the moment your code sends something wrong.
|
|
17
17
|
|
|
18
18
|
No cassettes. No scattered stubs. No surprises on deploy day.
|
|
19
19
|
|
|
@@ -56,10 +56,10 @@ This test passes even if:
|
|
|
56
56
|
|
|
57
57
|
You end up with 50 YAML files nobody touches, all slowly diverging from reality.
|
|
58
58
|
|
|
59
|
-
### Test 3 —
|
|
59
|
+
### Test 3 — http_decoy (what tests should look like)
|
|
60
60
|
|
|
61
61
|
```ruby
|
|
62
|
-
FakeStripe =
|
|
62
|
+
FakeStripe = HttpDecoy.define(:stripe) do
|
|
63
63
|
base_url "https://api.stripe.com"
|
|
64
64
|
|
|
65
65
|
post "/v1/charges" do
|
|
@@ -95,7 +95,7 @@ Now your tests:
|
|
|
95
95
|
```ruby
|
|
96
96
|
# Gemfile
|
|
97
97
|
group :test do
|
|
98
|
-
gem "
|
|
98
|
+
gem "http_decoy"
|
|
99
99
|
end
|
|
100
100
|
```
|
|
101
101
|
|
|
@@ -111,7 +111,7 @@ bundle install
|
|
|
111
111
|
|
|
112
112
|
```ruby
|
|
113
113
|
# spec/support/fakes/fake_stripe.rb
|
|
114
|
-
FakeStripe =
|
|
114
|
+
FakeStripe = HttpDecoy.define(:stripe) do
|
|
115
115
|
base_url "https://api.stripe.com"
|
|
116
116
|
|
|
117
117
|
post "/v1/charges" do
|
|
@@ -148,7 +148,7 @@ end
|
|
|
148
148
|
|
|
149
149
|
```ruby
|
|
150
150
|
# spec/spec_helper.rb
|
|
151
|
-
require "
|
|
151
|
+
require "http_decoy"
|
|
152
152
|
require "support/fakes/fake_stripe"
|
|
153
153
|
|
|
154
154
|
RSpec.configure do |config|
|
|
@@ -182,9 +182,9 @@ RSpec.describe StripeService do
|
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
it "catches bad requests before they reach prod" do
|
|
185
|
-
# Missing payment_method —
|
|
185
|
+
# Missing payment_method — http_decoy raises immediately with a descriptive error
|
|
186
186
|
expect { StripeService.charge(amount: 2000, currency: "usd") }
|
|
187
|
-
.to raise_error(
|
|
187
|
+
.to raise_error(HttpDecoy::HandlerContext::ContractError, /payment_method is required/)
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
end
|
|
@@ -199,7 +199,7 @@ No setup per test. No per-test `stub_request`. No cassette files.
|
|
|
199
199
|
### Defining a server
|
|
200
200
|
|
|
201
201
|
```ruby
|
|
202
|
-
MyFakeService =
|
|
202
|
+
MyFakeService = HttpDecoy.define(:my_service) do
|
|
203
203
|
base_url "https://api.example.com" # intercepted via WebMock automatically
|
|
204
204
|
# ...routes
|
|
205
205
|
end
|
|
@@ -243,7 +243,7 @@ post "/orders" do
|
|
|
243
243
|
end
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
-
When validation fails,
|
|
246
|
+
When validation fails, http_decoy raises `HttpDecoy::HandlerContext::ContractError` with a message naming the exact field and rule. Your test fails at the right place, with the right message.
|
|
247
247
|
|
|
248
248
|
### Dynamic responses
|
|
249
249
|
|
|
@@ -324,7 +324,7 @@ Inline per describe block:
|
|
|
324
324
|
|
|
325
325
|
```ruby
|
|
326
326
|
RSpec.describe "degraded upstream" do
|
|
327
|
-
include
|
|
327
|
+
include HttpDecoy::RSpec
|
|
328
328
|
|
|
329
329
|
fake_server(:api) do
|
|
330
330
|
get "/status" do
|
|
@@ -344,7 +344,7 @@ end
|
|
|
344
344
|
|
|
345
345
|
```ruby
|
|
346
346
|
# Opt out of WebMock auto-interception (e.g. if you manage stubs manually)
|
|
347
|
-
|
|
347
|
+
HttpDecoy.configure do |config|
|
|
348
348
|
config.auto_intercept = false
|
|
349
349
|
end
|
|
350
350
|
```
|
|
@@ -353,7 +353,7 @@ end
|
|
|
353
353
|
|
|
354
354
|
## Why not WebMock / VCR? (honest comparison)
|
|
355
355
|
|
|
356
|
-
| | WebMock | VCR | **
|
|
356
|
+
| | WebMock | VCR | **http_decoy** |
|
|
357
357
|
|---|---|---|---|
|
|
358
358
|
| Real server | No | No | **Yes** |
|
|
359
359
|
| Request contract validation | No | No | **Yes** |
|
|
@@ -365,7 +365,7 @@ end
|
|
|
365
365
|
| Define once, use everywhere | Requires setup | Yes | **Yes** |
|
|
366
366
|
| Catches API drift | No | No | **Yes** |
|
|
367
367
|
|
|
368
|
-
|
|
368
|
+
http_decoy uses WebMock internally to intercept requests — complementary, not a replacement.
|
|
369
369
|
|
|
370
370
|
---
|
|
371
371
|
|
|
@@ -375,7 +375,7 @@ httpfake uses WebMock internally to intercept requests — complementary, not a
|
|
|
375
375
|
<summary>Stripe (payments)</summary>
|
|
376
376
|
|
|
377
377
|
```ruby
|
|
378
|
-
FakeStripe =
|
|
378
|
+
FakeStripe = HttpDecoy.define(:stripe) do
|
|
379
379
|
base_url "https://api.stripe.com"
|
|
380
380
|
|
|
381
381
|
post "/v1/payment_intents" do
|
|
@@ -404,7 +404,7 @@ end
|
|
|
404
404
|
<summary>SendGrid (email)</summary>
|
|
405
405
|
|
|
406
406
|
```ruby
|
|
407
|
-
FakeSendGrid =
|
|
407
|
+
FakeSendGrid = HttpDecoy.define(:sendgrid) do
|
|
408
408
|
base_url "https://api.sendgrid.com"
|
|
409
409
|
|
|
410
410
|
post "/v3/mail/send" do
|
|
@@ -423,7 +423,7 @@ end
|
|
|
423
423
|
<summary>Internal microservice</summary>
|
|
424
424
|
|
|
425
425
|
```ruby
|
|
426
|
-
FakeInventory =
|
|
426
|
+
FakeInventory = HttpDecoy.define(:inventory) do
|
|
427
427
|
base_url "https://inventory.internal"
|
|
428
428
|
|
|
429
429
|
get "/products/:sku/stock" do
|
|
@@ -458,14 +458,14 @@ end
|
|
|
458
458
|
## Contributing
|
|
459
459
|
|
|
460
460
|
```bash
|
|
461
|
-
git clone https://github.com/jibranusman/
|
|
462
|
-
cd
|
|
461
|
+
git clone https://github.com/jibranusman/http_decoy
|
|
462
|
+
cd http_decoy
|
|
463
463
|
bundle install
|
|
464
464
|
bundle exec rspec # run all tests
|
|
465
465
|
bundle exec rubocop # lint
|
|
466
466
|
```
|
|
467
467
|
|
|
468
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines. Good first issues are labeled [`good first issue`](https://github.com/jibranusman/
|
|
468
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines. Good first issues are labeled [`good first issue`](https://github.com/jibranusman/http_decoy/issues?q=label%3A%22good+first+issue%22).
|
|
469
469
|
|
|
470
470
|
---
|
|
471
471
|
|
|
@@ -475,4 +475,4 @@ MIT. See [LICENSE](LICENSE).
|
|
|
475
475
|
|
|
476
476
|
---
|
|
477
477
|
|
|
478
|
-
*
|
|
478
|
+
*http_decoy — stop testing your assumptions, start testing your contracts.*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module HttpDecoy
|
|
6
6
|
# The `self` inside every route handler block.
|
|
7
7
|
# Provides the full DSL surface: respond, requires_body, validates,
|
|
8
8
|
# body, path_params, query_params, respond_sequence, raise_error.
|
|
@@ -81,9 +81,9 @@ module HttpFake
|
|
|
81
81
|
# Simulate transport-level failures.
|
|
82
82
|
def raise_error(type)
|
|
83
83
|
case type
|
|
84
|
-
when :timeout then raise Timeout::Error, "
|
|
85
|
-
when :reset then raise Errno::ECONNRESET, "
|
|
86
|
-
when :refused then raise Errno::ECONNREFUSED, "
|
|
84
|
+
when :timeout then raise Timeout::Error, "http_decoy simulated timeout"
|
|
85
|
+
when :reset then raise Errno::ECONNRESET, "http_decoy simulated connection reset"
|
|
86
|
+
when :refused then raise Errno::ECONNREFUSED, "http_decoy simulated connection refused"
|
|
87
87
|
else raise type.is_a?(Class) ? type : RuntimeError, type.to_s
|
|
88
88
|
end
|
|
89
89
|
end
|
|
@@ -5,7 +5,7 @@ require_relative "route_map"
|
|
|
5
5
|
require_relative "server"
|
|
6
6
|
require_relative "webmock_integration"
|
|
7
7
|
|
|
8
|
-
module
|
|
8
|
+
module HttpDecoy
|
|
9
9
|
# RSpec integration.
|
|
10
10
|
#
|
|
11
11
|
# Two equivalent usage patterns:
|
|
@@ -13,7 +13,7 @@ module HttpFake
|
|
|
13
13
|
# Pattern A — inline (per describe block):
|
|
14
14
|
#
|
|
15
15
|
# RSpec.describe MyService do
|
|
16
|
-
# include
|
|
16
|
+
# include HttpDecoy::RSpec
|
|
17
17
|
#
|
|
18
18
|
# fake_server(:payments) do
|
|
19
19
|
# post "/charges" do
|
|
@@ -29,7 +29,7 @@ module HttpFake
|
|
|
29
29
|
#
|
|
30
30
|
# Pattern B — suite-wide definition (most common):
|
|
31
31
|
#
|
|
32
|
-
# FakeStripe =
|
|
32
|
+
# FakeStripe = HttpDecoy.define(:stripe) do
|
|
33
33
|
# base_url "https://api.stripe.com"
|
|
34
34
|
# post "/v1/charges" do
|
|
35
35
|
# respond 200, json: { id: "ch_123" }
|
|
@@ -54,26 +54,26 @@ module HttpFake
|
|
|
54
54
|
def fake_server(name, &)
|
|
55
55
|
route_map = RouteMap.new
|
|
56
56
|
route_map.instance_eval(&)
|
|
57
|
-
|
|
57
|
+
_http_decoy_register(name, route_map)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
# Internal: register before/after hooks for a pre-built RouteMap.
|
|
61
61
|
# Called by both the inline macro and Definition#rspec_helpers.
|
|
62
|
-
def
|
|
62
|
+
def _http_decoy_register(name, route_map)
|
|
63
63
|
before(:each) do
|
|
64
64
|
server = Server.new(route_map)
|
|
65
65
|
server.start
|
|
66
66
|
stub = WebMockIntegration.setup(server)
|
|
67
67
|
|
|
68
|
-
@
|
|
69
|
-
@
|
|
70
|
-
@
|
|
71
|
-
@
|
|
68
|
+
@_http_decoy_servers ||= {}
|
|
69
|
+
@_http_decoy_webmock_stubs ||= {}
|
|
70
|
+
@_http_decoy_servers[name] = server
|
|
71
|
+
@_http_decoy_webmock_stubs[name] = stub
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
after(:each) do
|
|
75
|
-
server = @
|
|
76
|
-
stub = @
|
|
75
|
+
server = @_http_decoy_servers&.[](name)
|
|
76
|
+
stub = @_http_decoy_webmock_stubs&.[](name)
|
|
77
77
|
WebMockIntegration.teardown(stub)
|
|
78
78
|
server&.stop
|
|
79
79
|
end
|
|
@@ -82,21 +82,21 @@ module HttpFake
|
|
|
82
82
|
|
|
83
83
|
# Instance-level accessor — returns the live Server for this example.
|
|
84
84
|
def fake_server(name)
|
|
85
|
-
@
|
|
85
|
+
@_http_decoy_servers[name]
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Run a block with a named scenario active.
|
|
89
89
|
# server_name defaults to the only server if exactly one is registered.
|
|
90
90
|
def with_scenario(scenario_name, server_name = nil, &)
|
|
91
91
|
name = server_name || begin
|
|
92
|
-
servers = @
|
|
92
|
+
servers = @_http_decoy_servers || {}
|
|
93
93
|
raise ArgumentError, "server_name required when multiple fake servers are active" if servers.size > 1
|
|
94
94
|
raise ArgumentError, "No fake servers are active" if servers.empty?
|
|
95
95
|
|
|
96
96
|
servers.keys.first
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
server = @
|
|
99
|
+
server = @_http_decoy_servers[name]
|
|
100
100
|
raise ArgumentError, "No fake server named #{name.inspect}" unless server
|
|
101
101
|
|
|
102
102
|
server.with_scenario(scenario_name, &)
|
|
@@ -169,7 +169,7 @@ module HttpFake
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
# ---------------------------------------------------------------------------
|
|
172
|
-
# Definition — returned by
|
|
172
|
+
# Definition — returned by HttpDecoy.define
|
|
173
173
|
# ---------------------------------------------------------------------------
|
|
174
174
|
|
|
175
175
|
# Wraps a named RouteMap and generates an anonymous RSpec helper module.
|
|
@@ -190,16 +190,16 @@ module HttpFake
|
|
|
190
190
|
definition = self
|
|
191
191
|
|
|
192
192
|
Module.new do
|
|
193
|
-
include
|
|
193
|
+
include HttpDecoy::RSpec
|
|
194
194
|
|
|
195
195
|
# define_singleton_method closes over `definition` from the outer scope.
|
|
196
196
|
# `def self.included` would NOT — def never captures outer locals.
|
|
197
197
|
define_singleton_method(:included) do |base|
|
|
198
198
|
super(base)
|
|
199
|
-
base.
|
|
199
|
+
base._http_decoy_register(definition.name, definition.route_map)
|
|
200
200
|
end
|
|
201
201
|
|
|
202
|
-
define_method(:
|
|
202
|
+
define_method(:_http_decoy_definition) { definition }
|
|
203
203
|
end
|
|
204
204
|
end
|
|
205
205
|
end
|
|
@@ -7,7 +7,7 @@ require "json"
|
|
|
7
7
|
require_relative "request_log"
|
|
8
8
|
require_relative "handler_context"
|
|
9
9
|
|
|
10
|
-
module
|
|
10
|
+
module HttpDecoy
|
|
11
11
|
# A real WEBrick HTTP server that runs in a background thread.
|
|
12
12
|
#
|
|
13
13
|
# Uses WEBrick directly (no Rack::Handler) so it works with both
|
|
@@ -56,7 +56,7 @@ module HttpFake
|
|
|
56
56
|
# Poll until WEBrick enters its accept loop.
|
|
57
57
|
deadline = Time.now + 5
|
|
58
58
|
sleep(0.005) until @webrick.status == :Running || Time.now > deadline
|
|
59
|
-
raise "
|
|
59
|
+
raise "http_decoy: server failed to start within 5 seconds" unless @webrick.status == :Running
|
|
60
60
|
|
|
61
61
|
self
|
|
62
62
|
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module HttpDecoy
|
|
4
4
|
# Manages the WebMock stub that routes a declared base_url to the server's Rack app.
|
|
5
5
|
#
|
|
6
|
-
# Auto-detect: if WebMock is loaded and
|
|
6
|
+
# Auto-detect: if WebMock is loaded and HttpDecoy.configuration.auto_intercept is true,
|
|
7
7
|
# requests to the declared base_url are intercepted transparently.
|
|
8
8
|
#
|
|
9
|
-
# Teardown removes only the stub
|
|
9
|
+
# Teardown removes only the stub http_decoy created — never calls WebMock.reset!.
|
|
10
10
|
# If WebMock/RSpec has already cleared the registry (its own after(:each) hook),
|
|
11
11
|
# we rescue silently rather than crashing.
|
|
12
12
|
module WebMockIntegration
|
|
@@ -18,7 +18,7 @@ module HttpFake
|
|
|
18
18
|
# Install an interception stub for the given server.
|
|
19
19
|
# Returns the stub object so it can be removed precisely during teardown.
|
|
20
20
|
def setup(server)
|
|
21
|
-
return nil unless available? &&
|
|
21
|
+
return nil unless available? && HttpDecoy.configuration.auto_intercept
|
|
22
22
|
return nil unless server.route_map.declared_base_url
|
|
23
23
|
|
|
24
24
|
# Match the full base URL (scheme + host) so the regex anchors correctly.
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
4
|
-
require_relative "
|
|
5
|
-
require_relative "
|
|
6
|
-
require_relative "
|
|
7
|
-
require_relative "
|
|
8
|
-
require_relative "
|
|
9
|
-
require_relative "
|
|
10
|
-
require_relative "
|
|
11
|
-
require_relative "
|
|
3
|
+
require_relative "http_decoy/version"
|
|
4
|
+
require_relative "http_decoy/configuration"
|
|
5
|
+
require_relative "http_decoy/route"
|
|
6
|
+
require_relative "http_decoy/route_map"
|
|
7
|
+
require_relative "http_decoy/router"
|
|
8
|
+
require_relative "http_decoy/request_log"
|
|
9
|
+
require_relative "http_decoy/handler_context"
|
|
10
|
+
require_relative "http_decoy/server"
|
|
11
|
+
require_relative "http_decoy/webmock_integration"
|
|
12
12
|
|
|
13
|
-
module
|
|
13
|
+
module HttpDecoy
|
|
14
14
|
class << self
|
|
15
15
|
# Global configuration.
|
|
16
16
|
#
|
|
17
|
-
#
|
|
17
|
+
# HttpDecoy.configure do |c|
|
|
18
18
|
# c.auto_intercept = false # opt out of WebMock auto-interception
|
|
19
19
|
# end
|
|
20
20
|
def configure
|
|
@@ -27,7 +27,7 @@ module HttpFake
|
|
|
27
27
|
|
|
28
28
|
# Define a named fake service.
|
|
29
29
|
#
|
|
30
|
-
# FakeStripe =
|
|
30
|
+
# FakeStripe = HttpDecoy.define(:stripe) do
|
|
31
31
|
# base_url "https://api.stripe.com"
|
|
32
32
|
#
|
|
33
33
|
# post "/v1/charges" do
|
|
@@ -39,7 +39,7 @@ module HttpFake
|
|
|
39
39
|
# RSpec.configure { |c| c.include FakeStripe.rspec_helpers }
|
|
40
40
|
#
|
|
41
41
|
def define(name = :default, &)
|
|
42
|
-
require_relative "
|
|
42
|
+
require_relative "http_decoy/rspec"
|
|
43
43
|
route_map = RouteMap.new
|
|
44
44
|
route_map.instance_eval(&)
|
|
45
45
|
Definition.new(name, route_map)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: http_decoy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jibran Usman
|
|
@@ -38,9 +38,9 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '1.8'
|
|
41
|
-
description:
|
|
42
|
-
Define routes, validate request contracts, return dynamic fixtures, and tear
|
|
43
|
-
automatically. No VCR cassettes. No scattered WebMock stubs.
|
|
41
|
+
description: http_decoy spins up a real Rack server inside your tests with a clean
|
|
42
|
+
DSL. Define routes, validate request contracts, return dynamic fixtures, and tear
|
|
43
|
+
down automatically. No VCR cassettes. No scattered WebMock stubs.
|
|
44
44
|
email:
|
|
45
45
|
- jibran.usman@hotmail.com
|
|
46
46
|
executables: []
|
|
@@ -53,25 +53,25 @@ files:
|
|
|
53
53
|
- LICENSE
|
|
54
54
|
- README.md
|
|
55
55
|
- Rakefile
|
|
56
|
-
- lib/
|
|
57
|
-
- lib/
|
|
58
|
-
- lib/
|
|
59
|
-
- lib/
|
|
60
|
-
- lib/
|
|
61
|
-
- lib/
|
|
62
|
-
- lib/
|
|
63
|
-
- lib/
|
|
64
|
-
- lib/
|
|
65
|
-
- lib/
|
|
66
|
-
- lib/
|
|
67
|
-
- sig/
|
|
68
|
-
homepage: https://github.com/jibranusman95/
|
|
56
|
+
- lib/http_decoy.rb
|
|
57
|
+
- lib/http_decoy/configuration.rb
|
|
58
|
+
- lib/http_decoy/handler_context.rb
|
|
59
|
+
- lib/http_decoy/request_log.rb
|
|
60
|
+
- lib/http_decoy/route.rb
|
|
61
|
+
- lib/http_decoy/route_map.rb
|
|
62
|
+
- lib/http_decoy/router.rb
|
|
63
|
+
- lib/http_decoy/rspec.rb
|
|
64
|
+
- lib/http_decoy/server.rb
|
|
65
|
+
- lib/http_decoy/version.rb
|
|
66
|
+
- lib/http_decoy/webmock_integration.rb
|
|
67
|
+
- sig/http_decoy.rbs
|
|
68
|
+
homepage: https://github.com/jibranusman95/http_decoy
|
|
69
69
|
licenses:
|
|
70
70
|
- MIT
|
|
71
71
|
metadata:
|
|
72
|
-
homepage_uri: https://github.com/jibranusman95/
|
|
73
|
-
source_code_uri: https://github.com/jibranusman95/
|
|
74
|
-
changelog_uri: https://github.com/jibranusman95/
|
|
72
|
+
homepage_uri: https://github.com/jibranusman95/http_decoy
|
|
73
|
+
source_code_uri: https://github.com/jibranusman95/http_decoy
|
|
74
|
+
changelog_uri: https://github.com/jibranusman95/http_decoy/blob/main/CHANGELOG.md
|
|
75
75
|
rubygems_mfa_required: 'true'
|
|
76
76
|
post_install_message:
|
|
77
77
|
rdoc_options: []
|
data/lib/httpfake/version.rb
DELETED
|
File without changes
|