webspicy 0.20.16 → 0.20.20
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/README.md +1 -1
- data/lib/webspicy/tester/fakesendgrid/email.rb +7 -0
- data/lib/webspicy/tester/fakeses/email.rb +7 -0
- data/lib/webspicy/tester/fakesmtp/email.rb +12 -4
- data/lib/webspicy/tester/reporter/documentation.rb +4 -2
- data/lib/webspicy/tester.rb +3 -4
- data/lib/webspicy/version.rb +1 -1
- data/lib/webspicy/web/inferer/config.ru +8 -0
- data/lib/webspicy/web/inferer.rb +95 -0
- data/lib/webspicy/web/openapi/generator.rb +24 -4
- data/spec/unit/tester/fakesendgrid/test_email.rb +5 -1
- data/spec/unit/tester/fakeses/test_email.rb +6 -0
- data/spec/unit/tester/fakesmtp/test_email.rb +4 -0
- data/spec/unit/web/inferer/test_inferer.rb +49 -0
- metadata +23 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1540c9120b24bed9351dc01d8906cad2f4ffac8ea478c4e5cdf23ec48e3439d
|
4
|
+
data.tar.gz: a188f120ff0bed71f12ed525916ccafdb89e1c62d9fe6e5fc8acc1e7576d1e40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 582f993602ffec966ee10e7339806ce747acb5b6f93a89a9427687bb4ce098200a33fd99db9adf4fd70575177b25f07b2a3a9014f3513a17a261e0a62c797b3e
|
7
|
+
data.tar.gz: 1d42856145ee337d16bfdf85c2e94eaa8b144d8e089b9cadc4d71e607bf023ed9856d229169ca511f80111350255133f1c1c5e6c6a66cea490eff4e2d2ae5a49
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://github.com/enspirit/webspicy/actions/workflows/integration.yml)
|
2
2
|
# Webspicy
|
3
3
|
|
4
4
|
A specification and test framework for web services seen as black-box software
|
@@ -42,6 +42,13 @@ module Webspicy
|
|
42
42
|
@subject ||= data["subject"]
|
43
43
|
end
|
44
44
|
|
45
|
+
def headers
|
46
|
+
@headers ||= data["headers"].reduce(OpenStruct.new){|acc, (key, value)|
|
47
|
+
acc[key.downcase] = value
|
48
|
+
acc
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
45
52
|
end # class Email
|
46
53
|
end # class Fakesendgrid
|
47
54
|
end # class Tester
|
@@ -39,6 +39,13 @@ module Webspicy
|
|
39
39
|
recipients - cc - to
|
40
40
|
end
|
41
41
|
|
42
|
+
def headers
|
43
|
+
@headers ||= email.header.reduce(OpenStruct.new){|acc, h|
|
44
|
+
acc[h.name.downcase] = h.unparsed_value
|
45
|
+
acc
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
42
49
|
def email
|
43
50
|
@email ||= Mail.read_from_string(raw_data)
|
44
51
|
end
|
@@ -32,10 +32,18 @@ module Webspicy
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def subject
|
35
|
-
@subject ||= data["headerLines"]
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
@subject ||= data["subject"] || data["headerLines"]
|
36
|
+
.select{|h| h["key"] == "subject" }
|
37
|
+
.map{|h| h["line"][/Subject:\s*(.*)$/, 1] }
|
38
|
+
.first
|
39
|
+
end
|
40
|
+
|
41
|
+
def headers
|
42
|
+
@headers ||= data["headerLines"]
|
43
|
+
.reduce(OpenStruct.new){|acc, h|
|
44
|
+
acc[h["key"].downcase] = h["line"].split(': ')[1..].join(': ')
|
45
|
+
acc
|
46
|
+
}
|
39
47
|
end
|
40
48
|
|
41
49
|
end # class Email
|
data/lib/webspicy/tester.rb
CHANGED
@@ -118,13 +118,12 @@ module Webspicy
|
|
118
118
|
def run_service
|
119
119
|
scope.each_testcase(service) do |test_case|
|
120
120
|
@test_case = test_case
|
121
|
-
reporter.before_test_case
|
122
121
|
run_test_case
|
123
|
-
reporter.test_case_done
|
124
122
|
end
|
125
123
|
end
|
126
124
|
|
127
125
|
def run_test_case
|
126
|
+
reporter.before_test_case
|
128
127
|
hooks.fire_around(self) do
|
129
128
|
reporter.before_each
|
130
129
|
hooks.fire_before_each(self)
|
@@ -143,9 +142,9 @@ module Webspicy
|
|
143
142
|
reporter.after_each
|
144
143
|
hooks.fire_after_each(self)
|
145
144
|
reporter.after_each_done
|
146
|
-
|
147
|
-
raise FailFast if !result.success? and failfast?
|
148
145
|
end
|
146
|
+
reporter.test_case_done
|
147
|
+
raise FailFast if !result.success? && failfast?
|
149
148
|
end
|
150
149
|
|
151
150
|
def call_test_case_target
|
data/lib/webspicy/version.rb
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'rack/proxy'
|
2
|
+
module Webspicy
|
3
|
+
module Web
|
4
|
+
class Inferer < Rack::Proxy
|
5
|
+
|
6
|
+
def initialize(config, options = nil)
|
7
|
+
@webspicy_config = config
|
8
|
+
@webspicy_options = options || options_from_env
|
9
|
+
super(proxy_options)
|
10
|
+
end
|
11
|
+
attr_reader :webspicy_config, :webspicy_options
|
12
|
+
|
13
|
+
def rewrite_env(env)
|
14
|
+
env = env.merge(static_env)
|
15
|
+
env = handle_path_info(env)
|
16
|
+
env
|
17
|
+
end
|
18
|
+
|
19
|
+
def rewrite_response(triplet)
|
20
|
+
triplet
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def options_from_env
|
26
|
+
{
|
27
|
+
target_endpoint: ENV['PROXY_TARGET_ENDPOINT'] || config.host
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def proxy_options
|
32
|
+
uri = target_uri
|
33
|
+
backend = "#{uri.scheme}://#{uri.host}"
|
34
|
+
backend = "#{backend}:#{uri.port}" if uri.port != 80 && uri.port != 443
|
35
|
+
{
|
36
|
+
streaming: false,
|
37
|
+
backend: backend
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def static_env
|
42
|
+
@static_env ||= begin
|
43
|
+
e = {}
|
44
|
+
e['HTTP_HOST'] = target_uri.host
|
45
|
+
e
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def target_uri
|
50
|
+
@target_uri ||= URI.parse(webspicy_options[:target_endpoint])
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_path_info(env)
|
54
|
+
return env if target_uri.path.nil? || target_uri.path.empty?
|
55
|
+
|
56
|
+
env['PATH_INFO'] = "#{target_uri.path}#{env['PATH_INFO']}"
|
57
|
+
env
|
58
|
+
end
|
59
|
+
|
60
|
+
def perform_request(env)
|
61
|
+
webspicy_dump_request(env)
|
62
|
+
super.tap{|triplet|
|
63
|
+
webspicy_dump_response(env, triplet)
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def webspicy_dump_request(env)
|
68
|
+
base_file = webspicy_dump_basefile(env)
|
69
|
+
env['rack.input'].rewind
|
70
|
+
input = ''
|
71
|
+
env['rack.input'].each { |s| input << s }
|
72
|
+
base_file.add_ext('.body').write(input)
|
73
|
+
env['rack.input'].rewind
|
74
|
+
end
|
75
|
+
|
76
|
+
def webspicy_dump_response(env, triplet)
|
77
|
+
base_file = webspicy_dump_basefile(env)
|
78
|
+
base_file.add_ext('.env.json').write(
|
79
|
+
JSON.pretty_generate(env)
|
80
|
+
)
|
81
|
+
base_file.add_ext('.triplet.json').write(
|
82
|
+
JSON.pretty_generate(triplet)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def webspicy_dump_basefile(env)
|
87
|
+
path, method = env['PATH_INFO'], env['REQUEST_METHOD'].downcase
|
88
|
+
target_folder = (webspicy_config.folder/'inferer'/'dump')/path[1..-1]
|
89
|
+
target_folder.mkdir_p
|
90
|
+
target_folder/"#{method}.#{Time.now.to_i}"
|
91
|
+
end
|
92
|
+
|
93
|
+
end # class Inferer
|
94
|
+
end # module Web
|
95
|
+
end # module Webspicy
|
@@ -36,19 +36,25 @@ module Webspicy
|
|
36
36
|
|
37
37
|
def path_for(specification)
|
38
38
|
{
|
39
|
-
specification.url => {
|
39
|
+
standardize(specification.url) => {
|
40
40
|
summary: specification.name
|
41
41
|
}.merge(verbs_for(specification))
|
42
42
|
}
|
43
43
|
end
|
44
44
|
|
45
|
+
def standardize(url)
|
46
|
+
url = url.gsub(/\/$/, '') if url =~ /\/$/
|
47
|
+
url
|
48
|
+
end
|
49
|
+
|
45
50
|
def verbs_for(specification)
|
46
51
|
specification.services.inject({}) do |verbs,service|
|
47
52
|
verb = service.method.downcase
|
48
53
|
verb_defn = {
|
49
54
|
description: service.description,
|
55
|
+
parameters: parameters_for(service),
|
50
56
|
responses: responses_for(service)
|
51
|
-
}
|
57
|
+
}.compact
|
52
58
|
unless ["get", "options", "delete", "head"].include?(verb)
|
53
59
|
verb_defn[:requestBody] = request_body_for(service)
|
54
60
|
end
|
@@ -58,15 +64,29 @@ module Webspicy
|
|
58
64
|
|
59
65
|
def request_body_for(service)
|
60
66
|
schema = actual_input_schema(service)
|
67
|
+
example = nil # catch(:unfound) { generator.call(schema, {}) }
|
61
68
|
{
|
62
69
|
required: true,
|
63
70
|
content: {
|
64
71
|
"application/json" => {
|
65
72
|
schema: schema.to_json_schema,
|
66
|
-
example:
|
67
|
-
}
|
73
|
+
example: example
|
74
|
+
}.compact
|
75
|
+
}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def parameters_for(service)
|
80
|
+
schema = actual_input_schema(service)
|
81
|
+
params = service.specification.url_placeholders.map{|p|
|
82
|
+
{
|
83
|
+
in: 'path',
|
84
|
+
name: p,
|
85
|
+
schema: { type: "string" },
|
86
|
+
required: true
|
68
87
|
}
|
69
88
|
}
|
89
|
+
params.empty? ? nil : params
|
70
90
|
end
|
71
91
|
|
72
92
|
def responses_for(service)
|
@@ -44,7 +44,10 @@ module Webspicy
|
|
44
44
|
"value": "test <b>test</b> test",
|
45
45
|
"type": "text/html"
|
46
46
|
}
|
47
|
-
]
|
47
|
+
],
|
48
|
+
"headers": {
|
49
|
+
"x-header-key": "personalised-header-value"
|
50
|
+
}
|
48
51
|
}
|
49
52
|
J
|
50
53
|
|
@@ -58,6 +61,7 @@ module Webspicy
|
|
58
61
|
expect(subject.cc).to eql(["a-cc-recipient@world.com"])
|
59
62
|
expect(subject.bcc).to eql(["a-bcc-recipient@world.com"])
|
60
63
|
expect(subject.subject).to eql("Hello World")
|
64
|
+
expect(subject.headers['x-header-key']).to eql('personalised-header-value')
|
61
65
|
end
|
62
66
|
|
63
67
|
end
|
@@ -12,6 +12,7 @@ module Webspicy
|
|
12
12
|
To: someone@world.com, someoneelse@world.com
|
13
13
|
CC: a-cc-recipient@world.com
|
14
14
|
Subject: Hey world, hello!
|
15
|
+
X-Ses-Configuration-Set: SesConfigurationSet
|
15
16
|
Message-ID: <2421bae3-9c42-7988-23b4-b1f6168130c9@webspicy.io>
|
16
17
|
Date: Thu, 24 Jun 2021 13:45:16 +0000
|
17
18
|
MIME-Version: 1.0
|
@@ -55,6 +56,11 @@ module Webspicy
|
|
55
56
|
expect(subject.cc).to eql(["a-cc-recipient@world.com"])
|
56
57
|
expect(subject.bcc).to eql(["a-bcc-recipient@world.com"])
|
57
58
|
expect(subject.subject).to eql("Hey world, hello!")
|
59
|
+
expect(subject.headers[:from]).to eql("Webspicy <noreply@webspicy.io>")
|
60
|
+
expect(subject.headers[:cc]).to eql("a-cc-recipient@world.com")
|
61
|
+
expect(subject.headers["message-id"]).to eql("<2421bae3-9c42-7988-23b4-b1f6168130c9@webspicy.io>")
|
62
|
+
expect(subject.headers["mime-version"]).to eql("1.0")
|
63
|
+
expect(subject.headers["x-ses-configuration-set"]).to eql("SesConfigurationSet")
|
58
64
|
end
|
59
65
|
|
60
66
|
end
|
@@ -96,6 +96,10 @@ module Webspicy
|
|
96
96
|
expect(subject.to).to eql(["someone@world.com", "someoneelse@world.com"])
|
97
97
|
expect(subject.cc).to eql(["a-cc-recipient@world.com"])
|
98
98
|
expect(subject.subject).to eql("Hello World")
|
99
|
+
expect(subject.headers[:cc]).to eql("a-cc-recipient@world.com")
|
100
|
+
expect(subject.headers[:date]).to eql("Tue, 20 Apr 2021 14:06:13 +0000")
|
101
|
+
expect(subject.headers['message-id']).to eql("<607edfd56836e_1b0492af@1d3356d02030.mail>")
|
102
|
+
expect(subject.headers['mime-version']).to eql("1.0")
|
99
103
|
end
|
100
104
|
|
101
105
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'webspicy/web'
|
4
|
+
require 'webspicy/web/inferer'
|
5
|
+
module Webspicy
|
6
|
+
module Web
|
7
|
+
describe Inferer do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
|
10
|
+
let(:config) {
|
11
|
+
Configuration.dress(restful_folder)
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:options) {{
|
15
|
+
:target_endpoint => "https://reqres.in/api"
|
16
|
+
}}
|
17
|
+
|
18
|
+
let(:app) {
|
19
|
+
Inferer.new(config, options)
|
20
|
+
}
|
21
|
+
|
22
|
+
describe 'proxy_options' do
|
23
|
+
it 'works' do
|
24
|
+
expect(app.send(:proxy_options)).to eql({
|
25
|
+
:streaming => false,
|
26
|
+
:backend => "https://reqres.in"
|
27
|
+
})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'static_env' do
|
32
|
+
it 'works' do
|
33
|
+
expect(app.send(:static_env)).to eql({
|
34
|
+
"HTTP_HOST" => "reqres.in"
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'the proxy itself' do
|
40
|
+
it 'works as expected' do
|
41
|
+
get '/users'
|
42
|
+
expect(last_response.status).to eql(200)
|
43
|
+
expect(last_response.body).not_to be_empty
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
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.20.
|
4
|
+
version: 0.20.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -226,6 +226,20 @@ dependencies:
|
|
226
226
|
- - "~>"
|
227
227
|
- !ruby/object:Gem::Version
|
228
228
|
version: '2.7'
|
229
|
+
- !ruby/object:Gem::Dependency
|
230
|
+
name: rack-proxy
|
231
|
+
requirement: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - "~>"
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: 0.7.0
|
236
|
+
type: :runtime
|
237
|
+
prerelease: false
|
238
|
+
version_requirements: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - "~>"
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: 0.7.0
|
229
243
|
description: Webspicy helps testing web services as software operation black boxes
|
230
244
|
email: blambeau@gmail.com
|
231
245
|
executables:
|
@@ -310,6 +324,8 @@ files:
|
|
310
324
|
- lib/webspicy/web/client/rack_test_client.rb
|
311
325
|
- lib/webspicy/web/client/support.rb
|
312
326
|
- lib/webspicy/web/formaldoc.fio
|
327
|
+
- lib/webspicy/web/inferer.rb
|
328
|
+
- lib/webspicy/web/inferer/config.ru
|
313
329
|
- lib/webspicy/web/invocation.rb
|
314
330
|
- lib/webspicy/web/mocker.rb
|
315
331
|
- lib/webspicy/web/mocker/config.ru
|
@@ -344,6 +360,7 @@ files:
|
|
344
360
|
- spec/unit/tester/fakesmtp/test_email.rb
|
345
361
|
- spec/unit/tester/test_asserter.rb
|
346
362
|
- spec/unit/tester/test_assertions.rb
|
363
|
+
- spec/unit/web/inferer/test_inferer.rb
|
347
364
|
- spec/unit/web/mocker/test_mocker.rb
|
348
365
|
- spec/unit/web/openapi/test_generator.rb
|
349
366
|
- spec/unit/web/specification/test_instantiate_url.rb
|
@@ -354,7 +371,7 @@ homepage: http://github.com/enspirit/webspicy
|
|
354
371
|
licenses:
|
355
372
|
- MIT
|
356
373
|
metadata: {}
|
357
|
-
post_install_message:
|
374
|
+
post_install_message:
|
358
375
|
rdoc_options: []
|
359
376
|
require_paths:
|
360
377
|
- lib
|
@@ -369,8 +386,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
369
386
|
- !ruby/object:Gem::Version
|
370
387
|
version: '0'
|
371
388
|
requirements: []
|
372
|
-
rubygems_version: 3.
|
373
|
-
signing_key:
|
389
|
+
rubygems_version: 3.1.4
|
390
|
+
signing_key:
|
374
391
|
specification_version: 4
|
375
392
|
summary: Webspicy helps testing web services as software operation black boxes!
|
376
393
|
test_files: []
|