webspicy 0.12.5 → 0.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3d8a8db807de1959e59ebc27dec02a35c11749763c64932c4b38be2c763375f
4
- data.tar.gz: d8bdd2e5e1dfc7dfbf25034ccb5867f93b1dd09d63e60225c78f30b0d9577a22
3
+ metadata.gz: df662e6e4d8e94403071753f7f4e3a61919bf6fc8e5913316b847fee3b03d9d3
4
+ data.tar.gz: 4e18c04cff9b572d4173a267590f6e91cbfe1bbbf40236944c7fad50edff88dc
5
5
  SHA512:
6
- metadata.gz: 25f00703c45fdef554cb45d8699ed97b9bc61a1d395103260b2e1901960a21740eed8aa47f103c760b8d6e352aebb55d98377322b2fe0bdb033302d52694b50e
7
- data.tar.gz: 487fc0463160ff897ceab1ec3782ffb5c1cf89aa701970ddf0478dac71678ae458f95423aa7cdde3fbfa2c0a762fd61d3a9cfc14fe8e02efeacf978897ba5770
6
+ metadata.gz: 997f7223ba296843ff3ef1c4acaeed45815921c88e03ae756d7e27cf0c4ab60b3a644ddea34e0ac3df4bed41c3472a1135ac15801efc0052cca0c190ca5aceee
7
+ data.tar.gz: b1cdceb0a8a3b9bc756e2f7a763b4e529c4bb370d7db916d83c273f6e692cb08aa652f296571d846f3112c344d144f03117fecab9d21c7b622c0ed5867231af6
@@ -1,25 +1,29 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- webspicy (0.12.5)
5
- finitio (>= 0.6.1)
4
+ webspicy (0.13.0)
5
+ finitio (>= 0.8.0)
6
6
  http (~> 2)
7
+ mustermann (~> 1.0)
8
+ mustermann-contrib
7
9
  path (~> 1.3)
8
10
  rack-robustness (~> 1.1, >= 1.1.0)
9
11
  rack-test (~> 0.6.3)
10
12
  rspec (~> 3.7)
13
+ rspec_junit_formatter (~> 0.4.1)
11
14
 
12
15
  GEM
13
16
  remote: https://rubygems.org/
14
17
  specs:
15
- addressable (2.6.0)
16
- public_suffix (>= 2.0.2, < 4.0)
18
+ addressable (2.7.0)
19
+ public_suffix (>= 2.0.2, < 5.0)
17
20
  citrus (3.0.2)
18
21
  diff-lcs (1.3)
19
22
  domain_name (0.5.20190701)
20
23
  unf (>= 0.0.5, < 1.0.0)
21
- finitio (0.7.0)
24
+ finitio (0.8.0)
22
25
  citrus (>= 2.4, < 4.0)
26
+ hansi (0.2.0)
23
27
  http (2.2.2)
24
28
  addressable (~> 2.3)
25
29
  http-cookie (~> 1.0)
@@ -30,34 +34,39 @@ GEM
30
34
  http-form_data (1.0.3)
31
35
  http_parser.rb (0.6.0)
32
36
  mustermann (1.0.3)
37
+ mustermann-contrib (1.0.3)
38
+ hansi (~> 0.2.0)
39
+ mustermann (= 1.0.3)
33
40
  path (1.3.3)
34
- public_suffix (3.1.1)
41
+ public_suffix (4.0.3)
35
42
  rack (2.0.7)
36
- rack-protection (2.0.5)
43
+ rack-protection (2.0.7)
37
44
  rack
38
45
  rack-robustness (1.1.0)
39
46
  rack-test (0.6.3)
40
47
  rack (>= 1.0)
41
48
  rake (10.5.0)
42
- rspec (3.8.0)
43
- rspec-core (~> 3.8.0)
44
- rspec-expectations (~> 3.8.0)
45
- rspec-mocks (~> 3.8.0)
46
- rspec-core (3.8.2)
47
- rspec-support (~> 3.8.0)
48
- rspec-expectations (3.8.4)
49
+ rspec (3.9.0)
50
+ rspec-core (~> 3.9.0)
51
+ rspec-expectations (~> 3.9.0)
52
+ rspec-mocks (~> 3.9.0)
53
+ rspec-core (3.9.1)
54
+ rspec-support (~> 3.9.1)
55
+ rspec-expectations (3.9.0)
49
56
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.8.0)
51
- rspec-mocks (3.8.1)
57
+ rspec-support (~> 3.9.0)
58
+ rspec-mocks (3.9.1)
52
59
  diff-lcs (>= 1.2.0, < 2.0)
