restforce 2.5.4 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +56 -0
  3. data/.rubocop.yml +27 -14
  4. data/.rubocop_todo.yml +128 -81
  5. data/CHANGELOG.md +37 -3
  6. data/CONTRIBUTING.md +3 -3
  7. data/Gemfile +4 -2
  8. data/Guardfile +3 -1
  9. data/LICENSE +1 -1
  10. data/README.md +120 -19
  11. data/Rakefile +2 -1
  12. data/lib/restforce.rb +23 -1
  13. data/lib/restforce/abstract_client.rb +3 -0
  14. data/lib/restforce/attachment.rb +3 -0
  15. data/lib/restforce/client.rb +2 -0
  16. data/lib/restforce/collection.rb +3 -1
  17. data/lib/restforce/concerns/api.rb +20 -14
  18. data/lib/restforce/concerns/authentication.rb +2 -0
  19. data/lib/restforce/concerns/base.rb +2 -0
  20. data/lib/restforce/concerns/batch_api.rb +87 -0
  21. data/lib/restforce/concerns/caching.rb +4 -2
  22. data/lib/restforce/concerns/canvas.rb +3 -0
  23. data/lib/restforce/concerns/connection.rb +26 -20
  24. data/lib/restforce/concerns/picklists.rb +9 -6
  25. data/lib/restforce/concerns/streaming.rb +60 -1
  26. data/lib/restforce/concerns/verbs.rb +3 -1
  27. data/lib/restforce/config.rb +4 -1
  28. data/lib/restforce/data/client.rb +2 -0
  29. data/lib/restforce/document.rb +3 -0
  30. data/lib/restforce/mash.rb +2 -0
  31. data/lib/restforce/middleware.rb +2 -0
  32. data/lib/restforce/middleware/authentication.rb +8 -6
  33. data/lib/restforce/middleware/authentication/password.rb +2 -0
  34. data/lib/restforce/middleware/authentication/token.rb +2 -0
  35. data/lib/restforce/middleware/authorization.rb +3 -1
  36. data/lib/restforce/middleware/caching.rb +3 -1
  37. data/lib/restforce/middleware/custom_headers.rb +2 -0
  38. data/lib/restforce/middleware/gzip.rb +5 -3
  39. data/lib/restforce/middleware/instance_url.rb +7 -3
  40. data/lib/restforce/middleware/logger.rb +2 -0
  41. data/lib/restforce/middleware/mashify.rb +2 -0
  42. data/lib/restforce/middleware/multipart.rb +8 -4
  43. data/lib/restforce/middleware/raise_error.rb +26 -8
  44. data/lib/restforce/patches/parts.rb +2 -0
  45. data/lib/restforce/signed_request.rb +3 -0
  46. data/lib/restforce/sobject.rb +3 -0
  47. data/lib/restforce/tooling/client.rb +5 -3
  48. data/lib/restforce/upload_io.rb +2 -0
  49. data/lib/restforce/version.rb +3 -1
  50. data/restforce.gemspec +19 -12
  51. data/spec/fixtures/sobject/sobject_describe_success_response.json +48 -1
  52. data/spec/integration/abstract_client_spec.rb +51 -7
  53. data/spec/integration/data/client_spec.rb +24 -5
  54. data/spec/spec_helper.rb +2 -0
  55. data/spec/support/client_integration.rb +2 -0
  56. data/spec/support/concerns.rb +2 -0
  57. data/spec/support/event_machine.rb +2 -0
  58. data/spec/support/fixture_helpers.rb +4 -2
  59. data/spec/support/matchers.rb +2 -0
  60. data/spec/support/middleware.rb +3 -1
  61. data/spec/support/mock_cache.rb +4 -2
  62. data/spec/unit/abstract_client_spec.rb +2 -0
  63. data/spec/unit/attachment_spec.rb +2 -0
  64. data/spec/unit/collection_spec.rb +5 -3
  65. data/spec/unit/concerns/api_spec.rb +40 -11
  66. data/spec/unit/concerns/authentication_spec.rb +4 -2
  67. data/spec/unit/concerns/base_spec.rb +2 -0
  68. data/spec/unit/concerns/batch_api_spec.rb +107 -0
  69. data/spec/unit/concerns/caching_spec.rb +2 -0
  70. data/spec/unit/concerns/canvas_spec.rb +3 -1
  71. data/spec/unit/concerns/connection_spec.rb +5 -3
  72. data/spec/unit/concerns/streaming_spec.rb +115 -1
  73. data/spec/unit/config_spec.rb +10 -8
  74. data/spec/unit/data/client_spec.rb +2 -0
  75. data/spec/unit/document_spec.rb +2 -0
  76. data/spec/unit/mash_spec.rb +3 -1
  77. data/spec/unit/middleware/authentication/password_spec.rb +2 -0
  78. data/spec/unit/middleware/authentication/token_spec.rb +2 -0
  79. data/spec/unit/middleware/authentication_spec.rb +3 -1
  80. data/spec/unit/middleware/authorization_spec.rb +2 -0
  81. data/spec/unit/middleware/custom_headers_spec.rb +3 -1
  82. data/spec/unit/middleware/gzip_spec.rb +4 -2
  83. data/spec/unit/middleware/instance_url_spec.rb +2 -0
  84. data/spec/unit/middleware/logger_spec.rb +2 -0
  85. data/spec/unit/middleware/mashify_spec.rb +3 -1
  86. data/spec/unit/middleware/raise_error_spec.rb +34 -11
  87. data/spec/unit/signed_request_spec.rb +2 -0
  88. data/spec/unit/sobject_spec.rb +5 -3
  89. data/spec/unit/tooling/client_spec.rb +2 -0
  90. metadata +38 -20
  91. data/.travis.yml +0 -16
  92. data/Gemfile.travis +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Authentication middleware used if username and password flow is used
