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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +182 -0
  8. data/Rakefile +6 -0
  9. data/api-tester.gemspec +39 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/tester.rb +7 -0
  13. data/lib/tester/api_tester.rb +48 -0
  14. data/lib/tester/definition/boundary_case.rb +11 -0
  15. data/lib/tester/definition/endpoint.rb +22 -0
  16. data/lib/tester/definition/fields/array_field.rb +44 -0
  17. data/lib/tester/definition/fields/boolean_field.rb +18 -0
  18. data/lib/tester/definition/fields/email_field.rb +20 -0
  19. data/lib/tester/definition/fields/enum_field.rb +27 -0
  20. data/lib/tester/definition/fields/field.rb +47 -0
  21. data/lib/tester/definition/fields/number_field.rb +17 -0
  22. data/lib/tester/definition/fields/object_field.rb +42 -0
  23. data/lib/tester/definition/methods/api_get.rb +21 -0
  24. data/lib/tester/definition/methods/api_method.rb +22 -0
  25. data/lib/tester/definition/methods/api_post.rb +26 -0
  26. data/lib/tester/definition/request.rb +49 -0
  27. data/lib/tester/definition/response.rb +29 -0
  28. data/lib/tester/method_case_test.rb +67 -0
  29. data/lib/tester/modules/format.rb +26 -0
  30. data/lib/tester/modules/good_case.rb +29 -0
  31. data/lib/tester/modules/module.rb +38 -0
  32. data/lib/tester/modules/typo.rb +67 -0
  33. data/lib/tester/modules/unused_fields.rb +22 -0
  34. data/lib/tester/reporter/api_report.rb +33 -0
  35. data/lib/tester/reporter/missing_field_report.rb +23 -0
  36. data/lib/tester/reporter/missing_response_field_report.rb +19 -0
  37. data/lib/tester/reporter/report.rb +25 -0
  38. data/lib/tester/reporter/status_code_report.rb +12 -0
  39. data/lib/tester/test_helper.rb +7 -0
  40. data/lib/tester/util/response_evaluator.rb +73 -0
  41. data/lib/tester/util/supported_verbs.rb +25 -0
  42. data/lib/tester/version.rb +3 -0
  43. 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,7 @@
1
+ class TestHelper
2
+ def before
3
+ end
4
+
5
+ def after
6
+ end
7
+ 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
@@ -0,0 +1,3 @@
1
+ module Tester
2
+ VERSION = "0.0.1"
3
+ 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: []