53
- rspec-support (~> 3.8.0)
54
- rspec-support (3.8.2)
55
- sinatra (2.0.5)
60
+ rspec-support (~> 3.9.0)
61
+ rspec-support (3.9.2)
62
+ rspec_junit_formatter (0.4.1)
63
+ rspec-core (>= 2, < 4, != 2.12.0)
64
+ sinatra (2.0.7)
56
65
  mustermann (~> 1.0)
57
66
  rack (~> 2.0)
58
- rack-protection (= 2.0.5)
67
+ rack-protection (= 2.0.7)
59
68
  tilt (~> 2.0)
60
- tilt (2.0.9)
69
+ tilt (2.0.10)
61
70
  unf (0.1.4)
62
71
  unf_ext
63
72
  unf_ext (0.0.7.6)
@@ -71,4 +80,4 @@ DEPENDENCIES
71
80
  webspicy!
72
81
 
73
82
  BUNDLED WITH
74
- 2.0.1
83
+ 2.1.0.pre.1
data/lib/webspicy.rb CHANGED
@@ -7,6 +7,7 @@ require 'ostruct'
7
7
  require 'yaml'
8
8
  require 'rspec'
9
9
  require 'rack/test'
10
+ require "mustermann"
10
11
  module Webspicy
11
12
 
12
13
  ###
@@ -49,7 +49,7 @@ module Webspicy
49
49
  @last_response = HTTP[headers || {}].options(url, params: params)
50
50
 
51
51
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
52
- Webspicy.debug("Response: #{@last_response.body}")
52
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
53
53
 
54
54
  @last_response
55
55
  end
@@ -60,7 +60,7 @@ module Webspicy
60
60
  @last_response = HTTP[headers || {}].get(url, params: params)
61
61
 
62
62
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
63
- Webspicy.debug("Response: #{@last_response.body}")
63
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
64
64
 
65
65
  @last_response
66
66
  end
@@ -88,7 +88,7 @@ module Webspicy
88
88
  end
89
89
 
90
90
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
91
- Webspicy.debug("Response: #{@last_response.body}")
91
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
92
92
 
93
93
  @last_response
94
94
  end
@@ -101,7 +101,7 @@ module Webspicy
101
101
  @last_response = HTTP[headers].patch(url, body: params.to_json)
102
102
 
103
103
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
104
- Webspicy.debug("Response: #{@last_response.body}")
104
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
105
105
 
106
106
  @last_response
107
107
  end
@@ -112,7 +112,7 @@ module Webspicy
112
112
  @last_response = HTTP[headers || {}].post(url, form: params)
113
113
 
114
114
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
115
- Webspicy.debug("Response: #{@last_response.body}")
115
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
116
116
 
117
117
  @last_response
118
118
  end
@@ -123,7 +123,7 @@ module Webspicy
123
123
  @last_response = HTTP[headers || {}].delete(url, body: params.to_json)
124
124
 
125
125
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
126
- Webspicy.debug("Response: #{@last_response.body}")
126
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
127
127
 
128
128
  @last_response
129
129
  end
@@ -70,7 +70,7 @@ module Webspicy
70
70
  @last_response = handler.last_response
71
71
 
72
72
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
73
- Webspicy.debug("Response: #{@last_response.body}")
73
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
74
74
 
75
75
  @last_response
76
76
  end
@@ -85,7 +85,7 @@ module Webspicy
85
85
  @last_response = handler.last_response
86
86
 
87
87
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
88
- Webspicy.debug("Response: #{@last_response.body}")
88
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
89
89
 
90
90
  @last_response
91
91
  end
@@ -110,7 +110,7 @@ module Webspicy
110
110
  @last_response = handler.last_response
111
111
 
112
112
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
113
- Webspicy.debug("Response: #{@last_response.body}")
113
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
114
114
 
115
115
  @last_response
116
116
  end
@@ -124,7 +124,7 @@ module Webspicy
124
124
  @last_response = handler.last_response
125
125
 
126
126
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
127
- Webspicy.debug("Response: #{@last_response.body}")
127
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
128
128
 
129
129
  @last_response
130
130
  end
@@ -138,7 +138,7 @@ module Webspicy
138
138
  @last_response = handler.last_response
139
139
 
140
140
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
141
- Webspicy.debug("Response: #{@last_response.body}")
141
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
142
142
 
143
143
  @last_response
144
144
  end
@@ -152,7 +152,7 @@ module Webspicy
152
152
  @last_response = handler.last_response
153
153
 
154
154
  Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
155
- Webspicy.debug("Response: #{@last_response.body}")
155
+ Webspicy.debug("Response (#{@last_response.status}): #{@last_response.body}")
156
156
 
157
157
  @last_response
158
158
  end
@@ -273,7 +273,8 @@ module Webspicy
273
273
  # - FAILFAST <-> --fail-fast