3
5
  class Middleware::Authentication::Password < Restforce::Middleware::Authentication
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Authentication middleware used if oauth_token and refresh_token are set
3
5
  class Middleware::Authentication::Token < Restforce::Middleware::Authentication
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Piece of middleware that simply injects the OAuth token into the request
3
5
  # headers.
4
6
  class Middleware::Authorization < Restforce::Middleware
5
- AUTH_HEADER = 'Authorization'.freeze
7
+ AUTH_HEADER = 'Authorization'
6
8
 
7
9
  def call(env)
8
10
  env[:request_headers][AUTH_HEADER] = %(OAuth #{token})
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  class Middleware::Caching < FaradayMiddleware::Caching
3
5
  def call(env)
@@ -6,7 +8,7 @@ module Restforce
6
8
  end
7
9
 
8
10
  def expire(key)
9
- cache.delete(key) if cache
11
+ cache&.delete(key)
10
12
  end
11
13
 
12
14
  # We don't want to cache requests for different clients, so append the
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Middleware that allows you to specify custom request headers
3
5
  # when initializing Restforce client
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zlib'
2
4
 
3
5
  module Restforce
4
6
  # Middleware to uncompress GZIP compressed responses from Salesforce.
5
7
  class Middleware::Gzip < Restforce::Middleware
6
- ACCEPT_ENCODING_HEADER = 'Accept-Encoding'.freeze
7
- CONTENT_ENCODING_HEADER = 'Content-Encoding'.freeze
8
- ENCODING = 'gzip'.freeze
8
+ ACCEPT_ENCODING_HEADER = 'Accept-Encoding'
9
+ CONTENT_ENCODING_HEADER = 'Content-Encoding'
10
+ ENCODING = 'gzip'
9
11
 
10
12
  def call(env)
11
13
  env[:request_headers][ACCEPT_ENCODING_HEADER] = ENCODING if @options[:compress]
@@ -1,16 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Middleware which asserts that the instance_url is always set
3
5
  class Middleware::InstanceURL < Restforce::Middleware
4
6
  def call(env)
5
7
  # If the connection url_prefix isn't set, we must not be authenticated.
6
- raise Restforce::UnauthorizedError,
7
- 'Connection prefix not set' unless url_prefix_set?
8
+ unless url_prefix_set?
9
+ raise Restforce::UnauthorizedError,
10
+ 'Connection prefix not set'
11
+ end
8
12
 
9
13
  @app.call(env)
10
14
  end
11
15
 
12
16
  def url_prefix_set?
13
- !!(connection.url_prefix && connection.url_prefix.host)
17
+ !!(connection.url_prefix&.host)
14
18
  end
15
19
  end
16
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module Restforce
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  # Middleware the converts sobject records from JSON into Restforce::SObject objects
3
5
  # and collections of records into Restforce::Collection objects.
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  class Middleware::Multipart < Faraday::Request::UrlEncoded
3
- self.mime_type = 'multipart/form-data'.freeze
4
- DEFAULT_BOUNDARY = "--boundary_string".freeze
5
- JSON_CONTENT_TYPE = { "Content-Type" => "application/json" }
5
+ self.mime_type = 'multipart/form-data'
6
+ DEFAULT_BOUNDARY = "--boundary_string"
7
+ JSON_CONTENT_TYPE = { "Content-Type" => "application/json" }.freeze
6
8
 
7
9
  def call(env)
8
10
  match_content_type(env) do |params|
@@ -46,9 +48,11 @@ module Restforce
46
48
 
47
49
  # Files
48
50
  params.each do |k, v|
51
+ next unless v.respond_to? :content_type
52
+
49
53
  parts << Faraday::Parts::Part.new(boundary,
50
54
  k.to_s,
51
- v) if v.respond_to? :content_type
55
+ v)
52
56
  end
