api-tester 0.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/push.yml +39 -0
  4. data/.github/workflows/test.yml +31 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +61 -0
  7. data/Gemfile +2 -0
  8. data/Guardfile +70 -0
  9. data/README.md +106 -74
  10. data/Rakefile +8 -3
  11. data/api-tester.gemspec +31 -23
  12. data/changelog.txt +35 -0
  13. data/lib/api-tester.rb +15 -0
  14. data/lib/api-tester/config.rb +43 -0
  15. data/lib/api-tester/definition/boundary_case.rb +16 -0
  16. data/lib/api-tester/definition/contract.rb +20 -0
  17. data/lib/api-tester/definition/endpoint.rb +84 -0
  18. data/lib/api-tester/definition/fields/array_field.rb +47 -0
  19. data/lib/api-tester/definition/fields/boolean_field.rb +23 -0
  20. data/lib/api-tester/definition/fields/email_field.rb +25 -0
  21. data/lib/api-tester/definition/fields/enum_field.rb +32 -0
  22. data/lib/api-tester/definition/fields/field.rb +50 -0
  23. data/lib/api-tester/definition/fields/number_field.rb +22 -0
  24. data/lib/api-tester/definition/fields/object_field.rb +47 -0
  25. data/lib/api-tester/definition/fields/plain_array_field.rb +25 -0
  26. data/lib/api-tester/definition/method.rb +22 -0
  27. data/lib/api-tester/definition/request.rb +96 -0
  28. data/lib/api-tester/definition/response.rb +39 -0
  29. data/lib/api-tester/method_case_test.rb +83 -0
  30. data/lib/api-tester/modules/extra_verbs.rb +53 -0
  31. data/lib/api-tester/modules/format.rb +47 -0
  32. data/lib/api-tester/modules/good_case.rb +46 -0
  33. data/lib/api-tester/modules/injection_module.rb +81 -0
  34. data/lib/api-tester/modules/required_fields.rb +51 -0
  35. data/lib/api-tester/modules/server_information.rb +42 -0
  36. data/lib/api-tester/modules/typo.rb +70 -0
  37. data/lib/api-tester/modules/unexpected_fields.rb +61 -0
  38. data/lib/api-tester/modules/unused_fields.rb +31 -0
  39. data/lib/api-tester/reporter/api_report.rb +47 -0
  40. data/lib/api-tester/reporter/missing_field_report.rb +24 -0
  41. data/lib/api-tester/reporter/report.rb +30 -0
  42. data/lib/api-tester/reporter/status_code_report.rb +21 -0
  43. data/lib/api-tester/test_helper.rb +12 -0
  44. data/lib/api-tester/util/response_evaluator.rb +88 -0
  45. data/lib/api-tester/util/supported_verbs.rb +39 -0
  46. data/lib/api-tester/version.rb +5 -0
  47. metadata +159 -42
  48. data/.travis.yml +0 -6
  49. data/lib/tester.rb +0 -7
  50. data/lib/tester/api_tester.rb +0 -50
  51. data/lib/tester/definition/api_contract.rb +0 -13
  52. data/lib/tester/definition/api_method.rb +0 -11
  53. data/lib/tester/definition/boundary_case.rb +0 -11
  54. data/lib/tester/definition/endpoint.rb +0 -57
  55. data/lib/tester/definition/fields/array_field.rb +0 -44
  56. data/lib/tester/definition/fields/boolean_field.rb +0 -18
  57. data/lib/tester/definition/fields/email_field.rb +0 -20
  58. data/lib/tester/definition/fields/enum_field.rb +0 -27
  59. data/lib/tester/definition/fields/field.rb +0 -47
  60. data/lib/tester/definition/fields/number_field.rb +0 -17
  61. data/lib/tester/definition/fields/object_field.rb +0 -42
  62. data/lib/tester/definition/request.rb +0 -49
  63. data/lib/tester/definition/response.rb +0 -34
  64. data/lib/tester/method_case_test.rb +0 -67
  65. data/lib/tester/modules/extra_verbs.rb +0 -25
  66. data/lib/tester/modules/format.rb +0 -26
  67. data/lib/tester/modules/good_case.rb +0 -29
  68. data/lib/tester/modules/module.rb +0 -18
  69. data/lib/tester/modules/typo.rb +0 -41
  70. data/lib/tester/modules/unused_fields.rb +0 -22
  71. data/lib/tester/reporter/api_report.rb +0 -33
  72. data/lib/tester/reporter/missing_field_report.rb +0 -23
  73. data/lib/tester/reporter/missing_response_field_report.rb +0 -19
  74. data/lib/tester/reporter/report.rb +0 -25
  75. data/lib/tester/reporter/status_code_report.rb +0 -12
  76. data/lib/tester/test_helper.rb +0 -10
  77. data/lib/tester/util/response_evaluator.rb +0 -73
  78. data/lib/tester/util/supported_verbs.rb +0 -34
  79. data/lib/tester/version.rb +0 -3
