right_api_client 1.6.1 → 1.6.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 01ce5cf02bf62fd9aab1e367843abd835924dbe9
4
- data.tar.gz: 8ceac40391c3e53b3bcd59f43aeb63173f690b07
3
+ metadata.gz: 28ccc87f7f444e4e7a6d0a72695b5dc28ea9b313
4
+ data.tar.gz: 03f48d1c21be4aa93b53311c8562e65302820782
5
5
  SHA512:
6
- metadata.gz: 0911c6c1ad7333c1e9648b9b8c0fa9c0b11d4bccf6be04662d9217aba0d581fe9a0cc542b5344e625091cdb64c04857cc52c189639ad07e4fdfdfc1d022a338a
7
- data.tar.gz: 43b1c6d1cf941090a0333eace45d0b2b5bff26431c850820fe7270eedebe83bc13b1971505122d40c310674eacff224f850faf81b6e1d0e0c02a2bc0f28ec45b
6
+ metadata.gz: bd0bfe56b67ec25ce8ac83b8f455f329b14a7204a3140d45c5cfd1dcdd0a381777e5b760b1334941e305c5e8d2f8e295cc1f35713ac4c61ba458fd6e60bea815
7
+ data.tar.gz: 76ec1794e9eadd8ceb99c3430748402e30f045752b8614a9b225151ad39d7fc0ffe8e00102b9c34e156251f31046f3e353bb8fa7dbd95643255b44a8a8bc8a00
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format=nested
3
+ --backtrace
@@ -3,7 +3,16 @@
3
3
  ## Next
4
4
  - Your info here
5
5
 
6
- ## 1.6
6
+ ## 1.6.2
7
+ - \#108 Raise a specific error if the API returns an empty 200 response
8
+ - \#106 Bump mime-types version to resolve dependencies with fog-azure-rm gem
9
+ - \#104 Switch to a more bundlerish dev workflow
10
+ - \#102 Rework README to reflect gem version not tied to api version
11
+
12
+ ## 1.6.1
13
+ - Disassociate API version number from gem version number
14
+
15
+ ## 1.6.0
7
16
  - \#101 Deprecate support for ruby 1.x
8
17
  - \#100 Add support for using local proxy with RightLink10
9
18
 
data/Gemfile CHANGED
@@ -2,21 +2,20 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Runtime dependencies that should appear in the gemspec.
4
4
  gem 'json', '~> 1.0'
5
- gem 'mime-types', '~> 1.0'
5
+ gem 'mime-types', '~> 2.0'
6
6
  gem 'rest-client', '~> 1.6'
7
7
 
8
8
  # Development dependencies that should appear in the gemspec.
9
9
  group :development do
10
- gem 'rake', '0.8.7'
11
- gem 'rspec', '2.9.0'
12
- gem 'flexmock', '0.8.7'
10
+ gem 'rake'
11
+ gem 'rspec', '~> 2.9'
12
+ gem 'flexmock'
13
13
  gem 'coveralls', :require => false
14
14
  gem 'pry'
15
15
  end
16
16
 
17
17
  # Gems used during test and development that should be OMITTED from the gemspec
18
18
  group :test do
19
- gem 'byebug',
20
- :platforms => [:ruby_20, :ruby_21]
21
- gem 'jeweler', '~> 2.0'
19
+ gem 'pry-byebug'
20
+ gem 'jeweler'
22
21
  end
data/README.md CHANGED
@@ -18,10 +18,14 @@ Ruby 2.0 or higher is required as of version 1.6
18
18
  gem install right_api_client
19
19
 
20
20
  ## Versioning
21
- The right\_api\_client gem is versioned using the usual X.Y.Z notation, where X.Y is the
22
- RightScale API version, and Z is the client version. For example, if you want to use
23
- RightScale API 1.5, you should use the latest version of the 1.6 gem. This will ensure
24
- that you get the latest bug fixes for the client that is compatible with that API version.
21
+ * Version 1.6.x
22
+ - API 1.5
23
+ - Ruby 2.0 and above
24
+ - Patch level receives improvements and bug fixes moving forward.
25
+ * Version 1.5.x
26
+ - API 1.5
27
+ - Ruby 1.8, 1.9.3
28
+ - Patch level receives only security or high priority fixes if requested.
25
29
 
