api-tester 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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