webspicy 0.15.7 → 0.16.3

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -24
  3. data/bin/webspicy +30 -14
  4. data/examples/restful/Gemfile +2 -2
  5. data/examples/restful/Gemfile.lock +53 -33
  6. data/examples/restful/Rakefile +0 -1
  7. data/examples/restful/app.rb +4 -1
  8. data/examples/restful/webspicy/config.rb +8 -0
  9. data/examples/restful/webspicy/rack.rb +1 -1
  10. data/examples/restful/webspicy/real.rb +1 -1
  11. data/examples/restful/webspicy/schema.fio +2 -2
  12. data/examples/restful/webspicy/support/must_be_authenticated.rb +2 -2
  13. data/examples/restful/webspicy/support/todo_removed.rb +18 -0
  14. data/examples/restful/webspicy/todo/deleteTodo.yml +4 -1
  15. data/examples/restful/webspicy/todo/getTodoSingleServiceFormat.yml +46 -0
  16. data/examples/restful/webspicy/todo/options.yml +1 -1
  17. data/examples/restful/webspicy/todo/patchTodo.yml +3 -0
  18. data/examples/restful/webspicy/todo/postFile.yml +1 -1
  19. data/examples/single_spec/spec.yml +59 -0
  20. data/examples/website/config.rb +2 -0
  21. data/examples/website/schema.fio +1 -0
  22. data/examples/website/specification/get-http.yml +30 -0
  23. data/examples/website/specification/get-https.yml +30 -0
  24. data/lib/finitio/webspicy/scalars.fio +25 -0
  25. data/lib/webspicy.rb +48 -17
  26. data/lib/webspicy/checker.rb +2 -2
  27. data/lib/webspicy/configuration.rb +70 -14
  28. data/lib/webspicy/configuration/scope.rb +162 -0
  29. data/lib/webspicy/configuration/single_url.rb +58 -0
  30. data/lib/webspicy/configuration/single_yml_file.rb +30 -0
  31. data/lib/webspicy/formaldoc.fio +23 -8
  32. data/lib/webspicy/mocker.rb +8 -8
  33. data/lib/webspicy/mocker/config.ru +5 -0
  34. data/lib/webspicy/openapi.rb +1 -0
  35. data/lib/webspicy/openapi/generator.rb +127 -0
  36. data/lib/webspicy/{resource.rb → specification.rb} +28 -5
  37. data/lib/webspicy/specification/file_upload.rb +37 -0
  38. data/lib/webspicy/specification/postcondition.rb +16 -0
  39. data/lib/webspicy/specification/precondition.rb +19 -0
  40. data/lib/webspicy/specification/precondition/global_request_headers.rb +35 -0
  41. data/lib/webspicy/specification/precondition/robust_to_invalid_input.rb +68 -0
  42. data/lib/webspicy/{resource → specification}/service.rb +11 -6
  43. data/lib/webspicy/specification/test_case.rb +139 -0
  44. data/lib/webspicy/support.rb +1 -0
  45. data/lib/webspicy/support/colorize.rb +28 -0
  46. data/lib/webspicy/support/status_range.rb +6 -1
  47. data/lib/webspicy/tester.rb +16 -11
  48. data/lib/webspicy/tester/asserter.rb +3 -2
  49. data/lib/webspicy/tester/assertions.rb +5 -1
  50. data/lib/webspicy/tester/client.rb +63 -0
  51. data/lib/webspicy/tester/client/http_client.rb +154 -0
  52. data/lib/webspicy/tester/client/rack_test_client.rb +188 -0
  53. data/lib/webspicy/tester/client/support.rb +65 -0
  54. data/lib/webspicy/tester/invocation.rb +218 -0
  55. data/lib/webspicy/tester/rspec_asserter.rb +108 -0
  56. data/lib/webspicy/tester/rspec_matchers.rb +104 -0
  57. data/lib/webspicy/version.rb +2 -2
  58. data/spec/{unit/spec_helper.rb → spec_helper.rb} +0 -0
  59. data/spec/unit/configuration/scope/test_each_service.rb +49 -0
  60. data/spec/unit/configuration/scope/test_each_specification.rb +68 -0
  61. data/spec/unit/configuration/scope/test_expand_example.rb +65 -0
  62. data/spec/unit/configuration/scope/test_to_real_url.rb +82 -0
  63. data/spec/unit/openapi/test_generator.rb +28 -0
  64. data/spec/unit/specification/precondition/test_global_request_headers.rb +42 -0
  65. data/spec/unit/{resource → specification}/service/test_dress_params.rb +2 -2
  66. data/spec/unit/specification/test_case/test_mutate.rb +24 -0
  67. data/spec/unit/{resource → specification}/test_instantiate_url.rb +5 -5
  68. data/spec/unit/{resource → specification}/test_url_placeholders.rb +4 -4
  69. data/spec/unit/test_configuration.rb +24 -7
  70. data/spec/unit/tester/client/test_around.rb +61 -0
  71. data/spec/unit/tester/test_asserter.rb +51 -0
  72. data/spec/unit/tester/test_assertions.rb +4 -4
  73. data/tasks/test.rake +3 -1
  74. metadata +88 -45
  75. data/LICENSE.md +0 -22
  76. data/lib/webspicy/client.rb +0 -61
  77. data/lib/webspicy/client/http_client.rb +0 -145
  78. data/lib/webspicy/client/rack_test_client.rb +0 -181
  79. data/lib/webspicy/client/support.rb +0 -48
  80. data/lib/webspicy/file_upload.rb +0 -35
  81. data/lib/webspicy/postcondition.rb +0 -14
  82. data/lib/webspicy/precondition.rb +0 -15
  83. data/lib/webspicy/resource/service/invocation.rb +0 -212
  84. data/lib/webspicy/resource/service/test_case.rb +0 -132
  85. data/lib/webspicy/scope.rb +0 -160
  86. data/spec/unit/client/test_around.rb +0 -59
  87. data/spec/unit/scope/test_each_resource.rb +0 -66
  88. data/spec/unit/scope/test_each_service.rb +0 -47
  89. data/spec/unit/scope/test_expand_example.rb +0 -63
  90. data/spec/unit/scope/test_to_real_url.rb +0 -80
