webspicy 0.20.4 → 0.20.9
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/webspicy +2 -2
- data/lib/finitio/webspicy/shared.fio +10 -0
- data/lib/webspicy.rb +22 -53
- data/lib/webspicy/configuration.rb +3 -1
- data/lib/webspicy/configuration/scope.rb +2 -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 +5 -56
- data/lib/webspicy/specification/service.rb +1 -5
- data/lib/webspicy/specification/test_case.rb +0 -49
- data/lib/webspicy/support/colorize.rb +1 -1
- data/lib/webspicy/tester.rb +5 -3
- data/lib/webspicy/tester/fakesmtp.rb +1 -1
- data/lib/webspicy/tester/fakesmtp/email.rb +13 -0
- data/lib/webspicy/tester/file_checker.rb +1 -1
- data/lib/webspicy/tester/reporter.rb +2 -1
- data/lib/webspicy/tester/reporter/documentation.rb +11 -5
- data/lib/webspicy/tester/reporter/exceptions.rb +3 -1
- data/lib/webspicy/tester/reporter/junit_xml_file.rb +151 -0
- data/lib/webspicy/tester/reporter/progress.rb +1 -1
- data/lib/webspicy/tester/reporter/success_or_not.rb +14 -0
- data/lib/webspicy/tester/reporter/summary.rb +6 -2
- data/lib/webspicy/tester/result.rb +1 -0
- 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/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 +5 -1
- metadata +40 -23
- data/lib/webspicy/specification/file_upload.rb +0 -37
- data/lib/webspicy/tester/reporter/error_count.rb +0 -29
- data/spec/blackbox/commandline.yml +0 -24
- data/spec/blackbox/fixtures/passing/config.rb +0 -9
- data/spec/blackbox/fixtures/passing/formaldef/get.yml +0 -30
- 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: 0bdf5cfac3023b3a121368cd16c4b36df8cc212b6093672c836fbb2c392e5d68
|
4
|
+
data.tar.gz: 3506d6e9ec23a6d21299dcabf2564b1d643a49cf58ba853d6263763838d8efe7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c84f0fde9c02350d61969503fd93fa139dc2b39bd377f800597adfae760bfb60b25a83894bac2642b75029c67963a3293a463eed4c00eb85491920a8bd53af4
|
7
|
+
data.tar.gz: f215620b9e9a0b7346c09b1ef1a1d1e3acac1f28f57df64ea0864156ceb9e9a7a888bddb4b67462255efc1a15f9860af368fbe510f148ea09871526e90da79fa
|
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|
|
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
|
@@ -39,6 +39,7 @@ module Webspicy
|
|
39
39
|
:success => :green
|
40
40
|
}
|
41
41
|
@colorize = true
|
42
|
+
@factory = Webspicy::Web
|
42
43
|
@scope_factory = ->(config){ Scope.new(config) }
|
43
44
|
@client = Web::HttpClient
|
44
45
|
@reporter = default_reporter
|
@@ -109,6 +110,7 @@ module Webspicy
|
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
113
|
+
attr_accessor :factory
|
112
114
|
attr_accessor :scope_factory
|
113
115
|
|
114
116
|
def factor_scope
|
@@ -445,7 +447,7 @@ module Webspicy
|
|
445
447
|
@reporter << Tester::Reporter::Documentation.new
|
446
448
|
@reporter << Tester::Reporter::Exceptions.new
|
447
449
|
@reporter << Tester::Reporter::Summary.new
|
448
|
-
@reporter << Tester::Reporter::
|
450
|
+
@reporter << Tester::Reporter::SuccessOrNot.new
|
449
451
|
end
|
450
452
|
attr_accessor :reporter
|
451
453
|
|
@@ -35,7 +35,7 @@ module Webspicy
|
|
35
35
|
def each_specification(apply_filter = true, &bl)
|
36
36
|
return enum_for(:each_specification, apply_filter) unless block_given?
|
37
37
|
each_specification_file(apply_filter) do |file, folder|
|
38
|
-
yield
|
38
|
+
yield config.factory.specification(file.load, file, self)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -138,7 +138,7 @@ module Webspicy
|
|
138
138
|
return example unless service.default_example
|
139
139
|
h1 = service.default_example.to_info
|
140
140
|
h2 = example.to_info
|
141
|
-
ex =
|
141
|
+
ex = config.factory.test_case(merge_maps(h1, h2), self)
|
142
142
|
ex.bind(service, example.counterexample?)
|
143
143
|
end
|
144
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,25 +10,14 @@ 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
|
31
16
|
|
17
|
+
def relative_location
|
18
|
+
@location && @location.relative_to(config.folder)
|
19
|
+
end
|
20
|
+
|
32
21
|
def locate(relative_path)
|
33
22
|
file = @location.parent/relative_path
|
34
23
|
raise "File not found: #{file}" unless file.exists?
|
@@ -36,54 +25,15 @@ module Webspicy
|
|
36
25
|
end
|
37
26
|
|
38
27
|
def name
|
39
|
-
@raw[:name]
|
40
|
-
end
|
41
|
-
|
42
|
-
def url
|
43
|
-
@raw[:url]
|
44
|
-
end
|
45
|
-
|
46
|
-
def url_pattern
|
47
|
-
@url_pattern ||= Mustermann.new(url, type: :template)
|
28
|
+
@raw[:name] || relative_location || "Unnamed"
|
48
29
|
end
|
49
30
|
|
50
31
|
def services
|
51
32
|
@raw[:services] || []
|
52
33
|
end
|
53
34
|
|
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
35
|
private
|
72
36
|
|
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
37
|
def bind_services
|
88
38
|
services.each do |s|
|
89
39
|
s.specification = self
|
@@ -99,4 +49,3 @@ require_relative 'specification/post'
|
|
99
49
|
require_relative 'specification/err'
|
100
50
|
require_relative 'specification/oldies'
|
101
51
|
require_relative 'specification/test_case'
|
102
|
-
require_relative 'specification/file_upload'
|
@@ -21,10 +21,6 @@ module Webspicy
|
|
21
21
|
specification.config
|
22
22
|
end
|
23
23
|
|
24
|
-
def method
|
25
|
-
@raw[:method]
|
26
|
-
end
|
27
|
-
|
28
24
|
def description
|
29
25
|
@raw[:description]
|
30
26
|
end
|
@@ -68,7 +64,7 @@ module Webspicy
|
|
68
64
|
def generated_counterexamples
|
69
65
|
preconditions.map{|pre|
|
70
66
|
pre.counterexamples(self).map{|tc|
|
71
|
-
tc =
|
67
|
+
tc = config.factory.test_case(tc, Webspicy.current_scope)
|
72
68
|
tc.bind(self, true)
|
73
69
|
}
|
74
70
|
}.flatten
|
@@ -43,10 +43,6 @@ module Webspicy
|
|
43
43
|
@raw[:seeds]
|
44
44
|
end
|
45
45
|
|
46
|
-
def headers
|
47
|
-
@raw[:headers] ||= {}
|
48
|
-
end
|
49
|
-
|
50
46
|
def metadata
|
51
47
|
@raw[:metadata] ||= {}
|
52
48
|
end
|
@@ -55,47 +51,10 @@ module Webspicy
|
|
55
51
|
@raw[:tags] ||= []
|
56
52
|
end
|
57
53
|
|
58
|
-
def dress_params
|
59
|
-
@raw.fetch(:dress_params){ true }
|
60
|
-
end
|
61
|
-
alias :dress_params? :dress_params
|
62
|
-
|
63
|
-
def params
|
64
|
-
@raw[:params] || {}
|
65
|
-
end
|
66
|
-
|
67
|
-
def body
|
68
|
-
@raw[:body]
|
69
|
-
end
|
70
|
-
|
71
|
-
def file_upload
|
72
|
-
@raw[:file_upload]
|
73
|
-
end
|
74
|
-
|
75
|
-
def located_file_upload
|
76
|
-
file_upload ? file_upload.locate(specification) : nil
|
77
|
-
end
|
78
|
-
|
79
54
|
def expected
|
80
55
|
@raw[:expected] || {}
|
81
56
|
end
|
82
57
|
|
83
|
-
def expected_content_type
|
84
|
-
expected[:content_type]
|
85
|
-
end
|
86
|
-
|
87
|
-
def expected_status
|
88
|
-
expected[:status]
|
89
|
-
end
|
90
|
-
|
91
|
-
def is_expected_status?(status)
|
92
|
-
expected_status === status
|
93
|
-
end
|
94
|
-
|
95
|
-
def has_expected_status?
|
96
|
-
not expected[:status].nil?
|
97
|
-
end
|
98
|
-
|
99
58
|
def expected_error
|
100
59
|
expected[:error]
|
101
60
|
end
|
@@ -104,14 +63,6 @@ module Webspicy
|
|
104
63
|
!expected_error.nil?
|
105
64
|
end
|
106
65
|
|
107
|
-
def expected_headers
|
108
|
-
expected[:headers] || {}
|
109
|
-
end
|
110
|
-
|
111
|
-
def has_expected_headers?
|
112
|
-
!expected_headers.empty?
|
113
|
-
end
|
114
|
-
|
115
66
|
def assert
|
116
67
|
@raw[:assert] || []
|
117
68
|
end
|