api-tester 0.0.1

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