api-tester 1.0.0 → 1.1.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 (53) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/dependabot.yml +29 -0
  4. data/.github/workflows/push.yml +39 -0
  5. data/.github/workflows/test.yml +31 -0
  6. data/.rubocop.yml +171 -0
  7. data/Gemfile +2 -0
  8. data/Guardfile +70 -0
  9. data/README.md +65 -61
  10. data/Rakefile +8 -3
  11. data/api-tester.gemspec +28 -24
  12. data/changelog.txt +10 -0
  13. data/lib/api-tester/config.rb +17 -15
  14. data/lib/api-tester/definition/boundary_case.rb +5 -4
  15. data/lib/api-tester/definition/contract.rb +10 -5
  16. data/lib/api-tester/definition/endpoint.rb +58 -32
  17. data/lib/api-tester/definition/fields/array_field.rb +26 -21
  18. data/lib/api-tester/definition/fields/boolean_field.rb +17 -7
  19. data/lib/api-tester/definition/fields/email_field.rb +28 -11
  20. data/lib/api-tester/definition/fields/enum_field.rb +19 -12
  21. data/lib/api-tester/definition/fields/field.rb +52 -45
  22. data/lib/api-tester/definition/fields/number_field.rb +20 -6
  23. data/lib/api-tester/definition/fields/object_field.rb +37 -30
  24. data/lib/api-tester/definition/fields/plain_array_field.rb +25 -0
  25. data/lib/api-tester/definition/method.rb +8 -5
  26. data/lib/api-tester/definition/request.rb +43 -19
  27. data/lib/api-tester/definition/response.rb +35 -25
  28. data/lib/api-tester/method_case_test.rb +68 -54
  29. data/lib/api-tester/modules/benchmark_module.rb +35 -0
  30. data/lib/api-tester/modules/extra_verbs.rb +36 -10
  31. data/lib/api-tester/modules/format.rb +23 -7
  32. data/lib/api-tester/modules/good_case.rb +25 -10
  33. data/lib/api-tester/modules/good_variations.rb +69 -0
  34. data/lib/api-tester/modules/injection_module.rb +44 -23
  35. data/lib/api-tester/modules/missing_resource.rb +63 -0
  36. data/lib/api-tester/modules/required_fields.rb +51 -0
  37. data/lib/api-tester/modules/server_information.rb +14 -12
  38. data/lib/api-tester/modules/typo.rb +39 -14
  39. data/lib/api-tester/modules/unexpected_fields.rb +59 -0
  40. data/lib/api-tester/modules/unused_fields.rb +13 -7
  41. data/lib/api-tester/reporter/api_report.rb +25 -16
  42. data/lib/api-tester/reporter/missing_field_report.rb +11 -15
  43. data/lib/api-tester/reporter/report.rb +12 -13
  44. data/lib/api-tester/reporter/response_time_report.rb +24 -0
  45. data/lib/api-tester/reporter/status_code_report.rb +10 -4
  46. data/lib/api-tester/test_helper.rb +8 -6
  47. data/lib/api-tester/util/response_evaluator.rb +84 -56
  48. data/lib/api-tester/util/supported_verbs.rb +8 -5
  49. data/lib/api-tester/version.rb +3 -1
  50. data/lib/api-tester.rb +6 -3
  51. metadata +92 -27
  52. data/.travis.yml +0 -6
  53. data/lib/api-tester/reporter/missing_response_field_report.rb +0 -21
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiTester
4
+ # Report used for when response took too long
5
+ class ResponseTimeReport
6
+ attr_accessor :url, :verb, :payload, :max_time, :actual_time, :description
7
+
8
+ def initialize(url:, verb:, payload:, max_time:, actual_time:, description:)
9
+ self.url = url
10
+ self.verb = verb
11
+ self.payload = payload
12
+ self.max_time = max_time
13
+ self.actual_time = actual_time
14
+ self.description = description
15
+ end
16
+
17
+ def print
18
+ puts "#{description}:"
19
+ puts " #{verb} #{url} took #{actual_time}ms, the max time is #{max_time}ms:"
20
+ puts ' Payload:'
21
+ puts " #{payload}"
22
+ end
23
+ end
24
+ end
@@ -1,12 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'api-tester/reporter/report'
2
4
 
