webspicy 0.1.0.pre.rc1
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 +7 -0
- data/Gemfile +2 -0
- data/LICENSE.md +22 -0
- data/README.md +7 -0
- data/Rakefile +11 -0
- data/examples/restful/Gemfile +5 -0
- data/examples/restful/Gemfile.lock +69 -0
- data/examples/restful/Rakefile +21 -0
- data/examples/restful/app.rb +32 -0
- data/examples/restful/webspicy/schema.fio +4 -0
- data/examples/restful/webspicy/todo/getTodo.yml +52 -0
- data/examples/restful/webspicy/todo/getTodos.yml +39 -0
- data/lib/webspicy/checker.rb +26 -0
- data/lib/webspicy/client/http_client.rb +70 -0
- data/lib/webspicy/client.rb +20 -0
- data/lib/webspicy/configuration.rb +168 -0
- data/lib/webspicy/formaldoc.fio +47 -0
- data/lib/webspicy/resource/service/invocation.rb +158 -0
- data/lib/webspicy/resource/service/test_case.rb +74 -0
- data/lib/webspicy/resource/service.rb +49 -0
- data/lib/webspicy/resource.rb +43 -0
- data/lib/webspicy/scope.rb +113 -0
- data/lib/webspicy/tester/asserter.rb +94 -0
- data/lib/webspicy/tester/assertions.rb +103 -0
- data/lib/webspicy/tester.rb +96 -0
- data/lib/webspicy/version.rb +8 -0
- data/lib/webspicy.rb +112 -0
- data/spec/unit/resource/service/test_dress_params.rb +34 -0
- data/spec/unit/resource/test_instantiate_url.rb +20 -0
- data/spec/unit/resource/test_url_placeholders.rb +16 -0
- data/spec/unit/scope/test_each_resource.rb +59 -0
- data/spec/unit/scope/test_each_service.rb +51 -0
- data/spec/unit/scope/test_to_real_url.rb +75 -0
- data/spec/unit/spec_helper.rb +28 -0
- data/spec/unit/test_configuration.rb +84 -0
- data/spec/unit/tester/test_assertions.rb +108 -0
- data/tasks/test.rake +27 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b34d2485758616a81425a1f39fd0e5350fea1799
|
4
|
+
data.tar.gz: 8756493dea8e750857c172399dcebe2edcc2a76b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ee96045a18f309ca39859a8459cc2cf11b1dd02d3fbc9a45186f7f5ef45af46b5121f5626303e52eca886196b8baa0eb34c17e57702e5408514092a78c089de
|
7
|
+
data.tar.gz: 83db0b47519892d12acc7b73ff4bf2ec97642ffebb680d2f0535915c6f11321172656a0dee2ddd62c33317cd9045b0bb8104f28a997f9c7f92c2293fe39a009f
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The MIT Licence
|
2
|
+
|
3
|
+
Copyright (c) 2017 - Enspirit SPRL (Bernard Lambeau)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
webspicy (0.0.1)
|
5
|
+
finitio (~> 0.5.2)
|
6
|
+
http (~> 0.5)
|
7
|
+
path (~> 1.3)
|
8
|
+
rspec (~> 3.6)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
addressable (2.5.1)
|
14
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
15
|
+
citrus (3.0.2)
|
16
|
+
diff-lcs (1.3)
|
17
|
+
domain_name (0.5.20170404)
|
18
|
+
unf (>= 0.0.5, < 1.0.0)
|
19
|
+
finitio (0.5.2)
|
20
|
+
citrus (>= 2.4, < 4.0)
|
21
|
+
http (0.9.9)
|
22
|
+
addressable (~> 2.3)
|
23
|
+
http-cookie (~> 1.0)
|
24
|
+
http-form_data (~> 1.0.1)
|
25
|
+
http_parser.rb (~> 0.6.0)
|
26
|
+
http-cookie (1.0.3)
|
27
|
+
domain_name (~> 0.5)
|
28
|
+
http-form_data (1.0.3)
|
29
|
+
http_parser.rb (0.6.0)
|
30
|
+
mustermann (1.0.0)
|
31
|
+
path (1.3.3)
|
32
|
+
public_suffix (2.0.5)
|
33
|
+
rack (2.0.3)
|
34
|
+
rack-protection (2.0.0)
|
35
|
+
rack
|
36
|
+
rake (10.5.0)
|
37
|
+
rspec (3.6.0)
|
38
|
+
rspec-core (~> 3.6.0)
|
39
|
+
rspec-expectations (~> 3.6.0)
|
40
|
+
rspec-mocks (~> 3.6.0)
|
41
|
+
rspec-core (3.6.0)
|
42
|
+
rspec-support (~> 3.6.0)
|
43
|
+
rspec-expectations (3.6.0)
|
44
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
45
|
+
rspec-support (~> 3.6.0)
|
46
|
+
rspec-mocks (3.6.0)
|
47
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
48
|
+
rspec-support (~> 3.6.0)
|
49
|
+
rspec-support (3.6.0)
|
50
|
+
sinatra (2.0.0)
|
51
|
+
mustermann (~> 1.0)
|
52
|
+
rack (~> 2.0)
|
53
|
+
rack-protection (= 2.0.0)
|
54
|
+
tilt (~> 2.0)
|
55
|
+
tilt (2.0.7)
|
56
|
+
unf (0.1.4)
|
57
|
+
unf_ext
|
58
|
+
unf_ext (0.0.7.4)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
ruby
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
rake (~> 10)
|
65
|
+
sinatra (~> 2.0)
|
66
|
+
webspicy!
|
67
|
+
|
68
|
+
BUNDLED WITH
|
69
|
+
1.14.6
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'webspicy'
|
2
|
+
|
3
|
+
namespace :webspicy do
|
4
|
+
|
5
|
+
config = Webspicy::Configuration.new do |c|
|
6
|
+
c.host = "http://127.0.0.1:4567"
|
7
|
+
c.add_folder Path.dir/"webspicy"
|
8
|
+
end
|
9
|
+
|
10
|
+
task :check do
|
11
|
+
Webspicy::Checker.new(config).call
|
12
|
+
end
|
13
|
+
|
14
|
+
task :test do
|
15
|
+
Webspicy::Tester.new(config).call
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
task :test => :"webspicy:test"
|
21
|
+
task :default => :test
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
TODOLIST = [
|
5
|
+
{
|
6
|
+
id: 1,
|
7
|
+
description: "Refactor the framework"
|
8
|
+
},
|
9
|
+
{
|
10
|
+
id: 2,
|
11
|
+
description: "Write documentation"
|
12
|
+
}
|
13
|
+
]
|
14
|
+
|
15
|
+
disable :show_exceptions
|
16
|
+
enable :raise_errors
|
17
|
+
|
18
|
+
get '/todo/' do
|
19
|
+
content_type :json
|
20
|
+
TODOLIST.to_json
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/todo/:id' do |id|
|
24
|
+
content_type :json
|
25
|
+
todo = TODOLIST.find{|todo| todo[:id] == Integer(id) }
|
26
|
+
if todo.nil?
|
27
|
+
status 404
|
28
|
+
{error: "No such todo"}.to_json
|
29
|
+
else
|
30
|
+
todo.to_json
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
name: |-
|
3
|
+
Todo
|
4
|
+
|
5
|
+
url: |-
|
6
|
+
/todo/{id}
|
7
|
+
|
8
|
+
services:
|
9
|
+
- method: |-
|
10
|
+
GET
|
11
|
+
|
12
|
+
description: |-
|
13
|
+
Returns a single todo item
|
14
|
+
|
15
|
+
preconditions: |-
|
16
|
+
|
17
|
+
input_schema: |-
|
18
|
+
{
|
19
|
+
id: Integer
|
20
|
+
}
|
21
|
+
|
22
|
+
output_schema: |-
|
23
|
+
Todo
|
24
|
+
|
25
|
+
error_schema: |-
|
26
|
+
{
|
27
|
+
error: String
|
28
|
+
}
|
29
|
+
|
30
|
+
examples:
|
31
|
+
|
32
|
+
- description: |-
|
33
|
+
when requested on an existing TODO
|
34
|
+
params:
|
35
|
+
id: 1
|
36
|
+
expected:
|
37
|
+
content_type: application/json
|
38
|
+
status: 200
|
39
|
+
assert:
|
40
|
+
- "pathFD('', id: 1)"
|
41
|
+
|
42
|
+
counterexamples:
|
43
|
+
|
44
|
+
- description: |-
|
45
|
+
when requested on an unexisting TODO
|
46
|
+
params:
|
47
|
+
id: 999254654
|
48
|
+
expected:
|
49
|
+
content_type: application/json
|
50
|
+
status: 404
|
51
|
+
assert:
|
52
|
+
- "pathFD('', error: 'No such todo')"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
---
|
2
|
+
name: |-
|
3
|
+
Todo
|
4
|
+
|
5
|
+
url: |-
|
6
|
+
/todo/
|
7
|
+
|
8
|
+
services:
|
9
|
+
- method: |-
|
10
|
+
GET
|
11
|
+
|
12
|
+
description: |-
|
13
|
+
Returns the list of todo items
|
14
|
+
|
15
|
+
preconditions: |-
|
16
|
+
|
17
|
+
input_schema: |-
|
18
|
+
{
|
19
|
+
}
|
20
|
+
|
21
|
+
output_schema: |-
|
22
|
+
[Todo]
|
23
|
+
|
24
|
+
error_schema: |-
|
25
|
+
{
|
26
|
+
}
|
27
|
+
|
28
|
+
examples:
|
29
|
+
|
30
|
+
- description: |-
|
31
|
+
when requested
|
32
|
+
params: {}
|
33
|
+
expected:
|
34
|
+
content_type: application/json
|
35
|
+
status: 200
|
36
|
+
assert:
|
37
|
+
- notEmpty
|
38
|
+
|
39
|
+
counterexamples: []
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class Checker
|
3
|
+
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
end
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def call
|
10
|
+
Webspicy.with_scope_for(config) do |scope|
|
11
|
+
client = scope.get_client
|
12
|
+
scope.each_resource_file do |file, folder|
|
13
|
+
RSpec.describe file.relative_to(folder).to_s do
|
14
|
+
|
15
|
+
it 'meets the formal doc data schema' do
|
16
|
+
Webspicy.resource(file.load, file)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
RSpec::Core::Runner.run config.rspec_options
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class HttpClient < Client
|
3
|
+
|
4
|
+
def call(test_case, service, resource)
|
5
|
+
# Instantiate the parameters
|
6
|
+
headers = test_case.headers
|
7
|
+
params = test_case.dress_params? ? service.dress_params(test_case.params) : test_case.params
|
8
|
+
|
9
|
+
# Instantiate the url and strip parameters
|
10
|
+
url, params = resource.instantiate_url(params)
|
11
|
+
|
12
|
+
# Globalize the URL if required
|
13
|
+
url = scope.to_real_url(url)
|
14
|
+
|
15
|
+
# Invoke the service now
|
16
|
+
api = Api.new
|
17
|
+
api.public_send(service.method.to_s.downcase.to_sym, url, params, headers)
|
18
|
+
|
19
|
+
# Return the result
|
20
|
+
Resource::Service::Invocation.new(service, test_case, api.last_response)
|
21
|
+
end
|
22
|
+
|
23
|
+
class Api
|
24
|
+
|
25
|
+
attr_reader :last_response
|
26
|
+
|
27
|
+
def get(url, params, headers = nil)
|
28
|
+
headers, url = headers_and_url_for(url, params, headers)
|
29
|
+
|
30
|
+
Webspicy.info("GET #{url} -- #{params.inspect}")
|
31
|
+
|
32
|
+
@last_response = HTTP[headers].get(url, params: params)
|
33
|
+
|
34
|
+
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
35
|
+
Webspicy.debug("Response: #{@last_response.body}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def post(url, params, headers = nil)
|
39
|
+
headers, url = headers_and_url_for(url, params, headers)
|
40
|
+
|
41
|
+
Webspicy.info("POST #{url} -- #{params.inspect}")
|
42
|
+
|
43
|
+
@last_response = HTTP[headers].post(url, body: params.to_json)
|
44
|
+
|
45
|
+
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
46
|
+
Webspicy.debug("Response: #{@last_response.body}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def post_form(url, params, headers = nil)
|
50
|
+
headers, url = headers_and_url_for(url, params, headers)
|
51
|
+
|
52
|
+
Webspicy.info("POST #{url} -- #{params.inspect}")
|
53
|
+
|
54
|
+
@last_response = HTTP[headers].post(url, form: params)
|
55
|
+
|
56
|
+
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
57
|
+
Webspicy.debug("Response: #{@last_response.body}")
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def headers_and_url_for(url, params, headers)
|
63
|
+
headers = headers || {}
|
64
|
+
[ headers, url ]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class Client
|
3
|
+
|
4
|
+
def initialize(scope)
|
5
|
+
@scope = scope
|
6
|
+
end
|
7
|
+
attr_reader :scope
|
8
|
+
|
9
|
+
def config
|
10
|
+
scope.config
|
11
|
+
end
|
12
|
+
|
13
|
+
def before(*args, &bl)
|
14
|
+
config.before_listeners.each do |beach|
|
15
|
+
beach.call(*args, &bl)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Webspicy
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@folders = []
|
6
|
+
@before_listeners = []
|
7
|
+
@rspec_options = default_rspec_options
|
8
|
+
@run_counterexamples = default_run_counterexamples
|
9
|
+
@file_filter = default_file_filter
|
10
|
+
@service_filter = default_service_filter
|
11
|
+
@client = HttpClient
|
12
|
+
yield(self) if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
# Adds a folder to the list of folders where test case definitions are
|
16
|
+
# to be found.
|
17
|
+
def add_folder(folder)
|
18
|
+
folder = Path(folder)
|
19
|
+
raise "Folder `#{folder}` does not exists" unless folder.exists? && folder.directory?
|
20
|
+
@folders << folder
|
21
|
+
end
|
22
|
+
attr_reader :folders
|
23
|
+
|
24
|
+
# Sets whether counter examples have to be ran or not.
|
25
|
+
def run_counterexamples=(run_counterexamples)
|
26
|
+
@run_counterexamples = run_counterexamples
|
27
|
+
end
|
28
|
+
attr_reader :run_counterexamples
|
29
|
+
|
30
|
+
# Whether counter examples must be ran or not.
|
31
|
+
def run_counterexamples?
|
32
|
+
@run_counterexamples
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the defaut value for run_counterexamples
|
36
|
+
def default_run_counterexamples
|
37
|
+
ENV['ROBUST'].nil? || ENV['ROBUST'] != 'no'
|
38
|
+
end
|
39
|
+
private :default_run_counterexamples
|
40
|
+
|
41
|
+
# Installs a host (resolver).
|
42
|
+
#
|
43
|
+
# The host resolver is responsible from transforming URLs found in
|
44
|
+
# .yml test files to an absolute URL invoked by the client. Supported
|
45
|
+
# values are:
|
46
|
+
#
|
47
|
+
# - String: taken as a prefix for all relative URLs. Using this option
|
48
|
+
# lets specify all webservices through relative URLs and having the
|
49
|
+
# host itself as global configuration variable.
|
50
|
+
# - Proc: all URLs are passed to the proc, relative and absolute ones.
|
51
|
+
# The result of the proc is used as URL to use in practice.
|
52
|
+
#
|
53
|
+
# When no host provider is provided, all URLs are expected to be absolute
|
54
|
+
# URLs, otherwise an error will be thrown at runtime.
|
55
|
+
def host=(host)
|
56
|
+
@host = host
|
57
|
+
end
|
58
|
+
attr_reader :host
|
59
|
+
|
60
|
+
# Installs a file filter.
|
61
|
+
#
|
62
|
+
# A file filter can be added to restrict the scope attention only to the
|
63
|
+
# files that match the filter installed. Supported values are:
|
64
|
+
#
|
65
|
+
# - Proc: each file (a Path instance) is passed in turn. Only files for
|
66
|
+
# which a truthy value is returned will be considered by the scope.
|
67
|
+
# - Regexp: the path of each file is matched against the regexp. Only files
|
68
|
+
# that match are considered by the scope.
|
69
|
+
# - ===: any instance responding to `===` can be used as a matcher, following
|
70
|
+
# Ruby conventions. The match is done on a Path instance.
|
71
|
+
#
|
72
|
+
def file_filter=(file_filter)
|
73
|
+
@file_filter = file_filter
|
74
|
+
end
|
75
|
+
attr_reader :file_filter
|
76
|
+
|
77
|
+
# Returns the default file filter to use.
|
78
|
+
#
|
79
|
+
# By default no file filter is set, unless a RESOURCE environment variable is
|
80
|
+
# set. In that case, a file filter is set that matches the file name to the
|
81
|
+
# variable value, through a regular expression.
|
82
|
+
def default_file_filter
|
83
|
+
ENV['RESOURCE'] ? Regexp.compile(ENV['RESOURCE']) : nil
|
84
|
+
end
|
85
|
+
private :default_file_filter
|
86
|
+
|
87
|
+
# Installs a service filter.
|
88
|
+
#
|
89
|
+
# A service filter can be added to restrict the scope attention only to the
|
90
|
+
# services that match the filter installed. Supported values are:
|
91
|
+
#
|
92
|
+
# - Proc: each service is passed in turn. Only services for which a truthy value
|
93
|
+
# is returned will be considered by the scope.
|
94
|
+
# - ===: any instance responding to `===` can be used as a matcher, following
|
95
|
+
# Ruby conventions. The match is done on a Service instance.
|
96
|
+
#
|
97
|
+
def service_filter=(service_filter)
|
98
|
+
@service_filter = service_filter
|
99
|
+
end
|
100
|
+
attr_reader :service_filter
|
101
|
+
|
102
|
+
# Returns the default service filters.
|
103
|
+
#
|
104
|
+
# By default no filter is set unless a METHOD environment variable is set.
|
105
|
+
# In that case, a service filter is returned that filters the services whose
|
106
|
+
# HTTP method match the variable value.
|
107
|
+
def default_service_filter
|
108
|
+
ENV['METHOD'] ? ->(s){ s.method.to_s.downcase == ENV['METHOD'].downcase } : nil
|
109
|
+
end
|
110
|
+
private :default_service_filter
|
111
|
+
|
112
|
+
|
113
|
+
# Installs a client class to use to invoke web services for real.
|
114
|
+
#
|
115
|
+
# This configuration allows defining a subclass of Client to be used for
|
116
|
+
# actually invoking web services. Options are:
|
117
|
+
#
|
118
|
+
# - HttpClient: Uses the HTTP library to make real HTTP call to a web server.
|
119
|
+
#
|
120
|
+
# Note that this configuration variable expected a client *class*, not an
|
121
|
+
# instance
|
122
|
+
def client=(client)
|
123
|
+
@client = client
|
124
|
+
end
|
125
|
+
attr_reader :client
|
126
|
+
|
127
|
+
# Installs a listener that will be called before each web service invocation.
|
128
|
+
#
|
129
|
+
# The `listener` must respond to `call`.
|
130
|
+
def before_each(&listener)
|
131
|
+
raise "Must respond to call" unless listener.respond_to?(:call)
|
132
|
+
@before_listeners << listener
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the list of listeners that must be called before each web service
|
136
|
+
# invocation.
|
137
|
+
def before_listeners
|
138
|
+
@before_listeners
|
139
|
+
end
|
140
|
+
|
141
|
+
# Allows setting the options passed at RSpec, which is used by both the runner
|
142
|
+
# and checker classes.
|
143
|
+
#
|
144
|
+
# `options` is supposed to be valid RSpec options, to be passed at
|
145
|
+
# `RSpec::Core::Runner.run`
|
146
|
+
def rspec_options=(options)
|
147
|
+
@rspec_options = options
|
148
|
+
end
|
149
|
+
attr_reader :rspec_options
|
150
|
+
|
151
|
+
# Returns the default rspec options.
|
152
|
+
#
|
153
|
+
# By default rspec colors are enabled and the format set to 'documentation'.
|
154
|
+
# The following environment variables <-> rspec options are supported:
|
155
|
+
#
|
156
|
+
# - FAILFAST <-> --fail-fast
|
157
|
+
#
|
158
|
+
def default_rspec_options
|
159
|
+
options = ["--color", "--format=documentation"]
|
160
|
+
if ENV['FAILFAST']
|
161
|
+
options << (ENV['FAILFAST'] == 'no' ? "--no-fail-fast" : "--fail-fast=#{ENV['FAILFAST']}")
|
162
|
+
end
|
163
|
+
options
|
164
|
+
end
|
165
|
+
private :default_rspec_options
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
Method =
|
2
|
+
String( s | s =~ /^(GET|POST|POST_FORM|PUT|DELETE|PATCH)$/ )
|
3
|
+
|
4
|
+
Schema =
|
5
|
+
.Finitio::System <fio> String
|
6
|
+
\( s | ::Webspicy.schema(s) )
|
7
|
+
\( s | raise "Unsupported" )
|
8
|
+
|
9
|
+
Resource =
|
10
|
+
.Webspicy::Resource <info> {
|
11
|
+
name: String
|
12
|
+
url: String
|
13
|
+
services: [Service]
|
14
|
+
}
|
15
|
+
|
16
|
+
Service =
|
17
|
+
.Webspicy::Resource::Service <info> {
|
18
|
+
method : Method
|
19
|
+
description : String
|
20
|
+
preconditions : String
|
21
|
+
postconditions :? String
|
22
|
+
input_schema : Schema
|
23
|
+
output_schema : Schema
|
24
|
+
error_schema : Schema
|
25
|
+
blackbox :? String
|
26
|
+
examples :? [TestCase]
|
27
|
+
counterexamples :? [TestCase]
|
28
|
+
}
|
29
|
+
|
30
|
+
TestCase =
|
31
|
+
.Webspicy::Resource::Service::TestCase <info> {
|
32
|
+
description : String
|
33
|
+
dress_params :? Boolean
|
34
|
+
params : Params
|
35
|
+
headers :? .Hash
|
36
|
+
seeds :? String
|
37
|
+
requester :? String
|
38
|
+
expected: {
|
39
|
+
status : Integer
|
40
|
+
content_type :? String
|
41
|
+
error :? String
|
42
|
+
headers :? .Hash
|
43
|
+
}
|
44
|
+
assert :? [String]
|
45
|
+
}
|
46
|
+
|
47
|
+
Params = .Array|.Hash
|