greenlight 0.0.1.pre.alpha
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 +7 -0
- data/lib/greenlight/console.rb +92 -0
- data/lib/greenlight/injector.rb +25 -0
- data/lib/greenlight/request.rb +168 -0
- data/lib/greenlight/scenario.rb +48 -0
- data/lib/greenlight/test.rb +45 -0
- data/lib/greenlight.rb +164 -0
- metadata +63 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 456a4b33aa62487e1ceff2c2f08c13ed707c966f
|
|
4
|
+
data.tar.gz: e76bba99e28a32911d5540e7b54b78223b0e38c4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: dcd8b0b3ce263b5d92e5ecba6d930df802e2f612179477487f7e11dff404d83a5d9f0e316a4c856e11fe57f2d0a87b85976e9ecdeda3d003a95b164e636c9bdc
|
|
7
|
+
data.tar.gz: 92e78e6c8e0ce65b19ee4e1c31dc6c53d76230b7a398d9d71b24358cb639bd7ad51111c4a5e6612c834230bfed2c5011e1e9098e72d47eb994cad805a6a28a97
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
class Colors
|
|
4
|
+
|
|
5
|
+
COLORS_LIB = {
|
|
6
|
+
:red => '31',
|
|
7
|
+
:green => '32',
|
|
8
|
+
:yellow => '33',
|
|
9
|
+
:blue => '34',
|
|
10
|
+
:grey => '37',
|
|
11
|
+
:magenta => '35',
|
|
12
|
+
:cyan => '36',
|
|
13
|
+
:light_cyan => '96',
|
|
14
|
+
:light_red => '91',
|
|
15
|
+
:light_blue => '94',
|
|
16
|
+
:light_magenta => '95',
|
|
17
|
+
:light_green => '92',
|
|
18
|
+
:light_yellow => '93',
|
|
19
|
+
:white => '97'
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
class << self
|
|
23
|
+
COLORS_LIB.each do |color_name, color_val|
|
|
24
|
+
define_method(color_name.to_s) { |msg|
|
|
25
|
+
$stdout.tty? ? "\e[#{color_val}m#{msg}\e[0m" : msg
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class Console
|
|
33
|
+
|
|
34
|
+
include Singleton
|
|
35
|
+
|
|
36
|
+
attr_accessor :indent_level
|
|
37
|
+
|
|
38
|
+
INDENT_STR = ' '
|
|
39
|
+
|
|
40
|
+
def initialize
|
|
41
|
+
self.indent_level = 0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def info(msg)
|
|
45
|
+
puts Colors.grey(' - ' + get_indent + msg)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def action(msg)
|
|
49
|
+
puts ' * ' + get_indent + msg
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def error(msg)
|
|
53
|
+
puts Colors.light_red(' ' + Console.utf8("\u2718") + ' ' + get_indent + msg)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def success(msg)
|
|
57
|
+
puts Colors.light_green(' ' + Console.utf8("\u2713") + ' ' + get_indent + msg)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def get_indent
|
|
61
|
+
INDENT_STR * indent_level
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def indent
|
|
65
|
+
self.indent_level = self.indent_level + 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def unindent
|
|
69
|
+
self.indent_level = self.indent_level - 1 unless self.indent_level == 0
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.utf8(code)
|
|
73
|
+
code.encode('utf-8')
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def info(msg)
|
|
79
|
+
Console.instance.info(msg)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def action(msg)
|
|
83
|
+
Console.instance.action(msg)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def error(msg)
|
|
87
|
+
Console.instance.error(msg)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def success(msg)
|
|
91
|
+
Console.instance.success(msg)
|
|
92
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
class Injector
|
|
4
|
+
include Singleton
|
|
5
|
+
|
|
6
|
+
attr_accessor :headers
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
self.headers = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_header(header, value)
|
|
13
|
+
self.headers[header] = value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def rm_header(header)
|
|
17
|
+
self.headers.delete(header)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.decorate(options)
|
|
21
|
+
options[:headers] = {} unless (options.key?(:headers) && options[:headers].is_a?(Hash))
|
|
22
|
+
options[:headers].merge!(Injector.instance.headers)
|
|
23
|
+
options
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require 'typhoeus'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
require 'greenlight/injector'
|
|
5
|
+
require 'greenlight/console'
|
|
6
|
+
|
|
7
|
+
module Greenlight
|
|
8
|
+
|
|
9
|
+
class RequestException < StandardError; end
|
|
10
|
+
class AssertionException < StandardError; end
|
|
11
|
+
|
|
12
|
+
class RequestResponse
|
|
13
|
+
attr_accessor :body, :headers, :raw_body, :total_time, :code
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Request
|
|
17
|
+
|
|
18
|
+
# request description
|
|
19
|
+
attr_accessor :url, :options
|
|
20
|
+
|
|
21
|
+
# request response
|
|
22
|
+
attr_accessor :response
|
|
23
|
+
|
|
24
|
+
# response structure with json parsed body
|
|
25
|
+
attr_accessor :req_response
|
|
26
|
+
|
|
27
|
+
# request assertions
|
|
28
|
+
attr_accessor :expectations
|
|
29
|
+
|
|
30
|
+
# count assertions to report the index of the failed one
|
|
31
|
+
attr_accessor :assert_no
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def initialize(url, options)
|
|
35
|
+
self.url = url
|
|
36
|
+
self.options = options
|
|
37
|
+
self.expectations = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# define list of expectations (assertions)
|
|
41
|
+
def expect(&block)
|
|
42
|
+
self.expectations = block
|
|
43
|
+
run
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def _debug_info
|
|
47
|
+
if code != 0
|
|
48
|
+
info "response status code: #{code}"
|
|
49
|
+
else
|
|
50
|
+
info "library returned: #{response.return_code}"
|
|
51
|
+
end
|
|
52
|
+
info "request body: #{options[:body]}"
|
|
53
|
+
info "request headers: #{options[:headers]}"
|
|
54
|
+
info "response body: #{body}"
|
|
55
|
+
info "response headers: #{response.headers}"
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# define assertion
|
|
60
|
+
def assert(condition)
|
|
61
|
+
unless condition
|
|
62
|
+
error "assertion no. #{assert_no} failed"
|
|
63
|
+
_debug_info
|
|
64
|
+
raise AssertionException
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
self.assert_no = assert_no + 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# assertion helpers
|
|
71
|
+
def header(name)
|
|
72
|
+
response.headers[name]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def headers
|
|
76
|
+
response.headers
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def code
|
|
80
|
+
response.code
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def raw_body
|
|
84
|
+
response.body
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def body
|
|
88
|
+
req_response.body
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def total_time
|
|
92
|
+
response.total_time
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# run the request and evaluate expectations
|
|
96
|
+
def run
|
|
97
|
+
|
|
98
|
+
action Colors.grey("REQUEST ") + Colors.light_blue("#{options[:method].upcase} #{url}")
|
|
99
|
+
Console.instance.indent
|
|
100
|
+
# run the request
|
|
101
|
+
options[:ssl_verifypeer] = false
|
|
102
|
+
options[:followlocation] = true
|
|
103
|
+
|
|
104
|
+
Injector.decorate(options)
|
|
105
|
+
|
|
106
|
+
# convert all headers keys to strings to avoid having symbols like :"header" when
|
|
107
|
+
# declaring headers with colons instead of arrows
|
|
108
|
+
if options.key?(:headers)
|
|
109
|
+
new_opts = {}
|
|
110
|
+
options[:headers].map do |k, v|
|
|
111
|
+
new_opts[k.to_s] = v
|
|
112
|
+
end
|
|
113
|
+
options[:headers] = new_opts
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if options.key?(:headers) and options[:headers].key?('Content-Type')
|
|
117
|
+
ctype = options[:headers]['Content-Type']
|
|
118
|
+
if ctype.include?('application/json')
|
|
119
|
+
# automatically encode json content
|
|
120
|
+
options[:body] = JSON.generate(options[:body], quirks_mode: true)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
self.response = Typhoeus::Request.new(url, options).run
|
|
127
|
+
|
|
128
|
+
self.req_response = RequestResponse.new.tap { |r|
|
|
129
|
+
r.raw_body = response.body
|
|
130
|
+
r.headers = response.headers
|
|
131
|
+
r.code = response.code
|
|
132
|
+
r.total_time = response.total_time
|
|
133
|
+
|
|
134
|
+
if !r.headers.nil? && r.headers.key?('Content-Type') && r.headers['Content-Type'].include?('application/json')
|
|
135
|
+
r.body = JSON.parse(response.body)
|
|
136
|
+
else
|
|
137
|
+
r.body = response.body
|
|
138
|
+
end
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# reset assertion counter
|
|
142
|
+
self.assert_no = 1
|
|
143
|
+
|
|
144
|
+
# evaluate response against expectations
|
|
145
|
+
begin
|
|
146
|
+
instance_eval(&expectations)
|
|
147
|
+
rescue AssertionException
|
|
148
|
+
error error_msg + " at #{expectations.source_location}"
|
|
149
|
+
raise RequestException
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
error 'Exception ' + e.message
|
|
152
|
+
info e.backtrace.inspect
|
|
153
|
+
_debug_info
|
|
154
|
+
error error_msg
|
|
155
|
+
raise RequestException
|
|
156
|
+
ensure
|
|
157
|
+
Console.instance.unindent
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
req_response
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def error_msg
|
|
165
|
+
"REQUEST '#{options[:method].upcase} #{url}' failed"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'greenlight/console'
|
|
2
|
+
require 'greenlight/request'
|
|
3
|
+
require 'greenlight/test'
|
|
4
|
+
|
|
5
|
+
module Greenlight
|
|
6
|
+
|
|
7
|
+
class ScenarioException < StandardError; end
|
|
8
|
+
|
|
9
|
+
class Scenario
|
|
10
|
+
|
|
11
|
+
# tests - hash of tests
|
|
12
|
+
attr_accessor :name, :body
|
|
13
|
+
|
|
14
|
+
def initialize(name, &block)
|
|
15
|
+
self.name = name
|
|
16
|
+
self.body = block
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
action Colors.white("SCENARIO ") + Colors.light_magenta(name)
|
|
21
|
+
Console.instance.indent
|
|
22
|
+
ret = Greenlight.eval({}, &body)
|
|
23
|
+
success('scenario succeeded')
|
|
24
|
+
ret
|
|
25
|
+
rescue RequestException
|
|
26
|
+
error error_msg
|
|
27
|
+
raise ScenarioException
|
|
28
|
+
rescue TestException
|
|
29
|
+
error error_msg
|
|
30
|
+
raise ScenarioException
|
|
31
|
+
rescue LibraryException
|
|
32
|
+
error error_msg
|
|
33
|
+
raise ScenarioException
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
error e.backtrace.inspect
|
|
36
|
+
error e.message
|
|
37
|
+
error error_msg
|
|
38
|
+
raise ScenarioException
|
|
39
|
+
ensure
|
|
40
|
+
Console.instance.unindent
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def error_msg
|
|
44
|
+
"SCENARIO '#{name}' failed"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'greenlight/console'
|
|
2
|
+
require 'greenlight/request'
|
|
3
|
+
require 'greenlight/library'
|
|
4
|
+
|
|
5
|
+
module Greenlight
|
|
6
|
+
class TestException < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Test
|
|
9
|
+
attr_accessor :name
|
|
10
|
+
attr_accessor :body
|
|
11
|
+
attr_accessor :args
|
|
12
|
+
|
|
13
|
+
def initialize(name, &block)
|
|
14
|
+
self.name = name
|
|
15
|
+
self.body = block
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run(args = {})
|
|
19
|
+
action Colors.white("TEST ") + Colors.yellow(name)
|
|
20
|
+
Console.instance.indent
|
|
21
|
+
begin
|
|
22
|
+
ret = Greenlight.eval(args, &body)
|
|
23
|
+
success('test succeeded')
|
|
24
|
+
ret
|
|
25
|
+
rescue RequestException
|
|
26
|
+
error error_msg
|
|
27
|
+
raise TestException
|
|
28
|
+
rescue LibraryException
|
|
29
|
+
error error_msg
|
|
30
|
+
raise TestException
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
error e.backtrace.inspect
|
|
33
|
+
error e.message
|
|
34
|
+
error error_msg
|
|
35
|
+
raise TestException
|
|
36
|
+
ensure
|
|
37
|
+
Console.instance.unindent
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def error_msg
|
|
42
|
+
"TEST '#{name}' failed"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/greenlight.rb
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require 'greenlight/console'
|
|
2
|
+
require 'greenlight/request'
|
|
3
|
+
require 'greenlight/test'
|
|
4
|
+
require 'greenlight/scenario'
|
|
5
|
+
require 'singleton'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require 'json'
|
|
8
|
+
require 'typhoeus'
|
|
9
|
+
|
|
10
|
+
module Greenlight
|
|
11
|
+
class Runner
|
|
12
|
+
include Singleton
|
|
13
|
+
|
|
14
|
+
attr_accessor :params, :data
|
|
15
|
+
|
|
16
|
+
ATLAS_ENV_PREFIX = 'greenlight'
|
|
17
|
+
ATLAS_ENV_SEPARATOR = '_'
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
def load_data_url(uri)
|
|
21
|
+
resp = Typhoeus::Request.new(uri, {}).run
|
|
22
|
+
if resp.code == 200
|
|
23
|
+
case resp.headers['Content-Type'].split(';')[0]
|
|
24
|
+
when 'application/json'
|
|
25
|
+
JSON.parse(resp.body)
|
|
26
|
+
when 'text/yaml'
|
|
27
|
+
YAML.load(resp.body)
|
|
28
|
+
else
|
|
29
|
+
error 'unsupported data file format; only json and yaml are supported'
|
|
30
|
+
error resp.headers['Content-Type'] + ' found'
|
|
31
|
+
failure
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
else
|
|
35
|
+
error "loading test data from #{uri} failed with code #{resp.code}"
|
|
36
|
+
failure
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def load_data_file(uri)
|
|
42
|
+
ext = File.extname(uri)
|
|
43
|
+
case ext
|
|
44
|
+
when '.json'
|
|
45
|
+
JSON.parse(File.read(uri))
|
|
46
|
+
when '.yml'
|
|
47
|
+
YAML.load_file(uri)
|
|
48
|
+
else
|
|
49
|
+
error 'unsupported file format: ' + ext
|
|
50
|
+
error 'only .json and .yml are supported'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def env_override(env_var)
|
|
55
|
+
ptr = data
|
|
56
|
+
parts = env_var.split(ATLAS_ENV_SEPARATOR)
|
|
57
|
+
parts[1, parts.length - 2].each do |p|
|
|
58
|
+
if ptr[p].is_a? Hash
|
|
59
|
+
ptr = ptr[p]
|
|
60
|
+
else
|
|
61
|
+
ptr[p] = {}
|
|
62
|
+
ptr = ptr[p]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
ptr[parts[parts.length - 1]] = ENV[env_var]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def load_env
|
|
70
|
+
ENV.keys.each do |k|
|
|
71
|
+
|
|
72
|
+
next unless k.start_with?(ATLAS_ENV_PREFIX + ATLAS_ENV_SEPARATOR)
|
|
73
|
+
env_override(k)
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
public
|
|
79
|
+
|
|
80
|
+
%w[post get options delete put patch].each do |method|
|
|
81
|
+
define_method(method.to_s) do |url, options = {}|
|
|
82
|
+
options[:url] = url
|
|
83
|
+
options[:method] = method.to_sym
|
|
84
|
+
req = Request.new url, options
|
|
85
|
+
req
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def initialize
|
|
90
|
+
self.params = {}
|
|
91
|
+
self.data = {}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def load_data(uri, overwrite = false)
|
|
95
|
+
info "loading data from #{uri}"
|
|
96
|
+
if uri.start_with?('http://', 'https://')
|
|
97
|
+
new_data = load_data_url(uri)
|
|
98
|
+
else
|
|
99
|
+
new_data = load_data_file(uri)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if overwrite
|
|
103
|
+
self.data = new_data
|
|
104
|
+
else
|
|
105
|
+
self.data.merge!(new_data)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
load_env
|
|
109
|
+
new_data
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test(name, &block)
|
|
113
|
+
Test.new(name, &block).run
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def scenario(name, &block)
|
|
117
|
+
Scenario.new(name, &block).run
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def add_header(header, value)
|
|
121
|
+
Injector.instance.add_header(header, value)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def rm_header(header)
|
|
125
|
+
Injector.instance.rm_header(header)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_headers(headers)
|
|
129
|
+
headers.each do |key, val|
|
|
130
|
+
Injector.instance.add_header(key, val)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def self.eval(params, &block)
|
|
137
|
+
runner = Runner.instance
|
|
138
|
+
runner.params = params
|
|
139
|
+
runner.instance_eval(&block)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def greenlight(&block)
|
|
144
|
+
begin
|
|
145
|
+
Greenlight.eval({}, &block)
|
|
146
|
+
rescue Greenlight::LibraryException
|
|
147
|
+
failure
|
|
148
|
+
rescue Greenlight::ScenarioException
|
|
149
|
+
failure
|
|
150
|
+
rescue Greenlight::TestException
|
|
151
|
+
failure
|
|
152
|
+
rescue Greenlight::RequestException
|
|
153
|
+
failure
|
|
154
|
+
rescue StandardError => e
|
|
155
|
+
info e.backtrace.inspect
|
|
156
|
+
error e.message
|
|
157
|
+
failure
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def failure
|
|
162
|
+
error 'TEST RUN FAILED'
|
|
163
|
+
abort
|
|
164
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: greenlight
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1.pre.alpha
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Florin Mihalache
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-04-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: typhoeus
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.1'
|
|
27
|
+
description: A Ruby DSL to help writing automated tests for APIs.
|
|
28
|
+
email: florin.mihalache@gmail.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- lib/greenlight.rb
|
|
34
|
+
- lib/greenlight/console.rb
|
|
35
|
+
- lib/greenlight/injector.rb
|
|
36
|
+
- lib/greenlight/request.rb
|
|
37
|
+
- lib/greenlight/scenario.rb
|
|
38
|
+
- lib/greenlight/test.rb
|
|
39
|
+
homepage: http://github.com/mflorin/greenlight
|
|
40
|
+
licenses:
|
|
41
|
+
- MIT
|
|
42
|
+
metadata: {}
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 1.3.1
|
|
57
|
+
requirements: []
|
|
58
|
+
rubyforge_project:
|
|
59
|
+
rubygems_version: 2.5.2.3
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: Automated Tests Language for APIs
|
|
63
|
+
test_files: []
|