274
274
  #
275
275
  def default_rspec_options
276
- options = ["--color", "--format=documentation"]
276
+ dest_folder = (self.folder/'rspec.xml').to_s
277
+ options = %w{--color --format=documentation --format RspecJunitFormatter --out} << dest_folder
277
278
  if ENV['FAILFAST']
278
279
  options << (ENV['FAILFAST'] == 'no' ? "--no-fail-fast" : "--fail-fast=#{ENV['FAILFAST']}")
279
280
  end
@@ -299,6 +300,13 @@ module Webspicy
299
300
  end
300
301
  end
301
302
 
303
+ # Returns the data generator to use, for generating random data when
304
+ # needed.
305
+ def generator
306
+ @generator
307
+ end
308
+ attr_writer :generator
309
+
302
310
  # Duplicates this configuration and yields the block with the new one,
303
311
  # if a block is given.
304
312
  #
@@ -0,0 +1,88 @@
1
+ require "finitio/generation"
2
+ require "json"
3
+ module Webspicy
4
+ class Mocker
5
+
6
+ def initialize(config)
7
+ @config = Configuration.dress(config)
8
+ @generator = config.generator || Finitio::Generation.new
9
+ end
10
+ attr_reader :config, :generator
11
+
12
+ def call(env)
13
+ req = Rack::Request.new(env)
14
+ path = req.path
15
+ meth = req.request_method
16
+ if meth == "OPTIONS" && has_service?(path)
17
+ [204, {}, []]
18
+ elsif service = find_service(meth, path)
19
+ status = best_status_code(service)
20
+ body = status == 204 ? "" : random_body(service, req)
21
+ headers = generate_headers(service)
22
+ [ status, headers, [ body ].compact ]
23
+ else
24
+ [404, {}, []]
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def has_service?(path)
31
+ config.each_scope do |scope|
32
+ scope.each_resource do |resource|
33
+ next unless url_matches?(resource, path)
34
+ return true
35
+ end
36
+ end
37
+ return false
38
+ end
39
+
40
+ def find_service(method, path)
41
+ config.each_scope do |scope|
42
+ scope.each_resource do |resource|
43
+ next unless url_matches?(resource, path)
44
+ scope.each_service(resource) do |service|
45
+ return service if service.method == method
46
+ end
47
+ end
48
+ end
49
+ nil
50
+ end
51
+
52
+ def generate_headers(service)
53
+ {
54
+ "Content-Type" => best_content_type(service)
55
+ }.delete_if{|k,v| v.nil? }
56
+ end
57
+
58
+ def best_status_code(service)
59
+ if ex = service.examples.first
60
+ ex.expected_status || 200
61
+ else
62
+ 200
63
+ end
64
+ end
65
+
66
+ def best_content_type(service)
67
+ if ex = service.examples.first
68
+ ex.expected_content_type
69
+ else
70
+ "application/json"
71
+ end
72
+ end
73
+
74
+ def url_matches?(resource, path)
75
+ resource.url_pattern.match(path)
76
+ end
77
+
78
+ def random_body(service, request)
79
+ world = OpenStruct.new({
80
+ service: service,
81
+ request: request
82
+ })
83
+ data = generator.call(service.output_schema.main, world)
84
+ JSON.pretty_generate(data) if data
85
+ end
86
+
87
+ end # class Mocker
88
+ end # module Webspicy
@@ -26,6 +26,10 @@ module Webspicy
26
26
  @raw[:url]
27
27
  end
28
28
 
29
+ def url_pattern
30
+ @url_pattern ||= Mustermann.new(url, type: :template)
31
+ end
32
+
29
33
  def services
30
34
  @raw[:services]
31
35
  end
@@ -20,7 +20,7 @@ module Webspicy
20
20
  tester = self
21
21
  RSpec.reset
22
22
  rspec_config!
23
- RSpec.describe "Webspicy test suite" do
23
+ RSpec.describe "" do
24
24
  before(:all) do
25
25
  tester.config.listeners(:before_all).each do |l|
26
26
  l.call(tester.config)
@@ -71,15 +71,26 @@ module Webspicy
71
71
  @invocation
72
72
  end
73
73
 
