apirunner 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,7 +7,8 @@ source "http://rubygems.org"
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
 
9
9
  gem 'nokogiri', '~> 1.4.3.1'
10
- gem 'httparty', '~> 0.6.1'
10
+ #gem 'httparty', '~> 0.6.1'
11
+ gem 'rest-client', '>= 1.6.1'
11
12
 
12
13
  group :development do
13
14
  gem "rspec", ">= 2.0.0.beta.19"
data/Gemfile.lock CHANGED
@@ -2,7 +2,6 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  builder (2.1.2)
5
- crack (0.1.8)
6
5
  cucumber (0.8.5)
7
6
  builder (~> 2.1.2)
8
7
  diff-lcs (~> 1.1.2)
@@ -13,18 +12,19 @@ GEM
13
12
  gherkin (2.1.5)
14
13
  trollop (~> 1.16.2)
15
14
  git (1.2.5)
16
- httparty (0.6.1)
17
- crack (= 0.1.8)
18
15
  jeweler (1.5.0.pre3)
19
16
  bundler (~> 1.0.0)
20
17
  git (>= 1.2.5)
21
18
  rake
22
19
  json_pure (1.4.6)
20
+ mime-types (1.16)
23
21
  mocha (0.9.8)
24
22
  rake
25
23
  nokogiri (1.4.3.1)
26
24
  rake (0.8.7)
27
25
  rcov (0.9.9)
26
+ rest-client (1.6.1)
27
+ mime-types (>= 1.16)
28
28
  rspec (2.0.0.beta.22)
29
29
  rspec-core (= 2.0.0.beta.22)
30
30
  rspec-expectations (= 2.0.0.beta.22)
@@ -44,9 +44,9 @@ PLATFORMS
44
44
  DEPENDENCIES
45
45
  bundler (~> 1.0.0)
46
46
  cucumber
47
- httparty (~> 0.6.1)
48
47
  jeweler (~> 1.5.0.pre3)
49
48
  mocha (>= 0.9.8)
50
49
  nokogiri (~> 1.4.3.1)
51
50
  rcov
51
+ rest-client (>= 1.6.1)
52
52
  rspec (>= 2.0.0.beta.19)
data/README.rdoc CHANGED
@@ -26,6 +26,7 @@ apirunner was initially developed for testing of the mighty (m8ty) i18n recommen
26
26
  * print out a nice error report (that you as a awesome ruby coder will never see)
27
27
  * be invoked from within rake to generate some example configuration and testcase files
28
28
  * be invoked also from within rake to run your test's
29
+ * not travel to Ibiza
29
30
 
30
31
  == Installation
31
32
 
@@ -45,6 +46,44 @@ Additionally there will be some example testcases which can be found in:
45
46
  test/apirunner/002_delete_ressource.yml
46
47
  test/apirunner/excludes.yml
47
48
 
49
+ At first take some time and change config/api_runner.yml to your needs. You might for example want to test your app locally on localhost:3000, on staging machine and on production environment too. So your api_runner.yml could look like that:
50
+
51
+ local:
52
+ protocol: http
53
+ host: localhost
54
+ port: 3000
55
+ namespace: api
56
+ staging:
57
+ protocol: http
58
+ host: staging.yourstagingdomain.dom
59
+ port: 80
60
+ namespace: api
61
+ production:
62
+ protocol: https
63
+ host: www.yourproductiondomain.dom
64
+ port: 80
65
+ namespace: prod_api
66
+
67
+ Take a look at "namespace" here. It makes the expectation matcher build ressource URI's like so:
68
+
69
+ http://localhost:3000/api
70
+ http://staging.yourstagingdomain.dom/api
71
+ http://www.yourproductiondomain.dom/prod_api
72
+
73
+ The ressource pathes are simply appended before the request is sent.
74
+
75
+ The file also generates your rake tasks dynamically. The above config will generate 3 new tasks:
76
+
77
+ api:run:local
78
+ api:run:staging
79
+ api:run:production
80
+
81
+ == Excludes
82
+
83
+ You may also want to define some excludes for some of your environment. Imageine on your localhost's server there is no "Last-Modified" present in the header, but you would like to check that on staging and production boxes.
84
+
85
+ Simply define your story to check "Last-Modified" generally and exclude it for
86
+
48
87
  == Invocation
49
88
 
50
89
  Assuming you defined an environment "local" and "staging" you can invoke your masterpiece with:
@@ -68,6 +107,18 @@ apirunner heavily depends on the following great GEM's:
68
107
  1) nokogiri
