Skip to content

Commit a686f1b

Browse files
authored
Merge pull request #375 from ahx/test-ignore-unknown-routes
2.9.0: OpenapiFirst::Test raises error for unknown requests
2 parents 65c86cc + 13165cc commit a686f1b

10 files changed

Lines changed: 82 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
## Unreleased
44

5+
## 2.9.0
6+
7+
- OpenapiFirst::Test now raises an error for unknown requests. You can deactivate with:
8+
9+
```ruby
10+
OpenapiFirst::Test.setup do |test|
11+
# ...
12+
test.ignore_unknown_request = true
13+
end
14+
```
15+
16+
- NotFoundError#message now includes the requested path
17+
518
## 2.8.0
619

720
### OpenapiFirst::Test is now stricter and more configurable

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
openapi_first (2.8.0)
4+
openapi_first (2.9.0)
55
hana (~> 1.3)
66
json_schemer (>= 2.1, < 3.0)
77
openapi_parameters (>= 0.5.1, < 2.0)

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ Here is how to set it up:
7777

7878
(✷1): It does not matter what method of openapi_first you use to validate requests/responses. Instead of using `OpenapiFirstTest.app` to wrap your application, you could also use the [middlewares](#rack-middlewares) or [test assertion method](#test-assertions), but you would have to do that for all requests/responses defined in your API description to make coverage work.
7979

80+
OpenapiFirst' request validation raises an error when a request is not defined. You can deactivate this during testing:
81+
82+
```ruby
83+
OpenapiFirst::Test.setup do |test|
84+
test.ignore_unknown_requests = true
85+
end
86+
```
87+
8088
## Rack Middlewares
8189
8290
### Request validation

benchmarks/Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: ..
33
specs:
4-
openapi_first (2.8.0)
4+
openapi_first (2.9.0)
55
hana (~> 1.3)
66
json_schemer (>= 2.1, < 3.0)
77
openapi_parameters (>= 0.5.1, < 2.0)

lib/openapi_first/failure.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module OpenapiFirst
55
# This returned in ValidatedRequest#error and ValidatedResponse#error.
66
class Failure
77
TYPES = {
8-
not_found: [NotFoundError, 'Request path is not defined.'],
8+
not_found: [NotFoundError, 'Not found.'],
99
method_not_allowed: [RequestInvalidError, 'Request method is not defined.'],
1010
unsupported_media_type: [RequestInvalidError, 'Request content type is not defined.'],
1111
invalid_body: [RequestInvalidError, 'Request body invalid:'],

lib/openapi_first/router.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ def add_response(response, request_method:, path:, status:, response_content_typ
5454
# Return all request objects that match the given path and request method
5555
def match(request_method, path, content_type: nil)
5656
path_item, params = find_path_item(path)
57-
return NOT_FOUND unless path_item
57+
unless path_item
58+
message = "Request path #{path} is not defined in API description."
59+
return NOT_FOUND.with(error: Failure.new(:not_found, message:))
60+
end
5861

5962
contents = path_item.dig(request_method, :requests)
6063
return NOT_FOUND.with(error: Failure.new(:method_not_allowed)) unless contents

lib/openapi_first/test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def self.install
100100

101101
OpenapiFirst.configure do |config|
102102
@after_request_validation = config.after_request_validation do |validated_request, oad|
103+
raise validated_request.error.exception if raise_request_error?(validated_request)
104+
105+
configuration.ignore_unknown_requests && validated_request.known?
106+
103107
Coverage.track_request(validated_request, oad)
104108
end
105109

@@ -114,6 +118,13 @@ def self.install
114118
@installed = true
115119
end
116120

121+
def self.raise_request_error?(validated_request)
122+
return false if validated_request.valid?
123+
return true if validated_request.known?
124+
125+
!configuration.ignore_unknown_requests
126+
end
127+
117128
def self.raise_response_error?(validated_response)
118129
configuration.response_raise_error && !configuration.ignored_unknown_status.include?(validated_response.status)
119130
end

lib/openapi_first/test/configuration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def initialize
1212
@response_raise_error = true
1313
@ignored_unknown_status = [404]
1414
@report_coverage = true
15+
@ignore_unknown_requests = false
1516
@registry = {}
1617
@apps = {}
1718
end
@@ -28,7 +29,8 @@ def observe(app, api: :default)
2829
@apps[api] = app
2930
end
3031

31-
attr_accessor :coverage_formatter_options, :coverage_formatter, :response_raise_error, :minimum_coverage
32+
attr_accessor :coverage_formatter_options, :coverage_formatter, :response_raise_error, :minimum_coverage,
33+
:ignore_unknown_requests
3234
attr_reader :registry, :apps, :report_coverage, :ignored_unknown_status
3335

3436
# Configure report coverage

lib/openapi_first/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module OpenapiFirst
4-
VERSION = '2.8.0'
4+
VERSION = '2.9.0'
55
end

spec/test_spec.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,45 @@ def call(_env)
411411
end
412412
end
413413

414+
describe 'handling unknown requests paths' do
415+
let(:app) do
416+
described_class.app(
417+
->(_env) { [200, { 'content-type' => 'application/json' }, ['foo']] },
418+
spec: definition
419+
)
420+
end
421+
422+
before(:each) do
423+
described_class.setup do |test|
424+
test.register(definition)
425+
test.report_coverage = false
426+
end
427+
end
428+
429+
it 'raises an error' do
430+
expect do
431+
app.call(Rack::MockRequest.env_for('/unknown'))
432+
end.to raise_error(OpenapiFirst::NotFoundError)
433+
end
434+
435+
context 'with ignore_unknown_requests = true' do
436+
before(:each) do
437+
described_class.uninstall
438+
described_class.setup do |test|
439+
test.register(definition)
440+
test.ignore_unknown_requests = true
441+
test.report_coverage = false
442+
end
443+
end
444+
445+
it 'does not raise an error' do
446+
expect do
447+
app.call(Rack::MockRequest.env_for('/unknown'))
448+
end.not_to raise_error
449+
end
450+
end
451+
end
452+
414453
describe 'handling invalid responses' do
415454
let(:definition) do
416455
OpenapiFirst.parse(YAML.load(%(

0 commit comments

Comments
 (0)