3
5
  module ApiTester
6
+ # Report for when status code is different than expected
4
7
  class StatusCodeReport < Report
5
- attr_accessor :expected_status_code
6
- attr_accessor :actual_status_code
8
+ attr_accessor :expected_status_code, :actual_status_code
7
9
 
8
- def initialize description, url, request, expected_status_code, actual_status_code
9
- super description, url, request, expected_status_code, actual_status_code
10
+ def initialize(description:, url:, request:, expected_status_code:, actual_status_code:)
11
+ super description: description,
12
+ url: url,
13
+ request: request,
14
+ expected_response: expected_status_code,
15
+ actual_response: actual_status_code
10
16
  self.expected_status_code = expected_status_code
11
17
  self.actual_status_code = actual_status_code
12
18
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Interface for when things need to be done before or after an api call
2
5
  class TestHelper
3
- def before
4
- end
6
+ def initialize(url); end
7
+
8
+ def before; end
5
9
 
6
- def retrieve_param key
7
- end
10
+ def retrieve_param(key); end
8
11
 
9
- def after
10
- end
12
+ def after; end
11
13
  end
12
14
  end
@@ -1,75 +1,103 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Class for evaluating responses against what is expected
2
5
  class ResponseEvaluator
3
- attr_accessor :response_body
4
- attr_accessor :expected_response
6
+ attr_accessor :response_body, :expected_response, :expected_fields_hash
5
7
 
6
- def initialize(actual_response_body, expected_response_fields)
7
- self.response_body = actual_response_body
8
- self.expected_response = expected_response_fields
9
- end
8
+ def initialize(actual_body:, expected_fields:)
9
+ self.response_body = actual_body
10
+ self.expected_response = expected_fields
11
+ self.expected_fields_hash = expected_field_array(expected_response.body)
12
+ end
10
13
 
11
- def response_field_array
12
- field_array self.response_body
13
- end
14
+ def response_field_array
15
+ field_array response_body
16
+ end
14
17
 
15
- def expected_fields
16
- expected_fields_hash.keys
17
- end
18
+ def expected_fields
19
+ expected_fields_hash.keys
20
+ end
18
21
 
19
- def seen_fields
20
- seen = []
21
- fields = response_field_array - extra_fields
22
- expected = expected_fields_hash
23
- fields.each do |field_key|
24
- seen << expected[field_key]
25
- end
26
- seen
22
+ def seen_fields
23
+ seen = []
24
+ fields = response_field_array - extra_fields
25
+ expected = expected_fields_hash
26
+ fields.each do |field_key|
27
+ seen << expected[field_key]
27
28
  end
29
+ seen
30
+ end
28
31
 
29
- def expected_fields_hash
30
- expected_field_array self.expected_response.body
31
- end
32
+ def extra_fields
33
+ response_field_array - expected_fields
34
+ end
32
35
 
33
- def extra_fields
34
- response_field_array - expected_fields
35
- end
36
+ def missing_fields
37
+ expected_fields - response_field_array
38
+ end
36
39
 
37
- def missing_fields
38
- expected_fields - response_field_array
40
+ def expected_field_array(expected_fields)
41
+ fields = {}
42
+ expected_fields.each do |field|
43
+ field_name = field.name
44
+ if field.has_key
45
+ fields[field.name] = field
46
+ else
47
+ field_name = field.type
48
+ end
49
+ fields = fields.merge inner_expected_field(expected_fields: field.fields,
50
+ name: field_name)
39
51
  end
52
+ fields
53
+ end
40
54
 
