mtbb 0.1.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.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ /.mtbb-artifacts/
@@ -0,0 +1,10 @@
1
+ ---
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ script: bundle exec bin/mtbb
7
+ notifications:
8
+ email:
9
+ recipients:
10
+ - github+mtbb@modcloth.com
@@ -0,0 +1,4 @@
1
+ `mtbb` authors
2
+ ==============
3
+
4
+ - Dan Buch
@@ -0,0 +1,5 @@
1
+ `mtdd` Contribution Guidelines
2
+ ==============================
3
+
4
+ - Pull requests accepted!
5
+ - Please add yourself to the `AUTHORS.md` file alphabetically by first name.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mtbb.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 ModCloth, Inc.
2
+
3
+ MIT License
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.
@@ -0,0 +1,37 @@
1
+ `mtbb`
2
+ ======
3
+
4
+ [![Build Status](https://travis-ci.org/modcloth-labs/mtbb.png)](https://travis-ci.org/modcloth-labs/mtbb)
5
+
6
+ Minitest-based black box testing thing.
7
+
8
+ ## Installation
9
+
10
+ Download the whole thing as a standalone executable:
11
+
12
+ ``` bash
13
+ curl -s -o mtbb https://raw.github.com/modcloth-labs/mtbb/master/lib/mtbb.rb
14
+ chmod +x mtbb
15
+ ```
16
+
17
+ Or install via `gem`:
18
+
19
+ ``` bash
20
+ gem install mtbb
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Given a `test` directory containing minitest files of the format
26
+ `*_test.rb`, run the `mtbb` executable over them:
27
+
28
+ ``` bash
29
+ mtbb
30
+ ```
31
+
32
+ An alternate test discovery glob may be given a la:
33
+
34
+ ``` bash
35
+ MTBB_TEST_GLOB='./black-box-tests/**/*_test.rb' mtbb
36
+ ```
37
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'mtbb'
3
+ Mtbb::TestRunner.main(ARGV)
@@ -0,0 +1,335 @@
1
+ #!/usr/bin/env ruby
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # Copyright (c) 2013 ModCloth, Inc.
5
+ #
6
+ # MIT License
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to
13
+ # permit persons to whom the Software is furnished to do so, subject to
14
+ # the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be
17
+ # included in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #
27
+
28
+ require 'fileutils'
29
+ require 'json'
30
+ require 'minitest/spec'
31
+ require 'net/http'
32
+ require 'time'
33
+ require 'uri'
34
+
35
+ begin
36
+ require_relative 'mtbb/version'
37
+ rescue LoadError
38
+ end
39
+
40
+ module Mtbb
41
+ VERSION = '0.1.0' unless defined?(VERSION)
42
+
43
+ YELLOW = "\033\[33m"
44
+ RESET = "\033\[0m"
45
+ GREEN = "\033\[32m"
46
+ RED = "\033\[31m"
47
+ MAGENTA = "\033\[35m"
48
+ BRIGHT_GREEN = "\033\[32;1m"
49
+ BRIGHT_RED = "\033\[31;1m"
50
+ BRIGHT_MAGENTA = "\033\[35;1m"
51
+ BRIGHT_YELLOW = "\033\[33;1m"
52
+
53
+ SERVERS = {}
54
+
55
+ def register(server_name, server_config)
56
+ SERVERS[server_name.to_sym] = Mtbb::ServerRunner.new(server_config)
57
+ end
58
+
59
+ def server(server_name)
60
+ SERVERS[server_name.to_sym]
61
+ end
62
+
63
+ module_function :register, :server
64
+
65
+ class TestRunner
66
+ def self.main(argv = [].freeze)
67
+ mtbb_test_glob = ENV['MTBB_TEST_GLOB'] || "#{Dir.pwd}/test/**/*_test.rb"
68
+ Dir.glob(mtbb_test_glob).each do |f|
69
+ require f
70
+ end
71
+
72
+ unless argv.include?('-h') || argv.include?('--help')
73
+ ServerControl.start_servers
74
+ Mtbb.announce! 'Started servers'
75
+ at_exit do
76
+ ServerControl.stop_servers
77
+ Mtbb.announce! 'Stopped servers'
78
+ end
79
+
80
+ MiniTest::Unit.output = MiniTestReporter.new
81
+ end
82
+
83
+ exit_code = MiniTest::Unit.new.run(argv) || 1
84
+
85
+ if exit_code == 0
86
+ $stderr.puts BRIGHT_GREEN
87
+ $stderr.puts <<-EOF.gsub(/^ {8}/, '')
88
+ ✓✓ ✓✓ ✓✓✓✓ ✓✓ ✓✓
89
+ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓✓ ✓✓
90
+ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓✓✓ ✓✓
91
+ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓
92
+ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓✓✓
93
+ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓ ✓✓✓
94
+ ✓✓✓ ✓✓✓ ✓✓✓✓ ✓✓ ✓✓
95
+ EOF
96
+ $stderr.puts RESET
97
+ else
98
+ $stderr.puts BRIGHT_RED
99
+ $stderr.puts <<-EOF.gsub(/^ {8}/, '')
100
+ ✘✘✘✘✘✘✘✘ ✘✘✘ ✘✘✘✘ ✘✘
101
+ ✘✘ ✘✘ ✘✘ ✘✘ ✘✘
102
+ ✘✘ ✘✘ ✘✘ ✘✘ ✘✘
103
+ ✘✘✘✘✘✘ ✘✘ ✘✘ ✘✘ ✘✘
104
+ ✘✘ ✘✘✘✘✘✘✘✘✘ ✘✘ ✘✘
105
+ ✘✘ ✘✘ ✘✘ ✘✘ ✘✘
106
+ ✘✘ ✘✘ ✘✘ ✘✘✘✘ ✘✘✘✘✘✘✘✘
107
+ EOF
108
+ $stderr.puts RESET
109
+ Mtbb::SERVERS.each do |_, server|
110
+ Mtbb.announce! "Dumping stdout for #{server.description}:"
111
+ server.dump(:stdout)
112
+ Mtbb.announce! "Dumping stderr for #{server.description}:"
113
+ server.dump(:stderr)
114
+ end
115
+ end
116
+
117
+ if ENV['HOLD_ON_A_SEC']
118
+ print 'Holding on a sec... [Enter] '
119
+ gets
120
+ end
121
+ exit exit_code
122
+ end
123
+ end
124
+
125
+ def announce!(something)
126
+ $stderr.puts "#{BRIGHT_GREEN}mtbb#{RESET}: #{BRIGHT_YELLOW}#{something}#{RESET}"
127
+ end
128
+
129
+ module_function :announce!
130
+
131
+ class ServerRunner
132
+ attr_reader :executable, :server_name, :argv, :port, :working_dir, :start_time
133
+ attr_reader :server_pid, :stdout_file, :stderr_file, :server_exit_code
134
+ attr_reader :options
135
+
136
+ def initialize(options = {})
137
+ @options = options
138
+ @executable = options.fetch(:executable)
139
+ options.delete(:executable)
140
+ @argv = options.delete(:argv) || []
141
+
142
+ @server_name = options.delete(:server_name) || "mtbb-server-#{Time.now.utc.to_i}"
143
+ @start_time = options.delete(:start) || Time.now.utc
144
+ @port = options.delete(:port)
145
+ @working_dir = options.delete(:working_dir) || default_working_dir
146
+ @stdout_file = options.delete(:stdout_file) || default_stdout_file
147
+ @stderr_file = options.delete(:stderr_file) || default_stderr_file
148
+
149
+ if !File.exist?(executable)
150
+ raise "Can't locate `#{File.basename(executable).inspect}` executable! " <<
151
+ "(it's not here: #{executable.inspect})"
152
+ end
153
+ end
154
+
155
+ def start
156
+ FileUtils.mkdir_p(working_dir)
157
+ process_command = command
158
+ spawn_args = process_command + [
159
+ out: [stdout_file, 'w'], err: [stderr_file, 'w']
160
+ ]
161
+ Mtbb.announce! "Starting #{description}"
162
+ Mtbb.announce! " ---> #{process_command.join(' ')}"
163
+ Mtbb.announce! " (#{config_details.inspect})"
164
+ @server_pid = Process.spawn(*spawn_args)
165
+ server_pid
166
+ end
167
+
168
+ def stop
169
+ return if !server_pid
170
+ Mtbb.announce! "Stopping #{description} (PID=#{server_pid})"
171
+ Process.kill(:TERM, server_pid)
172
+ begin
173
+ wait_for_server_process(Integer(ENV['MTBB_PROCESS_EXIT_TIMEOUT'] || 3))
174
+ rescue TimeoutError
175
+ end
176
+ Process.kill(:KILL, server_pid)
177
+ _, status = Process.waitpid2(server_pid)
178
+ @server_exit_code = status.exitstatus || status.termsig
179
+ rescue Errno::ECHILD, Errno::ESRCH
180
+ true
181
+ end
182
+
183
+ def description
184
+ "#{server_name} on port #{port}"
185
+ end
186
+
187
+ def config_details
188
+ {
189
+ argv: argv,
190
+ working_dir: working_dir,
191
+ start_time: start_time,
192
+ stdout_file: stdout_file,
193
+ stderr_file: stderr_file,
194
+ }
195
+ end
196
+
197
+ def command
198
+ cmd = [executable] + argv
199
+ options.each do |k,v|
200
+ if v.nil?
201
+ cmd << k
202
+ next
203
+ end
204
+ cmd << k << v.inspect
205
+ end
206
+ cmd
207
+ end
208
+
209
+ def dump(which = :stdout)
210
+ $stderr.puts File.read(send(:"#{which.to_s}_file"))
211
+ end
212
+
213
+ private
214
+
215
+ def wait_for_server_process(timeout)
216
+ toolate = Time.now + timeout
217
+ unless (done = server_exited?) || Time.now > toolate
218
+ sleep Float(ENV['MTBB_PROCESS_EXIT_POLL_INTERVAL'] || 0.1)
219
+ end
220
+
221
+ unless done
222
+ raise TimeoutError
223
+ end
224
+ end
225
+
226
+ # Largely inspired by ChildProcess::Unix::Process#exited?
227
+ def server_exited?
228
+ return true if server_exit_code
229
+
230
+ pid, status = Process.waitpid2(server_pid, Process::WNOHANG)
231
+ pid = pid == 0 ? nil : pid
232
+
233
+ if pid
234
+ @server_exit_code = status.exitstatus || status.termsig
235
+ end
236
+
237
+ !!pid
238
+ end
239
+
240
+ def default_working_dir
241
+ File.join(Dir.pwd, '.mtbb-artifacts')
242
+ end
243
+
244
+ def default_stdout_file
245
+ File.join(working_dir, "#{server_name}.out")
246
+ end
247
+
248
+ def default_stderr_file
249
+ File.join(working_dir, "#{server_name}.err")
250
+ end
251
+ end
252
+
253
+ class MiniTestReporter
254
+ def puts(*args)
255
+ args.each { |arg| Mtbb.announce! arg }
256
+ end
257
+
258
+ alias print puts
259
+ end
260
+
261
+ module NetThings
262
+ def http(method_name, path, options = {})
263
+ options[:path] ||= path
264
+ send("#{method_name.downcase}_request", options)
265
+ end
266
+
267
+ def post_request(options = {})
268
+ request = Net::HTTP::Post.new(options[:path] || '/')
269
+ request.content_type = 'application/x-www-form-urlencoded'
270
+ request.body = options.fetch(:body)
271
+ perform_request(request, options.fetch(:port))
272
+ end
273
+
274
+ def get_request(options = {})
275
+ perform_request(
276
+ Net::HTTP::Get.new(options[:path] || '/'),
277
+ options.fetch(:port)
278
+ )
279
+ end
280
+
281
+ def delete_request(options = {})
282
+ perform_request(
283
+ Net::HTTP::Delete.new(options[:path] || '/'),
284
+ options.fetch(:port)
285
+ )
286
+ end
287
+
288
+ private
289
+
290
+ def perform_request(request, port)
291
+ Net::HTTP.start(ENV['MTBB_SERVER_HOST'] || 'localhost', port) do |http|
292
+ http.open_timeout = Integer(ENV['MTBB_HTTP_OPEN_TIMEOUT'] || 1)
293
+ http.read_timeout = Integer(ENV['MTBB_HTTP_READ_TIMEOUT'] || 3)
294
+ response = http.request(request)
295
+ response
296
+ end
297
+ end
298
+ end
299
+
300
+ class ServerControl
301
+ def self.stop_servers
302
+ Mtbb::SERVERS.each do |_,server|
303
+ server.stop
304
+ end
305
+ end
306
+
307
+ def self.start_servers
308
+ Dir.chdir(File.expand_path('../', __FILE__)) do
309
+ FileUtils.mkdir_p('./.mtbb-artifacts')
310
+ Mtbb::SERVERS.each do |_,runner|
311
+ runner.start
312
+ wait_for_server(runner.port)
313
+ end
314
+ end
315
+ end
316
+
317
+ def self.wait_for_server(http_port)
318
+ maxloops = 10
319
+ curloop = 0
320
+ begin
321
+ TCPSocket.new(ENV['MTBB_SERVER_HOST'] || 'localhost', http_port).close
322
+ rescue
323
+ curloop += 1
324
+ if curloop < maxloops
325
+ sleep 0.5
326
+ retry
327
+ end
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ if __FILE__ == $0
334
+ Mtbb::TestRunner.main(ARGV)
335
+ end
@@ -0,0 +1,3 @@
1
+ module Mtbb
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,25 @@
1
+ # vim:fileencoding=utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mtbb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mtbb'
8
+ spec.version = Mtbb::VERSION
9
+ spec.authors = ['Dan Buch']
10
+ spec.email = ['d.buch@modcloth.com']
11
+ spec.description = %q{Minitest-based black box testing thing}
12
+ spec.summary = %q{Minitest-based black box testing thing}
13
+ spec.homepage = 'https://github.com/modcloth-labs/mtbb'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler'
22
+ spec.add_development_dependency 'rack'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'thin'
25
+ end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rack'
4
+ require 'time'
5
+
6
+ class NavelApp
7
+ def call(env)
8
+ send(:"handle_#{env['REQUEST_METHOD'].downcase}", Rack::Request.new(env))
9
+ end
10
+
11
+ private
12
+
13
+ def handle_get(request)
14
+ case request.path_info
15
+ when '/affirmation'
16
+ return [200, {'Content-Type' => 'text/plain'}, ["yup\n"]]
17
+ else
18
+ handle_404(request)
19
+ end
20
+ end
21
+
22
+ def handle_post(request)
23
+ case request.path_info
24
+ when '/dinner/new'
25
+ body = request.body.read
26
+ if body.split("\n").include?('soup=splitpea')
27
+ return [201, {'Content-Type' => 'text/plain'}, ["soup is on!\n"]]
28
+ else
29
+ return [
30
+ 400,
31
+ {'Content-Type' => 'text/plain'},
32
+ ["invalid dinner:\n" << body << "\n"]
33
+ ]
34
+ end
35
+ else
36
+ handle_404(request)
37
+ end
38
+ end
39
+
40
+ def handle_delete(request)
41
+ case request.path_info
42
+ when '/pestilence'
43
+ return [204, {'Content-Type' => 'text/plain'}, ["orphanage saved!\n"]]
44
+ else
45
+ handle_404(client)
46
+ end
47
+ end
48
+
49
+ def handle_404(client)
50
+ [404, {'Content-Type' => 'text/plain'} ["nope\n"]]
51
+ end
52
+ end
53
+
54
+ def main(argv = [])
55
+ port = Integer(argv.first || 19080)
56
+ $stdout.sync = true
57
+ $stderr.sync = true
58
+ Rack::Handler::Thin.run(NavelApp.new, Port: port)
59
+ end
60
+
61
+ if __FILE__ == $0
62
+ main(ARGV)
63
+ end
@@ -0,0 +1,39 @@
1
+ require 'tmpdir'
2
+ require 'minitest/unit'
3
+
4
+ Mtbb.register(:navel,
5
+ executable: File.expand_path('../navel', __FILE__),
6
+ argv: %w(9899),
7
+ server_name: 'mtbb-navel',
8
+ port: 9899,
9
+ working_dir: Dir.mktmpdir('mtbb-navel'),
10
+ )
11
+
12
+ describe 'navel test' do
13
+ include Mtbb::NetThings
14
+
15
+ it 'supports HTTP GET' do
16
+ response = http('GET', '/affirmation', port: Mtbb.server(:navel).port)
17
+ response.code.must_equal '200'
18
+ end
19
+
20
+ it 'supports HTTP POST' do
21
+ response = http('POST', '/dinner/new',
22
+ port: Mtbb.server(:navel).port, body: "soup=splitpea\n")
23
+ response.code.must_equal '201'
24
+ end
25
+
26
+ it 'supports HTTP DELETE' do
27
+ response = http('DELETE', '/pestilence', port: Mtbb.server(:navel).port)
28
+ response.code.must_equal '204'
29
+ end
30
+ end
31
+
32
+ class NavelTest < MiniTest::Unit
33
+ include Mtbb::NetThings
34
+
35
+ def test_works_with_unit_tests_too
36
+ response = http('GET', '/nerp', port: Mtbb.server(:navel).port)
37
+ response.code.must_equal '404'
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/unit'
3
+
4
+ describe 'vanilla' do
5
+ it 'supports regular old minitest specs' do
6
+ (1 + 1).must_equal 2
7
+ end
8
+ end
9
+
10
+ class TestVanilla < MiniTest::Unit
11
+ def test_supports_regular_old_minitest_tests
12
+ (1 - 1).must_equal 0
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mtbb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Buch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rack
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: thin
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Minitest-based black box testing thing
79
+ email:
80
+ - d.buch@modcloth.com
81
+ executables:
82
+ - mtbb
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - .travis.yml
88
+ - AUTHORS.md
89
+ - CONTRIBUTING.md
90
+ - Gemfile
91
+ - LICENSE.txt
92
+ - README.md
93
+ - Rakefile
94
+ - bin/mtbb
95
+ - lib/mtbb.rb
96
+ - lib/mtbb/version.rb
97
+ - mtbb.gemspec
98
+ - test/navel
99
+ - test/navel_test.rb
100
+ - test/vanilla_test.rb
101
+ homepage: https://github.com/modcloth-labs/mtbb
102
+ licenses:
103
+ - MIT
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ segments:
115
+ - 0
116
+ hash: 4294838388783584232
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ segments:
124
+ - 0
125
+ hash: 4294838388783584232
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 1.8.23
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Minitest-based black box testing thing
132
+ test_files:
133
+ - test/navel
134
+ - test/navel_test.rb
135
+ - test/vanilla_test.rb