webspicy 0.20.1 → 0.20.6
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/bin/sandr +14 -0
- data/bin/search +2 -0
- data/bin/webspicy +3 -4
- data/lib/finitio/webspicy/shared.fio +10 -0
- data/lib/webspicy.rb +22 -53
- data/lib/webspicy/configuration.rb +17 -0
- data/lib/webspicy/configuration/scope.rb +3 -2
- data/lib/webspicy/configuration/single_url.rb +35 -25
- data/lib/webspicy/configuration/single_yml_file.rb +7 -2
- data/lib/webspicy/specification.rb +0 -55
- data/lib/webspicy/specification/oldies/bridge.rb +4 -1
- data/lib/webspicy/specification/post/missing_condition_impl.rb +2 -2
- data/lib/webspicy/specification/post/unexpected_condition_impl.rb +2 -2
- data/lib/webspicy/specification/service.rb +4 -5
- data/lib/webspicy/specification/test_case.rb +3 -49
- data/lib/webspicy/support/colorize.rb +7 -1
- data/lib/webspicy/tester.rb +21 -20
- data/lib/webspicy/tester/assertions.rb +2 -2
- data/lib/webspicy/tester/fakesmtp/email.rb +13 -0
- data/lib/webspicy/tester/reporter.rb +5 -0
- data/lib/webspicy/tester/reporter/documentation.rb +30 -8
- data/lib/webspicy/tester/reporter/error_count.rb +11 -7
- data/lib/webspicy/tester/reporter/file_progress.rb +2 -2
- data/lib/webspicy/tester/reporter/file_summary.rb +2 -2
- data/lib/webspicy/tester/reporter/progress.rb +4 -4
- data/lib/webspicy/tester/reporter/summary.rb +8 -7
- data/lib/webspicy/tester/result.rb +2 -2
- data/lib/webspicy/tester/result/errcondition_met.rb +1 -3
- data/lib/webspicy/tester/result/postcondition_met.rb +1 -3
- data/lib/webspicy/version.rb +1 -1
- data/lib/webspicy/web.rb +46 -0
- data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
- data/lib/webspicy/web/invocation.rb +1 -0
- data/lib/webspicy/web/specification.rb +68 -0
- data/lib/webspicy/web/specification/file_upload.rb +39 -0
- data/lib/webspicy/web/specification/service.rb +13 -0
- data/lib/webspicy/web/specification/test_case.rb +58 -0
- data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
- data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
- data/spec/unit/specification/service/test_dress_params.rb +2 -2
- data/spec/unit/test_configuration.rb +1 -0
- data/spec/unit/tester/fakesmtp/test_email.rb +93 -0
- data/spec/unit/web/specification/test_instantiate_url.rb +36 -0
- data/spec/unit/web/specification/test_url_placeholders.rb +23 -0
- data/tasks/test.rake +2 -1
- metadata +28 -19
- data/lib/webspicy/specification/file_upload.rb +0 -37
- data/spec/unit/specification/test_instantiate_url.rb +0 -34
- data/spec/unit/specification/test_url_placeholders.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 013055707cad05016cb794561d47a0408d39d6f462387c9eb66d31542ff2218c
|
4
|
+
data.tar.gz: b4c4778275ec96271b711ea0956c539fa35bf12b04d635fbc5062698996e7902
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcc079537f13b76af0e433c8591529824ea1e4f8b255f1411963e88cbd4df6953598504413dc8ad3da6db3005cf2c49867e80790594e3fb56cab039f2de450c7
|
7
|
+
data.tar.gz: e4479277fcec22a0928ae75a0120bc5c0a9644e73be6bb75a577dd33a42a03c445996b9b846a33bd20e6e439b4047a8f3ab4a418abb965777b4ce047e1824d7e
|
data/bin/sandr
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'path'
|
3
|
+
|
4
|
+
def sandr(file)
|
5
|
+
file.write file.read.gsub(ARGV[0], ARGV[1])
|
6
|
+
end
|
7
|
+
|
8
|
+
Path.dir.parent.glob("lib/**/*.rb") do |file|
|
9
|
+
sandr(file)
|
10
|
+
end
|
11
|
+
|
12
|
+
Path.dir.parent.glob("spec/**/*.rb") do |file|
|
13
|
+
sandr(file)
|
14
|
+
end
|
data/bin/search
ADDED
data/bin/webspicy
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#/
|
3
3
|
#/ Document & test web services as black-box operations.
|
4
|
-
#/ (c) Enspirit SRL. Distributed under MIT licence.
|
4
|
+
#/ Webspicy vVERSION, (c) Enspirit SRL. Distributed under MIT licence.
|
5
5
|
#/
|
6
6
|
#/ Usage: webspicy [options] URL # run default test againt url
|
7
7
|
#/ Usage: webspicy [options] path/to/config.rb # run whole test suite
|
@@ -28,7 +28,7 @@ require 'optparse'
|
|
28
28
|
|
29
29
|
def showhelp
|
30
30
|
file = __FILE__
|
31
|
-
exec "grep ^#/<'#{file}'|cut -c4
|
31
|
+
exec "grep ^#/<'#{file}'|cut -c4-|sed s/VERSION/#{Webspicy::VERSION}/g"
|
32
32
|
end
|
33
33
|
|
34
34
|
ARGV.options do |opts|
|
@@ -55,5 +55,4 @@ if ARGV.size != 1
|
|
55
55
|
end
|
56
56
|
|
57
57
|
config = Webspicy::Configuration.dress(ARGV[0])
|
58
|
-
|
59
|
-
abort("#{res} errors occured") unless res == 0
|
58
|
+
Webspicy::Tester.new(config).call!
|
data/lib/webspicy.rb
CHANGED
@@ -7,7 +7,7 @@ require 'ostruct'
|
|
7
7
|
require 'yaml'
|
8
8
|
require 'rack/test'
|
9
9
|
require 'mustermann'
|
10
|
-
require '
|
10
|
+
require 'paint'
|
11
11
|
require 'securerandom'
|
12
12
|
require 'forwardable'
|
13
13
|
module Webspicy
|
@@ -21,22 +21,10 @@ module Webspicy
|
|
21
21
|
require 'webspicy/specification'
|
22
22
|
require 'webspicy/configuration'
|
23
23
|
require 'webspicy/tester'
|
24
|
-
require 'webspicy/web'
|
25
24
|
|
26
25
|
class Error < StandardError; end
|
27
26
|
class TimeoutError < Error; end
|
28
27
|
|
29
|
-
###
|
30
|
-
### Backward compatibility
|
31
|
-
###
|
32
|
-
Client = Tester::Client
|
33
|
-
HttpClient = Web::HttpClient
|
34
|
-
RackTestClient = Web::RackTestClient
|
35
|
-
Resource = Specification
|
36
|
-
FileUpload = Specification::FileUpload
|
37
|
-
Scope = Configuration::Scope
|
38
|
-
Checker = Tester::FileChecker
|
39
|
-
|
40
28
|
###
|
41
29
|
### About folders
|
42
30
|
###
|
@@ -49,10 +37,11 @@ module Webspicy
|
|
49
37
|
### About formal doc and specifications defined there
|
50
38
|
###
|
51
39
|
Finitio.stdlib_path(Path.dir/"finitio")
|
40
|
+
|
52
41
|
DEFAULT_SYSTEM = Finitio.system(<<~FIO)
|
53
42
|
@import webspicy/scalars
|
54
43
|
FIO
|
55
|
-
|
44
|
+
|
56
45
|
|
57
46
|
###
|
58
47
|
### Exceptions that we let pass during testing
|
@@ -66,45 +55,6 @@ module Webspicy
|
|
66
55
|
end
|
67
56
|
module_function :default_scope
|
68
57
|
|
69
|
-
def specification(raw, file = nil, scope = default_scope)
|
70
|
-
raw = YAML.load(raw) if raw.is_a?(String)
|
71
|
-
with_scope(scope) do
|
72
|
-
r = FORMALDOC["Specification"].dress(raw)
|
73
|
-
r.config = scope.config
|
74
|
-
r.located_at!(file) if file
|
75
|
-
r
|
76
|
-
end
|
77
|
-
rescue Finitio::Error => ex
|
78
|
-
handle_finitio_error(ex, scope)
|
79
|
-
end
|
80
|
-
module_function :specification
|
81
|
-
|
82
|
-
def service(raw, scope = default_scope)
|
83
|
-
with_scope(scope) do
|
84
|
-
FORMALDOC["Service"].dress(raw)
|
85
|
-
end
|
86
|
-
rescue Finitio::Error => ex
|
87
|
-
handle_finitio_error(ex)
|
88
|
-
end
|
89
|
-
module_function :service
|
90
|
-
|
91
|
-
def test_case(raw, scope = default_scope)
|
92
|
-
with_scope(scope) do
|
93
|
-
FORMALDOC["TestCase"].dress(raw)
|
94
|
-
end
|
95
|
-
rescue Finitio::Error => ex
|
96
|
-
handle_finitio_error(ex)
|
97
|
-
end
|
98
|
-
module_function :test_case
|
99
|
-
|
100
|
-
def handle_finitio_error(ex, scope)
|
101
|
-
# msg = "#{ex.message}:\n #{ex.root_cause.message}"
|
102
|
-
# msg = Support::Colorize.colorize_error(msg, scope.config)
|
103
|
-
# fatal(msg)
|
104
|
-
raise
|
105
|
-
end
|
106
|
-
module_function :handle_finitio_error
|
107
|
-
|
108
58
|
#
|
109
59
|
# Yields the block after having installed `scope` globally.
|
110
60
|
#
|
@@ -185,4 +135,23 @@ module Webspicy
|
|
185
135
|
end
|
186
136
|
module_function :fatal
|
187
137
|
|
138
|
+
require 'webspicy/web'
|
139
|
+
|
140
|
+
###
|
141
|
+
### Backward compatibility
|
142
|
+
###
|
143
|
+
Client = Tester::Client
|
144
|
+
HttpClient = Web::HttpClient
|
145
|
+
RackTestClient = Web::RackTestClient
|
146
|
+
Resource = Specification
|
147
|
+
FileUpload = Web::Specification::FileUpload
|
148
|
+
Scope = Configuration::Scope
|
149
|
+
Checker = Tester::FileChecker
|
150
|
+
|
151
|
+
[:specification, :service, :test_case].each do |meth|
|
152
|
+
define_method(meth) do |*args, &bl|
|
153
|
+
Webspicy::Web.send(meth, *args, &bl)
|
154
|
+
end
|
155
|
+
module_function(meth)
|
156
|
+
end
|
188
157
|
end
|
@@ -33,12 +33,16 @@ module Webspicy
|
|
33
33
|
@service_filter = default_service_filter
|
34
34
|
@test_case_filter = default_test_case_filter
|
35
35
|
@colors = {
|
36
|
+
:section => :magenta,
|
36
37
|
:highlight => :cyan,
|
37
38
|
:error => :red,
|
38
39
|
:success => :green
|
39
40
|
}
|
41
|
+
@colorize = true
|
42
|
+
@factory = Webspicy::Web
|
40
43
|
@scope_factory = ->(config){ Scope.new(config) }
|
41
44
|
@client = Web::HttpClient
|
45
|
+
@reporter = default_reporter
|
42
46
|
Path.require_tree(@folder/'support') if (@folder/'support').exists?
|
43
47
|
@world = Support::World.new(folder/'world', self)
|
44
48
|
yield(self) if block_given?
|
@@ -47,6 +51,8 @@ module Webspicy
|
|
47
51
|
protected :folder=
|
48
52
|
|
49
53
|
attr_accessor :colors
|
54
|
+
attr_accessor :colorize
|
55
|
+
|
50
56
|
attr_reader :world
|
51
57
|
|
52
58
|
def self.dress(arg, &bl)
|
@@ -104,6 +110,7 @@ module Webspicy
|
|
104
110
|
end
|
105
111
|
end
|
106
112
|
|
113
|
+
attr_accessor :factory
|
107
114
|
attr_accessor :scope_factory
|
108
115
|
|
109
116
|
def factor_scope
|
@@ -434,6 +441,16 @@ module Webspicy
|
|
434
441
|
end
|
435
442
|
private :default_rspec_options
|
436
443
|
|
444
|
+
# Returns the default reporter to use.
|
445
|
+
def default_reporter
|
446
|
+
@reporter = Tester::Reporter::Composite.new
|
447
|
+
@reporter << Tester::Reporter::Documentation.new
|
448
|
+
@reporter << Tester::Reporter::Exceptions.new
|
449
|
+
@reporter << Tester::Reporter::Summary.new
|
450
|
+
@reporter << Tester::Reporter::ErrorCount.new
|
451
|
+
end
|
452
|
+
attr_accessor :reporter
|
453
|
+
|
437
454
|
# Returns the Data system to use for parsing schemas
|
438
455
|
#
|
439
456
|
# The data system associated with a configuration is build when the
|
@@ -23,6 +23,7 @@ module Webspicy
|
|
23
23
|
folder = config.folder
|
24
24
|
world = config.folder/"world"
|
25
25
|
fs = folder.glob("**/*.yml").reject{|f| f.to_s.start_with?(world.to_s) }
|
26
|
+
fs = fs.sort
|
26
27
|
fs = fs.select(&to_filter_proc(config.file_filter)) if apply_filter
|
27
28
|
fs.each do |file|
|
28
29
|
yield file, folder
|
@@ -34,7 +35,7 @@ module Webspicy
|
|
34
35
|
def each_specification(apply_filter = true, &bl)
|
35
36
|
return enum_for(:each_specification, apply_filter) unless block_given?
|
36
37
|
each_specification_file(apply_filter) do |file, folder|
|
37
|
-
yield
|
38
|
+
yield config.factory.specification(file.load, file, self)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -137,7 +138,7 @@ module Webspicy
|
|
137
138
|
return example unless service.default_example
|
138
139
|
h1 = service.default_example.to_info
|
139
140
|
h2 = example.to_info
|
140
|
-
ex =
|
141
|
+
ex = config.factory.test_case(merge_maps(h1, h2), self)
|
141
142
|
ex.bind(service, example.counterexample?)
|
142
143
|
end
|
143
144
|
|
@@ -10,37 +10,47 @@ module Webspicy
|
|
10
10
|
end
|
11
11
|
attr_reader :url
|
12
12
|
|
13
|
-
def
|
13
|
+
def each_specification_file(*args, &bl)
|
14
|
+
return enum_for(:each_specification_file) unless block_given?
|
15
|
+
yield Path.tempfile(["specification",".yml"]).tap{|f|
|
16
|
+
f.write(specification_src)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def each_specification(*args, &bl)
|
14
21
|
return enum_for(:each_specification) unless block_given?
|
15
|
-
|
22
|
+
yield config.factory.specification(specification_src, nil, self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def specification_src
|
26
|
+
<<~YML.tap{|s| Webspicy.debug(s) }
|
16
27
|
---
|
17
|
-
|
18
|
-
|
28
|
+
description: |-
|
29
|
+
Getting #{url}
|
30
|
+
|
19
31
|
url: |-
|
20
32
|
#{url}
|
21
33
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
method: |-
|
35
|
+
GET
|
36
|
+
|
37
|
+
input_schema: |-
|
38
|
+
Any
|
39
|
+
|
40
|
+
output_schema: |-
|
41
|
+
Any
|
42
|
+
|
43
|
+
error_schema: |-
|
44
|
+
Any
|
45
|
+
|
46
|
+
examples:
|
47
|
+
|
48
|
+
- description: |-
|
49
|
+
it returns a 200
|
50
|
+
params: {}
|
51
|
+
expected:
|
52
|
+
status: 200
|
41
53
|
YML
|
42
|
-
Webspicy.debug(spec)
|
43
|
-
yield Webspicy.specification(spec, nil, self)
|
44
54
|
end
|
45
55
|
|
46
56
|
end # class SingleUrlScope
|
@@ -10,9 +10,14 @@ module Webspicy
|
|
10
10
|
end
|
11
11
|
attr_reader :file
|
12
12
|
|
13
|
-
def
|
13
|
+
def each_specification_file(*args, &bl)
|
14
|
+
return enum_for(:each_specification_file) unless block_given?
|
15
|
+
yield(file)
|
16
|
+
end
|
17
|
+
|
18
|
+
def each_specification(*args, &bl)
|
14
19
|
return enum_for(:each_specification) unless block_given?
|
15
|
-
yield
|
20
|
+
yield config.factory.specification(file.read, nil, self)
|
16
21
|
end
|
17
22
|
|
18
23
|
end # class SingleYmlFileScope
|
@@ -10,21 +10,6 @@ module Webspicy
|
|
10
10
|
attr_accessor :config
|
11
11
|
attr_reader :location
|
12
12
|
|
13
|
-
def self.info(raw)
|
14
|
-
new(raw)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.singleservice(raw)
|
18
|
-
converted = {
|
19
|
-
name: raw[:name] || "Unamed specification",
|
20
|
-
url: raw[:url],
|
21
|
-
services: [
|
22
|
-
Webspicy.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
|
23
|
-
]
|
24
|
-
}
|
25
|
-
info(converted)
|
26
|
-
end
|
27
|
-
|
28
13
|
def located_at!(location)
|
29
14
|
@location = Path(location)
|
30
15
|
end
|
@@ -39,51 +24,12 @@ module Webspicy
|
|
39
24
|
@raw[:name]
|
40
25
|
end
|
41
26
|
|
42
|
-
def url
|
43
|
-
@raw[:url]
|
44
|
-
end
|
45
|
-
|
46
|
-
def url_pattern
|
47
|
-
@url_pattern ||= Mustermann.new(url, type: :template)
|
48
|
-
end
|
49
|
-
|
50
27
|
def services
|
51
28
|
@raw[:services] || []
|
52
29
|
end
|
53
30
|
|
54
|
-
def url_placeholders
|
55
|
-
url.scan(/\{([a-zA-Z]+(\.[a-zA-Z]+)*)\}/).map{|x| x.first }
|
56
|
-
end
|
57
|
-
|
58
|
-
def instantiate_url(params)
|
59
|
-
url, rest = self.url, params.dup
|
60
|
-
url_placeholders.each do |placeholder|
|
61
|
-
value, rest = extract_placeholder_value(rest, placeholder)
|
62
|
-
url = url.gsub("{#{placeholder}}", value.to_s)
|
63
|
-
end
|
64
|
-
[ url, rest ]
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_singleservice
|
68
|
-
raise NotImplementedError
|
69
|
-
end
|
70
|
-
|
71
31
|
private
|
72
32
|
|
73
|
-
def extract_placeholder_value(params, placeholder, split = nil)
|
74
|
-
return extract_placeholder_value(params, placeholder, placeholder.split(".")) unless split
|
75
|
-
|
76
|
-
key = [ split.first, split.first.to_sym ].find{|k| params.has_key?(k) }
|
77
|
-
raise "Missing URL parameter `#{placeholder}`" unless key
|
78
|
-
|
79
|
-
if split.size == 1
|
80
|
-
[ params[key], params.dup.delete_if{|k| k == key } ]
|
81
|
-
else
|
82
|
-
value, rest = extract_placeholder_value(params[key], placeholder, split[1..-1])
|
83
|
-
[ value, params.merge(key => rest) ]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
33
|
def bind_services
|
88
34
|
services.each do |s|
|
89
35
|
s.specification = self
|
@@ -99,4 +45,3 @@ require_relative 'specification/post'
|
|
99
45
|
require_relative 'specification/err'
|
100
46
|
require_relative 'specification/oldies'
|
101
47
|
require_relative 'specification/test_case'
|
102
|
-
require_relative 'specification/file_upload'
|
@@ -10,11 +10,14 @@ module Webspicy
|
|
10
10
|
attr_reader :target
|
11
11
|
|
12
12
|
def instrument
|
13
|
+
return unless target.respond_to?(:instrument)
|
13
14
|
target.instrument(test_case, client)
|
14
15
|
end
|
15
16
|
|
16
17
|
def check!
|
17
|
-
target.check
|
18
|
+
return unless target.respond_to?(:check)
|
19
|
+
res = target.check(invocation)
|
20
|
+
res ? fail!(res) : nil
|
18
21
|
end
|
19
22
|
|
20
23
|
def to_s
|