hobby-test 0.0.5 → 0.0.6
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/lib/hobby/test.rb +285 -19
- metadata +31 -30
- data/.gitignore +0 -2
- data/Gemfile +0 -15
- data/debug.rb +0 -7
- data/hobby-test.gemspec +0 -11
- data/lib/hobby/test/env.rb +0 -17
- data/lib/hobby/test/exchange.rb +0 -32
- data/lib/hobby/test/exchange/assert.rb +0 -38
- data/lib/hobby/test/exchange/request.rb +0 -33
- data/lib/hobby/test/exchange/response.rb +0 -25
- data/lib/hobby/test/report.rb +0 -17
- data/lib/hobby/test/template.rb +0 -15
- data/readme.adoc +0 -8
- data/spec/apps/main.rb +0 -77
- data/spec/auto_spec.rb +0 -23
- data/spec/helper.rb +0 -30
- data/spec/run_mutant.rb +0 -70
- data/spec/setup/mutant.rb +0 -24
- data/spec/setup/power_assert.rb +0 -19
- data/spec/tcp_spec.rb +0 -28
- data/spec/yml/json/access_last_response.yml +0 -11
- data/spec/yml/json/chain_assertions.yml +0 -36
- data/spec/yml/json/echo.yml +0 -23
- data/spec/yml/json/headers.yml +0 -10
- data/spec/yml/json/referring_to_json_body.yml +0 -9
- data/spec/yml/plain/basic.yml +0 -12
- data/spec/yml/plain/counter.yml +0 -11
- data/spec/yml/plain/query.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a60e90863e407799c95ff9818d97222f58c38b34
|
4
|
+
data.tar.gz: 4701b42b3a437785fda965030244a5ec2112c2e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e873a7390744c1c13b5c8a1735c0cc41ba45412eba228f82922783c64c4fc555a74f31373ff5955f9d15ae65421b9b8342c2cd317b0bb34d76f3939ca48ccf85
|
7
|
+
data.tar.gz: 94f007bf3c084735363eee587db7661ffc661bd578c3ec62474b6c62ab290c25b2167a53f5368e925bf4e45a8c0f5059ba61b2d955e3620333cbfd3e7f47b4eb
|
data/lib/hobby/test.rb
CHANGED
@@ -1,28 +1,44 @@
|
|
1
|
-
require 'to_proc/all'
|
2
|
-
require 'include_constants'
|
3
|
-
require 'excon'
|
4
|
-
|
5
|
-
require 'yaml'
|
6
|
-
require 'json'
|
7
|
-
require 'forwardable'
|
8
|
-
require 'ostruct'
|
9
|
-
|
10
1
|
module Hobby
|
11
2
|
class Test
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'ostruct'
|
7
|
+
|
8
|
+
require 'to_proc/all'
|
9
|
+
require 'include_constants'
|
10
|
+
require 'excon'
|
11
|
+
require 'terminal-table'
|
12
|
+
require 'rainbow'
|
13
|
+
|
14
|
+
require 'hash/as/tree'
|
15
|
+
using Hash::As::Tree
|
16
|
+
|
17
|
+
include_constants from: ToProc
|
18
|
+
|
12
19
|
def self.from_file string, **defaults
|
13
20
|
new (YAML.load_file string), defaults: defaults
|
14
21
|
end
|
15
|
-
|
22
|
+
|
16
23
|
def self.from_string string, **defaults
|
17
24
|
new (YAML.load string), defaults: defaults
|
18
25
|
end
|
19
|
-
|
26
|
+
|
27
|
+
using Module.new {
|
28
|
+
refine Hash do
|
29
|
+
def symbolize_keys
|
30
|
+
map { |k, v| [k.to_sym, v] }.to_h
|
31
|
+
end
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
20
35
|
def initialize array_of_hashes, defaults: {}
|
21
36
|
@exchanges = array_of_hashes
|
37
|
+
.map(&:symbolize_keys)
|
22
38
|
.map(&[defaults, :merge])
|
23
39
|
.map(&Exchange)
|
24
40
|
end
|
25
|
-
|
41
|
+
|
26
42
|
def [] address
|
27
43
|
connection = if address.start_with? 'http'
|
28
44
|
Excon.new address
|
@@ -30,14 +46,264 @@ module Hobby
|
|
30
46
|
Excon.new 'unix:///', socket: address
|
31
47
|
end
|
32
48
|
env = Env.new connection
|
33
|
-
|
49
|
+
|
34
50
|
Report.new @exchanges.map &[env]
|
35
51
|
end
|
36
|
-
|
37
|
-
|
52
|
+
|
53
|
+
class Env < OpenStruct
|
54
|
+
def initialize connection
|
55
|
+
super connection: connection, responses: []
|
56
|
+
end
|
57
|
+
|
58
|
+
def last_response
|
59
|
+
responses.last
|
60
|
+
end
|
61
|
+
|
62
|
+
def uri *all
|
63
|
+
"/#{all.join '/'}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Exchange
|
68
|
+
using Module.new {
|
69
|
+
refine Object do
|
70
|
+
def template?
|
71
|
+
is_a?(String) &&
|
72
|
+
start_with?('(') &&
|
73
|
+
end_with?(')')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
def initialize hash
|
79
|
+
hash = hash.rewrite do |node|
|
80
|
+
value = node.value
|
81
|
+
|
82
|
+
if value.template?
|
83
|
+
node.with value: (Template.new value)
|
84
|
+
else
|
85
|
+
node
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
verb, params = hash.find &Key[Request::VERBS, :include?]
|
90
|
+
@request = Request.new [verb, params, *hash[:format]]
|
91
|
+
@asserts = (hash[:response]&.map &Assert) || []
|
92
|
+
end
|
93
|
+
|
94
|
+
def [] env
|
95
|
+
Report.new \
|
96
|
+
request: (@request.perform_in env),
|
97
|
+
asserts: @asserts.map(&[env]),
|
98
|
+
response: env.last_response
|
99
|
+
end
|
100
|
+
|
101
|
+
class Assert
|
102
|
+
def initialize pair
|
103
|
+
@pair = pair
|
104
|
+
|
105
|
+
key, delimiter, chain = pair[0].partition /\.|\[/
|
106
|
+
chain.prepend (delimiter == '[' ? 'self[' : 'self.') unless chain.empty?
|
107
|
+
|
108
|
+
@key, @chain, @specified_value = key, chain, pair[1]
|
109
|
+
end
|
110
|
+
attr_reader :key, :chain, :specified_value, :actual_value
|
111
|
+
|
112
|
+
def ok?
|
113
|
+
@ok
|
114
|
+
end
|
115
|
+
|
116
|
+
def [] response
|
117
|
+
dup.assert response
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_s
|
121
|
+
@pair.to_yaml
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
def assert env
|
126
|
+
@specified_value = fill_templates_with env
|
127
|
+
@actual_value = env.last_response.public_send key
|
128
|
+
compare
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def compare
|
133
|
+
@ok = chain.empty? ? actual_value == specified_value : compare_chain
|
134
|
+
end
|
135
|
+
|
136
|
+
def compare_chain
|
137
|
+
if chain.end_with? '>', '=', '<'
|
138
|
+
actual_value.instance_eval "#{chain}(#{specified_value})"
|
139
|
+
else
|
140
|
+
(actual_value.instance_eval chain) == specified_value
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def fill_templates_with env
|
145
|
+
case specified_value
|
146
|
+
when Template
|
147
|
+
specified_value[env]
|
148
|
+
when Hash
|
149
|
+
specified_value.rewrite do |node|
|
150
|
+
value = node.value
|
151
|
+
|
152
|
+
if value.is_a? Template
|
153
|
+
node.with value: (value[env])
|
154
|
+
else
|
155
|
+
node
|
156
|
+
end
|
157
|
+
end
|
158
|
+
else
|
159
|
+
specified_value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class Report
|
165
|
+
def initialize asserts:, request:, response:
|
166
|
+
@asserts, @request, @response = asserts, request, response
|
167
|
+
end
|
168
|
+
|
169
|
+
def ok?
|
170
|
+
@asserts.all? &:ok?
|
171
|
+
end
|
172
|
+
|
173
|
+
def to_s
|
174
|
+
Terminal::Table.new do |t|
|
175
|
+
status = exchange_report.ok? ? Rainbow('passed').green : Rainbow('failed').red
|
176
|
+
t.add_row ['Status', status]
|
177
|
+
|
178
|
+
t.add_row ['Request', @request.to_yaml]
|
179
|
+
t.add_row ['Response', @response.to_yaml]
|
180
|
+
|
181
|
+
unless exchange_report.ok?
|
182
|
+
t.add_row ['Failed', @asserts.map(&:to_s).join("\n\n")]
|
183
|
+
end
|
184
|
+
|
185
|
+
t.style = { all_separators: true }
|
186
|
+
end.to_s
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class Request < OpenStruct
|
191
|
+
VERBS = %i[delete get head options patch post put]
|
192
|
+
def initialize triple
|
193
|
+
@verb, hash, @format = triple
|
194
|
+
super hash
|
195
|
+
end
|
196
|
+
attr_reader :verb
|
197
|
+
|
198
|
+
def perform_in env
|
199
|
+
params = create_params env
|
200
|
+
report = Report.new params, @format
|
201
|
+
|
202
|
+
excon_response = env.connection.public_send verb, **(serialize params)
|
203
|
+
|
204
|
+
response = Response.new excon_response, format: @format
|
205
|
+
env.responses << response
|
206
|
+
|
207
|
+
report
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
def create_params env
|
212
|
+
to_h.rewrite { |node|
|
213
|
+
next node unless node.value.is_a? Template
|
214
|
+
node.with value: node.value[env]
|
215
|
+
}
|
216
|
+
end
|
217
|
+
|
218
|
+
def serialize hash
|
219
|
+
hash = hash.dup
|
220
|
+
|
221
|
+
if body && @format
|
222
|
+
hash[:body] = @format.dump body
|
223
|
+
end
|
224
|
+
|
225
|
+
hash
|
226
|
+
end
|
227
|
+
|
228
|
+
class Report
|
229
|
+
def initialize params, format
|
230
|
+
@params = params.dup
|
231
|
+
|
232
|
+
if format
|
233
|
+
@params[:format] = format
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def to_yaml
|
238
|
+
@params.to_yaml
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class Response
|
244
|
+
def initialize excon_response, format:
|
245
|
+
@excon_response, @format = excon_response, format
|
246
|
+
end
|
247
|
+
attr_reader :format
|
248
|
+
|
249
|
+
def body
|
250
|
+
@body ||= if format
|
251
|
+
format.load @excon_response.body
|
252
|
+
else
|
253
|
+
PlainBody.new @excon_response.body
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class PlainBody < String
|
258
|
+
def == expected_response
|
259
|
+
eql? expected_response.to_s
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
extend Forwardable
|
264
|
+
delegate [:status, :headers] => :@excon_response
|
265
|
+
|
266
|
+
def to_yaml
|
267
|
+
{
|
268
|
+
status: status,
|
269
|
+
headers: headers,
|
270
|
+
body: body,
|
271
|
+
format: format,
|
272
|
+
}.to_yaml
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class Template
|
277
|
+
def initialize string
|
278
|
+
@string = string[1..-2]
|
279
|
+
end
|
280
|
+
|
281
|
+
def [] env
|
282
|
+
env.instance_eval @string
|
283
|
+
end
|
284
|
+
|
285
|
+
def to_s
|
286
|
+
"(#{@string})"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
class Report
|
292
|
+
def initialize exchange_reports
|
293
|
+
@exchange_reports = exchange_reports
|
294
|
+
end
|
295
|
+
|
296
|
+
def ok?
|
297
|
+
@exchange_reports.all? &:ok?
|
298
|
+
end
|
299
|
+
|
300
|
+
def to_s
|
301
|
+
@exchange_reports.join "\n\n"
|
302
|
+
end
|
303
|
+
|
304
|
+
include Enumerable
|
305
|
+
extend Forwardable
|
306
|
+
delegate [:each, :[], :size] => :@exchange_reports
|
307
|
+
end
|
38
308
|
end
|
39
309
|
end
|
40
|
-
|
41
|
-
require 'hobby/test/exchange'
|
42
|
-
require 'hobby/test/report'
|
43
|
-
require 'hobby/test/env'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hobby-test
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anatoly Chernow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: excon
|
@@ -52,40 +52,41 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: terminal-table
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rainbow
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
description:
|
56
84
|
email:
|
57
85
|
executables: []
|
58
86
|
extensions: []
|
59
87
|
extra_rdoc_files: []
|
60
88
|
files:
|
61
|
-
- ".gitignore"
|
62
|
-
- Gemfile
|
63
|
-
- debug.rb
|
64
|
-
- hobby-test.gemspec
|
65
89
|
- lib/hobby/test.rb
|
66
|
-
- lib/hobby/test/env.rb
|
67
|
-
- lib/hobby/test/exchange.rb
|
68
|
-
- lib/hobby/test/exchange/assert.rb
|
69
|
-
- lib/hobby/test/exchange/request.rb
|
70
|
-
- lib/hobby/test/exchange/response.rb
|
71
|
-
- lib/hobby/test/report.rb
|
72
|
-
- lib/hobby/test/template.rb
|
73
|
-
- readme.adoc
|
74
|
-
- spec/apps/main.rb
|
75
|
-
- spec/auto_spec.rb
|
76
|
-
- spec/helper.rb
|
77
|
-
- spec/run_mutant.rb
|
78
|
-
- spec/setup/mutant.rb
|
79
|
-
- spec/setup/power_assert.rb
|
80
|
-
- spec/tcp_spec.rb
|
81
|
-
- spec/yml/json/access_last_response.yml
|
82
|
-
- spec/yml/json/chain_assertions.yml
|
83
|
-
- spec/yml/json/echo.yml
|
84
|
-
- spec/yml/json/headers.yml
|
85
|
-
- spec/yml/json/referring_to_json_body.yml
|
86
|
-
- spec/yml/plain/basic.yml
|
87
|
-
- spec/yml/plain/counter.yml
|
88
|
-
- spec/yml/plain/query.yml
|
89
90
|
homepage:
|
90
91
|
licenses: []
|
91
92
|
metadata: {}
|
@@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
106
|
version: '0'
|
106
107
|
requirements: []
|
107
108
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.6.11
|
109
110
|
signing_key:
|
110
111
|
specification_version: 4
|
111
112
|
summary: A way to test HTTP exchanges via YAML specifications
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/debug.rb
DELETED
data/hobby-test.gemspec
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
Gem::Specification.new do |g|
|
2
|
-
g.name = 'hobby-test'
|
3
|
-
g.files = `git ls-files`.split($/)
|
4
|
-
g.version = '0.0.5'
|
5
|
-
g.summary = 'A way to test HTTP exchanges via YAML specifications'
|
6
|
-
g.authors = ['Anatoly Chernow']
|
7
|
-
|
8
|
-
g.add_dependency 'excon'
|
9
|
-
g.add_dependency 'to_proc', '>= 0.0.7'
|
10
|
-
g.add_dependency 'include_constants'
|
11
|
-
end
|
data/lib/hobby/test/env.rb
DELETED
data/lib/hobby/test/exchange.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module Hobby
|
2
|
-
class Test
|
3
|
-
class Exchange
|
4
|
-
def initialize hash
|
5
|
-
verb, params = hash.find &Key[Request::VERBS, :include?]
|
6
|
-
@request = Request.new [verb, params, *hash[:format]]
|
7
|
-
@asserts = (hash['response']&.map &Assert) || []
|
8
|
-
end
|
9
|
-
attr_reader :request, :asserts
|
10
|
-
|
11
|
-
def [] env
|
12
|
-
dup.perform_in env
|
13
|
-
end
|
14
|
-
|
15
|
-
def ok?
|
16
|
-
asserts.all? &:ok?
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
def perform_in env
|
21
|
-
request.perform_in env
|
22
|
-
@asserts = asserts.map &[env.last_response]
|
23
|
-
self
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
require 'hobby/test/exchange/request'
|
30
|
-
require 'hobby/test/exchange/response'
|
31
|
-
require 'hobby/test/exchange/assert'
|
32
|
-
require 'hobby/test/template'
|
@@ -1,38 +0,0 @@
|
|
1
|
-
class Hobby::Test::Exchange
|
2
|
-
class Assert
|
3
|
-
def initialize pair
|
4
|
-
key, delimiter, chain = pair[0].partition /\.|\[/
|
5
|
-
chain.prepend (delimiter == '[' ? 'self[' : 'self.') unless chain.empty?
|
6
|
-
|
7
|
-
@key, @chain, @specified_value = key, chain, pair[1]
|
8
|
-
end
|
9
|
-
attr_reader :key, :chain, :specified_value, :actual_value
|
10
|
-
|
11
|
-
def ok?
|
12
|
-
@ok
|
13
|
-
end
|
14
|
-
|
15
|
-
def [] response
|
16
|
-
dup.assert response
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
def assert response
|
21
|
-
@actual_value = response.public_send key
|
22
|
-
compare
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def compare
|
27
|
-
@ok = chain.empty? ? actual_value == specified_value : compare_chain
|
28
|
-
end
|
29
|
-
|
30
|
-
def compare_chain
|
31
|
-
if chain.end_with? '>', '=', '<'
|
32
|
-
actual_value.instance_eval "#{chain}(#{specified_value})"
|
33
|
-
else
|
34
|
-
(actual_value.instance_eval chain) == specified_value
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
class Hobby::Test::Exchange
|
2
|
-
class Request < OpenStruct
|
3
|
-
include ToProc
|
4
|
-
VERBS = %w[delete get head options patch post put]
|
5
|
-
def initialize triple
|
6
|
-
@verb, hash, @format = triple
|
7
|
-
|
8
|
-
template_fields, regular_fields = hash.partition &Key[:start_with?, 'template.']
|
9
|
-
@templates = template_fields.map &Hobby::Test::Template
|
10
|
-
|
11
|
-
super regular_fields.to_h
|
12
|
-
end
|
13
|
-
attr_reader :verb
|
14
|
-
|
15
|
-
def regular_fields
|
16
|
-
hash = to_h
|
17
|
-
|
18
|
-
if body && @format
|
19
|
-
hash[:body] = @format.dump body
|
20
|
-
end
|
21
|
-
|
22
|
-
hash
|
23
|
-
end
|
24
|
-
|
25
|
-
def perform_in env
|
26
|
-
params = regular_fields.merge @templates.map(&[env]).to_h
|
27
|
-
|
28
|
-
excon_response = env.connection.public_send verb, **params
|
29
|
-
response = Response.new excon_response, format: @format
|
30
|
-
env.responses << response
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class Hobby::Test::Exchange
|
2
|
-
class Response
|
3
|
-
def initialize excon_response, format:
|
4
|
-
@excon_response, @format = excon_response, format
|
5
|
-
end
|
6
|
-
attr_reader :format
|
7
|
-
|
8
|
-
def body
|
9
|
-
@body ||= if format
|
10
|
-
format.load @excon_response.body
|
11
|
-
else
|
12
|
-
PlainBody.new @excon_response.body
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class PlainBody < String
|
17
|
-
def == expected_response
|
18
|
-
eql? expected_response.to_s
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
extend Forwardable
|
23
|
-
delegate [:status, :headers] => :@excon_response
|
24
|
-
end
|
25
|
-
end
|
data/lib/hobby/test/report.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module Hobby
|
2
|
-
class Test
|
3
|
-
class Report
|
4
|
-
def initialize exchanges
|
5
|
-
@exchanges = exchanges
|
6
|
-
end
|
7
|
-
|
8
|
-
def ok?
|
9
|
-
@exchanges.all? &:ok?
|
10
|
-
end
|
11
|
-
|
12
|
-
include Enumerable
|
13
|
-
extend Forwardable
|
14
|
-
delegate [:each, :[], :size] => :@exchanges
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/hobby/test/template.rb
DELETED
data/readme.adoc
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
= hobby-test
|
2
|
-
|
3
|
-
:uri-for-rack-test: https://github.com/brynary/rack-test
|
4
|
-
|
5
|
-
A way to test HTTP exchanges via YAML specifications. In contrast to {uri-for-rack-test}[rack-test], it works via real HTTP requests, which makes it applicable to HTTP services written in any language, not only Ruby.
|
6
|
-
|
7
|
-
== How it works
|
8
|
-
I'll write it later. For now, I just want to see how Github renders it.
|
data/spec/apps/main.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'hobby'
|
2
|
-
require 'hobby/json'
|
3
|
-
|
4
|
-
class MainApp
|
5
|
-
include Hobby
|
6
|
-
get { 'root' }
|
7
|
-
|
8
|
-
class Counter
|
9
|
-
include Hobby
|
10
|
-
@@counter = 0
|
11
|
-
get { @@counter }
|
12
|
-
post { @@counter += 1 }
|
13
|
-
end
|
14
|
-
map('/counter') { run Counter.new }
|
15
|
-
|
16
|
-
class Echo
|
17
|
-
include Hobby::App
|
18
|
-
include Hobby::JSON
|
19
|
-
|
20
|
-
get { json }
|
21
|
-
end
|
22
|
-
map('/echo') { run Echo.new }
|
23
|
-
get('/echo-with-query') { request.params.to_json }
|
24
|
-
|
25
|
-
class Query
|
26
|
-
include Hobby
|
27
|
-
get { request.params['array'].class }
|
28
|
-
end
|
29
|
-
map('/query') { run Query.new }
|
30
|
-
|
31
|
-
class HashApp
|
32
|
-
include Hobby::App
|
33
|
-
include Hobby::JSON
|
34
|
-
get do
|
35
|
-
{
|
36
|
-
'a' => 1,
|
37
|
-
'b' => 2,
|
38
|
-
'c' => 3
|
39
|
-
}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
map('/hash') { run HashApp.new }
|
43
|
-
|
44
|
-
class ArrayApp
|
45
|
-
include Hobby::App
|
46
|
-
include Hobby::JSON
|
47
|
-
get do
|
48
|
-
[
|
49
|
-
{
|
50
|
-
'first' => {
|
51
|
-
'a' => 0, 'b' => 1
|
52
|
-
},
|
53
|
-
'second' => {
|
54
|
-
'c' => 2, 'd' => 3
|
55
|
-
}
|
56
|
-
},
|
57
|
-
{
|
58
|
-
'first' => {
|
59
|
-
'a' => 5, 'b' => 6
|
60
|
-
},
|
61
|
-
'second' => {
|
62
|
-
'c' => 2, 'd' => 3
|
63
|
-
}
|
64
|
-
}
|
65
|
-
]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
map('/array') { run ArrayApp.new }
|
69
|
-
|
70
|
-
class ForLastResponse
|
71
|
-
include Hobby
|
72
|
-
include JSON
|
73
|
-
post { 42 }
|
74
|
-
get '/:id' do my[:id].to_i * 2 end
|
75
|
-
end
|
76
|
-
map('/for_last_response') { run ForLastResponse.new }
|
77
|
-
end
|
data/spec/auto_spec.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe 'passing and failing YAML specifications' do
|
4
|
-
Dir["spec/yml/json/*.yml"].each do |path|
|
5
|
-
name = path.split('/').last
|
6
|
-
test = Hobby::Test.from_file path, format: JSON
|
7
|
-
|
8
|
-
it "passing #{name}" do
|
9
|
-
report = test[@socket]
|
10
|
-
assert { report.ok? }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
Dir["spec/yml/plain/*.yml"].each do |path|
|
15
|
-
name = path.split('/').last
|
16
|
-
test = Hobby::Test.from_file path
|
17
|
-
|
18
|
-
it "passing #{name} plain text" do
|
19
|
-
report = test[@socket]
|
20
|
-
assert { report.ok? }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/spec/helper.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require_relative 'setup/power_assert'
|
2
|
-
require_relative 'setup/mutant'
|
3
|
-
require_relative 'apps/main'
|
4
|
-
|
5
|
-
require 'hobby/test'
|
6
|
-
require 'puma'
|
7
|
-
|
8
|
-
RSpec.configure do |config|
|
9
|
-
config.expect_with :rspec, :minitest
|
10
|
-
|
11
|
-
config.before :each do |example|
|
12
|
-
@socket = "MainApp.for.#{example}.socket"
|
13
|
-
@pid = fork do
|
14
|
-
server = Puma::Server.new MainApp.new
|
15
|
-
server.add_unix_listener @socket
|
16
|
-
server.run
|
17
|
-
sleep
|
18
|
-
end
|
19
|
-
|
20
|
-
sleep 0.01 until File.exist? @socket
|
21
|
-
end
|
22
|
-
|
23
|
-
config.after :each do
|
24
|
-
`kill #{@pid}`
|
25
|
-
end
|
26
|
-
|
27
|
-
config.after :suite do
|
28
|
-
`rm *.socket` unless Dir['*.socket'].empty?
|
29
|
-
end
|
30
|
-
end
|
data/spec/run_mutant.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# A workaround for
|
2
|
-
# https://github.com/mbj/mutant/#the-crash--stuck-problem-mri
|
3
|
-
#
|
4
|
-
# For Hobby::Test::Report
|
5
|
-
# https://gist.github.com/ch1c0t/c5e0a8de8de14d10bec49839fb6e2fee
|
6
|
-
# this mutation
|
7
|
-
# https://gist.github.com/ch1c0t/c1626fe232032489fad93dab8d3a10c0
|
8
|
-
# causes the infinite running.
|
9
|
-
#
|
10
|
-
# This workaround "solves" it by introducing a timeout enforced
|
11
|
-
# from the parent process.
|
12
|
-
#
|
13
|
-
# With this workaround, Mutant ends its run successfully, but lefts out
|
14
|
-
# a process which keeps running in the background. That process, apparently,
|
15
|
-
# is forked from the process with the offending mutation.
|
16
|
-
# TODO: find out why it happens; create a workaround for the workaround
|
17
|
-
# (because killing that process manually every time is too much hassle).
|
18
|
-
require 'mutant'
|
19
|
-
|
20
|
-
Runner = Mutant::Runner
|
21
|
-
Bootstrap = Mutant::Env::Bootstrap
|
22
|
-
Integration = Mutant::Integration
|
23
|
-
|
24
|
-
require 'tra/run'
|
25
|
-
module MyIsolation
|
26
|
-
def self.call &block
|
27
|
-
pid = fork do
|
28
|
-
Process.setproctitle Process.pid.to_s
|
29
|
-
Process.ppid.put block.call
|
30
|
-
end
|
31
|
-
Timeout.timeout(3) { Tra.next }
|
32
|
-
rescue
|
33
|
-
Process.kill :KILL, pid
|
34
|
-
fail Mutant::Isolation::Error
|
35
|
-
ensure
|
36
|
-
Process.waitpid pid
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class MyIntegration
|
41
|
-
def initialize _config
|
42
|
-
end
|
43
|
-
|
44
|
-
def setup
|
45
|
-
self
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
DEFAULT = Mutant::Config::DEFAULT
|
50
|
-
config = DEFAULT.with \
|
51
|
-
matcher: DEFAULT.matcher.add(:match_expressions, DEFAULT.expression_parser.(ARGV[0])),
|
52
|
-
integration: Integration.setup(Kernel, 'rspec'),
|
53
|
-
isolation: MyIsolation
|
54
|
-
|
55
|
-
#Runner.call Bootstrap.call config
|
56
|
-
|
57
|
-
env = Bootstrap.call config
|
58
|
-
puts "#{env.mutations.size} mutations are to be checked."
|
59
|
-
result_mutations = env.mutations.map.with_index 1 do |mutation, index|
|
60
|
-
puts index
|
61
|
-
env.kill mutation
|
62
|
-
end
|
63
|
-
|
64
|
-
failed_mutations = result_mutations.reject &:success?
|
65
|
-
if failed_mutations.empty?
|
66
|
-
puts 'Covered.'
|
67
|
-
else
|
68
|
-
require 'pry'
|
69
|
-
failed_mutations.__binding__.pry
|
70
|
-
end
|
data/spec/setup/mutant.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
if defined? Mutant::CLI
|
2
|
-
module Mutant
|
3
|
-
class Selector::Expression
|
4
|
-
def call _subject
|
5
|
-
integration.all_tests
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
require 'timeout'
|
10
|
-
class Isolation::Fork
|
11
|
-
def parent reader, writer, &block
|
12
|
-
pid = process.fork do
|
13
|
-
child reader, writer, &block
|
14
|
-
end
|
15
|
-
|
16
|
-
writer.close
|
17
|
-
Timeout::timeout(3) { marshal.load reader }
|
18
|
-
ensure
|
19
|
-
process.kill :KILL, pid
|
20
|
-
process.waitpid pid
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/spec/setup/power_assert.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'minitest'
|
2
|
-
require 'minitest-power_assert'
|
3
|
-
|
4
|
-
assert = if ENV['PRY']
|
5
|
-
require 'pry'
|
6
|
-
require 'awesome_print'
|
7
|
-
|
8
|
-
Module.new do
|
9
|
-
def assert &block
|
10
|
-
PowerAssert.start Proc.new, assertion_method: __method__ do |pa|
|
11
|
-
block.binding.pry unless pa.yield
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
else
|
16
|
-
Minitest::PowerAssert::Assertions
|
17
|
-
end
|
18
|
-
|
19
|
-
Minitest::Assertions.prepend assert
|
data/spec/tcp_spec.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
describe Hobby::Test do
|
2
|
-
before do
|
3
|
-
@tcp_pid = fork do
|
4
|
-
server = Puma::Server.new MainApp.new
|
5
|
-
server.add_tcp_listener 'localhost', 8080
|
6
|
-
server.run
|
7
|
-
sleep
|
8
|
-
end
|
9
|
-
|
10
|
-
begin
|
11
|
-
Excon.get 'http://localhost:8080'
|
12
|
-
rescue
|
13
|
-
sleep 0.01
|
14
|
-
retry
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
after do
|
20
|
-
`kill #{@tcp_pid}`
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'in case of success' do
|
24
|
-
test = described_class.from_file 'spec/yml/plain/basic.yml'
|
25
|
-
report = test['http://localhost:8080']
|
26
|
-
assert { report.ok? }
|
27
|
-
end
|
28
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
- get:
|
2
|
-
path: /hash
|
3
|
-
|
4
|
-
response:
|
5
|
-
body:
|
6
|
-
a: 1
|
7
|
-
b: 2
|
8
|
-
c: 3
|
9
|
-
body.>:
|
10
|
-
a: 1
|
11
|
-
body.size: 3
|
12
|
-
body['b']: 2
|
13
|
-
|
14
|
-
- get:
|
15
|
-
path: /array
|
16
|
-
|
17
|
-
response:
|
18
|
-
body:
|
19
|
-
- first:
|
20
|
-
a: 0
|
21
|
-
b: 1
|
22
|
-
second:
|
23
|
-
c: 2
|
24
|
-
d: 3
|
25
|
-
- first:
|
26
|
-
a: 5
|
27
|
-
b: 6
|
28
|
-
second:
|
29
|
-
c: 2
|
30
|
-
d: 3
|
31
|
-
body.size: 2
|
32
|
-
body[1]['first']:
|
33
|
-
a: 5
|
34
|
-
b: 6
|
35
|
-
body[1]['first'].>:
|
36
|
-
a: 5
|
data/spec/yml/json/echo.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
- get:
|
2
|
-
path: /echo-with-query
|
3
|
-
query:
|
4
|
-
first: one
|
5
|
-
second: two
|
6
|
-
|
7
|
-
response:
|
8
|
-
status: 200
|
9
|
-
body:
|
10
|
-
first: one
|
11
|
-
second: two
|
12
|
-
|
13
|
-
- get:
|
14
|
-
path: /echo
|
15
|
-
body:
|
16
|
-
first: one
|
17
|
-
second: two
|
18
|
-
|
19
|
-
response:
|
20
|
-
status: 200
|
21
|
-
body:
|
22
|
-
first: one
|
23
|
-
second: two
|
data/spec/yml/json/headers.yml
DELETED
data/spec/yml/plain/basic.yml
DELETED
data/spec/yml/plain/counter.yml
DELETED