apirunner 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.1.9
data/apirunner.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{apirunner}
8
- s.version = "0.1.8"
8
+ s.version = "0.1.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["jan@moviepilot.com"]
12
- s.date = %q{2010-09-23}
12
+ s.date = %q{2010-09-27}
13
13
  s.description = %q{apirunner is a testsuite to query your RESTful JSON API and match response with your defined expectations}
14
14
  s.email = %q{developers@moviepilot.com}
15
15
  s.extra_rdoc_files = [
@@ -34,11 +34,13 @@ Gem::Specification.new do |s|
34
34
  "features/apirunner.feature",
35
35
  "features/step_definitions/apirunner_steps.rb",
36
36
  "features/support/env.rb",
37
+ "lib/api_configuration.rb",
37
38
  "lib/api_runner.rb",
38
39
  "lib/apirunner.rb",
39
40
  "lib/apirunner/railtie.rb",
40
41
  "lib/expectation_matcher.rb",
41
42
  "lib/http_client.rb",
43
+ "lib/result.rb",
42
44
  "lib/tasks/api.rake",
43
45
  "spec/.rspec",
44
46
  "spec/api_runner_spec.rb",
@@ -13,3 +13,9 @@ production:
13
13
  host: www.moviepilot.com
14
14
  port: 80
15
15
  namespace: api1v0
16
+ general:
17
+ verbosity:
18
+ - rspec
19
+ - verbose_on_error
20
+ - verbose_on_success
21
+ - verbose_with_curl
@@ -0,0 +1,6 @@
1
+ class ApiConfiguration
2
+
3
+ attr_accessor :protocol, :host, :namespace, :port, :verbosity
4
+
5
+ end
6
+
data/lib/api_runner.rb CHANGED
@@ -2,6 +2,7 @@ class ApiRunner
2
2
  require 'yaml'
3
3
  require 'expectation_matcher'
4
4
  require 'http_client'
5
+ require 'api_configuration'
5
6
 
6
7
  CONFIG_FILE = "config/api_runner.yml"
7
8
  SPEC_PATH = "test/api_runner/"
@@ -10,12 +11,13 @@ class ApiRunner
10
11
  # initializes the object, loads environment, build base_uri
11
12
  def initialize(env)
12
13
  @spec = []
13
- @errors = []
14
+ @results = []
14
15
  @excludes = []
16
+ @configuration = ApiConfiguration.new
15
17
  load_config(env)
16
18
  load_excludes(env)
17
19
  load_url_spec
18
- @http_client = HttpClient.new(@host, @port, @namespace)
20
+ @http_client = HttpClient.new(@configuration.host, @configuration.port, @configuration.namespace)
19
21
  @expectation = ExpectationMatcher.new(@excludes)
20
22
  end
21
23
 
@@ -23,11 +25,11 @@ class ApiRunner
23
25
  def run
24
26
  if server_is_available?
25
27
  run_tests
26
- @errors.each_with_index do |error, index|
27
- puts("\n\nError (#{index+1}): #{error}")
28
- end unless @errors.empty?
28
+ @results.each_with_index do |result, index|
29
+ result.honk_in(@configuration.verbosity, index)
30
+ end unless @results.empty?
29
31
  else
30
- puts("Server #{@host} seems to be unavailable!")
32
+ puts("Server #{@configuration.host} seems to be unavailable!")
31
33
  end
32
34
  end
33
35
 
@@ -38,13 +40,16 @@ class ApiRunner
38
40
  @spec.each do |test_case|
39
41
  response = send_request(test_case['request']['method'].downcase.to_sym, test_case['request']['path'], test_case['request']['body'])
40
42
  @expectation.test_types.each do |test_type|
41
- test = @expectation.check(test_type, response, test_case)
42
- if not test.succeeded
43
- @errors << test.error
43
+ result = @expectation.check(test_type, response, test_case)
44
+ if not result.succeeded
44
45
  putc "F"
46
+ @results << result
45
47
  break
46
48
  else
47
- putc "." if test_type == @expectation.test_types.last
49
+ if test_type == @expectation.test_types.last
50
+ @results << result
51
+ putc "."
52
+ end
48
53
  end
49
54
  end
50
55
  end
@@ -57,19 +62,20 @@ class ApiRunner
57
62
 
58
63
  # builds target uri from base uri generated of host port and namespace as well as the ressource path
59
64
  def target_uri
60
- "#{@protocol}://#{@host}"
65
+ "#{@configuration.protocol}://#{@configuration.host}"
61
66
  end
62
67
 
63
68
  # returns true if server is available
64
69
  def server_is_available?
65
70
  return true
66
- !@http_client.send_request(:get, "#{@protocol}://#{@host}:#{@port}", {:timeout => 5}).nil?
71
+ !@http_client.send_request(:get, "#{@configuration.protocol}://#{@configuration.host}:#{@configuration.port}", {:timeout => 5}).nil?
67
72
  end
68
73
 
69
74
  # loads environment config data from yaml file
70
75
  def load_config(env)
71
76
  config = YAML.load_file(self.class.config_file)
72
- config[env.to_s].each { |key, value| instance_variable_set("@#{key}", value) }
77
+ config[env.to_s].each { |key, value| @configuration.instance_variable_set("@#{key}", value) }
78
+ @configuration.verbosity = config['general']['verbosity'].first
73
79
  end
74
80
 
75
81
  # loads spec cases from yaml files
@@ -1,4 +1,5 @@
1
1
  class ExpectationMatcher
2
+ require 'result'
2
3
  require 'nokogiri'
3
4
  require 'JSON'
4
5
 
@@ -21,13 +22,12 @@ class ExpectationMatcher
21
22
 
22
23
  # matches the given response code
23
24
  def response_code(response, testcase)
24
- result_struct = Struct.new(:succeeded, :error)
25
- results = result_struct.new(:succeeded => true, :error => nil)
25
+ result = Result.new(testcase, response)
26
26
  if not testcase['response_expectation']['status_code'].to_s == response.code.to_s
27
- results.succeeded = false
28
- results.error = "testcase '#{testcase['name']}'\n expected response code --#{testcase['response_expectation']['status_code']}--\n got response code --#{response.code}--"
27
+ result.succeeded = false
28
+ result.error_message = " expected response code --#{testcase['response_expectation']['status_code']}--\n got response code --#{response.code}--"
29
29
  end
30
- results
30
+ result
31
31
  end
32
32
 
33
33
  # checks the format of the given data of JSON conformity
@@ -35,55 +35,51 @@ class ExpectationMatcher
35
35
  def response_body_format(response, testcase)
36
36
  result_struct = Struct.new(:succeeded, :error)
37
37
  results = result_struct.new(:succeeded => true, :error => nil)
38
+ result = Result.new(testcase, response)
38
39
  if not valid_json?(response.body)
39
- results.succeeded = false
40
- results.error = "testcase '#{testcase['name']}'\n expected valid JSON in body\n got --#{response.body[1..400]}--"
40
+ result.succeeded = false
41
+ result.error_message = "expected valid JSON in body\n got --#{response.body[1..400]}--"
41
42
  end
42
- results
43
+ result
43
44
  end
44
45
 
45
46
  # matches the given response header
46
47
  def response_headers(response, testcase)
47
- result_struct = Struct.new(:succeeded, :error)
48
- results = result_struct.new(:succeeded => true, :error => nil)
48
+ result = Result.new(testcase, response)
49
49
 
50
50
  testcase['response_expectation']['headers'].each_pair do |header_name, header_value|
51
51
  if is_regex?(header_value)
52
52
  if not (excluded?(header_name) or regex_matches?(header_value, response.headers[header_name]))
53
- results.succeeded = false
54
- results.error = "testcase '#{testcase['name']}'\n expected header identifier --#{header_name}-- to match regex --#{header_value}--\n got --#{response.headers[header_name]}--"
53
+ result.succeeded = false
54
+ result.error_message = " expected header identifier --#{header_name}-- to match regex --#{header_value}--\n got --#{response.headers[header_name]}--"
55
55
  end
56
56
  else
57
57
  if not (excluded?(header_name) or string_matches?(header_value, response.headers[header_name]))
58
- results.succeeded = false
59
- results.error = "testcase '#{testcase['name']}'\n expected header identifier --#{header_name}-- to match --#{header_value}--\n got --#{response.headers[header_name]}--"
58
+ result.succeeded = false
59
+ result.error_message = " expected header identifier --#{header_name}-- to match --#{header_value}--\n got --#{response.headers[header_name]}--"
60
60
  end
61
61
  end
62
62
  end unless (testcase['response_expectation']['headers'].nil? or testcase['response_expectation']['headers'].empty?)
63
- return results
63
+ return result
64
64
  end
65
65
 
66
66
  # matches the given attributes and values against the ones from the response body
67
67
  def response_body(response, testcase)
68
- puts("Testcase #{testcase['name']}\n")
69
- puts("got response --#{response.body}--\n\n")
70
- puts("exp response --#{testcase['response_expectation']['body']}--\n")
71
- puts("___________________________\n\n\n")
72
- result_struct = Struct.new(:succeeded, :error)
73
- results = result_struct.new(:succeeded => true, :error => nil)
68
+ result = Result.new(testcase, response)
74
69
 
75
70
  expected_body_hash = testcase['response_expectation']['body']
76
71
 
77
72
  # in case we have no body expectation we simply return success
78
- return results if expected_body_hash.nil?
73
+ return result if expected_body_hash.nil?
79
74
 
80
75
  # in case the response body is nil or damaged we return an error
81
76
  begin
82
77
  responded_body_hash = JSON.parse(response.body)
83
78
  rescue
84
- results.succeeded = false
85
- results.error = "testcase '#{testcase['name']}'\n expected response to have a body\n got raw body --#{response.body}-- which is nil or an unparseable hash"
86
- return results
79
+ result = Result.new(testcase, response)
80
+ result.success = false
81
+ result.error_message = " expected response to have a body\n got raw body --#{response.body}-- which is nil or an unparseable hash"
82
+ return result
87
83
  end
88
84
 
89
85
  # else we build trees from both body structures...
@@ -97,25 +93,25 @@ class ExpectationMatcher
97
93
 
98
94
  # return error if response body does not have the expected entry
99
95
  if response_node.nil?
100
- results.succeeded = false
101
- results.error = "testcase '#{testcase['name']}'\n expected body to have identifier --#{expectation_node.name}--\n got nil"
102
- return results
96
+ result.succeeded = false
97
+ result.error_message = " expected body to have identifier --#{expectation_node.name}--\n got nil"
98
+ return result
103
99
  end
104
100
 
105
101
  # last but not least try the regex or direct match and return errors in case of any
106
102
  if is_regex?(expectation_node.text)
107
103
  if not (excluded?(expectation_node.name) or regex_matches?(expectation_node.text, response_node.text))
108
- results.succeeded = false
109
- results.error = "testcase '#{testcase['name']}'\n expected body identifier --#{expectation_node.name}-- to match regex --#{expectation_node.text}--\n got --#{response_node.text}--"
104
+ result.succeeded = false
105
+ result.error_message = " expected body identifier --#{expectation_node.name}-- to match regex --#{expectation_node.text}--\n got --#{response_node.text}--"
110
106
  end
111
107
  else
112
108
  if not (excluded?(expectation_node.name) or string_matches?(expectation_node.text, response_node.text))
113
- results.succeeded = false
114
- results.error = "testcase '#{testcase['name']}'\n expected body identifier --#{expectation_node.name}-- to match --#{expectation_node.text}--\n got --#{response_node.text}--"
109
+ result.succeeded = false
110
+ result.error_message = " expected body identifier --#{expectation_node.name}-- to match --#{expectation_node.text}--\n got --#{response_node.text}--"
115
111
  end
116
112
  end
117
113
  end
118
- results
114
+ result
119
115
  end
120
116
 
121
117
  # recursively parses the tree and returns a set of relative pathes
data/lib/result.rb ADDED
@@ -0,0 +1,69 @@
1
+ class Result
2
+
3
+ attr_accessor :succeeded
4
+ attr_accessor :error_message
5
+
6
+ def initialize(testcase, response)
7
+ @succeeded = true
8
+ @testcase = testcase
9
+ @response = response
10
+ @error_message = nil
11
+ end
12
+
13
+ # honk out the errors message corresponding to the verbosity configuration the user took
14
+ def honk_in(verbosity="rspec", index)
15
+ self.send(verbosity.to_sym, index)
16
+ end
17
+
18
+ private
19
+
20
+ # yields out rspec like error messages only in case of an error
21
+ def rspec(index)
22
+ if not @succeeded
23
+ puts "\nError (#{index}) - \"#{@testcase['name']}\""
24
+ puts @error_message
25
+ end
26
+ end
27
+
28
+ # yields a more verbose error message only in case of an error
29
+ def verbose_on_error(index)
30
+ if not @succeeded
31
+ be_verbose(index)
32
+ end
33
+ end
34
+
35
+ # yields a more verbose message in case of an error AND success
36
+ def verbose_on_success(index)
37
+ be_verbose(index)
38
+ end
39
+
40
+ # yields a more verbose message in any case and includes a curl command to manually simulate the testcase
41
+ def verbose_with_curl(index)
42
+ be_verbose(index)
43
+ puts "\n simulate this call with: \"curl TODO\""
44
+ end
45
+
46
+ # yields the verbose error messages
47
+ def be_verbose(index)
48
+ puts "\n#{result_case} (#{index+1}) - \"#{@testcase['name']}\""
49
+ puts @error_message
50
+ puts (" More more more verbosity\n")
51
+ puts (" request method: #{@testcase['request']['method']}")
52
+ puts (" resource path: #{@testcase['request']['path']}")
53
+ puts (" request headers: #{@testcase['request']['headers']}")
54
+ puts (" JSON body sent: #{@testcase['request']['body']}")
55
+ puts (" response status code: #{@testcase['response_expectation']['status_code']}")
56
+ puts (" response headers: #{@testcase['response_expectation']['headers']}")
57
+ puts (" response body: #{@testcase['response_expectation']['body']}")
58
+ end
59
+
60
+ # returns the result case for interpolation in the output message header
61
+ def result_case
62
+ if @succeeded
63
+ "Success"
64
+ else
65
+ "Error"
66
+ end
67
+ end
68
+
69
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 8
9
- version: 0.1.8
8
+ - 9
9
+ version: 0.1.9
10
10
  platform: ruby
11
11
  authors:
12
12
  - jan@moviepilot.com
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-09-23 00:00:00 +02:00
17
+ date: 2010-09-27 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -238,11 +238,13 @@ files:
238
238
  - features/apirunner.feature
239
239
  - features/step_definitions/apirunner_steps.rb
240
240
  - features/support/env.rb
241
+ - lib/api_configuration.rb
241
242
  - lib/api_runner.rb
242
243
  - lib/apirunner.rb
243
244
  - lib/apirunner/railtie.rb
244
245
  - lib/expectation_matcher.rb
245
246
  - lib/http_client.rb
247
+ - lib/result.rb
246
248
  - lib/tasks/api.rake
247
249
  - spec/.rspec
248
250
  - spec/api_runner_spec.rb
@@ -263,7 +265,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
265
  requirements:
264
266
  - - ">="
265
267
  - !ruby/object:Gem::Version
266
- hash: 1758241369738370513
268
+ hash: -2943715373765808099
267
269
  segments:
268
270
  - 0
269
271
  version: "0"