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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 41838b2f4db0842af70e1449780812ed8e211551
4
- data.tar.gz: 51d875cc4515fa99e8c5f643f8086ee6b8cbe989
3
+ metadata.gz: 2f7e458fbf3c7ac65bd95574e127f16791f56391
4
+ data.tar.gz: e2cdfa60d3e9ba3831bd49cb4a6931e675752eea
5
5
  SHA512:
6
- metadata.gz: 1f2d125ccb018ab4e4b524cf5798024474084ea7ff8b46f036b2418a300072bf21814cae586cbf65d7de3ce4fef3f8b7712d67783a8ab9260edec20fa74b7b99
7
- data.tar.gz: 1d2bfa5d4009220a4b4cb1aabbdc1a17017c02281cd1c497c1b1a909867aca21ae29566ce3f8dc03d1a3d7d264497c37e2b03fc2071b6db9b9703d25f5be157f
6
+ metadata.gz: 94edf71925034c01b1297c58e049f2f4729330c80e4db0e601e24f9409b6d609f88b24b8b8f8c707d3d6e52c7cf18dc137d948d4728e222e2305bf097ca1dfd8
7
+ data.tar.gz: a88aecd9681674821f4953e96519635f1a2a5d452abf100de57de0fd8d01b7121f54a72f97252384be4d23e2c93dcee5d6518f1b2ff1f1ef317d8e8de07c99b0
@@ -5,3 +5,4 @@ gem 'sinatra', "~> 2.0"
5
5
  gem "path", "~> 1.3"
6
6
  gem "finitio", "~> 0.5.2"
7
7
  gem "webspicy", path: "../.."
8
+ gem "rack-robustness", "~> 1.1.0"
@@ -1,25 +1,26 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- webspicy (0.3.0.pre.rc2)
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.1)
15
- public_suffix (~> 2.0, >= 2.0.2)
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.1)
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 (2.0.5)
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!
@@ -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) }
@@ -2,3 +2,12 @@ Todo = {
2
2
  id : Integer
3
3
  description : String
4
4
  }
5
+
6
+ TodoPatch = {
7
+ id :? Integer
8
+ description :? String
9
+ }
10
+
11
+ ErrorSchema = {
12
+ error: String
13
+ }
@@ -23,9 +23,7 @@ services:
23
23
  .
24
24
 
25
25
  error_schema: |-
26
- {
27
- error: String
28
- }
26
+ ErrorSchema
29
27
 
30
28
  examples:
31
29
 
@@ -23,9 +23,7 @@ services:
23
23
  Todo
24
24
 
25
25
  error_schema: |-
26
- {
27
- error: String
28
- }
26
+ ErrorSchema
29
27
 
30
28
  examples:
31
29
 
@@ -22,8 +22,7 @@ services:
22
22
  [Todo]
23
23
 
24
24
  error_schema: |-
25
- {
26
- }
25
+ ErrorSchema
27
26
 
28
27
  examples:
29
28
 
@@ -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
@@ -21,9 +21,7 @@ services:
21
21
  Todo
22
22
 
23
23
  error_schema: |-
24
- {
25
- error: String
26
- }
24
+ ErrorSchema
27
25
 
28
26
  examples:
29
27
 
@@ -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, domain)
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 = "http://#{domain}#{url}" if domain
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, domain)
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
 
@@ -75,7 +75,7 @@ module Webspicy
75
75
 
76
76
  def instrument
77
77
  service.preconditions.each do |pre|
78
- pre.ensure(self)
78
+ pre.instrument(self)
79
79
  end
80
80
  end
81
81
 
@@ -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
- def to_real_url(url)
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
@@ -1,8 +1,8 @@
1
1
  module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 4
5
- TINY = 2
4
+ MINOR = 5
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -18,7 +18,12 @@ module Webspicy
18
18
  expect(got).to eql(url)
19
19
  end
20
20
 
21
- it 'fails on relative URLs' do
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.2
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