41
- def expected_field_array expected_fields
42
- fields = {}
43
- expected_fields.each do |field|
44
- fields[field.name] = field
45
- fields = fields.merge inner_expected_field(field.fields, field.name)
46
- end
47
- fields
55
+ def inner_expected_field(expected_fields:, name:)
56
+ fields = {}
57
+ expected_fields.each do |field|
58
+ inner_name = "#{name}.#{field.name}"
59
+ if field.has_key
60
+ fields[inner_name] = field
61
+ else
62
+ inner_name = "#{name}.#{field.type}"
63
+ end
64
+ fields = fields.merge inner_expected_field(expected_fields: field.fields,
65
+ name: inner_name)
48
66
  end
67
+ fields
68
+ end
49
69
 
50
- def inner_expected_field expected_fields, name
51
- fields = {}
52
- expected_fields.each do |field|
53
- inner_name = "#{name}.#{field.name}"
54
- fields[inner_name] = field
55
- fields = fields.merge inner_expected_field(field.fields, inner_name)
56
- end
57
- fields
58
- end
70
+ def field_array(object)
71
+ fields = []
59
72
 
60
- def field_array object
61
- fields = []
62
- object.each do |key, value|
63
- if(value)
64
- fields << key.to_s
65
- fields.concat(field_array(value).map{|i| "#{key}.#{i}"})
66
- else
67
- fields.concat(field_array(key))
68
- end
73
+ if object.instance_of?(Array)
74
+ name = 'array'
75
+ fields.concat(field_array(object[0]).map { |i| "#{name}.#{i}" })
76
+ else
77
+ object.each do |key, value|
78
+ if key.respond_to?('each')
79
+ fields.concat(field_array(key))
80
+ elsif value == nil || value == 0 || value == false
81
+ fields << key.to_s
82
+ fields.concat(field_array(value).map { |i| "#{key}.#{i}" })
83
+ elsif value.to_s[0] == '[' && value.to_s[-1] == ']' && !value.to_s.include?('=>')
84
+ fields << key.to_s
85
+ elsif value
86
+ passed_value = value
87
+ fields << key.to_s
88
+ if value.instance_of?(Array)
89
+ passed_value = value[0]
90
+ end
91
+ fields.concat(field_array(passed_value).map { |i| "#{key}.#{i}" })
92
+ else
93
+ fields.concat(field_array(key))
69
94
  end
70
- fields
71
- rescue NoMethodError
72
- fields
95
+ end
73
96
  end
97
+
98
+ fields
99
+ rescue NoMethodError
100
+ fields
101
+ end
74
102
  end
75
103
  end
@@ -1,19 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Class defining the verbs this tool supports
2
5
  class SupportedVerbs
3
- def SupportedVerbs.add_item(key, value)
6
+ def self.add_item(key, value)
4
7
  @hash ||= {}
5
8
  @hash[key] = value
6
9
  end
7
10
 
8
- def SupportedVerbs.const_missing(key)
11
+ def self.const_missing(key)
9
12
  @hash[key]
10
13
  end
11
14
 
12
- def SupportedVerbs.each
13
- @hash.each {|key,value| yield(key,value)}
15
+ def self.each(&block)
16
+ @hash.each(&block)
14
17
  end
15
18
 
16
- def SupportedVerbs.all
19
+ def self.all
17
20
  @hash.values
18
21
  end
19
22
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
2
- VERSION = "1.0.0"
4
+ VERSION = '1.1.3'
3
5
  end
data/lib/api-tester.rb CHANGED
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tool for testing through API definitions
1
4
  module ApiTester
2
- def self.go contract, config
5
+ def self.go(contract, config)
3
6
  reporter = config.reporter
4
7
 
5
- config.modules.sort_by{ |mod| mod.order }.each do |mod|
8
+ config.modules.sort_by(&:order).each do |mod|
6
9
  reporter.add_reports mod.go contract
7
10
  end
8
11
 
9
12
  reporter.print
10
- reporter.reports.size == 0
13
+ reporter.reports.size.zero?
11
14
  end
