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,18 @@
1
+ require 'tester/definition/fields/field'
2
+
3
+ class BooleanField < Field
4
+ def initialize(name, default_value=true)
5
+ super(name, default_value)
6
+ end
7
+
8
+ def negative_boundary_values
9
+ super +
10
+ [
11
+ "string",
12
+ 123,
13
+ 0,
14
+ 1,
15
+ {}
16
+ ]
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ require 'tester/definition/fields/field'
2
+
3
+ class EmailField < Field
4
+ def initialize(name, default_value="test@test.com")
5
+ super(name, default_value)
6
+ end
7
+
8
+ def negative_boundary_values
9
+ super +
10
+ [
11
+ "string",
12
+ 123,
13
+ 1,
14
+ 0,
15
+ true,
16
+ false,
17
+ {}
18
+ ]
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require 'tester/definition/fields/field'
2
+
3
+ class EnumField < Field
4
+ attr_accessor :acceptable_values
5
+
6
+ def initialize name, acceptable_values, default_value=nil
7
+ if default_value
8
+ super name, default_value
9
+ else
10
+ super name, acceptable_values[0]
11
+ end
12
+
13
+ self.acceptable_values = acceptable_values
14
+ end
15
+
16
+ def negative_boundary_values
17
+ super +
18
+ [
19
+ 123,
20
+ 0,
21
+ 1,
22
+ true,
23
+ false,
24
+ {}
25
+ ]
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ class Field
2
+ attr_accessor :name
3
+ attr_accessor :default_value
4
+ attr_accessor :required
5
+ attr_accessor :is_seen
6
+
7
+ def initialize name, default_value="string"
8
+ self.name = name
9
+ self.default_value = default_value
10
+ self.required = false
11
+ self.is_seen = 0
12
+ end
13
+
14
+ def is_required
15
+ self.required = true
16
+ self
17
+ end
18
+
19
+ def is_not_required
20
+ self.required = false
21
+ self
22
+ end
23
+
24
+ def has_subfields?
25
+ false
26
+ end
27
+
28
+ def fields
29
+ []
30
+ end
31
+
32
+ def negative_boundary_values
33
+ cases = []
34
+ if self.required
35
+ cases << nil
36
+ end
37
+ cases
38
+ end
39
+
40
+ def seen
41
+ self.is_seen += 1
42
+ end
43
+
44
+ def display_class
45
+ self.class
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ require 'tester/definition/fields/field'
2
+
3
+ class NumberField < Field
4
+ def initialize(name, default_value=5)
5
+ super(name, default_value)
6
+ end
7
+
8
+ def negative_boundary_values
9
+ super +
10
+ [
11
+ "string",
12
+ true,
13
+ false,
14
+ {}
15
+ ]
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ require 'tester/definition/fields/field'
2
+
3
+ class ObjectField < Field
4
+ attr_accessor :fields
5
+
6
+ def initialize name
7
+ super(name)
8
+ self.fields = []
9
+ end
10
+
11
+ def with_field(newField)
12
+ self.fields << newField
13
+ self
14
+ end
15
+
16
+ def has_subfields?
17
+ true
18
+ end
19
+
20
+ def default_value
21
+ obj = Hash.new
22
+
23
+ self.fields.each do |field|
24
+ obj[field.name] = field.default_value
25
+ end
26
+
27
+ obj
28
+ end
29
+
30
+ def negative_boundary_values
31
+ super +
32
+ [
33
+ "string",
34
+ [],
35
+ 123,
36
+ 1,
37
+ 0,
38
+ true,
39
+ false
40
+ ]
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ require 'tester/definition/request'
2
+ require 'tester/definition/response'
3
+ require "tester/version"
4
+ require 'tester/util/supported_verbs'
5
+ require 'rest-client'
6
+ require 'json'
7
+ require 'tester/definition/methods/api_method'
8
+
9
+ class ApiGet < ApiMethod
10
+ def call params={}, headers={}
11
+ headers[:params] = params
12
+
13
+ RestClient.get(self.url, headers) { |real_response, request, result|
14
+ real_response
15
+ }
16
+ end
17
+
18
+ def verb
19
+ SupportedVerbs::GET
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ require 'tester/definition/request'
2
+ require 'tester/definition/response'
3
+ require 'tester/reporter/status_code_report'
4
+ require 'tester/reporter/missing_field_report'
5
+ require 'tester/reporter/api_report'
6
+ require 'json'
7
+
8
+ class ApiMethod
9
+ attr_accessor :request
10
+ attr_accessor :expected_response
11
+ attr_accessor :url
12
+
13
+ def initialize url
14
+ self.url = url
15
+ self.request = Request.new
16
+ self.expected_response = Response.new 200
17
+ end
18
+
19
+ def verb
20
+ "None"
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ require 'tester/definition/request'
2
+ require 'tester/definition/response'
3
+ require "tester/version"
4
+ require 'rest-client'
5
+ require 'json'
6
+ require 'tester/definition/methods/api_method'
7
+ require 'tester/reporter/api_report'
8
+ require 'tester/reporter/status_code_report'
9
+
10
+ class ApiPost < ApiMethod
11
+ attr_accessor :syntax_error_response
12
+
13
+ def post json_payload, headers
14
+ RestClient.post(self.url, json_payload, headers) { |real_response, request, result|
15
+ real_response
16
+ }
17
+ end
18
+
19
+ def call body_params={}, request_params={}
20
+ post body_params.to_json, request_params
21
+ end
22
+
23
+ def verb
24
+ SupportedVerbs::POST
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ require 'tester/definition/boundary_case'
2
+
3
+ class Request
4
+ attr_accessor :definition
5
+ attr_accessor :headers
6
+ attr_accessor :fields
7
+
8
+ def initialize
9
+ self.fields = []
10
+ end
11
+
12
+ def add_field(new_field)
13
+ self.fields << new_field
14
+ self
15
+ end
16
+
17
+ def payload
18
+ response = Hash.new
19
+ self.fields.each do |field|
20
+ response[field.name] = field.default_value
21
+ end
22
+ response
23
+ end
24
+
25
+ def default_payload
26
+ payload
27
+ end
28
+
29
+ def default_headers
30
+ {content_type: :json, accept: :json}
31
+ end
32
+
33
+ def cases
34
+ boundary_cases = Array.new
35
+ self.fields.each do |field|
36
+ field.negative_boundary_values.each do |value|
37
+ bcase = BoundaryCase.new("Setting #{field.name} to #{value}", altered_payload(field.name, value), default_headers)
38
+ boundary_cases.push(bcase)
39
+ end
40
+ end
41
+ boundary_cases
42
+ end
43
+
44
+ def altered_payload field_name, value
45
+ body = payload
46
+ body[field_name] = value
47
+ body
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ class Response
2
+ attr_accessor :code
3
+ attr_accessor :body
4
+
5
+ def initialize(status_code)
6
+ self.code = status_code
7
+ self.body = []
8
+ end
9
+
10
+ def add_field(new_field)
11
+ self.body << new_field
12
+ self
13
+ end
14
+
15
+ def to_s
16
+ s = self.body.map do |f|
17
+ field_display f
18
+ end
19
+ s.to_s
20
+ end
21
+
22
+ def field_display field
23
+ if field.has_subfields?
24
+ "#{field.name}:#{field.fields.map{|f| field_display(f)}}"
25
+ else
26
+ "#{field.name}:#{field.display_class}"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
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
@@ -0,0 +1,26 @@
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 = self.call method, format_case
13
+ test = FormatTest.new response, format_case.payload, definition.bad_request_response, method.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
@@ -0,0 +1,29 @@
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 definition, report
7
+ super
8
+
9
+ definition.methods.each do |method|
10
+ default_case = BoundaryCase.new method.url, method.request.default_payload, method.request.default_headers
11
+ response = self.call method, default_case
12
+ test = GoodCaseTest.new response, 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, method
27
+ super response, method.request.default_payload, method.expected_response, method.url, method.verb, "GoodCaseModule"
28
+ end
29
+ end