right_api_client 1.6.1 → 1.6.2

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