53
57
 
54
58
  parts << Faraday::Parts::EpiloguePart.new(boundary)
@@ -1,26 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  class Middleware::RaiseError < Faraday::Response::Middleware
3
5
  def on_complete(env)
4
6
  @env = env
5
7
  case env[:status]
6
8
  when 300
7
- raise Faraday::Error::ClientError.new("300: The external ID provided matches " \
8
- "more than one record",
9
- response_values)
9
+ raise Restforce::MatchesMultipleError.new(
10
+ "300: The external ID provided matches more than one record",
11
+ response_values
12
+ )
10
13
  when 401
11
14
  raise Restforce::UnauthorizedError, message
12
15
  when 404
13
- raise Faraday::Error::ResourceNotFound, message
16
+ raise Restforce::NotFoundError, message
14
17
  when 413
15
- raise Faraday::Error::ClientError.new("413: Request Entity Too Large",
16
- response_values)
18
+ raise Restforce::EntityTooLargeError.new(
19
+ "413: Request Entity Too Large",
20
+ response_values
21
+ )
17
22
  when 400...600
18
- raise Faraday::Error::ClientError.new(message, response_values)
23
+ klass = exception_class_for_error_code(body['errorCode'])
24
+ raise klass.new(message, response_values)
19
25
  end
20
26
  end
21
27
 
22
28
  def message
23
- "#{body['errorCode']}: #{body['message']}"
29
+ message = "#{body['errorCode']}: #{body['message']}"
30
+ message << "\nRESPONSE: #{JSON.dump(@env[:body])}"
31
+ rescue StandardError
32
+ message # if JSON.dump fails, return message without extra detail
24
33
  end
25
34
 
26
35
  def body
@@ -41,5 +50,14 @@ module Restforce
41
50
  body: @env[:body]
42
51
  }
43
52
  end
53
+
54
+ ERROR_CODE_MATCHER = /\A[A-Z_]+\z/.freeze
55
+
56
+ def exception_class_for_error_code(error_code)
57
+ return Restforce::ResponseError unless ERROR_CODE_MATCHER.match?(error_code)
58
+
59
+ constant_name = error_code.split('_').map(&:capitalize).join.to_sym
60
+ Restforce::ErrorCode.const_get(constant_name)
61
+ end
44
62
  end