26
30
  ## Usage Instructions
27
31
  New users can start with the following few lines of code and navigate their way around the API by following
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.1
1
+ 1.6.2
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ GIT_ROOT = File.expand_path('../..', __FILE__)
4
+ CONFIG_FILE = "#{GIT_ROOT}/config/login.yml"
5
+
6
+ require 'yaml'
7
+
8
+ require 'bundler/setup'
9
+
10
+ # TODO convert from jeweler to bundler workflow and use `gemspec` directive in Gemfile
11
+ $: << "#{GIT_ROOT}/lib"
12
+ require 'right_api_client'
13
+
14
+ begin
15
+ puts "Using configuration file #{CONFIG_FILE}"
16
+ if File.readable? CONFIG_FILE
17
+ @client = RightApi::Client.new(YAML.load_file(CONFIG_FILE))
18
+ STDERR.puts "Logged in to Rightscale CM API."
19
+ else
20
+ STDERR.puts "Configuration file is unreadable or nonexistent!"
21
+ STDERR.puts "Please copy login.yml.example and add your RightScale API credentials."
22
+ exit 1
23
+ end
24
+ end
25
+
26
+ puts
27
+ puts "Opening pry or irb session; call API methods on self"
28
+ puts "Example: self.deployments.index"
29
+ puts
30
+
31
+ begin
32
+ require 'pry'
33
+ Pry.start(@client)
34
+ rescue LoadError
35
+ require 'irb'
36
+ IRB.setup nil
37
+ IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
38
+ require 'irb/ext/multi-irb'
39
+ IRB.irb nil, @client
40
+ end
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
@@ -0,0 +1,43 @@
1
+ # The API login details can be put in a YAML file. This is an example login.yml which
2
+ # will be needed for bin/console
3
+
4
+ # Account ID is a required parameter. You can find your account number by logging into the
5
+ # RightScale dashboard (https://my.rightscale.com), navigate to the Settings > Account Settings page.
6
+ # The account number is at the end of the browser address bar.
7
+ :account_id: my_account_id
8
+
9
+ # There are six login mechanisms:
10
+
11
+ # 0. Use the following parameters to login with your email and base64-encoded password:
12
+ # To encode your plaintext password, use 'base64' command or similar.
13
+ :email: my@email.com
14
+ :password_base64: my_password_encoded_as_base64
15
+
16
+ # 1. Use the following parameters to login with your email and plaintext password:
17
+ :email: my@email.com
18
+ :password: my_password
19
+
20
+ # 2. Use the following parameter to login with an instance_token:
21
+ # To find the instance_token, launch a server, navigate to the info page and under
22
+ # User Data box, you will see RS_API_TOKEN = your_account_id:the_instance_token
23
+ :instance_token: my_instance_token
24
+
25
+ # 3. Use the following parameter to send a pre-authenticated cookie with every request:
26
+ :cookies: my_cookie_string
27
+
28
+ # 4. Use the following parameter to send an existing OAuth access token with every request:
29
+ # To learn more about OAuth and how to obtain an access token, see
30
+ # http://support.rightscale.com/12-Guides/03-Rightscale_API/OAuth
31
+ :access_token: my_token_string
32
+
33
+ # 5. Use the following parameter to use your personal OAuth Token with your requests:
34
+ # Please be careful! This is a user-specific OAuth 2.0 refresh token representing a grant with unrestricted scope.
35
+ # Anyone who possesses it can login to RightScale's API and perform requests on this account with all of your permissions.
36
+ # For more information, consult http://support.rightscale.com/12-Guides/03-Rightscale_API/OAuth
37
+ # ex: @client = RightApi::Client.new(:api_url => "https://us-x.rightscale.com", :account_id => <account_id>, :refresh_token => <token>)
38
+ :refresh_token: my_token_string
39
+
40
+ # The following are optional parameters:
41
+ :api_url: (this defaults to https://my.rightscale.com)
42
+ :api_version: (this defaults to 1.5)
43
+ :ssl_version: (this defaults to TLSv1)
@@ -198,9 +198,12 @@ module RightApi
198
198
  end
199
199
 
200
200
  def to_s
201
- "#<RightApi::Client #{api_url}>"
201
+ api_host = URI.parse(api_url).host.split('.').first rescue 'unknown'
202
+ "#<RightApi::Client host=#{api_host} account=#{@account_id}>"
202
203
  end
203
204
 
205
+ alias inspect to_s
206
+
204
207
  # Log HTTP calls to file (file can be STDOUT as well)
205
208
  def log(file)
206
209
  RestClient.log = file
@@ -379,6 +382,11 @@ module RightApi
379
382
  response.body.force_encoding(charset)
380
383
  end
381
384
 
385
+ # raise an error if the API is misbehaving and returning an empty response when it shouldn't
386
+ if type != 'text' && response.body.empty?
387
+ raise EmptyBodyError.new(request, response)
388
+ end
389
+
382
390
  [type, response.body]
383
391
  when 301, 302
384
392
  update_api_url(response)
@@ -434,6 +442,8 @@ module RightApi
434
442
  # This is needed for the tags Resource -- which returns a 200 and has a content type
435
443
  # therefore, ResourceDetail objects needs to be returned
436
444
  if response.code == 200 && response.headers[:content_type].index('rightscale')
445
+ # raise an error if the API is misbehaving and returning an empty response when it shouldn't
446
+ raise EmptyBodyError.new(request, response) if response.body.empty?
437
447
  resource_type = get_resource_type(response.headers[:content_type])
438
448
  data = JSON.parse(response, :allow_nan => true)
439
449
  # Resource_tag is returned after querying tags.by_resource or tags.by_tags.
@@ -476,8 +486,7 @@ module RightApi
476
486
  update_last_request(request, response)
477
487
 
478
488
  case response.code
479
- when 200
480
- when 204
489
+ when 200, 204
481
490
  nil
482
491
  when 301, 302
483
492
  update_api_url(response)
@@ -39,11 +39,15 @@ module RightApi
39
39
  end
40
40
 
41
41
  class UnknownRouteError < ApiError
42
-
43
42
  def prefix
44
-
45
43
  'Unknown action or route. '
46
44
  end
47
45
  end
46
+
47
+ class EmptyBodyError < ApiError
48
+ def prefix
49
+ 'Empty response body: '
50
+ end
51
+ end
48
52
  end
49
53
 
@@ -1,6 +1,6 @@
1
1
  # A quick way to login to the API and jump into IRB so you can experiment with the client.
2
2
  # Add this to your bash profile to make it simpler:
3
- # alias client='bundle exec ruby login_to_client_irb.rb'
3
+ # alias client='bin/console'
4
4
 
5
5
  require File.expand_path('../lib/right_api_client', __FILE__)
6
6
  require 'yaml'
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: right_api_client 1.6.2 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "right_api_client"
9
+ s.version = "1.6.2"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["RightScale, Inc."]
14
+ s.date = "2016-11-02"
15
+ s.description = "\nThe right_api_client gem simplifies the use of RightScale's MultiCloud API.\nIt provides a simple object model of the API resources, and handles all of the\nfine details involved in making HTTP calls and translating their responses.\n"
16
+ s.email = "rubygems@rightscale.com"
17
+ s.executables = ["console", "setup"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt",
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ ".coveralls.yml",
24
+ ".rspec",
25
+ ".travis.yml",
26
+ "CHANGELOG.md",
27
+ "Gemfile",
28
+ "LICENSE.txt",
29
+ "README.md",
30
+ "Rakefile",
31
+ "VERSION",
32
+ "bin/console",
33
+ "bin/setup",
34
+ "config/login.yml.example",
35
+ "lib/right_api_client.rb",
36
+ "lib/right_api_client/client.rb",
37
+ "lib/right_api_client/errors.rb",
38
+ "lib/right_api_client/exceptions.rb",
39
+ "lib/right_api_client/helper.rb",
40
+ "lib/right_api_client/resource.rb",
41
+ "lib/right_api_client/resource_detail.rb",
42
+ "lib/right_api_client/resources.rb",
43
+ "lib/right_api_client/version.rb",
44
+ "login_to_client_irb.rb",
45
+ "right_api_client.gemspec",
46
+ "right_api_client.rconf",
47
+ "spec/functional/client_spec.rb",
48
+ "spec/spec_helper.rb",
49
+ "spec/support/mock_spec_helper.rb",
50
+ "spec/unit/client_spec.rb",
51
+ "spec/unit/helper_spec.rb",
52
+ "spec/unit/instance_facing_spec.rb",
53
+ "spec/unit/resource_detail_spec.rb",
54
+ "spec/unit/resource_spec.rb",
55
+ "spec/unit/resources_spec.rb"
56
+ ]
57
+ s.homepage = "https://github.com/rightscale/right_api_client"
58
+ s.licenses = ["MIT"]
59
+ s.rubygems_version = "2.4.8"
60
+ s.summary = "RightScale MultiCloud API HTTP Client"
61
+
62
+ if s.respond_to? :specification_version then
63
+ s.specification_version = 4
64
+
65
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
66
+ s.add_runtime_dependency(%q<json>, ["~> 1.0"])
67
+ s.add_runtime_dependency(%q<mime-types>, ["~> 2.0"])
68
+ s.add_runtime_dependency(%q<rest-client>, ["~> 1.6"])
69
+ s.add_development_dependency(%q<rake>, [">= 0"])
70
+ s.add_development_dependency(%q<rspec>, ["~> 2.9"])
71
+ s.add_development_dependency(%q<flexmock>, [">= 0"])
72
+ s.add_development_dependency(%q<coveralls>, [">= 0"])
73
+ s.add_development_dependency(%q<pry>, [">= 0"])
74
+ else
75
+ s.add_dependency(%q<json>, ["~> 1.0"])
76
+ s.add_dependency(%q<mime-types>, ["~> 2.0"])
77
+ s.add_dependency(%q<rest-client>, ["~> 1.6"])
78
+ s.add_dependency(%q<rake>, [">= 0"])
79
+ s.add_dependency(%q<rspec>, ["~> 2.9"])
80
+ s.add_dependency(%q<flexmock>, [">= 0"])
81
+ s.add_dependency(%q<coveralls>, [">= 0"])
82
+ s.add_dependency(%q<pry>, [">= 0"])
83
+ end
84
+ else
85
+ s.add_dependency(%q<json>, ["~> 1.0"])
86
+ s.add_dependency(%q<mime-types>, ["~> 2.0"])
87
+ s.add_dependency(%q<rest-client>, ["~> 1.6"])
88
+ s.add_dependency(%q<rake>, [">= 0"])
89
+ s.add_dependency(%q<rspec>, ["~> 2.9"])
90
+ s.add_dependency(%q<flexmock>, [">= 0"])
91
+ s.add_dependency(%q<coveralls>, [">= 0"])
92
+ s.add_dependency(%q<pry>, [">= 0"])
93
+ end
94
+ end
95
+
@@ -0,0 +1,181 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe RightApi::Client, :functional=>true do
4
+ context "given valid OAuth credentials" do
5
+ before(:each) do
6
+ @rest_client = flexmock("rest_client")
7
+ flexmock(RestClient::Resource.extend(PostOverride)).should_receive(:new).and_return(@rest_client)
8
+
9
+ oauth_endpoint = flexmock("OAuth endpoint")
10
+ overwrite_post = flexmock("Overwrite Post")
11
+ oauth_post_response = '{"refresh_token": "moo", "expires_in": 3600}'
12
+ @rest_client.should_receive(:[]).with('/api/oauth2').and_return(oauth_endpoint)
13
+ oauth_endpoint.should_receive(:extend).and_return(overwrite_post)
14
+ overwrite_post.should_receive(:post).and_return(oauth_post_response)
15
+
16
+ get_response = "session", "{\"links\":[{\"rel\":\"deployments\",\"href\":\"/api/deployments\"}, {\"rel\":\"tags\",\"href\":\"/api/tags\"}],\"message\":\"You have successfully logged into the RightScale API.\"}"
17
+ session_resource = flexmock("session resource")
18
+ @rest_client.should_receive(:[]).with('/api/session').and_return(session_resource)
19
+ session_resource.should_receive(:get).and_return(get_response)
20
+ end
21
+
22
+ it "accepts a refresh_token when creating a new client" do
23
+ client = RightApi::Client.new({:refresh_token => "refresh token only"})
24
+ client.refresh_token.should == "refresh token only"
25
+ end
26
+ end
27
+
28
+ context "given a logged-in client" do
29
+ before(:each) do
30
+ @rest_client = flexmock("rest_client")
31
+ flexmock(RestClient::Resource.extend(PostOverride)).should_receive(:new).and_return(@rest_client)
32
+
33
+ cookies = {"cookies" => "cookies"}
34
+ get_response = "session", "{\"links\":[{\"rel\":\"deployments\",\"href\":\"/api/deployments\"}, {\"rel\":\"tags\",\"href\":\"/api/tags\"}],\"message\":\"You have successfully logged into the RightScale API.\"}"
35
+ post_response = flexmock("post_response", :code => 204, :cookies => cookies, :body => " ")
36
+ session = flexmock("session")
37
+ overwrite_post = flexmock("Overwrite Post")
38
+
39
+ @rest_client.should_receive(:[]).with('/api/session').and_return(session)
40
+ session.should_receive(:get).and_return(get_response)
41
+ session.should_receive(:extend).and_return(overwrite_post)
42
+ overwrite_post.should_receive(:post).and_return(post_response)
43
+
44
+ @client = RightApi::Client.new(:email => "email", :password => "password", :account_id => 60073)
45
+ end
46
+
47
+ it "logs in" do
48
+ @client.send(:headers)[:cookies].should == {"cookies" => "cookies"}
49
+ @client.cookies.class.should == Hash
50
+ @client.cookies["cookies"].should == "cookies"
51
+ @client.cookies.timestamp.should_not == nil
52
+ @client.session.index.message.should == 'You have successfully logged into the RightScale API.'
53
+ end
54
+
55
+ it "logs in with cookies" do
56
+ client = RightApi::Client.new({:cookies => "cookies only"})
57
+ client.cookies.should == "cookies only"
58
+ end
59
+
60
+ context 'given :access_token parameter' do
61
+ let(:client) { RightApi::Client.new({:access_token => "access token only"}) }
62
+
63
+ it "accepts the token" do
64
+ client.access_token.should == "access token only"
65
+
66
+ @rest_client.should_receive(:[]).with('/api/oauth2').never
67
+ deployment_session = flexmock("Deployment Session")
68
+ deployment_session.should_receive(:post).and_return(1)
69
+ @rest_client.should_receive(:[]).with('/api/deployments').and_return(deployment_session)
70
+
71
+ response = @client.deployments.create(:deployment => {:name => "deployment_name"})
72
+ response.should == 1
73
+ end
74
+
75
+ it "doesn't try to login" do
76
+ client.access_token.should == "access token only"
77
+
78
+ @rest_client.should_receive(:[]).with('/api/oauth2').never
79
+ @rest_client.should_receive(:[]).with('/api/session').never
80
+
81
+ deployment_session = flexmock("Deployment Session")
82
+ deployment_session.should_receive(:post).and_return(1)
83
+ @rest_client.should_receive(:[]).with('/api/deployments').and_return(deployment_session)
84
+
85
+ response = @client.deployments.create(:deployment => {:name => "deployment_name"})
86
+ response.should == 1
87
+ end
88
+ end
89
+
90
+ it "posts" do
91
+ deployment_session = flexmock("Deployment Session")
92
+ deployment_session.should_receive(:post).and_return(1)
93
+ @rest_client.should_receive(:[]).with('/api/deployments').and_return(deployment_session)
94
+ response = @client.deployments.create(:deployment => {:name => "deployment_name"})
95
+ response.should == 1
96
+ end
97
+
98
+ it "gets" do
99
+ deployment_session = flexmock("Deployment Session")
100
+ deployment_session.should_receive(:get).and_return(nil)
101
+ @rest_client.should_receive(:[]).with("/api/deployments/1/to_ary").and_return(deployment_session)
102
+ deployment = @client.deployments(:id => 1)
103
+ deployment.href.should == "/api/deployments/1"
104
+ end
105
+
106
+ it "puts" do
107
+ deployment_session = flexmock("Deployment Session")
108
+ deployment_session.should_receive(:get)
109
+ @rest_client.should_receive(:[]).with("/api/deployments/1/to_ary").and_return(deployment_session)
110
+ deployment = @client.deployments(:id => 1)
111
+
112
+ @rest_client.should_receive(:[]).with("/api/deployments/1").and_return(deployment_session)
113
+ deployment_session.should_receive(:put).and_return(1)
114
+ deployment.update(:deployment => {:name => "updated"}).should == 1
115
+ end
116
+
117
+ it "deletes" do
118
+ deployment_session = flexmock("Deployment Session")
119
+ deployment_session.should_receive(:get)
120
+ @rest_client.should_receive(:[]).with("/api/deployments/1/to_ary").and_return(deployment_session)
121
+ deployment = @client.deployments(:id => 1)
122
+
123
+ @rest_client.should_receive(:[]).with("/api/deployments/1").and_return(deployment_session)
124
+ deployment_session.should_receive(:delete).and_return(1)
125
+ deployment.destroy.should == 1
126
+ end
127
+
128
+ it "multi-adds tags as a special request" do
129
+ tag_session = flexmock("Tag Session")
130
+ tag_session.should_receive(:post).and_return(1)
131
+ @rest_client.should_receive(:[]).with("/api/tags/multi_add").and_return(tag_session)
132
+ response = @client.tags.multi_add("resource_hrefs[]=/api/deployments/1&tags[]=tag1")
133
+ response.should == 1
134
+ end
135
+
136
+ it "singularizes resource_types correctly" do
137
+ @client.get_singular('servers').should == 'server'
138
+ @client.get_singular('deployments').should == 'deployment'
139
+ @client.get_singular('audit_entries').should == 'audit_entry'
140
+ @client.get_singular('processes').should == 'process'
141
+ @client.get_singular('ip_addresses').should == 'ip_address'
142
+ end
143
+
144
+ it "returns the resource when calling #resource(href)" do
145
+ resource_session = flexmock("Resource Session")
146
+ response = "deployment","{\"links\":[{\"rel\":\"self\",\"href\":\"/api/deployments/1\"}],\"name\":\"Mock Deployment\"}"
147
+ resource_session.should_receive(:get).and_return(response)
148
+ @rest_client.should_receive(:[]).with("/api/deployments/1").and_return(resource_session)
149
+ deployment = @client.resource("/api/deployments/1")
150
+ deployment.href.should == "/api/deployments/1"
151
+ deployment.name.should == "Mock Deployment"
152
+ end
153
+
154
+ it "raises meaningful errors" do
155
+ error_message = flexmock("Error Message", :code => 422, :body => "ERROR")
156
+ @rest_client.should_receive(:[]).with("/api/nada").and_raise(RightApi::UnknownRouteError.new(error_message))
157
+ err = begin
158
+ @client.resource('/api/nada')
159
+ rescue => e
160
+ e
161
+ end
162
+
163
+ err.class.should == RightApi::UnknownRouteError
164
+ err.message.should == "Unknown action or route. HTTP Code: 422, Response body: ERROR"
165
+ end
166
+
167
+ it "wraps errors with _details" do
168
+ response = flexmock("response", :code => 422, :body => "ResourceNotFound: Couldn't find Deployment with ID=asdf ")
169
+ @rest_client.should_receive(:[]).with("/api/deployments/nada").and_raise(RightApi::ApiError.new(response))
170
+ err = begin
171
+ @client.deployments(:id => 'nada').show
172
+ rescue => e
173
+ e
174
+ end
175
+
176
+ err._details.method.should == :get
177
+ err._details.path.should == '/api/deployments/nada'
178
+ err._details.params.should == {}
179
+ end
180
+ end
181
+ end