12
15
  end
metadata CHANGED
@@ -1,43 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-tester
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - arane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-08 00:00:00.000000000 Z
11
+ date: 2022-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler-audit
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1.13'
33
+ version: 0.9.0
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1.13'
40
+ version: 0.9.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 4.7.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 4.7.3
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: '10.0'
61
+ version: 13.0.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 13.0.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: require_all
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
34
76
  type: :development
35
77
  prerelease: false
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
80
  - - "~>"
39
81
  - !ruby/object:Gem::Version
40
- version: '10.0'
82
+ version: 3.0.0
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: rspec
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -53,75 +95,89 @@ dependencies:
53
95
  - !ruby/object:Gem::Version
54
96
  version: '3.0'
55
97
  - !ruby/object:Gem::Dependency
56
- name: webmock
98
+ name: rubocop
57
99
  requirement: !ruby/object:Gem::Requirement
58
100
  requirements:
59
101
  - - "~>"
60
102
  - !ruby/object:Gem::Version
61
- version: '3.4'
103
+ version: 1.31.0
62
104
  type: :development
63
105
  prerelease: false
64
106
  version_requirements: !ruby/object:Gem::Requirement
65
107
  requirements:
66
108
  - - "~>"
67
109
  - !ruby/object:Gem::Version
68
- version: '3.4'
110
+ version: 1.31.0
69
111
  - !ruby/object:Gem::Dependency
70
- name: pry
112
+ name: terminal-notifier
71
113
  requirement: !ruby/object:Gem::Requirement
72
114
  requirements:
73
115
  - - "~>"
74
116
  - !ruby/object:Gem::Version
75
- version: '0.11'
117
+ version: 2.0.0
76
118
  type: :development
77
119
  prerelease: false
78
120
  version_requirements: !ruby/object:Gem::Requirement
79
121
  requirements:
80
122
  - - "~>"
81
123
  - !ruby/object:Gem::Version
82
- version: '0.11'
124
+ version: 2.0.0
83
125
  - !ruby/object:Gem::Dependency
84
- name: require_all
126
+ name: terminal-notifier-guard
85
127
  requirement: !ruby/object:Gem::Requirement
86
128
  requirements:
87
129
  - - "~>"
88
130
  - !ruby/object:Gem::Version
89
- version: 2.0.0
131
+ version: 1.7.0
90
132
  type: :development
91
133
  prerelease: false
92
134
  version_requirements: !ruby/object:Gem::Requirement
93
135
  requirements:
94
136
  - - "~>"
95
137
  - !ruby/object:Gem::Version
96
- version: 2.0.0
138
+ version: 1.7.0
97
139
  - !ruby/object:Gem::Dependency
98
- name: rest-client
140
+ name: webmock
99
141
  requirement: !ruby/object:Gem::Requirement
100
142
  requirements:
101
143
  - - "~>"
102
144
  - !ruby/object:Gem::Version
103
- version: '2.0'
104
- type: :runtime
145
+ version: '3.4'
146
+ type: :development
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
- version: '2.0'
152
+ version: '3.4'
111
153
  - !ruby/object:Gem::Dependency
112
154
  name: injection_vulnerability_library
113
155
  requirement: !ruby/object:Gem::Requirement
114
156
  requirements:
115
157
  - - '='
116
158
  - !ruby/object:Gem::Version
117
- version: 0.0.2
159
+ version: 0.1.3
118
160
  type: :runtime
119
161
  prerelease: false
120
162
  version_requirements: !ruby/object:Gem::Requirement
121
163
  requirements:
122
164
  - - '='
123
165
  - !ruby/object:Gem::Version
124
- version: 0.0.2
166
+ version: 0.1.3
167
+ - !ruby/object:Gem::Dependency
168
+ name: rest-client
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '2.0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '2.0'
125
181
  description: Tool to test APIs which will eventually do boundary testing and other