69
108
  2) httparty
70
109
 
110
+ == Examples
111
+
112
+ After invoking:
113
+
114
+ rake api:scaffold
115
+
116
+ you will find some YAML example files for request and expectation generation in test/api_runner. You can create as many story files here as you like, they are executed in the order they are read from the filesystem, so you should name them like 000_create_some_ressource.yml, 001_read_some_ressource.yml and so on.
117
+
118
+ Alternatively you can place all your stories into one single file.
119
+
120
+ Addition
121
+
71
122
  == Authors
72
123
 
73
124
  apirunner was written by:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
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.5"
8
+ s.version = "0.1.6"
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-22}
12
+ s.date = %q{2010-09-23}
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 = [
@@ -63,7 +63,7 @@ Gem::Specification.new do |s|
63
63
 
64
64
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
65
  s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
66
- s.add_runtime_dependency(%q<httparty>, ["~> 0.6.1"])
66
+ s.add_runtime_dependency(%q<rest-client>, [">= 1.6.1"])
67
67
  s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
68
68
  s.add_development_dependency(%q<cucumber>, [">= 0"])
69
69
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -77,7 +77,7 @@ Gem::Specification.new do |s|
77
77
  s.add_development_dependency(%q<rcov>, [">= 0"])
78
78
  else
79
79
  s.add_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
80
- s.add_dependency(%q<httparty>, ["~> 0.6.1"])
80
+ s.add_dependency(%q<rest-client>, [">= 1.6.1"])
81
81
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
82
82
  s.add_dependency(%q<cucumber>, [">= 0"])
83
83
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -92,7 +92,7 @@ Gem::Specification.new do |s|
92
92
  end
93
93
  else
94
94
  s.add_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
95
- s.add_dependency(%q<httparty>, ["~> 0.6.1"])
95
+ s.add_dependency(%q<rest-client>, [">= 1.6.1"])
96
96
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
97
97
  s.add_dependency(%q<cucumber>, [">= 0"])
98
98
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -5,13 +5,42 @@
5
5
  method: 'PUT'
6
6
  body:
7
7
  username: 'duffyduck'
8
+ watchlist:
9
+ - m333
10
+ - m79
11
+ blacklist:
12
+ - m334
13
+ - m77
14
+ skiplist:
15
+ - m335
16
+ - m78
17
+ ratings:
18
+ m336: 4
19
+ m79: 2.5
20
+ m777: 3.0
21
+ m567: 4.0
22
+ m354: 5.0
23
+ expires_at: 2011-09-09T22:41:50+00:00
8
24
  response_expectation:
9
25
  status_code: 201
10
26
  headers:
11
27
  Last-Modified: /.*/
12
28
  body:
13
29
  username: 'duffyduck'
14
- fsk: "17"
30
+ watchlist:
31
+ - m333
32
+ - m79
33
+ blacklist:
34
+ - m334
35
+ - m77
36
+ skiplist:
37
+ - m335
38
+ - m78
39
+ ratings:
40
+ m336: 4.0
41
+ m79: 2.5
42
+ fsk: "18"
43
+ expires_at: Fri, 09 Sep 2011 22:41:50 +0000
15
44
  - name: 'Update existing User - Update watchlist'
16
45
  request:
17
46
  path: '/users/duffyduck/watchlist'
@@ -22,4 +51,75 @@
22
51
  response_expectation:
23
52
  status_code: 204
24
53
  body:
25
-
54
+ - name: 'Check User FSK,Watchlist'
55
+ request:
56
+ path: '/users/duffyduck'
57
+ method: 'GET'
58
+ response_expectation:
59
+ status_code: 200
60
+ headers:
61
+ Last-Modified: /.*/
62
+ body:
63
+ username: 'duffyduck'
64
+ fsk: "18"
65
+ watchlist:
66
+ - m367
67
+ - m73
68
+ blacklist:
69
+ - m334
70
+ - m77
71
+ skiplist:
72
+ - m335
73
+ - m78
74
+ ratings:
75
+ m336: 4.0
76
+ m79: 2.5
77
+ - name: 'Set 10 Ratings'
78
+ request:
79
+ path: '/users/duffyduck/ratings'
80
+ method: 'PUT'
81
+ body:
82
+ "m1035": 4
83
+ "m2087": 3
84
+ "m1554": 2
85
+ "m2981": 1
86
+ "m1590": 2
87
+ "m1056": 3
88
+ "m12493": 4
89
+ "m1875": 5
90
+ "m7258": 2.5
91
+ "m7339": 3.5
92
+ response_expectation:
93
+ status_code: 204
94
+ headers:
95
+ Last-Modified: /.*/
96
+ - name: 'Check User Ratings Update'
97
+ request:
98
+ path: '/users/duffyduck'
99
+ method: 'GET'
100
+ response_expectation:
101
+ status_code: 200
102
+ headers:
103
+ Last-Modified: /.*/
104
+ body:
105
+ username: 'duffyduck'
106
+ fsk: "18"
107
+ watchlist:
108
+ - m367
109
+ - m73
110
+ blacklist:
111
+ - m334
112
+ - m77
113
+ skiplist:
114
+ - m335
115
+ - m78
116
+ ratings:
117
+ "m1035": "1.0"
118
+ "m2087": "3.0"
119
+ "m1554": "2.0"
120
+ "m1590": "2.0"
121
+ "m1056": "3.0"
122
+ "m12493": "4.0"
123
+ "m1875": "5.0"
124
+ "m7258": "2.5"
125
+ "m7339": "3.5"
data/lib/api_runner.rb CHANGED
@@ -10,13 +10,13 @@ class ApiRunner
10
10
 
11
11
  # initializes the object, loads environment, build base_uri
12
12
  def initialize(env)
13
- @http_client = HttpClient.new
14
13
  @spec = []
15
14
  @errors = []
16
15
  @excludes = []
17
16
  load_config(env)
18
17
  load_excludes(env)
19
18
  load_url_spec
19
+ @http_client = HttpClient.new(@host, @port, @namespace)
20
20
  @expectation = ExpectationMatcher.new(@excludes)
21
21
  end
22
22
 
@@ -37,7 +37,7 @@ class ApiRunner
37
37
  # runs all testcases that are provided by the testclass an fills errors if there are any
38
38
  def run_tests
39
39
  @spec.each do |test_case|
40
- response = send_request(test_case['request']['method'].downcase.to_sym, target_uri(test_case['request']['path']), {:body => test_case['request']['body'].to_json})
40
+ response = send_request(test_case['request']['method'].downcase.to_sym, test_case['request']['path'], test_case['request']['body'])
41
41
  @expectation.test_types.each do |test_type|
42
42
  test = @expectation.check(test_type, response, test_case)
43
43
  if not test.succeeded
@@ -57,12 +57,13 @@ class ApiRunner
57
57
  end
58
58
 
59
59
  # builds target uri from base uri generated of host port and namespace as well as the ressource path
60
- def target_uri(ressource_path)
61
- "#{@protocol}://#{@host}:#{@port}/#{@namespace}" + ressource_path
60
+ def target_uri
61
+ "#{@protocol}://#{@host}"
62
62
  end
63
63
 
64
64
  # returns true if server is available
65
65
  def server_is_available?
66
+ return true
66
67
  !@http_client.send_request(:get, "#{@protocol}://#{@host}:#{@port}", {:timeout => 5}).nil?
67
68
  end
68
69
 
@@ -83,7 +84,7 @@ class ApiRunner
83
84
  # loads and parses items that need to be excluded from the checks in certain environments
84
85
  def load_excludes(env)
85
86
  excludes_file = self.class.excludes_file
86
- @excludes = YAML.load_file(excludes_file).detect{ |a| a.first == env.to_s }[1]["excludes"]
87
+ @excludes = YAML.load_file(excludes_file).detect{ |a| a.first == env.to_s }[1]["excludes"] rescue nil
87
88
  end
88
89
 
89
90
  # returns config files path and can be stubbed this way
@@ -22,7 +22,7 @@ class ExpectationMatcher
22
22
  def response_code(response, testcase)
23
23
  result_struct = Struct.new(:succeeded, :error)
24
24
  results = result_struct.new(:succeeded => true, :error => nil)
25
- if not testcase['response_expectation']['status_code'] == response.code
25
+ if not testcase['response_expectation']['status_code'].to_s == response.code.to_s
26
26
  results.succeeded = false
27
27
  results.error = "testcase '#{testcase['name']}'\n expected response code --#{testcase['response_expectation']['status_code']}--\n got response code --#{response.code}--"
28
28
  end
@@ -64,6 +64,10 @@ class ExpectationMatcher
64
64
 
65
65
  # matches the given attributes and values against the ones from the response body
66
66
  def response_body(response, testcase)
67
+ puts("Testcase #{testcase['name']}\n")
68
+ puts("got response --#{response.body}--\n\n")
69
+ puts("exp response --#{testcase['response_expectation']['body']}--\n")
70
+ puts("___________________________\n\n\n")
67
71
  result_struct = Struct.new(:succeeded, :error)
68
72
  results = result_struct.new(:succeeded => true, :error => nil)
69
73
 
data/lib/http_client.rb CHANGED
@@ -1,10 +1,70 @@
1
1
  class HttpClient
2
+ require 'net/http'
3
+ require 'JSON'
4
+
5
+ def initialize(host, port, namespace)
6
+ @http = Net::HTTP.new(host, port)
7
+ @host = host
8
+ @port = port
9
+ @namespace = namespace
10
+ end
11
+
12
+ def send_request(method, resource, data=nil)
13
+ build_response(self.send(method.to_s.downcase, resource, data))
14
+ end
15
+
16
+ protected
17
+
18
+ # returns struct containing response.code, headers, body and message
19
+ # this is only for easily interfaceing another http client
20
+ def build_response(raw_response)
21
+ response_struct = Struct.new(:code, :message, :headers, :body)
22
+ response = response_struct.new
23
+ response.code = raw_response.code
24
+ response.message = raw_response.message
25
+ response.body = raw_response.body
26
+ response.headers = raw_response.header
27
+ response
28
+ end
29
+
30
+ def get(resource, params)
31
+ request = Net::HTTP::Get.new(resource_path(resource), initheader = {'Content-Type' =>'application/json'})
32
+ response = @http.request(request)
33
+ return response
34
+ end
35
+
36
+ def put(resource, data)
37
+ request = Net::HTTP::Put.new(resource_path(resource), initheader = {'Content-Type' =>'application/json'})
38
+ request.body = data.to_json
39
+ response = @http.request(request)
40
+ end
41
+
42
+ def post(resource, data)
43
+ request = Net::HTTP::Post.new(resource_path(resource), initheader = {'Content-Type' =>'application/json'})
44
+ request.body = data.to_json
45
+ response = @http.request(request)
46
+ end
47
+
48
+
49
+ def delete(resource, params)
50
+ request = Net::HTTP::Delete.new(resource_path(resource), initheader = {'Content-Type' =>'application/json'})
51
+ response = @http.request(request)
52
+ end
53
+
54
+ def resource_path(resource)
55
+ "/" + @namespace + resource
56
+ end
57
+ end
58
+
59
+
60
+ class HttPartyClient
2
61
  require 'httparty'
3
62
  include HTTParty
4
63
 
5
64
  # sends http request with given method, uri and data and returns servers response
6
65
  def send_request(method, uri, data=nil)
7
- build_response(self.class.send(method, uri, data ||= {}))
66
+ options = { :body => data.to_json, :format => :json }
67
+ build_response(self.class.send(method, uri, options))
8
68
  end
9
69
 
10
70
  protected
data/lib/tasks/api.rake CHANGED
@@ -1,5 +1,7 @@
1
- config = YAML.load_file("#{Rails.root}/vendor/plugins/telekom_api/config/api_runner.yaml")
2
-
1
+ begin
2
+ config = YAML.load_file("#{Rails.root}/config/api_runner.yml")
3
+ rescue
4
+ end
3
5
  namespace :api do
4
6
  namespace :run do
5
7
  config.each_key do |env|
@@ -10,7 +12,7 @@ namespace :api do
10
12
  api_runner.run
11
13
  puts "\nTestrun finished\n\n"
12
14
  end
13
- end
15
+ end unless config.nil?
14
16
  end
15
17
  desc "generates configuration and a skeleton for apirunner tests as well as excludes"
16
18
  task :scaffold do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 5
9
- version: 0.1.5
8
+ - 6
9
+ version: 0.1.6
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-22 00:00:00 +02:00
17
+ date: 2010-09-23 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -34,17 +34,17 @@ dependencies:
34
34
  prerelease: false
35
35
  version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
37
- name: httparty
37
+ name: rest-client
38
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
- - - ~>
41
+ - - ">="
42
42
  - !ruby/object:Gem::Version
43
43
  segments:
44
- - 0
44
+ - 1
45
45
  - 6
46
46
  - 1
47
- version: 0.6.1
47
+ version: 1.6.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: *id002
@@ -263,7 +263,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
263
  requirements:
264
264
  - - ">="
265
265
  - !ruby/object:Gem::Version
266
- hash: -2331822948028323562
266
+ hash: -4500206872193641389
267
267
  segments:
268
268
  - 0
269
269
  version: "0"