webspicy 0.4.2 → 0.5.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 +4 -4
- data/examples/restful/Gemfile +1 -0
- data/examples/restful/Gemfile.lock +8 -5
- data/examples/restful/app.rb +25 -0
- data/examples/restful/webspicy/schema.fio +9 -0
- data/examples/restful/webspicy/todo/deleteTodo.yml +1 -3
- data/examples/restful/webspicy/todo/getTodo.yml +1 -3
- data/examples/restful/webspicy/todo/getTodos.yml +1 -2
- data/examples/restful/webspicy/todo/patchTodo.yml +60 -0
- data/examples/restful/webspicy/todo/postTodos.yml +1 -3
- data/lib/webspicy/client/http_client.rb +20 -1
- data/lib/webspicy/client/rack_test_client.rb +26 -12
- data/lib/webspicy/resource/service/invocation.rb +3 -2
- data/lib/webspicy/resource/service/test_case.rb +1 -1
- data/lib/webspicy/scope.rb +7 -2
- data/lib/webspicy/version.rb +2 -2
- data/spec/unit/scope/test_to_real_url.rb +6 -1
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f7e458fbf3c7ac65bd95574e127f16791f56391
|
4
|
+
data.tar.gz: e2cdfa60d3e9ba3831bd49cb4a6931e675752eea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94edf71925034c01b1297c58e049f2f4729330c80e4db0e601e24f9409b6d609f88b24b8b8f8c707d3d6e52c7cf18dc137d948d4728e222e2305bf097ca1dfd8
|
7
|
+
data.tar.gz: a88aecd9681674821f4953e96519635f1a2a5d452abf100de57de0fd8d01b7121f54a72f97252384be4d23e2c93dcee5d6518f1b2ff1f1ef317d8e8de07c99b0
|
data/examples/restful/Gemfile
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
webspicy (0.
|
4
|
+
webspicy (0.5.0.pre.rc0)
|
5
5
|
finitio (~> 0.5.2)
|
6
6
|
http (~> 2)
|
7
7
|
path (~> 1.3)
|
8
|
+
rack-robustness (~> 1.1.0)
|
8
9
|
rack-test (~> 0.6.3)
|
9
10
|
rspec (~> 3.6)
|
10
11
|
|
11
12
|
GEM
|
12
13
|
remote: https://rubygems.org/
|
13
14
|
specs:
|
14
|
-
addressable (2.5.
|
15
|
-
public_suffix (
|
15
|
+
addressable (2.5.2)
|
16
|
+
public_suffix (>= 2.0.2, < 4.0)
|
16
17
|
citrus (3.0.2)
|
17
18
|
diff-lcs (1.3)
|
18
19
|
domain_name (0.5.20170404)
|
19
20
|
unf (>= 0.0.5, < 1.0.0)
|
20
21
|
finitio (0.5.2)
|
21
22
|
citrus (>= 2.4, < 4.0)
|
22
|
-
http (2.2.
|
23
|
+
http (2.2.2)
|
23
24
|
addressable (~> 2.3)
|
24
25
|
http-cookie (~> 1.0)
|
25
26
|
http-form_data (~> 1.0.1)
|
@@ -30,10 +31,11 @@ GEM
|
|
30
31
|
http_parser.rb (0.6.0)
|
31
32
|
mustermann (1.0.0)
|
32
33
|
path (1.3.3)
|
33
|
-
public_suffix (
|
34
|
+
public_suffix (3.0.0)
|
34
35
|
rack (2.0.3)
|
35
36
|
rack-protection (2.0.0)
|
36
37
|
rack
|
38
|
+
rack-robustness (1.1.0)
|
37
39
|
rack-test (0.6.3)
|
38
40
|
rack (>= 1.0)
|
39
41
|
rake (10.5.0)
|
@@ -66,6 +68,7 @@ PLATFORMS
|
|
66
68
|
DEPENDENCIES
|
67
69
|
finitio (~> 0.5.2)
|
68
70
|
path (~> 1.3)
|
71
|
+
rack-robustness (~> 1.1.0)
|
69
72
|
rake (~> 10)
|
70
73
|
sinatra (~> 2.0)
|
71
74
|
webspicy!
|
data/examples/restful/app.rb
CHANGED
@@ -2,6 +2,7 @@ require 'sinatra'
|
|
2
2
|
require 'json'
|
3
3
|
require 'path'
|
4
4
|
require 'finitio'
|
5
|
+
require 'rack/robustness'
|
5
6
|
|
6
7
|
SCHEMA = Finitio::DEFAULT_SYSTEM.parse (Path.dir/'webspicy/schema.fio').read
|
7
8
|
|
@@ -21,6 +22,15 @@ enable :raise_errors
|
|
21
22
|
|
22
23
|
set :todolist, TODOLIST.dup
|
23
24
|
|
25
|
+
use Rack::Robustness do |g|
|
26
|
+
g.no_catch_all
|
27
|
+
g.status 400
|
28
|
+
g.content_type 'application/json'
|
29
|
+
g.body{|ex| { error: ex.message }.to_json }
|
30
|
+
g.on(Finitio::TypeError)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
24
34
|
post '/reset' do
|
25
35
|
settings.todolist = TODOLIST.dup
|
26
36
|
status 200
|
@@ -56,6 +66,21 @@ get '/todo/:id' do |id|
|
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
69
|
+
patch '/todo/:id' do |id|
|
70
|
+
content_type :json
|
71
|
+
todo = settings.todolist.find{|todo| todo[:id] == Integer(id) }
|
72
|
+
if todo.nil?
|
73
|
+
status 404
|
74
|
+
{error: "No such todo"}.to_json
|
75
|
+
else
|
76
|
+
patch = SCHEMA["TodoPatch"].dress(JSON.load(request.body.read))
|
77
|
+
patched = todo.merge(patch)
|
78
|
+
settings.todolist = settings.todolist.reject{|todo| todo[:id] == Integer(id) }
|
79
|
+
settings.todolist << patched
|
80
|
+
patched.to_json
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
59
84
|
delete '/todo/:id' do |id|
|
60
85
|
content_type :json
|
61
86
|
todo = settings.todolist.find{|todo| todo[:id] == Integer(id) }
|
@@ -0,0 +1,60 @@
|
|
1
|
+
---
|
2
|
+
name: |-
|
3
|
+
Todo
|
4
|
+
|
5
|
+
url: |-
|
6
|
+
/todo/{id}
|
7
|
+
|
8
|
+
services:
|
9
|
+
- method: |-
|
10
|
+
PATCH
|
11
|
+
|
12
|
+
description: |-
|
13
|
+
Patches a single Todo item
|
14
|
+
|
15
|
+
preconditions: |-
|
16
|
+
|
17
|
+
input_schema: |-
|
18
|
+
TodoPatch
|
19
|
+
|
20
|
+
output_schema: |-
|
21
|
+
Todo
|
22
|
+
|
23
|
+
error_schema: |-
|
24
|
+
ErrorSchema
|
25
|
+
|
26
|
+
examples:
|
27
|
+
|
28
|
+
- description: |-
|
29
|
+
when requested on an existing TODO
|
30
|
+
params:
|
31
|
+
id: 1
|
32
|
+
description: 'hello world'
|
33
|
+
expected:
|
34
|
+
content_type: application/json
|
35
|
+
status: 200
|
36
|
+
assert:
|
37
|
+
- "pathFD('', description: 'hello world')"
|
38
|
+
|
39
|
+
counterexamples:
|
40
|
+
|
41
|
+
- description: |-
|
42
|
+
when requested on an unexisting TODO
|
43
|
+
params:
|
44
|
+
id: 999254654
|
45
|
+
expected:
|
46
|
+
content_type: application/json
|
47
|
+
status: 404
|
48
|
+
assert:
|
49
|
+
- "pathFD('', error: 'No such todo')"
|
50
|
+
|
51
|
+
- description: |-
|
52
|
+
when violating the Patch data type
|
53
|
+
params:
|
54
|
+
id: 1
|
55
|
+
nosuchone: 'foobar'
|
56
|
+
dress_params:
|
57
|
+
false
|
58
|
+
expected:
|
59
|
+
content_type: application/json
|
60
|
+
status: 400
|
@@ -24,7 +24,7 @@ module Webspicy
|
|
24
24
|
api.public_send(service.method.to_s.downcase.to_sym, url, params, headers)
|
25
25
|
|
26
26
|
# Return the result
|
27
|
-
Resource::Service::Invocation.new(service, test_case, api.last_response)
|
27
|
+
Resource::Service::Invocation.new(service, test_case, api.last_response, self)
|
28
28
|
end
|
29
29
|
|
30
30
|
class Api
|
@@ -38,6 +38,8 @@ module Webspicy
|
|
38
38
|
|
39
39
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
40
40
|
Webspicy.debug("Response: #{@last_response.body}")
|
41
|
+
|
42
|
+
@last_response
|
41
43
|
end
|
42
44
|
|
43
45
|
def post(url, params = {}, headers = nil)
|
@@ -47,6 +49,19 @@ module Webspicy
|
|
47
49
|
|
48
50
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
49
51
|
Webspicy.debug("Response: #{@last_response.body}")
|
52
|
+
|
53
|
+
@last_response
|
54
|
+
end
|
55
|
+
|
56
|
+
def patch(url, params = {}, headers = nil)
|
57
|
+
Webspicy.info("PATCH #{url} -- #{params.inspect}")
|
58
|
+
|
59
|
+
@last_response = HTTP[headers || {}].patch(url, body: params.to_json)
|
60
|
+
|
61
|
+
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
62
|
+
Webspicy.debug("Response: #{@last_response.body}")
|
63
|
+
|
64
|
+
@last_response
|
50
65
|
end
|
51
66
|
|
52
67
|
def post_form(url, params = {}, headers = nil)
|
@@ -56,6 +71,8 @@ module Webspicy
|
|
56
71
|
|
57
72
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
58
73
|
Webspicy.debug("Response: #{@last_response.body}")
|
74
|
+
|
75
|
+
@last_response
|
59
76
|
end
|
60
77
|
|
61
78
|
def delete(url, params = {}, headers = nil)
|
@@ -65,6 +82,8 @@ module Webspicy
|
|
65
82
|
|
66
83
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
67
84
|
Webspicy.debug("Response: #{@last_response.body}")
|
85
|
+
|
86
|
+
@last_response
|
68
87
|
end
|
69
88
|
|
70
89
|
end
|
@@ -5,13 +5,11 @@ module Webspicy
|
|
5
5
|
Factory.new(app)
|
6
6
|
end
|
7
7
|
|
8
|
-
def initialize(scope, app
|
8
|
+
def initialize(scope, app)
|
9
9
|
super(scope)
|
10
10
|
@api = Api.new(app)
|
11
|
-
@domain = domain
|
12
11
|
end
|
13
12
|
attr_reader :api
|
14
|
-
attr_reader :domain
|
15
13
|
|
16
14
|
def call(test_case)
|
17
15
|
service, resource = test_case.service, test_case.resource
|
@@ -22,13 +20,13 @@ module Webspicy
|
|
22
20
|
|
23
21
|
# Instantiate the url and strip parameters
|
24
22
|
url, params = resource.instantiate_url(params)
|
25
|
-
url =
|
23
|
+
url = scope.to_real_url(url){ url }
|
26
24
|
|
27
25
|
# Invoke the service now
|
28
26
|
api.public_send(service.method.to_s.downcase.to_sym, url, params, headers)
|
29
27
|
|
30
28
|
# Return the result
|
31
|
-
Resource::Service::Invocation.new(service, test_case, api.last_response)
|
29
|
+
Resource::Service::Invocation.new(service, test_case, api.last_response, self)
|
32
30
|
end
|
33
31
|
|
34
32
|
class Factory
|
@@ -37,15 +35,9 @@ module Webspicy
|
|
37
35
|
@app = app
|
38
36
|
end
|
39
37
|
attr_reader :app
|
40
|
-
attr_reader :domain
|
41
|
-
|
42
|
-
def on(domain)
|
43
|
-
@domain = domain
|
44
|
-
self
|
45
|
-
end
|
46
38
|
|
47
39
|
def new(scope)
|
48
|
-
RackTestClient.new(scope, app
|
40
|
+
RackTestClient.new(scope, app)
|
49
41
|
end
|
50
42
|
|
51
43
|
end # class Factory
|
@@ -78,6 +70,8 @@ module Webspicy
|
|
78
70
|
|
79
71
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
80
72
|
Webspicy.debug("Response: #{@last_response.body}")
|
73
|
+
|
74
|
+
@last_response
|
81
75
|
end
|
82
76
|
|
83
77
|
def post(url, params = {}, headers = nil)
|
@@ -90,6 +84,22 @@ module Webspicy
|
|
90
84
|
|
91
85
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
92
86
|
Webspicy.debug("Response: #{@last_response.body}")
|
87
|
+
|
88
|
+
@last_response
|
89
|
+
end
|
90
|
+
|
91
|
+
def patch(url, params = {}, headers = nil)
|
92
|
+
handler = get_handler(headers)
|
93
|
+
|
94
|
+
Webspicy.info("PATCH #{url} -- #{params.inspect} -- #{headers.inspect}")
|
95
|
+
|
96
|
+
handler.patch(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
|
97
|
+
@last_response = handler.last_response
|
98
|
+
|
99
|
+
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
100
|
+
Webspicy.debug("Response: #{@last_response.body}")
|
101
|
+
|
102
|
+
@last_response
|
93
103
|
end
|
94
104
|
|
95
105
|
def post_form(url, params = {}, headers = nil)
|
@@ -102,6 +112,8 @@ module Webspicy
|
|
102
112
|
|
103
113
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
104
114
|
Webspicy.debug("Response: #{@last_response.body}")
|
115
|
+
|
116
|
+
@last_response
|
105
117
|
end
|
106
118
|
|
107
119
|
def delete(url, params = {}, headers = nil)
|
@@ -114,6 +126,8 @@ module Webspicy
|
|
114
126
|
|
115
127
|
Webspicy.debug("Headers: #{@last_response.headers.to_hash}")
|
116
128
|
Webspicy.debug("Response: #{@last_response.body}")
|
129
|
+
|
130
|
+
@last_response
|
117
131
|
end
|
118
132
|
|
119
133
|
private
|
@@ -3,13 +3,14 @@ module Webspicy
|
|
3
3
|
class Service
|
4
4
|
class Invocation
|
5
5
|
|
6
|
-
def initialize(service, test_case, response)
|
6
|
+
def initialize(service, test_case, response, client)
|
7
7
|
@service = service
|
8
8
|
@test_case = test_case
|
9
9
|
@response = response
|
10
|
+
@client = client
|
10
11
|
end
|
11
12
|
|
12
|
-
attr_reader :service, :test_case, :response
|
13
|
+
attr_reader :service, :test_case, :response, :client
|
13
14
|
|
14
15
|
### Getters on response
|
15
16
|
|
data/lib/webspicy/scope.rb
CHANGED
@@ -93,8 +93,12 @@ module Webspicy
|
|
93
93
|
end
|
94
94
|
|
95
95
|
# Convert an instantiated URL found in a webservice definition
|
96
|
-
# to a real URL, using the configuration host
|
97
|
-
|
96
|
+
# to a real URL, using the configuration host.
|
97
|
+
#
|
98
|
+
# When no host resolved on the configuration and the url is not
|
99
|
+
# already an absolute URL, yields the block if given, or raise
|
100
|
+
# an exception.
|
101
|
+
def to_real_url(url, &bl)
|
98
102
|
case config.host
|
99
103
|
when Proc
|
100
104
|
config.host.call(url)
|
@@ -102,6 +106,7 @@ module Webspicy
|
|
102
106
|
url =~ /^http/ ? url : "#{config.host}#{url}"
|
103
107
|
else
|
104
108
|
return url if url =~ /^http/
|
109
|
+
return yield(url) if block_given?
|
105
110
|
raise "Unable to resolve `#{url}` : no host resolver provided\nSee `Configuration#host="
|
106
111
|
end
|
107
112
|
end
|
data/lib/webspicy/version.rb
CHANGED
@@ -18,7 +18,12 @@ module Webspicy
|
|
18
18
|
expect(got).to eql(url)
|
19
19
|
end
|
20
20
|
|
21
|
-
it '
|
21
|
+
it 'yields the block relative URLs' do
|
22
|
+
got = scope.to_real_url("/todo"){ "hello" }
|
23
|
+
expect(got).to eql("hello")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'fails on relative URLs and no block is given' do
|
22
27
|
expect(->(){
|
23
28
|
scope.to_real_url("/todo")
|
24
29
|
}).to raise_error(/Unable to resolve `\/todo`/)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webspicy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rack-robustness
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.1.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.1.0
|
111
125
|
description: Webspicy helps testing web services as software operation black boxes
|
112
126
|
email: blambeau@gmail.com
|
113
127
|
executables: []
|
@@ -129,6 +143,7 @@ files:
|
|
129
143
|
- examples/restful/webspicy/todo/deleteTodo.yml
|
130
144
|
- examples/restful/webspicy/todo/getTodo.yml
|
131
145
|
- examples/restful/webspicy/todo/getTodos.yml
|
146
|
+
- examples/restful/webspicy/todo/patchTodo.yml
|
132
147
|
- examples/restful/webspicy/todo/postTodos.yml
|
133
148
|
- lib/webspicy.rb
|
134
149
|
- lib/webspicy/checker.rb
|