45
63
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  module Parts
3
5
  module Part
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'openssl'
2
4
  require 'base64'
3
5
  require 'json'
@@ -25,6 +27,7 @@ module Restforce
25
27
  # Returns nil if the signed request is invalid.
26
28
  def decode
27
29
  return nil if signature != hmac
30
+
28
31
  JSON.parse(Base64.decode64(payload))
29
32
  end
30
33
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  class SObject < Restforce::Mash
3
5
  def sobject_type
@@ -61,6 +63,7 @@ module Restforce
61
63
 
62
64
  def ensure_id
63
65
  return true if self.Id?
66
+
64
67
  raise ArgumentError, 'You need to query the Id for the record first.'
65
68
  end
66
69
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
4
  module Tooling
3
5
  class Client < AbstractClient
4
6
  private
5
7
 
6
- def api_path(path)
7
- super("tooling/#{path}")
8
- end
8
+ def api_path(path)
9
+ super("tooling/#{path}")
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday/upload_io'
2
4
 
3
5
  module Restforce
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restforce
2
- VERSION = '2.5.4'.freeze
4
+ VERSION = '4.0.0'
3
5
  end
@@ -1,33 +1,40 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/restforce/version', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('lib/restforce/version', __dir__)
3
4
 
4
5
  Gem::Specification.new do |gem|
5
6
  gem.authors = ["Eric J. Holmes", "Tim Rogers"]
6
7
  gem.email = ["eric@ejholmes.net", "tim@gocardless.com"]
7
- gem.description = %q{A lightweight ruby client for the Salesforce REST API.}
8
- gem.summary = %q{A lightweight ruby client for the Salesforce REST API.}
8
+ gem.description = 'A lightweight ruby client for the Salesforce REST API.'
9
+ gem.summary = 'A lightweight ruby client for the Salesforce REST API.'
9
10
  gem.homepage = "http://restforce.org/"
10
11
  gem.license = "MIT"
11
12
 
12
- gem.files = `git ls-files`.split($\)
13
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
16
  gem.name = "restforce"
16
17
  gem.require_paths = ["lib"]
17
18
  gem.version = Restforce::VERSION
18
19
 
19
- gem.required_ruby_version = '>= 2.0'
20
+ gem.metadata = {
21
+ 'source_code_uri' => 'https://github.com/restforce/restforce',
22
+ 'changelog_uri' => 'https://github.com/restforce/restforce/blob/master/CHANGELOG.md'
23
+ }
24
+
25
+ gem.required_ruby_version = '>= 2.4'
20
26
 
21
- gem.add_dependency 'faraday', ['>= 0.9.0', '<= 1.0']
27
+ gem.add_dependency 'faraday', '<= 1.0', '>= 0.9.0'
22
28
  gem.add_dependency 'faraday_middleware', ['>= 0.8.8', '<= 1.0']
23
29
 
24
30
  gem.add_dependency 'json', '>= 1.7.5'
25
31
 
26
32
  gem.add_dependency 'hashie', ['>= 1.2.0', '< 4.0']
27
33
 
28
- gem.add_development_dependency 'rspec', '~> 2.14.0'
29
- gem.add_development_dependency 'webmock', '~> 1.13.0'
30
- gem.add_development_dependency 'simplecov', '~> 0.7.1'
31
- gem.add_development_dependency 'rubocop', '~> 0.31.0'
32
34
  gem.add_development_dependency 'faye' unless RUBY_PLATFORM == 'java'
35
+ gem.add_development_dependency 'rspec', '~> 2.14.0'
36
+ gem.add_development_dependency 'rspec_junit_formatter', '~> 0.3.0'
37
+ gem.add_development_dependency 'rubocop', '~> 0.75.0'
38
+ gem.add_development_dependency 'simplecov', '~> 0.17.1'
39
+ gem.add_development_dependency 'webmock', '~> 3.7.6'
33
40
  end
