openapi_first 2.3.0 → 2.4.0
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/CHANGELOG.md +13 -0
- data/README.md +5 -7
- data/lib/openapi_first/response.rb +6 -2
- data/lib/openapi_first/test/coverage/terminal_formatter.rb +8 -4
- data/lib/openapi_first/test.rb +36 -11
- data/lib/openapi_first/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 131c3511b96fc2a420b9c0a1b2e4deeb5b24d8602ad6210e5a60ed1a46fe6257
|
4
|
+
data.tar.gz: f6b7a44491e9aedf68498b2200a46e6048b9036360447a34c077c7476da8fc70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 498b7341aa473504c5fa13dd95e92d7d1e2317d690ddbd88fac36974c05b10cccd8ae8b9dccc025036151aab484304e14f053003668b576c547ac1c7c0716d4b
|
7
|
+
data.tar.gz: 5cb776022d6e0fb684b3c30e7dd507a6591e5bc0b34bc384347a28e2b5030f20c976fa6f92b9b3e81c8d8ec6912d46e6b0ee053189267de320ccf418e7d88f4f
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,19 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 2.4.0
|
6
|
+
|
7
|
+
- Support less verbose test setup without the need to call `OpenapiFirst::Test.report_coverage`, which will be called `at_exit`:
|
8
|
+
```ruby
|
9
|
+
OpenapiFirst::Test.setup do |test|
|
10
|
+
test.register('openapi/openapi.yaml')
|
11
|
+
test.minimum_coverage = 100 # Setting this will lead to an `exit 2` if coverage is below minimum
|
12
|
+
end
|
13
|
+
```
|
14
|
+
- Add `OpenapiFirst::Test::Setup#minimum_coverage=` to control exit behaviour (exit 2 if coverage is below minimum)
|
15
|
+
- Add `verbose` option to `OpenapiFirst::Test.report_coverage(verbose: true)`
|
16
|
+
to see all passing requests/responses
|
17
|
+
|
5
18
|
## 2.3.0
|
6
19
|
|
7
20
|
### New feature
|
data/README.md
CHANGED
@@ -129,9 +129,11 @@ This can be useful in a test or staging environment, especially if you are adopt
|
|
129
129
|
use OpenapiFirst::Middlewares::ResponseValidation, spec: 'openapi.yaml' if ENV['RACK_ENV'] == 'test'
|
130
130
|
|
131
131
|
# Pass `raise_error: false` to not raise an error:
|
132
|
-
use OpenapiFirst::Middlewares::ResponseValidation, raise_error:
|
132
|
+
use OpenapiFirst::Middlewares::ResponseValidation, raise_error: false, spec: 'openapi.yaml'
|
133
133
|
```
|
134
134
|
|
135
|
+
If you are adopting OpenAPI you can use these options together with [hooks](#hooks) to get notified about requests/responses that do match your API description.
|
136
|
+
|
135
137
|
## Contract Testing
|
136
138
|
|
137
139
|
### Coverage
|
@@ -149,21 +151,17 @@ Here is how to set it up for RSpec in your `spec/spec_helper.rb`:
|
|
149
151
|
require 'openapi_first'
|
150
152
|
OpenapiFirst::Test.setup do |test|
|
151
153
|
test.register('openapi/openapi.yaml')
|
154
|
+
test.minimum_coverage = 100 # Setting this will lead to an `exit 2` if coverage is below minimum
|
152
155
|
end
|
153
156
|
```
|
154
157
|
2. Wrap your app with silent request / response validation. This validates all requets/responses you do during your test run. (✷1)
|
155
158
|
```ruby
|
156
159
|
config.before type: :request do
|
157
160
|
def app
|
158
|
-
OpenapiFirst::Test
|
161
|
+
OpenapiFirst::Test.app(App)
|
159
162
|
end
|
160
163
|
end
|
161
164
|
```
|
162
|
-
3. Check coverage after your test suite has finished
|
163
|
-
```ruby
|
164
|
-
# Prints a coverage report to the terminal
|
165
|
-
config.after(:suite) { OpenapiFirst::Test.report_coverage }
|
166
|
-
```
|
167
165
|
|
168
166
|
(✷1): Instead of using `OpenapiFirstTest.app` to wrap your application, you can use the 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.
|
169
167
|
|
@@ -26,8 +26,12 @@ module OpenapiFirst
|
|
26
26
|
attr_reader :status, :content_type, :content_schema, :headers, :headers_schema, :key
|
27
27
|
|
28
28
|
def validate(response)
|
29
|
-
parsed_values =
|
30
|
-
error =
|
29
|
+
parsed_values = nil
|
30
|
+
error = catch FAILURE do
|
31
|
+
parsed_values = @parser.parse(response)
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
error ||= @validator.call(parsed_values)
|
31
35
|
ValidatedResponse.new(response, parsed_values:, error:, response_definition: self)
|
32
36
|
end
|
33
37
|
|
@@ -5,6 +5,10 @@ module OpenapiFirst
|
|
5
5
|
module Coverage
|
6
6
|
# This is the default formatter
|
7
7
|
class TerminalFormatter
|
8
|
+
def initialize(verbose: false)
|
9
|
+
@verbose = verbose
|
10
|
+
end
|
11
|
+
|
8
12
|
# This takes a list of Coverage::Plan instances and outputs a String
|
9
13
|
def format(coverage_result)
|
10
14
|
@out = StringIO.new
|
@@ -12,7 +16,7 @@ module OpenapiFirst
|
|
12
16
|
@out.string
|
13
17
|
end
|
14
18
|
|
15
|
-
private attr_reader :out
|
19
|
+
private attr_reader :out, :verbose
|
16
20
|
|
17
21
|
private
|
18
22
|
|
@@ -27,10 +31,10 @@ module OpenapiFirst
|
|
27
31
|
def format_plan(plan)
|
28
32
|
filepath = plan.filepath
|
29
33
|
puts ['', "API validation coverage for #{filepath}: #{plan.coverage}%"]
|
30
|
-
return if plan.done?
|
34
|
+
return if plan.done? && !verbose
|
31
35
|
|
32
36
|
plan.routes.each do |route|
|
33
|
-
next if route.finished?
|
37
|
+
next if route.finished? && !verbose
|
34
38
|
|
35
39
|
format_requests(route.requests)
|
36
40
|
next if route.requests.none?(&:requested?)
|
@@ -52,7 +56,7 @@ module OpenapiFirst
|
|
52
56
|
def format_responses(responses)
|
53
57
|
responses.each do |response|
|
54
58
|
if response.finished?
|
55
|
-
puts green " ✓ #{response_label(response)}"
|
59
|
+
puts green " ✓ #{response_label(response)}" if verbose
|
56
60
|
else
|
57
61
|
puts red " ❌ #{response_label(response)} – #{explain_unfinished_response(response)}"
|
58
62
|
end
|
data/lib/openapi_first/test.rb
CHANGED
@@ -14,33 +14,58 @@ module OpenapiFirst
|
|
14
14
|
|
15
15
|
# Helper class to setup tests
|
16
16
|
class Setup
|
17
|
+
def initialize
|
18
|
+
@minimum_coverage = 0
|
19
|
+
yield self
|
20
|
+
end
|
21
|
+
|
17
22
|
def register(*)
|
18
23
|
Test.register(*)
|
19
24
|
end
|
25
|
+
|
26
|
+
attr_accessor :minimum_coverage
|
27
|
+
|
28
|
+
# This called at_exit
|
29
|
+
def handle_exit
|
30
|
+
coverage = Coverage.result.coverage
|
31
|
+
# :nocov:
|
32
|
+
puts 'API Coverage did not detect any API requests for the registered API descriptions' if coverage.zero?
|
33
|
+
Test.report_coverage if coverage.positive?
|
34
|
+
return unless minimum_coverage > coverage
|
35
|
+
|
36
|
+
puts "API Coverage fails with exit 2, because API coverage of #{coverage}%" \
|
37
|
+
"is below minimum of #{minimum_coverage}%!"
|
38
|
+
exit 2
|
39
|
+
# :nocov:
|
40
|
+
end
|
20
41
|
end
|
21
42
|
|
22
|
-
def self.setup
|
43
|
+
def self.setup(&)
|
23
44
|
unless block_given?
|
24
45
|
raise ArgumentError, "Please provide a block to #{self.class}.setup to register you API descriptions"
|
25
46
|
end
|
26
47
|
|
27
48
|
Coverage.start
|
28
|
-
setup = Setup.new
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
setup = Setup.new(&)
|
50
|
+
|
51
|
+
if definitions.empty?
|
52
|
+
raise NotRegisteredError,
|
53
|
+
'No API descriptions have been registered. ' \
|
54
|
+
'Please register your API description via ' \
|
55
|
+
"OpenapiFirst::Test.setup { |test| test.register('myopenapi.yaml') }"
|
56
|
+
end
|
57
|
+
|
58
|
+
@setup ||= at_exit do
|
59
|
+
setup.handle_exit
|
60
|
+
end
|
36
61
|
end
|
37
62
|
|
38
63
|
# Print the coverage report
|
39
64
|
# @param formatter A formatter to define the report.
|
40
65
|
# @output [IO] An output where to puts the report.
|
41
|
-
def self.report_coverage(formatter: Coverage::TerminalFormatter)
|
66
|
+
def self.report_coverage(formatter: Coverage::TerminalFormatter, **)
|
42
67
|
coverage_result = Coverage.result
|
43
|
-
puts formatter.new.format(coverage_result)
|
68
|
+
puts formatter.new(**).format(coverage_result)
|
44
69
|
puts "The overal API validation coverage of this run is: #{coverage_result.coverage}%"
|
45
70
|
end
|
46
71
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openapi_first
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Haller
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-02-
|
10
|
+
date: 2025-02-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: hana
|
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
- !ruby/object:Gem::Version
|
161
161
|
version: '0'
|
162
162
|
requirements: []
|
163
|
-
rubygems_version: 3.6.
|
163
|
+
rubygems_version: 3.6.5
|
164
164
|
specification_version: 4
|
165
165
|
summary: Implement HTTP APIs based on OpenApi 3.x
|
166
166
|
test_files: []
|