@@ -1,67 +0,0 @@
1
- require 'tester/util/response_evaluator.rb'
2
-
3
- class MethodCaseTest
4
- attr_accessor :expected_response
5
- attr_accessor :payload
6
- attr_accessor :response
7
- attr_accessor :reports
8
- attr_accessor :url
9
- attr_accessor :module_name
10
-
11
- def initialize response, payload, expected_response, url, verb, module_name
12
- self.payload = payload
13
- self.response = response
14
- self.expected_response = expected_response
15
- self.reports = []
16
- self.url = "#{verb} #{url}"
17
- self.module_name = module_name
18
- end
19
-
20
- def response_code_report
21
- report = StatusCodeReport.new "#{module_name} - Incorrect response code", self.url, self.payload, self.expected_response.code, self.response.code
22
- self.reports << report
23
- nil
24
- end
25
-
26
- def missing_field_report field
27
- report = Report.new "#{module_name} - Missing field #{field}", self.url, self.payload, self.expected_response, self.response
28
- self.reports << report
29
- nil
30
- end
31
-
32
- def extra_field_report field
33
- report = Report.new "#{module_name} - Found extra field #{field}", self.url, self.payload, self.expected_response, self.response
34
- self.reports << report
35
- nil
36
- end
37
-
38
- def check
39
- if check_response_code
40
- evaluator = ResponseEvaluator.new json_parse(self.response.body), self.expected_response
41
- evaluator.missing_fields.map{|field| missing_field_report(field)}
42
- evaluator.extra_fields.map{|field| extra_field_report(field)}
43
- increment_fields evaluator.seen_fields
44
- end
45
- return self.reports
46
- end
47
-
48
- def check_response_code
49
- if response.code != expected_response.code
50
- response_code_report
51
- return false
52
- end
53
- return true
54
- end
55
-
56
- def increment_fields seen_fields
57
- seen_fields.each do |field|
58
- field.seen
59
- end
60
- end
61
-
62
- def json_parse body
63
- JSON.parse!(body)
64
- rescue JSON::ParserError
65
- body
66
- end
67
- end
@@ -1,25 +0,0 @@
1
- require 'tester/modules/module'
2
- require 'tester/util/supported_verbs'
3
-
4
- class ExtraVerbs < Module
5
- def go(endpoint, report)
6
- super
7
-
8
- extras = SupportedVerbs.all - endpoint.verbs
9
- extras.each do |verb|
10
- verb_case = BoundaryCase.new("Verb check with #{verb} for #{endpoint.name}", {}, {})
11
- method = ApiMethod.new verb, Response.new, Request.new
12
- response = endpoint.call method, verb_case.payload, verb_case.headers
13
- test = VerbClass.new response, verb_case.payload, endpoint.not_allowed_response, endpoint.url, verb
14
- reports = test.check
15
- self.report.reports.concat reports
16
- end
17
- self.report.reports == []
18
- end
19
- end
20
-
21
- class VerbClass < MethodCaseTest
22
- def initialize response, payload, expected_response, url, verb
23
- super response, payload, expected_response, url, verb, "VerbModule"
24
- end
25
- end
@@ -1,26 +0,0 @@
1
- require 'tester/reporter/status_code_report'
2
- require 'tester/modules/module'
3
- require 'tester/method_case_test'
4
-
5
- class Format < Module
6
- def go definition, report
7
- super
8
-
9
- definition.methods.each do |method|
10
- cases = method.request.cases
11
- cases.each do |format_case|
12
- response = definition.call method, format_case.payload, format_case.headers
13
- test = FormatTest.new response, format_case.payload, definition.bad_request_response, definition.url, method.verb
14
- self.report.reports.concat test.check
15
- end
16
- end
17
-
18
- report.reports == []
19
- end
20
- end
21
-
22
- class FormatTest < MethodCaseTest
23
- def initialize response, payload, expected_response, url, verb
24
- super response, payload, expected_response, url, verb, "FormatModule"
25
- end
26
- end
@@ -1,29 +0,0 @@
1
- require 'tester/reporter/status_code_report'
2
- require 'tester/modules/module'
3
- require 'tester/method_case_test'
4
-
5
- class GoodCase < Module
6
- def go endpoint, report
7
- super
8
-
9
- endpoint.methods.each do |method|
10
- default_case = BoundaryCase.new endpoint.url, method.request.default_payload, method.request.default_headers
11
- response = endpoint.call method, default_case.payload, default_case.headers
12
- test = GoodCaseTest.new response, endpoint.url, method
13
- self.report.reports.concat test.check
14
- end
15
-
16
- self.report.reports == []
17
- end
18
-
19
- def order
20
- 1
21
- end
22
- end
23
-
24
-
25
- class GoodCaseTest < MethodCaseTest
26
- def initialize response, url, method
27
- super response, method.request.default_payload, method.expected_response, url, method.verb, "GoodCaseModule"
28
- end
29
- end
@@ -1,18 +0,0 @@
1
- require 'tester/reporter/status_code_report'
2
- require 'tester/test_helper'
3
-
4
- class Module
5
- attr_accessor :report
6
-
7
- def set_report report
8
- self.report = report
9
- end
10
-
11
- def go definition, report
12
- set_report report
13
- end
14
-
15
- def order
16
- 5
17
- end
18
- end
@@ -1,41 +0,0 @@
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(endpoint, report)
7
- super
8
-
9
- allowances(endpoint).each do |verbs|
10
- check_typo_url endpoint
11
- end
12
-
13
- report.reports == []
14
- end
15
-
16
- def check_typo_url endpoint
17
- bad_url = "#{endpoint.url}gibberishadsfasdf"
18
- bad_endpoint = Endpoint.new "Bad URL", bad_url
19
- typo_case = BoundaryCase.new("Typo URL check", {}, {})
20
- method = ApiMethod.new SupportedVerbs::GET, Response.new(200), Request.new
21
- response = bad_endpoint.call method, typo_case.payload, typo_case.headers
22
-
23
- test = TypoClass.new response, typo_case.payload, endpoint.not_found_response, bad_url, SupportedVerbs::GET
24
- reports = test.check
25
- self.report.reports.concat reports
26
- end
27
-
28
- def allowances(endpoint)
29
- allowances = []
30
- endpoint.methods.each do |method|
31
- allowances << method.verb
32
- end
33
- allowances.uniq
34
- end
35
- end
36
-
37
- class TypoClass < MethodCaseTest
38
- def initialize response, payload, expected_response, url, verb
39
- super response, payload, expected_response, url, verb, "TypoModule"
40
- end
41
- end
@@ -1,22 +0,0 @@
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(definition.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
@@ -1,33 +0,0 @@
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
@@ -1,23 +0,0 @@
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
@@ -1,19 +0,0 @@
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
@@ -1,25 +0,0 @@
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.to_s
22
- puts " Receiving: "
23
- puts " #{self.actual_response}"
24
- end
25
- end
@@ -1,12 +0,0 @@
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
@@ -1,10 +0,0 @@
1
- class TestHelper
2
- def before
3
- end
4
-
5
- def retrieve_param key
6
- end
7
-
8
- def after
9
- end
10
- end
@@ -1,73 +0,0 @@
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
71
- fields
72
- end
73
- end
@@ -1,34 +0,0 @@
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
- SupportedVerbs.add_item :COPY, :copy
20
- SupportedVerbs.add_item :DELETE, :delete
21
- SupportedVerbs.add_item :GET, :get
22
- SupportedVerbs.add_item :HEAD, :head
23
- SupportedVerbs.add_item :LOCK, :lock
24
- SupportedVerbs.add_item :MKCOL, :mkcol
25
- SupportedVerbs.add_item :MOVE, :move
26
- SupportedVerbs.add_item :OPTIONS, :options
27
- SupportedVerbs.add_item :PATCH, :patch
28
- SupportedVerbs.add_item :POST, :post
29
- SupportedVerbs.add_item :PROPFIND, :propfind
30
- SupportedVerbs.add_item :PROPPATCH, :proppatch
31
- SupportedVerbs.add_item :PUT, :put
32
- SupportedVerbs.add_item :TRACE, :trace
33
- SupportedVerbs.add_item :UNLOCK, :unlock
34
- end