@@ -767,7 +767,48 @@
767
767
  "label" : "three",
768
768
  "defaultValue" : false,
769
769
  "validFor" : null
770
- } ],
770
+ }, {
771
+ "value" : "control_four",
772
+ "active" : true,
773
+ "label" : "control_four",
774
+ "defaultValue" : false,
775
+ "validFor" : null
776
+ }, {
777
+ "value" : "control_five",
778
+ "active" : true,
779
+ "label" : "control_five",
780
+ "defaultValue" : false,
781
+ "validFor" : null
782
+ }, {
783
+ "value" : "control_six",
784
+ "active" : true,
785
+ "label" : "control_six",
786
+ "defaultValue" : false,
787
+ "validFor" : null
788
+ }, {
789
+ "value" : "control_seven",
790
+ "active" : true,
791
+ "label" : "control_seven",
792
+ "defaultValue" : false,
793
+ "validFor" : null
794
+ }, {
795
+ "value" : "control_eight",
796
+ "active" : true,
797
+ "label" : "control_eight",
798
+ "defaultValue" : false,
799
+ "validFor" : null
800
+ }, {
801
+ "value" : "control_nine",
802
+ "active" : true,
803
+ "label" : "control_nine",
804
+ "defaultValue" : false,
805
+ "validFor" : null
806
+ }, {
807
+ "value" : "control_ten",
808
+ "active" : true,
809
+ "label" : "control_ten",
810
+ "defaultValue" : false,
811
+ "validFor" : null}],
771
812
  "referenceTo" : [ ],
772
813
  "relationshipName" : null,
773
814
  "relationshipOrder" : null,
@@ -883,6 +924,12 @@
883
924
  "label" : "nine",
884
925
  "defaultValue" : false,
885
926
  "validFor" : "QAAA"
927
+ }, {
928
+ "value" : "ten",
929
+ "active" : true,
930
+ "label" : "nine",
931
+ "defaultValue" : false,
932
+ "validFor" : "AEAA"
886
933
  } ],
887
934
  "referenceTo" : [ ],
888
935
  "relationshipName" : null,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  shared_examples_for Restforce::AbstractClient do
@@ -35,7 +37,7 @@ shared_examples_for Restforce::AbstractClient do
35
37
  end
36
38
 
37
39
  describe '.get_updated' do
38
- let(:start_date) { Time.new(2015, 8, 17, 0, 0, 0, "+02:00") }
40
+ let(:start_date) { Time.new(2015, 8, 17, 0, 0, 0, "+02:00") }
39
41
  let(:end_date) { Time.new(2016, 8, 19, 0, 0, 0, "+02:00") }
40
42
  end_string = '2016-08-18T22:00:00Z'
41
43
  start_string = '2015-08-16T22:00:00Z'
@@ -46,7 +48,7 @@ shared_examples_for Restforce::AbstractClient do
46
48
  end
47
49
 
48
50
  describe '.get_deleted' do
49
- let(:start_date) { Time.new(2015, 8, 17, 0, 0, 0, "+02:00") }
51
+ let(:start_date) { Time.new(2015, 8, 17, 0, 0, 0, "+02:00") }
50
52
  let(:end_date) { Time.new(2016, 8, 19, 0, 0, 0, "+02:00") }
51
53
  end_string = '2016-08-18T22:00:00Z'
52
54
  start_string = '2015-08-16T22:00:00Z'
@@ -94,7 +96,7 @@ shared_examples_for Restforce::AbstractClient do
94
96
  subject do
95
97
  client.create('Account', Name: 'Foobar',
96
98
  Blob: Restforce::UploadIO.new(
97
- File.expand_path('../../fixtures/blob.jpg', __FILE__),
99
+ File.expand_path('../fixtures/blob.jpg', __dir__),
98
100
  'image/jpeg'
99
101
  ))
100
102
  end
