api-tester 0.1.0 → 0.2.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -12
  3. data/api-tester.gemspec +2 -2
  4. data/changelog.txt +5 -0
  5. data/lib/api-tester.rb +14 -0
  6. data/lib/api-tester/config.rb +40 -0
  7. data/lib/api-tester/definition/api_contract.rb +15 -0
  8. data/lib/api-tester/definition/api_method.rb +13 -0
  9. data/lib/api-tester/definition/boundary_case.rb +13 -0
  10. data/lib/api-tester/definition/endpoint.rb +61 -0
  11. data/lib/api-tester/definition/fields/array_field.rb +46 -0
  12. data/lib/api-tester/definition/fields/boolean_field.rb +20 -0
  13. data/lib/api-tester/definition/fields/email_field.rb +22 -0
  14. data/lib/api-tester/definition/fields/enum_field.rb +29 -0
  15. data/lib/api-tester/definition/fields/field.rb +49 -0
  16. data/lib/api-tester/definition/fields/number_field.rb +19 -0
  17. data/lib/api-tester/definition/fields/object_field.rb +44 -0
  18. data/lib/api-tester/definition/request.rb +51 -0
  19. data/lib/api-tester/definition/response.rb +36 -0
  20. data/lib/api-tester/method_case_test.rb +69 -0
  21. data/lib/api-tester/modules/extra_verbs.rb +27 -0
  22. data/lib/api-tester/modules/format.rb +28 -0
  23. data/lib/api-tester/modules/good_case.rb +31 -0
  24. data/lib/api-tester/modules/module.rb +20 -0
  25. data/lib/api-tester/modules/typo.rb +43 -0
  26. data/lib/api-tester/modules/unused_fields.rb +24 -0
  27. data/lib/api-tester/reporter/api_report.rb +35 -0
  28. data/lib/api-tester/reporter/missing_field_report.rb +25 -0
  29. data/lib/api-tester/reporter/missing_response_field_report.rb +21 -0
  30. data/lib/api-tester/reporter/report.rb +27 -0
  31. data/lib/api-tester/reporter/status_code_report.rb +14 -0
  32. data/lib/api-tester/test_helper.rb +12 -0
  33. data/lib/api-tester/util/response_evaluator.rb +75 -0
  34. data/lib/api-tester/util/supported_verbs.rb +36 -0
  35. data/lib/api-tester/version.rb +3 -0
  36. metadata +33 -33
  37. data/lib/tester.rb +0 -7
  38. data/lib/tester/api_tester.rb +0 -50
  39. data/lib/tester/definition/api_contract.rb +0 -13
  40. data/lib/tester/definition/api_method.rb +0 -11
  41. data/lib/tester/definition/boundary_case.rb +0 -11
  42. data/lib/tester/definition/endpoint.rb +0 -57
  43. data/lib/tester/definition/fields/array_field.rb +0 -44
  44. data/lib/tester/definition/fields/boolean_field.rb +0 -18
  45. data/lib/tester/definition/fields/email_field.rb +0 -20
  46. data/lib/tester/definition/fields/enum_field.rb +0 -27
  47. data/lib/tester/definition/fields/field.rb +0 -47
  48. data/lib/tester/definition/fields/number_field.rb +0 -17
  49. data/lib/tester/definition/fields/object_field.rb +0 -42
  50. data/lib/tester/definition/request.rb +0 -49
  51. data/lib/tester/definition/response.rb +0 -34
  52. data/lib/tester/method_case_test.rb +0 -67
  53. data/lib/tester/modules/extra_verbs.rb +0 -25
  54. data/lib/tester/modules/format.rb +0 -26
  55. data/lib/tester/modules/good_case.rb +0 -29
  56. data/lib/tester/modules/module.rb +0 -18
  57. data/lib/tester/modules/typo.rb +0 -41
  58. data/lib/tester/modules/unused_fields.rb +0 -22
  59. data/lib/tester/reporter/api_report.rb +0 -33
  60. data/lib/tester/reporter/missing_field_report.rb +0 -23
  61. data/lib/tester/reporter/missing_response_field_report.rb +0 -19
  62. data/lib/tester/reporter/report.rb +0 -25
  63. data/lib/tester/reporter/status_code_report.rb +0 -12
  64. data/lib/tester/test_helper.rb +0 -10
  65. data/lib/tester/util/response_evaluator.rb +0 -73
  66. data/lib/tester/util/supported_verbs.rb +0 -34
  67. data/lib/tester/version.rb +0 -3
