api-tester 0.0.1
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/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +182 -0
- data/Rakefile +6 -0
- data/api-tester.gemspec +39 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/tester.rb +7 -0
- data/lib/tester/api_tester.rb +48 -0
- data/lib/tester/definition/boundary_case.rb +11 -0
- data/lib/tester/definition/endpoint.rb +22 -0
- data/lib/tester/definition/fields/array_field.rb +44 -0
- data/lib/tester/definition/fields/boolean_field.rb +18 -0
- data/lib/tester/definition/fields/email_field.rb +20 -0
- data/lib/tester/definition/fields/enum_field.rb +27 -0
- data/lib/tester/definition/fields/field.rb +47 -0
- data/lib/tester/definition/fields/number_field.rb +17 -0
- data/lib/tester/definition/fields/object_field.rb +42 -0
- data/lib/tester/definition/methods/api_get.rb +21 -0
- data/lib/tester/definition/methods/api_method.rb +22 -0
- data/lib/tester/definition/methods/api_post.rb +26 -0
- data/lib/tester/definition/request.rb +49 -0
- data/lib/tester/definition/response.rb +29 -0
- data/lib/tester/method_case_test.rb +67 -0
- data/lib/tester/modules/format.rb +26 -0
- data/lib/tester/modules/good_case.rb +29 -0
- data/lib/tester/modules/module.rb +38 -0
- data/lib/tester/modules/typo.rb +67 -0
- data/lib/tester/modules/unused_fields.rb +22 -0
- data/lib/tester/reporter/api_report.rb +33 -0
- data/lib/tester/reporter/missing_field_report.rb +23 -0
- data/lib/tester/reporter/missing_response_field_report.rb +19 -0
- data/lib/tester/reporter/report.rb +25 -0
- data/lib/tester/reporter/status_code_report.rb +12 -0
- data/lib/tester/test_helper.rb +7 -0
- data/lib/tester/util/response_evaluator.rb +73 -0
- data/lib/tester/util/supported_verbs.rb +25 -0
- data/lib/tester/version.rb +3 -0
- metadata +157 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'tester/reporter/status_code_report'
|
2
|
+
require 'tester/test_helper'
|
3
|
+
|
4
|
+
class Module
|
5
|
+
attr_accessor :report
|
6
|
+
attr_accessor :test_helper
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.test_helper = TestHelper.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_report report
|
13
|
+
self.report = report
|
14
|
+
end
|
15
|
+
|
16
|
+
def go definition, report
|
17
|
+
set_report report
|
18
|
+
end
|
19
|
+
|
20
|
+
def order
|
21
|
+
5
|
22
|
+
end
|
23
|
+
|
24
|
+
def before
|
25
|
+
self.test_helper.before
|
26
|
+
end
|
27
|
+
|
28
|
+
def after
|
29
|
+
self.test_helper.after
|
30
|
+
end
|
31
|
+
|
32
|
+
def call method, format_case
|
33
|
+
self.before
|
34
|
+
response = method.call format_case.payload, format_case.headers
|
35
|
+
self.after
|
36
|
+
response
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'tester/reporter/status_code_report'
|
2
|
+
require 'tester/modules/module'
|
3
|
+
require 'tester/util/supported_verbs'
|
4
|
+
|
5
|
+
class Typo < Module
|
6
|
+
def go(definition, report)
|
7
|
+
super
|
8
|
+
|
9
|
+
contract = allowances(definition)
|
10
|
+
|
11
|
+
contract.each do |url, verbs|
|
12
|
+
check_verbs definition, url, verbs
|
13
|
+
|
14
|
+
check_typo_url definition, url
|
15
|
+
end
|
16
|
+
|
17
|
+
report.reports == []
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_verbs definition, url, verbs
|
21
|
+
missing_verbs = SupportedVerbs.all - verbs
|
22
|
+
missing_verbs.each do |verb|
|
23
|
+
check_method = create_api_method url, verb
|
24
|
+
typo_case = BoundaryCase.new("Typo verb check #{verb}", {}, {})
|
25
|
+
response = self.call check_method, typo_case
|
26
|
+
|
27
|
+
test = TypoClass.new response, typo_case.payload, definition.not_allowed_response, url, verb
|
28
|
+
reports = test.check
|
29
|
+
self.report.reports.concat reports
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def check_typo_url definition, url
|
34
|
+
bad_url = "#{url}gibberishadsfasdf"
|
35
|
+
typo_case = BoundaryCase.new("Typo URL check", {}, {})
|
36
|
+
check_method = create_api_method bad_url, SupportedVerbs::GET
|
37
|
+
response = self.call check_method, typo_case
|
38
|
+
|
39
|
+
test = TypoClass.new response, typo_case.payload, definition.not_found_response, bad_url, SupportedVerbs::GET
|
40
|
+
reports = test.check
|
41
|
+
self.report.reports.concat reports
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_api_method url, verb
|
45
|
+
method = SupportedVerbs.get_method_for(verb)
|
46
|
+
method.new url
|
47
|
+
end
|
48
|
+
|
49
|
+
def allowances(definition)
|
50
|
+
allowances = {}
|
51
|
+
definition.methods.each do |method|
|
52
|
+
url = method.url
|
53
|
+
if allowances[url]
|
54
|
+
allowances[url] << method.verb
|
55
|
+
else
|
56
|
+
allowances[url] = [method.verb]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
allowances
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class TypoClass < MethodCaseTest
|
64
|
+
def initialize response, payload, expected_response, url, verb
|
65
|
+
super response, payload, expected_response, url, verb, "TypoModule"
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'tester/reporter/missing_response_field_report'
|
2
|
+
require 'tester/modules/module'
|
3
|
+
|
4
|
+
class UnusedFields < Module
|
5
|
+
def go definition, report
|
6
|
+
super
|
7
|
+
|
8
|
+
definition.methods.each do |method|
|
9
|
+
method.expected_response.body.each do |field|
|
10
|
+
if field.is_seen == 0
|
11
|
+
report.add_new_report MissingResponseFieldReport.new(method.url, method.verb, field.name, "UnusedFieldsModule")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
report.reports == []
|
17
|
+
end
|
18
|
+
|
19
|
+
def order
|
20
|
+
99
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'tester/reporter/report'
|
2
|
+
|
3
|
+
class ApiReport
|
4
|
+
attr_accessor :reports
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
self.reports = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_new url, request, expected_response, actual_response, description="A case"
|
11
|
+
report = Report.new description, url, request, expected_response, actual_response
|
12
|
+
self.reports << report
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_new_report report
|
16
|
+
self.reports << report
|
17
|
+
end
|
18
|
+
|
19
|
+
def print
|
20
|
+
if self.reports.size > 0
|
21
|
+
puts "Issues discovered: #{self.reports.size}"
|
22
|
+
self.reports.each do |report|
|
23
|
+
report.print
|
24
|
+
puts "\n"
|
25
|
+
puts "\n"
|
26
|
+
end
|
27
|
+
puts ""
|
28
|
+
puts "Issues discovered: #{self.reports.size}"
|
29
|
+
else
|
30
|
+
puts "No issues found"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class MissingFieldReport
|
2
|
+
attr_accessor :description
|
3
|
+
attr_accessor :url
|
4
|
+
attr_accessor :request
|
5
|
+
attr_accessor :expected_field
|
6
|
+
attr_accessor :actual_response
|
7
|
+
|
8
|
+
def initialize(description, url, request, expected_field)
|
9
|
+
self.description = description
|
10
|
+
self.url = url
|
11
|
+
self.request = request
|
12
|
+
self.expected_field = expected_field
|
13
|
+
self.actual_response = ''
|
14
|
+
end
|
15
|
+
|
16
|
+
def print
|
17
|
+
puts "#{self.description}: "
|
18
|
+
puts " Requested #{self.url} with payload:"
|
19
|
+
puts " #{self.request}"
|
20
|
+
puts ' Missing field: '
|
21
|
+
puts " #{self.expected_field}"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class MissingResponseFieldReport
|
2
|
+
attr_accessor :url
|
3
|
+
attr_accessor :verb
|
4
|
+
attr_accessor :expected_field
|
5
|
+
attr_accessor :description
|
6
|
+
|
7
|
+
def initialize(url, verb, expected_field, description)
|
8
|
+
self.url = url
|
9
|
+
self.verb = verb
|
10
|
+
self.expected_field = expected_field
|
11
|
+
self.description = description
|
12
|
+
end
|
13
|
+
|
14
|
+
def print
|
15
|
+
puts "#{self.description}:"
|
16
|
+
puts " #{self.verb} #{self.url} is missing response field:"
|
17
|
+
puts " #{self.expected_field}"
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Report
|
2
|
+
attr_accessor :description
|
3
|
+
attr_accessor :url
|
4
|
+
attr_accessor :request
|
5
|
+
attr_accessor :expected_response
|
6
|
+
attr_accessor :actual_response
|
7
|
+
|
8
|
+
def initialize description, url, request, expected_response, actual_response
|
9
|
+
self.description = description
|
10
|
+
self.url = url
|
11
|
+
self.request = request
|
12
|
+
self.expected_response = expected_response
|
13
|
+
self.actual_response = actual_response
|
14
|
+
end
|
15
|
+
|
16
|
+
def print
|
17
|
+
puts "#{self.description}: "
|
18
|
+
puts " Requested #{self.url} with payload:"
|
19
|
+
puts " #{self.request.to_json}"
|
20
|
+
puts " Expecting: "
|
21
|
+
puts " #{self.expected_response}"
|
22
|
+
puts " Receiving: "
|
23
|
+
puts " #{self.actual_response}"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'tester/reporter/report'
|
2
|
+
|
3
|
+
class StatusCodeReport < Report
|
4
|
+
attr_accessor :expected_status_code
|
5
|
+
attr_accessor :actual_status_code
|
6
|
+
|
7
|
+
def initialize description, url, request, expected_status_code, actual_status_code
|
8
|
+
super description, url, request, expected_status_code, actual_status_code
|
9
|
+
self.expected_status_code = expected_status_code
|
10
|
+
self.actual_status_code = actual_status_code
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class ResponseEvaluator
|
2
|
+
attr_accessor :response_body
|
3
|
+
attr_accessor :expected_response
|
4
|
+
|
5
|
+
def initialize(actual_response_body, expected_response_fields)
|
6
|
+
self.response_body = actual_response_body
|
7
|
+
self.expected_response = expected_response_fields
|
8
|
+
end
|
9
|
+
|
10
|
+
def response_field_array
|
11
|
+
field_array self.response_body
|
12
|
+
end
|
13
|
+
|
14
|
+
def expected_fields
|
15
|
+
expected_fields_hash.keys
|
16
|
+
end
|
17
|
+
|
18
|
+
def seen_fields
|
19
|
+
seen = []
|
20
|
+
fields = response_field_array - extra_fields
|
21
|
+
expected = expected_fields_hash
|
22
|
+
fields.each do |field_key|
|
23
|
+
seen << expected[field_key]
|
24
|
+
end
|
25
|
+
seen
|
26
|
+
end
|
27
|
+
|
28
|
+
def expected_fields_hash
|
29
|
+
expected_field_array self.expected_response.body
|
30
|
+
end
|
31
|
+
|
32
|
+
def extra_fields
|
33
|
+
response_field_array - expected_fields
|
34
|
+
end
|
35
|
+
|
36
|
+
def missing_fields
|
37
|
+
expected_fields - response_field_array
|
38
|
+
end
|
39
|
+
|
40
|
+
def expected_field_array expected_fields
|
41
|
+
fields = {}
|
42
|
+
expected_fields.each do |field|
|
43
|
+
fields[field.name] = field
|
44
|
+
fields = fields.merge inner_expected_field(field.fields, field.name)
|
45
|
+
end
|
46
|
+
fields
|
47
|
+
end
|
48
|
+
|
49
|
+
def inner_expected_field expected_fields, name
|
50
|
+
fields = {}
|
51
|
+
expected_fields.each do |field|
|
52
|
+
inner_name = "#{name}.#{field.name}"
|
53
|
+
fields[inner_name] = field
|
54
|
+
fields = fields.merge inner_expected_field(field.fields, inner_name)
|
55
|
+
end
|
56
|
+
fields
|
57
|
+
end
|
58
|
+
|
59
|
+
def field_array object
|
60
|
+
fields = []
|
61
|
+
object.each do |key, value|
|
62
|
+
if(value)
|
63
|
+
fields << key.to_s
|
64
|
+
fields.concat(field_array(value).map{|i| "#{key}.#{i}"})
|
65
|
+
else
|
66
|
+
fields.concat(field_array(key))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
fields
|
70
|
+
rescue NoMethodError => e
|
71
|
+
fields
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SupportedVerbs
|
2
|
+
def SupportedVerbs.add_item(key, value)
|
3
|
+
@hash ||= {}
|
4
|
+
@hash[key] = value
|
5
|
+
end
|
6
|
+
|
7
|
+
def SupportedVerbs.const_missing(key)
|
8
|
+
@hash[key]
|
9
|
+
end
|
10
|
+
|
11
|
+
def SupportedVerbs.each
|
12
|
+
@hash.each {|key,value| yield(key,value)}
|
13
|
+
end
|
14
|
+
|
15
|
+
def SupportedVerbs.all
|
16
|
+
@hash.values
|
17
|
+
end
|
18
|
+
|
19
|
+
def SupportedVerbs.get_method_for(verb)
|
20
|
+
{:get => ApiGet, :post => ApiPost}[verb]
|
21
|
+
end
|
22
|
+
|
23
|
+
SupportedVerbs.add_item :GET, :get
|
24
|
+
SupportedVerbs.add_item :POST, :post
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api-tester
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- arane
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
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: rest-client
|
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'
|
83
|
+
description: Tool to test APIs which will eventually do boundary testing and other
|
84
|
+
sorts of testing automatically given a contract
|
85
|
+
email:
|
86
|
+
- arane9@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- api-tester.gemspec
|
99
|
+
- bin/console
|
100
|
+
- bin/setup
|
101
|
+
- lib/tester.rb
|
102
|
+
- lib/tester/api_tester.rb
|
103
|
+
- lib/tester/definition/boundary_case.rb
|
104
|
+
- lib/tester/definition/endpoint.rb
|
105
|
+
- lib/tester/definition/fields/array_field.rb
|
106
|
+
- lib/tester/definition/fields/boolean_field.rb
|
107
|
+
- lib/tester/definition/fields/email_field.rb
|
108
|
+
- lib/tester/definition/fields/enum_field.rb
|
109
|
+
- lib/tester/definition/fields/field.rb
|
110
|
+
- lib/tester/definition/fields/number_field.rb
|
111
|
+
- lib/tester/definition/fields/object_field.rb
|
112
|
+
- lib/tester/definition/methods/api_get.rb
|
113
|
+
- lib/tester/definition/methods/api_method.rb
|
114
|
+
- lib/tester/definition/methods/api_post.rb
|
115
|
+
- lib/tester/definition/request.rb
|
116
|
+
- lib/tester/definition/response.rb
|
117
|
+
- lib/tester/method_case_test.rb
|
118
|
+
- lib/tester/modules/format.rb
|
119
|
+
- lib/tester/modules/good_case.rb
|
120
|
+
- lib/tester/modules/module.rb
|
121
|
+
- lib/tester/modules/typo.rb
|
122
|
+
- lib/tester/modules/unused_fields.rb
|
123
|
+
- lib/tester/reporter/api_report.rb
|
124
|
+
- lib/tester/reporter/missing_field_report.rb
|
125
|
+
- lib/tester/reporter/missing_response_field_report.rb
|
126
|
+
- lib/tester/reporter/report.rb
|
127
|
+
- lib/tester/reporter/status_code_report.rb
|
128
|
+
- lib/tester/test_helper.rb
|
129
|
+
- lib/tester/util/response_evaluator.rb
|
130
|
+
- lib/tester/util/supported_verbs.rb
|
131
|
+
- lib/tester/version.rb
|
132
|
+
homepage: https://github.com/araneforseti/api-tester
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata:
|
136
|
+
allowed_push_host: https://rubygems.org/
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.6.12
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: Tool to help test APIs
|
157
|
+
test_files: []
|