126
182
  sorts of testing automatically given a contract
127
183
  email:
@@ -130,10 +186,15 @@ executables: []
130
186
  extensions: []
131
187
  extra_rdoc_files: []
132
188
  files:
189
+ - ".github/dependabot.yml"
190
+ - ".github/workflows/dependabot.yml"
191
+ - ".github/workflows/push.yml"
192
+ - ".github/workflows/test.yml"
133
193
  - ".gitignore"
134
194
  - ".rspec"
135
- - ".travis.yml"
195
+ - ".rubocop.yml"
136
196
  - Gemfile
197
+ - Guardfile
137
198
  - LICENSE.txt
138
199
  - README.md
139
200
  - Rakefile
@@ -153,21 +214,27 @@ files:
153
214
  - lib/api-tester/definition/fields/field.rb
154
215
  - lib/api-tester/definition/fields/number_field.rb
155
216
  - lib/api-tester/definition/fields/object_field.rb
217
+ - lib/api-tester/definition/fields/plain_array_field.rb
156
218
  - lib/api-tester/definition/method.rb
157
219
  - lib/api-tester/definition/request.rb
158
220
  - lib/api-tester/definition/response.rb
159
221
  - lib/api-tester/method_case_test.rb
222
+ - lib/api-tester/modules/benchmark_module.rb
160
223
  - lib/api-tester/modules/extra_verbs.rb
161
224
  - lib/api-tester/modules/format.rb
162
225
  - lib/api-tester/modules/good_case.rb
226
+ - lib/api-tester/modules/good_variations.rb
163
227
  - lib/api-tester/modules/injection_module.rb
228
+ - lib/api-tester/modules/missing_resource.rb
229
+ - lib/api-tester/modules/required_fields.rb
164
230
  - lib/api-tester/modules/server_information.rb
165
231
  - lib/api-tester/modules/typo.rb
232
+ - lib/api-tester/modules/unexpected_fields.rb
166
233
  - lib/api-tester/modules/unused_fields.rb
167
234
  - lib/api-tester/reporter/api_report.rb
168
235
  - lib/api-tester/reporter/missing_field_report.rb
169
- - lib/api-tester/reporter/missing_response_field_report.rb
170
236
  - lib/api-tester/reporter/report.rb
237
+ - lib/api-tester/reporter/response_time_report.rb
171
238
  - lib/api-tester/reporter/status_code_report.rb
172
239
  - lib/api-tester/test_helper.rb
173
240
  - lib/api-tester/util/response_evaluator.rb
@@ -176,8 +243,7 @@ files:
176
243
  homepage: https://github.com/araneforseti/api-tester
177
244
  licenses:
178
245
  - MIT
179
- metadata:
180
- allowed_push_host: https://rubygems.org/
246
+ metadata: {}
181
247
  post_install_message:
182
248
  rdoc_options: []
183
249
  require_paths:
@@ -193,8 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
259
  - !ruby/object:Gem::Version
194
260
  version: '0'
195
261
  requirements: []
196
- rubyforge_project:
197
- rubygems_version: 2.6.12
262
+ rubygems_version: 3.0.3.1
198
263
  signing_key:
199
264
  specification_version: 4
200
265
  summary: Tool to help test APIs
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 2.2.1
5
-
6
- before_install: gem install bundler -v 1.13.6
@@ -1,21 +0,0 @@
1
- module ApiTester
2
- class MissingResponseFieldReport
3
- attr_accessor :url
4
- attr_accessor :verb
5
- attr_accessor :expected_field
6
- attr_accessor :description
7
-
8
- def initialize(url, verb, expected_field, description)
9
- self.url = url
10
- self.verb = verb
11
- self.expected_field = expected_field
12
- self.description = description
13
- end
14
-
15
- def print
16
- puts "#{self.description}:"
17
- puts " #{self.verb} #{self.url} is missing response field:"
18
- puts " #{self.expected_field}"
19
- end
20
- end
21
- end