74
- it 'meets its specification' do
75
- expect(invocation.done?).to eq(true)
76
- expect(invocation.expected_status_unmet).to(be_nil)
77
- expect(invocation.expected_content_type_unmet).to(be_nil)
78
- expect(invocation.expected_headers_unmet).to(be_nil) if test_case.has_expected_headers?
79
- expect(invocation.expected_schema_unmet).to(be_nil)
80
- expect(invocation.assertions_unmet).to(be_nil) if test_case.has_assertions?
81
- expect(invocation.postconditions_unmet).to(be_nil) if test_case.service.has_postconditions? and not(counterexample)
82
- expect(invocation.expected_error_unmet).to(be_nil) if test_case.has_expected_error?
74
+ it 'works' do
75
+ raise "Test not ran" unless invocation.done?
76
+ fails = [
77
+ [:expected_status_unmet, true],
78
+ [:expected_content_type_unmet, true],
79
+ [:expected_headers_unmet, test_case.has_expected_headers?],
80
+ [:expected_schema_unmet, true],
81
+ [:assertions_unmet, test_case.has_assertions?],
82
+ [:postconditions_unmet, test_case.service.has_postconditions? && !counterexample],
83
+ [:expected_error_unmet, test_case.has_expected_error?]
84
+ ].map do |(expectation,only_if)|
85
+ next unless only_if
86
+ begin
87
+ invocation.send(expectation)
88
+ rescue => ex
89
+ ex.message
90
+ end
91
+ end
92
+ fails = fails.compact
93
+ raise "\n* " + fails.join("\n* ") + "\n" unless fails.empty?
83
94
  end
84
95
  end
85
96
  end
@@ -1,8 +1,8 @@
1
1
  module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 12
5
- TINY = 5
4
+ MINOR = 13
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+ require 'webspicy/mocker'
4
+ module Webspicy
5
+ describe Mocker do
6
+ include Rack::Test::Methods
7
+
8
+ let(:app) {
9
+ Mocker.new(Configuration.dress(restful_folder))
10
+ }
11
+
12
+ it 'works as expected' do
13
+ get '/todo/'
14
+ expect(last_response.status).to eql(200)
15
+ expect(last_response.body).not_to be_empty
16
+ end
17
+
18
+ it 'supports CORS on OPTIONS' do
19
+ options '/todo/'
20
+ expect(last_response.status).to eql(204)
21
+ expect(last_response.body).to be_empty
22
+ end
23
+
24
+ it 'returns the correct status code, taken from first example' do
25
+ delete '/todo/1'
26
+ expect(last_response.status).to eql(204)
27
+ expect(last_response.body).to be_empty
28
+ expect(last_response["Content-Type"]).to be_nil
29
+ end
30
+
31
+ end
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webspicy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.5
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-17 00:00:00.000000000 Z
11
+ date: 2020-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '3.7'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec_junit_formatter
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.4.1
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.4.1
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: rack-test
63
77
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +92,14 @@ dependencies:
78
92
  requirements:
79
93
  - - ">="
80
94
  - !ruby/object:Gem::Version
81
- version: 0.6.1
95
+ version: 0.8.0
82
96
  type: :runtime
83
97
  prerelease: false
84
98
  version_requirements: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - ">="
87
101
  - !ruby/object:Gem::Version
88
- version: 0.6.1
102
+ version: 0.8.0
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: http
91
105
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +148,34 @@ dependencies:
134
148
  - - ">="
135
149
  - !ruby/object:Gem::Version
136
150
  version: 1.1.0
151
+ - !ruby/object:Gem::Dependency
152
+ name: mustermann
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '1.0'
158
+ type: :runtime
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '1.0'
165
+ - !ruby/object:Gem::Dependency
166
+ name: mustermann-contrib
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ type: :runtime
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
137
179
  description: Webspicy helps testing web services as software operation black boxes
138
180
  email: blambeau@gmail.com
139
181
  executables: []
@@ -171,6 +213,7 @@ files:
171
213
  - lib/webspicy/configuration.rb
172
214
  - lib/webspicy/file_upload.rb
173
215
  - lib/webspicy/formaldoc.fio
216
+ - lib/webspicy/mocker.rb
174
217
  - lib/webspicy/postcondition.rb
175
218
  - lib/webspicy/precondition.rb
176
219
  - lib/webspicy/resource.rb
@@ -184,6 +227,7 @@ files:
184
227
  - lib/webspicy/version.rb
185
228
  - spec/unit/client/test_around.rb
186
229
  - spec/unit/configuration/config.rb
230
+ - spec/unit/mocker/test_mocker.rb
187
231
  - spec/unit/resource/service/test_dress_params.rb
188
232
  - spec/unit/resource/test_instantiate_url.rb
189
233
  - spec/unit/resource/test_url_placeholders.rb
@@ -215,8 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
259
  - !ruby/object:Gem::Version
216
260
  version: '0'
217
261
  requirements: []
218
- rubyforge_project:
219
- rubygems_version: 2.7.6
262
+ rubygems_version: 3.1.0.pre1
220
263
  signing_key:
221
264
  specification_version: 4
222
265
  summary: Webspicy helps testing web services as software operation black boxes!