@@ -168,7 +170,8 @@ shared_examples_for Restforce::AbstractClient do
168
170
  context 'when updated' do
169
171
  requests 'sobjects/Account/External__c/foobar',
170
172
  method: :patch,
171
- with_body: "{\"Name\":\"Foobar\"}"
173
+ with_body: "{\"Name\":\"Foobar\"}",
174
+ fixture: "sobject/upsert_updated_success_response"
172
175
 
173
176
  context 'with symbol external Id key' do
174
177
  subject do
@@ -206,6 +209,24 @@ shared_examples_for Restforce::AbstractClient do
206
209
  end
207
210
  end
208
211
  end
212
+
213
+ context 'when created with a space in the id' do
214
+ requests 'sobjects/Account/External__c/foo%20bar',
215
+ method: :patch,
216
+ with_body: "{\"Name\":\"Foobar\"}",
217
+ fixture: 'sobject/upsert_created_success_response'
218
+
219
+ [:External__c, 'External__c', :external__c, 'external__c'].each do |key|
220
+ context "with #{key.inspect} as the external id" do
221
+ subject do
222
+ client.upsert!('Account', 'External__c', key => 'foo bar',
223
+ :Name => 'Foobar')
224
+ end
225
+
226
+ it { should eq 'foo' }
227
+ end
228
+ end
229
+ end
209
230
  end
210
231
 
211
232
  describe '.destroy!' do
@@ -226,6 +247,13 @@ shared_examples_for Restforce::AbstractClient do
226
247
 
227
248
  it { should be_true }
228
249
  end
250
+
251
+ context 'with a space in the id' do
252
+ subject(:destroy!) { client.destroy!('Account', '001D000000 INjVe') }
253
+ requests 'sobjects/Account/001D000000%20INjVe', method: :delete
254
+
255
+ it { should be_true }
256
+ end
229
257
  end
230
258
 
231
259
  describe '.destroy' do
@@ -263,6 +291,14 @@ shared_examples_for Restforce::AbstractClient do
263
291
  subject { client.find('Account', '1234', 'External_Field__c') }
264
292
  it { should be_a Hash }
265
293
  end
294
+
295
+ context 'with a space in an external id' do
296
+ requests 'sobjects/Account/External_Field__c/12%2034',
297
+ fixture: 'sobject/sobject_find_success_response'
298
+
299
+ subject { client.find('Account', '12 34', 'External_Field__c') }
300
+ it { should be_a Hash }
301
+ end
266
302
  end
267
303
 
268
304
  describe '.select' do
@@ -281,6 +317,14 @@ shared_examples_for Restforce::AbstractClient do
281
317
  subject { client.select('Account', '1234', ['External_Field__c']) }
282
318
  it { should be_a Hash }
283
319
  end
320
+
321
+ context 'with a space in the id' do
322
+ requests 'sobjects/Account/12%2034',
323
+ fixture: 'sobject/sobject_select_success_response'
324
+
325
+ subject { client.select('Account', '12 34', nil, nil) }
326
+ it { should be_a Hash }
327
+ end
284
328
  end
285
329
 
286
330
  context 'when an external id is specified' do
@@ -379,11 +423,11 @@ shared_examples_for Restforce::AbstractClient do
379
423
 
380
424
  before do
381
425
  @query = stub_api_request('query\?q=SELECT%20some,%20fields%20FROM%20object').
382
- with(headers: { 'Authorization' => "OAuth #{oauth_token}" }).
383
- to_return(status: 401,
426
+ with(headers: { 'Authorization' => "OAuth #{oauth_token}" }).
427
+ to_return(status: 401,
384
428
  body: fixture('expired_session_response'),
385
429
  headers: { 'Content-Type' => 'application/json' }).then.
386
- to_return(status: 200,
430
+ to_return(status: 200,
387
431
  body: fixture('sobject/query_success_response'),
388
432
  headers: { 'Content-Type' => 'application/json' })
389
433