data/LICENSE.md DELETED
@@ -1,22 +0,0 @@
1
- # The MIT Licence
2
-
3
- Copyright (c) 2020 - 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.
@@ -1,61 +0,0 @@
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 around(*args, &bl)
14
- args << self
15
- ls = config.listeners(:around_each)
16
- if ls.size == 0
17
- bl.call
18
- elsif ls.size > 1
19
- _around(ls.first, ls[1..-1], args, &bl)
20
- else
21
- ls.first.call(*args, &bl)
22
- end
23
- end
24
-
25
- def _around(head, tail, args, &bl)
26
- head.call(*args) do
27
- if tail.empty?
28
- bl.call
29
- else
30
- _around(tail.first, tail[1..-1], args, &bl)
31
- end
32
- end
33
- end
34
- private :_around
35
-
36
- def instrument(*args, &bl)
37
- args << self
38
- config.listeners(:instrument).each do |i|
39
- i.call(*args, &bl)
40
- end
41
- end
42
-
43
- def before(*args, &bl)
44
- args << self
45
- config.listeners(:before_each).each do |beach|
46
- beach.call(*args, &bl)
47
- end
48
- end
49
-
50
- def after(*args, &bl)
51
- args << self
52
- config.listeners(:after_each).each do |aeach|
53
- aeach.call(*args, &bl)
54
- end
55
- end
56
-
57
- end
58
- end
59
- require_relative 'client/support'
60
- require_relative 'client/http_client'
61
- require_relative 'client/rack_test_client'
@@ -1,145 +0,0 @@
1
- module Webspicy
2
- class HttpClient < Client
3
-
4
- class ::HTTP::Request
5
-
6
- # We monkey patch the URI normalization on Http because
7
- # we don't want it to interfere with URIs that are encoded
8
- # in tests, especially security tests.
9
- def normalize_uri(uri)
10
- uri
11
- end
12
-
13
- end # class ::HTTP::Request
14
-
15
- def initialize(scope)
16
- super(scope)
17
- @api = Api.new
18
- end
19
- attr_reader :api
20
-
21
- def call(test_case)
22
- service, resource = test_case.service, test_case.resource
23
-
24
- # Instantiate the parameters
25
- headers = test_case.headers
26
- params = test_case.dress_params? ? service.dress_params(test_case.params) : test_case.params
27
- body = test_case.body || test_case.located_file_upload
28
-
29
- # Instantiate the url and strip parameters
30
- url, params = resource.instantiate_url(params)
31
-
32
- # Globalize the URL if required
33
- url = scope.to_real_url(url, test_case)
34
-
35
- # Invoke the service now
36
- api.public_send(service.method.to_s.downcase.to_sym, url, params, headers, body)
37
-
38
- # Return the result
39
- Resource::Service::Invocation.new(service, test_case, api.last_response, self)
40
- end
41
-
42
- class Api
43
- include Client::Support
44
-
45
- attr_reader :last_response
46
-
47
- def options(url, params = {}, headers = nil, body = nil)
48
- info_request("OPTIONS", url, params, headers, body)
49
-
50
- params = querystring_params(params)
51
- @last_response = HTTP[headers || {}].options(url, params: params)
52
-
53
- debug_response(@last_response)
54
-
55
- @last_response
56
- end
57
-
58
- def get(url, params = {}, headers = nil, body = nil)
59
- info_request("GET", url, params, headers, body)
60
-
61
- params = querystring_params(params)
62
- @last_response = HTTP[headers || {}].get(url, params: params)
63
-
64
- debug_response(@last_response)
65
-
66
- @last_response
67
- end
68
-
69
- def post(url, params = {}, headers = nil, body = nil)
70
- info_request("POST", url, params, headers, body)
71
-
72
- url = url + "?" + Rack::Utils.build_query(params) if body && !params.empty?
73
-
74
- headers ||= {}
75
-
76
- case body
77
- when NilClass
78
- headers['Content-Type'] ||= 'application/json'
79
- @last_response = HTTP[headers].post(url, body: params.to_json)
80
- when FileUpload
81
- file = HTTP::FormData::File.new(body.path.to_s, {
82
- content_type: body.content_type,
83
- filename: body.path.basename.to_s
84
- })
85
- @last_response = HTTP[headers].post(url, form: {
86
- body.param_name.to_sym => file
87
- })
88
- else
89
- headers['Content-Type'] ||= 'application/json'
90
- @last_response = HTTP[headers].post(url, body: body)
91
- end
92
-
93
- debug_response(@last_response)
94
-
95
- @last_response
96
- end
97
-
98
- def patch(url, params = {}, headers = nil, body = nil)
99
- info_request("PATCH", url, params, headers, body)
100
-
101
- headers ||= {}
102
- headers['Content-Type'] ||= 'application/json'
103
- @last_response = HTTP[headers].patch(url, body: params.to_json)
104
-
105
- debug_response(@last_response)
106
-
107
- @last_response
108
- end
109
-
110
- def put(url, params = {}, headers = nil, body = nil)
111
- info_request("PUT", url, params, headers, body)
112
-
113
- headers ||= {}
114
- headers['Content-Type'] ||= 'application/json'
115
- @last_response = HTTP[headers].put(url, body: params.to_json)
116
-
117
- debug_response(@last_response)
118
-
119
- @last_response
120
- end
121
-
122
- def post_form(url, params = {}, headers = nil, body = nil)
123
- info_request("POST", url, params, headers, body)
124
-
125
- @last_response = HTTP[headers || {}].post(url, form: params)
126
-
127
- debug_response(@last_response)
128
-
129
- @last_response
130
- end
131
-
132
- def delete(url, params = {}, headers = nil, body = nil)
133
- info_request("DELETE", url, params, headers, body)
134
-
135
- @last_response = HTTP[headers || {}].delete(url, body: params.to_json)
136
-
137
- debug_response(@last_response)
138
-
139
- @last_response
140
- end
141
-
142
- end
143
-
144
- end
145
- end
@@ -1,181 +0,0 @@
1
- module Webspicy
2
- class RackTestClient < Client
3
-
4
- def self.for(app)
5
- Factory.new(app)
6
- end
7
-
8
- def initialize(scope, app)
9
- super(scope)
10
- @api = Api.new(app)
11
- end
12
- attr_reader :api
13
-
14
- def call(test_case)
15
- service, resource = test_case.service, test_case.resource
16
-
17
- # Instantiate the parameters
18
- headers = test_case.headers.dup
19
- params = test_case.dress_params? ? service.dress_params(test_case.params) : test_case.params
20
- body = test_case.body || test_case.located_file_upload
21
-
22
- # Instantiate the url and strip parameters
23
- url, params = resource.instantiate_url(params)
24
- url = scope.to_real_url(url, test_case){|u,_| u }
25
-
26
- # Invoke the service now
27
- api.public_send(service.method.to_s.downcase.to_sym, url, params, headers, body)
28
-
29
- # Return the result
30
- Resource::Service::Invocation.new(service, test_case, api.last_response, self)
31
- end
32
-
33
- class Factory
34
-
35
- def initialize(app)
36
- @app = app
37
- end
38
- attr_reader :app
39
-
40
- def new(scope)
41
- RackTestClient.new(scope, app)
42
- end
43
-
44
- end # class Factory
45
-
46
- class RackHandler
47
- include Rack::Test::Methods
48
-
49
- def initialize(app)
50
- @app = app
51
- end
52
- attr_reader :app
53
-
54
- end # class RackHandler
55
-
56
- class Api
57
- include Client::Support
58
-
59
- attr_reader :last_response
60
-
61
- def initialize(app)
62
- @app = app
63
- end
64
-
65
- def options(url, params = {}, headers = nil, body = nil)
66
- handler = get_handler(headers)
67
-
68
- info_request("OPTIONS", url, params, headers, body)
69
-
70
- handler.options(url, params)
71
- @last_response = handler.last_response
72
-
73
- debug_response(@last_response)
74
-
75
- @last_response
76
- end
77
-
78
- def get(url, params = {}, headers = nil, body = nil)
79
- handler = get_handler(headers)
80
-
81
- params = Hash[params.map{|k,v| [k, v.nil? ? "" : v] }]
82
- info_request("GET", url, params, headers, body)
83
-
84
- handler.get(url, params)
85
- @last_response = handler.last_response
86
-
87
- debug_response(@last_response)
88
-
89
- @last_response
90
- end
91
-
92
- def post(url, params = {}, headers = nil, body = nil)
93
- handler = get_handler(headers)
94
-
95
- url = url + "?" + Rack::Utils.build_query(params) if body && !params.empty?
96
-
97
- case body
98
- when NilClass
99
- info_request("POST", url, params, headers, body)
100
- handler.post(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
101
- when FileUpload
102
- file = Rack::Test::UploadedFile.new(body.path, body.content_type)
103
- info_request("POST", url, params, headers, body)
104
- handler.post(url, body.param_name.to_sym => file)
105
- else
106
- info_request("POST", url, params, headers, body)
107
- handler.post(url, body)
108
- end
109
- @last_response = handler.last_response
110
-
111
- debug_response(@last_response)
112
-
113
- @last_response
114
- end
115
-
116
- def patch(url, params = {}, headers = nil, body = nil)
117
- handler = get_handler(headers)
118
-
119
- info_request("PATCH", url, params, headers, body)
120
-
121
- handler.patch(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
122
- @last_response = handler.last_response
123
-
124
- debug_response(@last_response)
125
-
126
- @last_response
127
- end
128
-
129
- def put(url, params = {}, headers = nil, body = nil)
130
- handler = get_handler(headers)
131
-
132
- info_request("PUT", url, params, headers, body)
133
-
134
- handler.put(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
135
- @last_response = handler.last_response
136
-
137
- debug_response(@last_response)
138
-
139
- @last_response
140
- end
141
-
142
- def post_form(url, params = {}, headers = nil, body = nil)
143
- handler = get_handler(headers)
144
-
145
- info_request("POST", url, params, headers, body)
146
-
147
- handler.post(url, params)
148
- @last_response = handler.last_response
149
-
150
- debug_response(@last_response)
151
-
152
- @last_response
153
- end
154
-
155
- def delete(url, params = {}, headers = nil, body = nil)
156
- handler = get_handler(headers)
157
-
158
- info_request("DELETE", url, params, headers, body)
159
-
160
- handler.delete(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
161
- @last_response = handler.last_response
162
-
163
- debug_response(@last_response)
164
-
165
- @last_response
166
- end
167
-
168
- private
169
-
170
- def get_handler(hs)
171
- handler = RackHandler.new(@app)
172
- hs.each_pair do |k,v|
173
- handler.header(k,v)
174
- end if hs
175
- handler
176
- end
177
-
178
- end # class Api
179
-
180
- end # class RackTestClient
181
- end # module Webspicy
@@ -1,48 +0,0 @@
1
- module Webspicy
2
- class Client
3
- module Support
4
-
5
- def querystring_params(params)
6
- Hash[params.each_pair.map{|k,v| [k.to_s,v.to_s] }]
7
- end
8
-
9
- def info_request(kind, url, params, headers, body)
10
- Webspicy.info("#{kind} #{url}")
11
- debug("Req params", JSON.pretty_generate(params)) if params
12
- debug("Req headers", JSON.pretty_generate(headers)) if headers
13
- debug("Req body", request_body_to_s(body)) if body
14
- Webspicy.debug("")
15
- end
16
-
17
- def debug_response(response)
18
- debug("Res status", @last_response.status)
19
- debug("Res headers", JSON.pretty_generate(last_response.headers.to_h))
20
- debug("Res body", response_body_to_s(last_response))
21
- Webspicy.debug("")
22
- end
23
-
24
- def debug(what, value)
25
- Webspicy.debug(" #{what}: " + value_to_s(value))
26
- end
27
-
28
- def request_body_to_s(body)
29
- body = body.to_info if body.is_a?(Webspicy::FileUpload)
30
- JSON.pretty_generate(body)
31
- end
32
-
33
- def response_body_to_s(response)
34
- case response.content_type.to_s
35
- when /json/
36
- JSON.pretty_generate(JSON.load(response.body))
37
- else
38
- response.body.to_s
39
- end
40
- end
41
-
42
- def value_to_s(value)
43
- value.to_s.gsub(/\n/, "\n ")
44
- end
45
-
46
- end # module Support
47
- end # class Client
48
- end # module Webspicy