api_mini_tester 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab778aea0e70140ad7987422ea3cc84423ca3c83
4
+ data.tar.gz: 482db1276239fca74afb2b54a490e464f1529ccb
5
+ SHA512:
6
+ metadata.gz: f75c1d2e8af06c2629da0c2e52f8b63f154871df0c3a0fb950e03dd2adf8f485f99161cbeb22f385d7869c5460341893a3f65ed366c9f217b1ecf4a8c3bf7bae
7
+ data.tar.gz: d72335d77cab38d7f09a0171914b2a56323a59ae057c9ef2acac8a38ae9c5b6a1b176aa0de9889d675988eeceb4c9bbe099d2258b49a8cd2eaad04bf0dcbcb09
@@ -0,0 +1,6 @@
1
+ module ApiMiniTester
2
+ end
3
+
4
+ require 'api_mini_tester/test_step'
5
+ require 'api_mini_tester/test_scenario'
6
+ require 'api_mini_tester/test_suite'
@@ -0,0 +1,209 @@
1
+ require 'builder'
2
+ require 'socket'
3
+
4
+ class TestFormatter
5
+
6
+ RESULT_SECTIONS = %i[status headers body timing].freeze
7
+ SECTION_TRANSLATE = {
8
+ status: "Status",
9
+ headers: "Headers",
10
+ body: "Body",
11
+ timing: "Timing"
12
+ }.freeze
13
+
14
+ attr_accessor :results
15
+
16
+ def initialize(results)
17
+ @results = results
18
+ end
19
+
20
+ def to_json
21
+ clean_up_infinity.to_json
22
+ end
23
+
24
+ def to_yaml
25
+ clean_up_infinity.to_yaml
26
+ end
27
+
28
+ def to_junit_xml
29
+ xml = Builder::XmlMarkup.new(indent: 2)
30
+ xml.instruct! :xml, encoding: "UTF-8"
31
+ xml.testsuites do
32
+ results[:scenarios].each do |scenario|
33
+ xml.testsuite name: scenario[:name],
34
+ timestamp: timestamp,
35
+ hostname: hostname,
36
+ tests: tests_in_scenario(scenario),
37
+ skipped: 0,
38
+ failures: failed_in_scenario(scenario),
39
+ errors: 0,
40
+ time: time_in_scenario(scenario) do
41
+ scenario[:steps].each do |step|
42
+ classname = name_to_camelcase(step[:name])
43
+ RESULT_SECTIONS.each do |section|
44
+ step[section].each do |s|
45
+ xml.testcase classname: classname,
46
+ name: s[:name],
47
+ time: step_timing(step),
48
+ file: "./#{classname}.rb" do
49
+ s[:result] ? nil : xml.failure(message: s[:desc])
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def timestamp
60
+ Time.now.strftime("%FT%T%:z")
61
+ end
62
+
63
+ def scenarios_count
64
+ results[:scenarios].size
65
+ end
66
+
67
+ def steps_count(scenario)
68
+ scenario[:steps].size
69
+ end
70
+
71
+ def test_count(step)
72
+ count = 0
73
+ [:status, :headers, :body, :timing].each do |section|
74
+ count += step[section].size
75
+ end
76
+ count
77
+ end
78
+
79
+ def tests_in_scenario(scenario)
80
+ count = 0
81
+ scenario[:steps].each do |step|
82
+ count += test_count(step)
83
+ end
84
+ count
85
+ end
86
+
87
+ def time_in_scenario(scenario)
88
+ time = 0.0
89
+ scenario[:steps].each do |step|
90
+ time += step[:timing].first[:real]
91
+ end
92
+ time
93
+ end
94
+
95
+ def failed_in_scenario(scenario)
96
+ count = 0
97
+ scenario[:steps].each do |step|
98
+ [:status, :headers, :body, :timing].each do |section|
99
+ count += step[section].map { |res| res[:result] }.select(&:!).size
100
+ end
101
+ end
102
+ count
103
+ end
104
+
105
+ def hostname
106
+ Socket.gethostname
107
+ end
108
+
109
+ def name_to_camelcase(name)
110
+ name.gsub(/[[:space:]]+/, '_').downcase.gsub(/(?:^|_)([a-z])/) { $1.upcase }
111
+ end
112
+
113
+ def step_timing(step)
114
+ step[:timing].first ? step[:timing].first[:real] : 0
115
+ end
116
+
117
+ def clean_up_infinity
118
+ res = results.dup
119
+ res[:scenarios].each do |scenario|
120
+ scenario[:steps].each do |step|
121
+ step[:timing].each do |timing|
122
+ timing[:exp] = "Not Specified" if timing.is_a?(Hash) && timing[:exp] && timing[:exp] == Float::INFINITY
123
+ end
124
+ end
125
+ end
126
+ res
127
+ end
128
+
129
+ def array_in(array)
130
+ list = ''
131
+ array.each do |item|
132
+ if item.instance_of?(Array)
133
+ list << array_in(item)
134
+ elsif item.instance_of?(Hash)
135
+ list << hash_in(item)
136
+ end
137
+ end
138
+ list
139
+ end
140
+
141
+ def hash_in(hash)
142
+ list = ''
143
+ hash.each do |k, v|
144
+ if v.instance_of?(Hash)
145
+ list << hash_in(v)
146
+ elsif v.instance_of?(Array)
147
+ list << array_in(v)
148
+ elsif k == :result
149
+ list << (v ? '.' : 'E')
150
+ end
151
+ end
152
+ list
153
+ end
154
+
155
+ def to_simple
156
+ hash_in results
157
+ end
158
+
159
+ def md_section_header(header, desc, level)
160
+ output = []
161
+ output << "#{'#' * level} #{header}"
162
+ output << ""
163
+ if desc
164
+ output << "Desc: #{desc}"
165
+ output << ""
166
+ end
167
+ output
168
+ end
169
+
170
+ def md_step_header(step)
171
+ output = []
172
+ output.push(*md_section_header(step[:name], step[:desc], 3))
173
+ output.push(*md_section_header("Call", nil, 4))
174
+ step[:url].each do |url|
175
+ output << "* #{url[:desc]}"
176
+ end
177
+ step[:method].each do |method|
178
+ output << "* #{method[:desc]}"
179
+ end
180
+ output << ""
181
+ output
182
+ end
183
+
184
+ def md_section_content(step, section)
185
+ output = []
186
+ output << md_section_header(SECTION_TRANSLATE[section], nil, 4)
187
+ step[section].each do |status|
188
+ output << "* `#{status[:result]}`: #{status[:desc]}"
189
+ end
190
+ output << ""
191
+ output
192
+ end
193
+
194
+ def to_markdown
195
+ output = []
196
+ output << md_section_header(results[:name], results[:desc], 1)
197
+ results[:scenarios].each do |scenario|
198
+ output << md_section_header(scenario[:name], scenario[:desc], 2)
199
+ scenario[:steps].each do |step|
200
+ output.push(*md_step_header(step))
201
+ RESULT_SECTIONS.each do |section|
202
+ output.push(*md_section_content(step, section))
203
+ end
204
+ end
205
+ end
206
+ output.join("\n")
207
+ end
208
+
209
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'test_step'
2
+
3
+ module ApiMiniTester
4
+ class TestScenario
5
+
6
+ attr_accessor :base_uri, :scenario, :data, :results, :name
7
+
8
+ def initialize(base_uri, scenario, data)
9
+ @base_uri = base_uri
10
+ @scenario = scenario
11
+ @data = data
12
+ @name = scenario['name']
13
+ @results = {name: scenario['name'], desc: scenario['desc'], steps: []}
14
+ end
15
+
16
+ def valid?
17
+ return false if scenario.nil? || scenario['steps'].nil?
18
+ return false unless scenario['steps'].is_a?(Array) || scenario['steps'].empty?
19
+ return false if name.nil? || name.empty?
20
+ return false if base_uri.nil? || base_uri.empty?
21
+ true
22
+ end
23
+
24
+ def add_result(result)
25
+ @results.steps << result
26
+ end
27
+
28
+ def print_results
29
+ @results.each do |line|
30
+ puts line
31
+ end
32
+ end
33
+
34
+ def run_scenario
35
+ @context = []
36
+ scenario['steps'].each do |step|
37
+ step = TestStep.new(base_uri, step, @context, data)
38
+ step_result, context = step.run_step
39
+ @results[:steps] << step_result
40
+ @context << context
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,199 @@
1
+ require 'httparty'
2
+ require 'liquid'
3
+ require 'hash_parser'
4
+ require 'uri'
5
+ require 'faker'
6
+ require 'json'
7
+
8
+ module ApiMiniTester
9
+ class TestStep
10
+
11
+ include HTTParty
12
+
13
+ SUPPORTED_METHODS = %i[ get post put delete ].freeze
14
+
15
+ attr_accessor :uri, :method, :name, :input, :output
16
+ attr_reader :results
17
+
18
+ def initialize(base_uri, step, context = nil, data = nil)
19
+ @context = context
20
+ uri_template = Liquid::Template.parse([base_uri, step['uri']].join("/"), error_mode: :strict)
21
+ @name = step['name']
22
+ @uri = uri_template.render({'context' => context, 'data' => data}, { strict_variables: true })
23
+ @method = step['method'].downcase.to_sym
24
+
25
+ input_template = Liquid::Template.parse(step['input'].to_yaml.to_s, error_mode: :strict)
26
+ @input = YAML.load(input_template.render({'context' => context, 'data' => data}, { strict_variables: true }))
27
+
28
+ output_template = Liquid::Template.parse(step['output'].to_yaml.to_s, error_mode: :strict)
29
+ @output = YAML.load(output_template.render({'context' => context, 'data' => data}, { strict_variables: true }))
30
+
31
+ @results = { name: step['name'], desc: step['desc'], status: [], headers: [], body: [], url: [], method: [], timing: [] }
32
+ end
33
+
34
+ def valid?
35
+ return false if uri.nil? || uri.empty?
36
+ return false unless URI.parse(uri) rescue false
37
+ return false unless SUPPORTED_METHODS.include? method
38
+ return false if @name.nil? || @name.empty?
39
+ true
40
+ end
41
+
42
+ def content_type
43
+ @input['content_type'] || 'application/json'
44
+ end
45
+
46
+ def headers
47
+ @input['header']['Content-type'] = content_type if content_type == 'application/json'
48
+ @input['header']
49
+ end
50
+
51
+ def body
52
+ case content_type
53
+ when 'application/x-www-form-urlencoded'
54
+ body_to_form_data
55
+ when 'multipart/form-data'
56
+ body_to_form_data
57
+ else
58
+ @input["body"].to_json
59
+ end
60
+ end
61
+
62
+ def body_to_form_data
63
+ body = {}
64
+ @input["body"].each do |item|
65
+ body[item['name']] = item['value'] if item['type'] == 'input'
66
+ body[item['name']] = File.open(item['value'], 'r') if item['type'] == 'file'
67
+ end
68
+ body
69
+ end
70
+
71
+ def test_headers
72
+ @output['header']
73
+ end
74
+
75
+ def test_body
76
+ @output['body']
77
+ end
78
+
79
+ def test_status
80
+ @output['status']
81
+ end
82
+
83
+ def test_timing
84
+ @output['timing']
85
+ end
86
+
87
+ def run_step
88
+ @timing = Time.now
89
+ case method
90
+ when :get
91
+ response = HTTParty.get(uri, headers: headers)
92
+ when :post
93
+ response = HTTParty.post(uri, headers: headers, body: body)
94
+ when :put
95
+ response = HTTParty.put(uri, headers: headers, body: body)
96
+ when :delete
97
+ response = HTTParty.delete(uri, headers: headers)
98
+ end
99
+ @timing = Time.now - @timing
100
+
101
+ add_result :url, { result: true, desc: "Url: #{uri}" }
102
+ add_result :method, { result: true, desc: "Method: #{method}" }
103
+
104
+ assert_status(response.code, test_status)
105
+ assert_headers(response.headers, test_headers)
106
+ assert_body(response.parsed_response, test_body)
107
+ assert_timing(@timing, test_timing)
108
+
109
+ [ results, response ]
110
+ end
111
+
112
+ def print_results
113
+ @results.each do |line|
114
+ puts line
115
+ end
116
+ end
117
+
118
+ def add_result(section, result)
119
+ @results[section] << result
120
+ end
121
+
122
+ def assert_timing(runtime, limit = nil)
123
+ limit ||= Float::INFINITY
124
+ add_result :timing, { result: (runtime < limit),
125
+ name: "Request time < #{limit}",
126
+ desc: "Expected request time #{limit}, real time #{runtime}",
127
+ exp: limit, real: runtime }
128
+ end
129
+
130
+ def assert_status(response, output)
131
+ add_result :status, { result: (response == output),
132
+ name: "Response code == #{output}",
133
+ desc: "Expected response #{output}, got response #{response}",
134
+ exp: output, real: response }
135
+ end
136
+
137
+ def assert_headers(response, output)
138
+ return if output.nil?
139
+ output.each do |k, v|
140
+ add_result :headers, { result: (v == response[k]),
141
+ name: "Header value: #{k} == #{v}",
142
+ desc: "Header #{k} expected: #{v}, got #{response[k]}",
143
+ exp: v, real: response[k] }
144
+ end
145
+ end
146
+
147
+ def assert_body(response, output)
148
+ if output.instance_of?(Hash)
149
+ hash_diff(output, response)
150
+ elsif output.instance_of?(Array)
151
+ array_diff(output, response)
152
+ end
153
+ end
154
+
155
+ def array_diff(a, b, path = nil, section = :body)
156
+ a.each do |a_item|
157
+ if a_item.instance_of?(Hash)
158
+ found = false
159
+ b.each do |b_item|
160
+ matching = true
161
+ a_item.each_key do |k, v|
162
+ matching = (b_item[k] == a_item[k]) if matching
163
+ end
164
+ found = true if matching
165
+ end
166
+ add_result section, { result: found,
167
+ name: "Response body value: #{[path].join(".")}",
168
+ desc: "Assert #{[path].join(".")} #{found ? 'contains' : 'does not contains'} #{a_item}" }
169
+ elsif a_item.instance_of?(Array)
170
+ # TODO: Add support for array of array it isn't so needed to compate so deep structures
171
+ else
172
+ add_result section, { result: b.include?(a_item),
173
+ name: "Response boby value: #{[path].join(".")}",
174
+ desc: "Assert #{[path].join(".")} #{b.include?(a_item) ? 'contains' : 'does not contains'} #{a_item}" }
175
+ end
176
+ end
177
+ end
178
+
179
+ def hash_diff(a, b, path = nil, section = :body)
180
+ return nil if a.nil? || b.nil?
181
+ a.each_key do |k, v|
182
+ current_path = [path, k].join('.')
183
+ if b[k].nil?
184
+ add_result section, { result: false,
185
+ name: "Reponse value: #{[path, k].join(".")}",
186
+ desc: "Missing #{current_path}" }
187
+ elsif v.instance_of?(Hash)
188
+ hash_diff(a[k], b[k], current_path, section)
189
+ elsif v.instance_of?(Array)
190
+ array_diff(a[k], b[k], current_path, section)
191
+ else
192
+ add_result section, { result: (a[k] == b[k]),
193
+ name: "Reponse body value: #{[path, k].join(".")}",
194
+ desc: "Assert #{[path, k].join(".")}: #{a[k]} #{a[k] == b[k] ? '==' : '!='} #{b[k]}" }
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,47 @@
1
+ require 'yaml'
2
+ require_relative 'test_scenario'
3
+ require_relative 'test_formatter'
4
+
5
+ module ApiMiniTester
6
+ class TestSuite
7
+
8
+ attr_accessor :base_uri, :scenarios, :data, :results
9
+
10
+ def initialize(suite_def)
11
+ if suite_def.is_a?(String)
12
+ @test = YAML.load(File.open(suite_def))
13
+ elsif suite_def.is_a?(Hash)
14
+ @test = suite_def
15
+ end
16
+ setup
17
+ end
18
+
19
+ def valid?
20
+ return false if base_uri.nil? || base_uri.empty?
21
+ return false if scenarios.nil? || scenarios.empty?
22
+ true
23
+ end
24
+
25
+ def setup
26
+ @base_uri = @test['settings']['baseurl']
27
+ @scenarios = @test['tests']
28
+ @data = @test['data']
29
+ @results = {name: @test['name'], desc: @test['desc'], scenarios: []}
30
+ end
31
+
32
+ def run_scenarios
33
+ scenarios.each do |scenario|
34
+ runner = TestScenario.new(base_uri, scenario, data)
35
+ runner.run_scenario
36
+ @results[:scenarios] << runner.results
37
+ end
38
+ @results
39
+ end
40
+
41
+ def print_results(format)
42
+ formatter = TestFormatter.new(results)
43
+ formatter.send("to_#{format}")
44
+ end
45
+
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,268 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_mini_tester
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Jindrich Skupa (@eMan)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: builder
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.4
33
+ - !ruby/object:Gem::Dependency
34
+ name: faker
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.8'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.8.7
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.8'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.8.7
53
+ - !ruby/object:Gem::Dependency
54
+ name: hash_parser
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.0'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.2
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.0'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.0.2
73
+ - !ruby/object:Gem::Dependency
74
+ name: httparty
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.16'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.16.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.16'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.16.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: liquid
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '4.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 4.0.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '4.0'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 4.0.0
113
+ - !ruby/object:Gem::Dependency
114
+ name: minitest
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '5.11'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 5.11.3
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '5.11'
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 5.11.3
133
+ - !ruby/object:Gem::Dependency
134
+ name: minitest-reporters-json_reporter
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '1.0'
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 1.0.0
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '1.0'
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 1.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: nexus
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.4'
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: 1.4.0
163
+ type: :development
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - "~>"
168
+ - !ruby/object:Gem::Version
169
+ version: '1.4'
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 1.4.0
173
+ - !ruby/object:Gem::Dependency
174
+ name: rubocop
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '0.58'
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: 0.58.2
183
+ type: :development
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '0.58'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 0.58.2
193
+ - !ruby/object:Gem::Dependency
194
+ name: simplecov
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '0.16'
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: 0.16.1
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: '0.16'
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: 0.16.1
213
+ - !ruby/object:Gem::Dependency
214
+ name: webmock
215
+ requirement: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: '3.4'
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 3.4.2
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '3.4'
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: 3.4.2
233
+ description: Runs automated REST API based on YAML definiti
234
+ email: jindrich.skupa@gmail.com
235
+ executables: []
236
+ extensions: []
237
+ extra_rdoc_files: []
238
+ files:
239
+ - lib/api_mini_tester.rb
240
+ - lib/api_mini_tester/test_formatter.rb
241
+ - lib/api_mini_tester/test_scenario.rb
242
+ - lib/api_mini_tester/test_step.rb
243
+ - lib/api_mini_tester/test_suite.rb
244
+ homepage: http://rubygems.org/gems/api_mini_tester
245
+ licenses:
246
+ - MIT
247
+ metadata: {}
248
+ post_install_message:
249
+ rdoc_options: []
250
+ require_paths:
251
+ - lib
252
+ required_ruby_version: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
257
+ required_rubygems_version: !ruby/object:Gem::Requirement
258
+ requirements:
259
+ - - ">="
260
+ - !ruby/object:Gem::Version
261
+ version: '0'
262
+ requirements: []
263
+ rubyforge_project:
264
+ rubygems_version: 2.6.8
265
+ signing_key:
266
+ specification_version: 4
267
+ summary: Runs automated REST API based on YAML definition
268
+ test_files: []