@@ -0,0 +1,44 @@
1
+ require 'api-tester/definition/fields/field'
2
+
3
+ module ApiTester
4
+ class ObjectField < Field
5
+ attr_accessor :fields
6
+
7
+ def initialize name
8
+ super(name)
9
+ self.fields = []
10
+ end
11
+
12
+ def with_field(newField)
13
+ self.fields << newField
14
+ self
15
+ end
16
+
17
+ def has_subfields?
18
+ true
19
+ end
20
+
21
+ def default_value
22
+ obj = Hash.new
23
+
24
+ self.fields.each do |field|
25
+ obj[field.name] = field.default_value
26
+ end
27
+
28
+ obj
29
+ end
30
+
31
+ def negative_boundary_values
32
+ super +
33
+ [
34
+ "string",
35
+ [],
36
+ 123,
37
+ 1,
38
+ 0,
39
+ true,
40
+ false
41
+ ]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,51 @@
1
+ require 'api-tester/definition/boundary_case'
2
+
3
+ module ApiTester
4
+ class Request
5
+ attr_accessor :definition
6
+ attr_accessor :headers
7
+ attr_accessor :fields
8
+
9
+ def initialize
10
+ self.fields = []
11
+ end
12
+
13
+ def add_field(new_field)
14
+ self.fields << new_field
15
+ self
16
+ end
17
+
18
+ def payload
19
+ response = Hash.new
20
+ self.fields.each do |field|
21
+ response[field.name] = field.default_value
22
+ end
23
+ response
24
+ end
25
+
26
+ def default_payload
27
+ payload
28
+ end
29
+
30
+ def default_headers
31
+ {content_type: :json, accept: :json}
32
+ end
33
+
34
+ def cases
35
+ boundary_cases = Array.new
36
+ self.fields.each do |field|
37
+ field.negative_boundary_values.each do |value|
38
+ bcase = BoundaryCase.new("Setting #{field.name} to #{value}", altered_payload(field.name, value), default_headers)
39
+ boundary_cases.push(bcase)
40
+ end
41
+ end
42
+ boundary_cases
43
+ end
44
+
45
+ def altered_payload field_name, value
46
+ body = payload
47
+ body[field_name] = value
48
+ body
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ module ApiTester
2
+ class Response
3
+ attr_accessor :code
4
+ attr_accessor :body
5
+
6
+ def initialize(status_code=200)
7
+ self.code = status_code
8
+ self.body = []
9
+ end
10
+
11
+ def add_field(new_field)
12
+ self.body << new_field
13
+ self
14
+ end
15
+
16
+ def to_s
17
+ des = {}
18
+ self.body.map do |f|
19
+ des[f.name] = field_display f
20
+ end
21
+ des.to_json
22
+ end
23
+
24
+ def field_display field
25
+ des = field.display_class
26
+ if field.has_subfields?
27
+ des = {}
28
+ field.fields.map do |f|
29
+ des[f.name] = field_display f
30
+ end
31
+ des.to_json
32
+ end
33
+ des
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,69 @@
1
+ require 'api-tester/util/response_evaluator.rb'
2
+
3
+ module ApiTester
4
+ class MethodCaseTest
5
+ attr_accessor :expected_response
6
+ attr_accessor :payload
7
+ attr_accessor :response
8
+ attr_accessor :reports
9
+ attr_accessor :url
10
+ attr_accessor :module_name
11
+
12
+ def initialize response, payload, expected_response, url, verb, module_name
13
+ self.payload = payload
14
+ self.response = response
15
+ self.expected_response = expected_response
16
+ self.reports = []
17
+ self.url = "#{verb} #{url}"
18
+ self.module_name = module_name
19
+ end
20
+
21
+ def response_code_report
22
+ report = StatusCodeReport.new "#{module_name} - Incorrect response code", self.url, self.payload, self.expected_response.code, self.response.code
23
+ self.reports << report
24
+ nil
25
+ end
26
+
27
+ def missing_field_report field
28
+ report = Report.new "#{module_name} - Missing field #{field}", self.url, self.payload, self.expected_response, self.response
29
+ self.reports << report
30
+ nil
31
+ end
32
+
33
+ def extra_field_report field
34
+ report = Report.new "#{module_name} - Found extra field #{field}", self.url, self.payload, self.expected_response, self.response
35
+ self.reports << report
36
+ nil
37
+ end
38
+
39
+ def check
40
+ if check_response_code
41
+ evaluator = ApiTester::ResponseEvaluator.new json_parse(self.response.body), self.expected_response
42
+ evaluator.missing_fields.map{|field| missing_field_report(field)}
43
+ evaluator.extra_fields.map{|field| extra_field_report(field)}
44
+ increment_fields evaluator.seen_fields
45
+ end
46
+ return self.reports
47
+ end
48
+
49
+ def check_response_code
50
+ if response.code != expected_response.code
51
+ response_code_report
52
+ return false
53
+ end
54
+ return true
55
+ end
56
+
57
+ def increment_fields seen_fields
58
+ seen_fields.each do |field|
59
+ field.seen
60
+ end
61
+ end
62
+
63
+ def json_parse body
64
+ JSON.parse!(body)
65
+ rescue JSON::ParserError
66
+ body
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,27 @@
1
+ require 'api-tester/modules/module'
2
+ require 'api-tester/util/supported_verbs'
3
+
4
+ module ApiTester
5
+ class ExtraVerbs < Module
6
+ def go(endpoint, report)
7
+ super
8
+
9
+ extras = ApiTester::SupportedVerbs.all - endpoint.verbs
10
+ extras.each do |verb|
11
+ verb_case = BoundaryCase.new("Verb check with #{verb} for #{endpoint.name}", {}, {})
12
+ method = ApiTester::ApiMethod.new verb, ApiTester::Response.new, ApiTester::Request.new
13
+ response = endpoint.call method, verb_case.payload, verb_case.headers
14
+ test = VerbClass.new response, verb_case.payload, endpoint.not_allowed_response, endpoint.url, verb
15
+ reports = test.check
16
+ self.report.reports.concat reports
17
+ end
18
+ self.report.reports == []
19
+ end
20
+ end
21
+
22
+ class VerbClass < MethodCaseTest
23
+ def initialize response, payload, expected_response, url, verb
24
+ super response, payload, expected_response, url, verb, "VerbModule"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'api-tester/reporter/status_code_report'
2
+ require 'api-tester/modules/module'
3
+ require 'api-tester/method_case_test'
4
+
5
+ module ApiTester
6
+ class Format < Module
7
+ def go definition, report
8
+ super
9
+
10
+ definition.methods.each do |method|
11
+ cases = method.request.cases
12
+ cases.each do |format_case|
13
+ response = definition.call method, format_case.payload, format_case.headers
14
+ test = FormatTest.new response, format_case.payload, definition.bad_request_response, definition.url, method.verb
15
+ self.report.reports.concat test.check
16
+ end
17
+ end
18
+
19
+ report.reports == []
20
+ end
21
+ end
22
+
23
+ class FormatTest < MethodCaseTest
24
+ def initialize response, payload, expected_response, url, verb
25
+ super response, payload, expected_response, url, verb, "FormatModule"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require 'api-tester/reporter/status_code_report'
2
+ require 'api-tester/modules/module'
3
+ require 'api-tester/method_case_test'
4
+
5
+ module ApiTester
6
+ class GoodCase < Module
7
+ def go endpoint, report
8
+ super
9
+
10
+ endpoint.methods.each do |method|
11
+ default_case = BoundaryCase.new endpoint.url, method.request.default_payload, method.request.default_headers
12
+ response = endpoint.call method, default_case.payload, default_case.headers
13
+ test = GoodCaseTest.new response, endpoint.url, method
14
+ self.report.reports.concat test.check
15
+ end
16
+
17
+ self.report.reports == []
18
+ end
19
+
20
+ def order
21
+ 1
22
+ end
23
+ end
24
+
25
+
26
+ class GoodCaseTest < MethodCaseTest
27
+ def initialize response, url, method
28
+ super response, method.request.default_payload, method.expected_response, url, method.verb, "GoodCaseModule"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ require 'api-tester/reporter/status_code_report'
2
+ require 'api-tester/test_helper'
3
+
4
+ module ApiTester
5
+ class Module
6
+ attr_accessor :report
7
+
8
+ def set_report report
9
+ self.report = report
10
+ end
11
+
12
+ def go definition, report
13
+ set_report report
14
+ end
15
+
16
+ def order
17
+ 5
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ require 'api-tester/reporter/status_code_report'
2
+ require 'api-tester/modules/module'
3
+ require 'api-tester/util/supported_verbs'
4
+
5
+ module ApiTester
6
+ class Typo < Module
7
+ def go(endpoint, report)
8
+ super
9
+
10
+ allowances(endpoint).each do |verbs|
11
+ check_typo_url endpoint
12
+ end
13
+
14
+ report.reports == []
15
+ end
16
+
17
+ def check_typo_url endpoint
18
+ bad_url = "#{endpoint.url}gibberishadsfasdf"
19
+ bad_endpoint = ApiTester::Endpoint.new "Bad URL", bad_url
20
+ typo_case = BoundaryCase.new("Typo URL check", {}, {})
21
+ method = ApiTester::ApiMethod.new ApiTester::SupportedVerbs::GET, ApiTester::Response.new(200), ApiTester::Request.new
22
+ response = bad_endpoint.call method, typo_case.payload, typo_case.headers
23
+
24
+ test = TypoClass.new response, typo_case.payload, endpoint.not_found_response, bad_url, ApiTester::SupportedVerbs::GET
25
+ reports = test.check
26
+ self.report.reports.concat reports
27
+ end
28
+
29
+ def allowances(endpoint)
30
+ allowances = []
31
+ endpoint.methods.each do |method|
32
+ allowances << method.verb
33
+ end
34
+ allowances.uniq
35
+ end
36
+ end
37
+
38
+ class TypoClass < MethodCaseTest
39
+ def initialize response, payload, expected_response, url, verb
40
+ super response, payload, expected_response, url, verb, "TypoModule"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ require 'api-tester/reporter/missing_response_field_report'
2
+ require 'api-tester/modules/module'
3
+
4
+ module ApiTester
5
+ class UnusedFields < Module
6
+ def go definition, report
7
+ super
8
+
9
+ definition.methods.each do |method|
10
+ method.expected_response.body.each do |field|
11
+ if field.is_seen == 0
12
+ report.add_new_report MissingResponseFieldReport.new(definition.url, method.verb, field.name, "UnusedFieldsModule")
13
+ end
14
+ end
15
+ end
16
+
17
+ report.reports == []
18
+ end
19
+
20
+ def order
21
+ 99
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ require 'api-tester/reporter/report'
2
+
3
+ module ApiTester
4
+ class ApiReport
5
+ attr_accessor :reports
6
+
7
+ def initialize
8
+ self.reports = []
9
+ end
10
+
11
+ def add_new url, request, expected_response, actual_response, description="A case"
12
+ report = Report.new description, url, request, expected_response, actual_response
13
+ self.reports << report
14
+ end
15
+
16
+ def add_new_report report
17
+ self.reports << report
18
+ end
19
+
20
+ def print
21
+ if self.reports.size > 0
22
+ puts "Issues discovered: #{self.reports.size}"
23
+ self.reports.each do |report|
24
+ report.print
25
+ puts "\n"
26
+ puts "\n"
27
+ end
28
+ puts ""
29
+ puts "Issues discovered: #{self.reports.size}"
30
+ else
31
+ puts "No issues found"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module ApiReport
2
+ class MissingFieldReport
3
+ attr_accessor :description
4
+ attr_accessor :url
5
+ attr_accessor :request
6
+ attr_accessor :expected_field
7
+ attr_accessor :actual_response
8
+
9
+ def initialize(description, url, request, expected_field)
10
+ self.description = description
11
+ self.url = url
12
+ self.request = request
13
+ self.expected_field = expected_field
14
+ self.actual_response = ''
15
+ end
16
+
17
+ def print
18
+ puts "#{self.description}: "
19
+ puts " Requested #{self.url} with payload:"
20
+ puts " #{self.request}"
21
+ puts ' Missing field: '
22
+ puts " #{self.expected_field}"
23
+ end
24
+ end
25
+ end