restforce 2.5.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +56 -0
  3. data/.rubocop.yml +18 -3
  4. data/.rubocop_todo.yml +8 -8
  5. data/CHANGELOG.md +12 -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 +22 -16
  11. data/Rakefile +2 -1
  12. data/lib/restforce.rb +2 -0
  13. data/lib/restforce/abstract_client.rb +2 -0
  14. data/lib/restforce/attachment.rb +2 -0
  15. data/lib/restforce/client.rb +2 -0
  16. data/lib/restforce/collection.rb +3 -1
  17. data/lib/restforce/concerns/api.rb +11 -8
  18. data/lib/restforce/concerns/authentication.rb +2 -0
  19. data/lib/restforce/concerns/base.rb +2 -0
  20. data/lib/restforce/concerns/caching.rb +4 -2
  21. data/lib/restforce/concerns/canvas.rb +2 -0
  22. data/lib/restforce/concerns/connection.rb +26 -20
  23. data/lib/restforce/concerns/picklists.rb +7 -5
  24. data/lib/restforce/concerns/streaming.rb +2 -0
  25. data/lib/restforce/concerns/verbs.rb +3 -1
  26. data/lib/restforce/config.rb +3 -1
  27. data/lib/restforce/data/client.rb +2 -0
  28. data/lib/restforce/document.rb +2 -0
  29. data/lib/restforce/mash.rb +2 -0
  30. data/lib/restforce/middleware.rb +2 -0
  31. data/lib/restforce/middleware/authentication.rb +8 -6
  32. data/lib/restforce/middleware/authentication/password.rb +2 -0
  33. data/lib/restforce/middleware/authentication/token.rb +2 -0
  34. data/lib/restforce/middleware/authorization.rb +3 -1
  35. data/lib/restforce/middleware/caching.rb +3 -1
  36. data/lib/restforce/middleware/custom_headers.rb +2 -0
  37. data/lib/restforce/middleware/gzip.rb +5 -3
  38. data/lib/restforce/middleware/instance_url.rb +7 -3
  39. data/lib/restforce/middleware/logger.rb +2 -0
  40. data/lib/restforce/middleware/mashify.rb +2 -0
  41. data/lib/restforce/middleware/multipart.rb +7 -4
  42. data/lib/restforce/middleware/raise_error.rb +2 -0
  43. data/lib/restforce/patches/parts.rb +2 -0
  44. data/lib/restforce/signed_request.rb +2 -0
  45. data/lib/restforce/sobject.rb +2 -0
  46. data/lib/restforce/tooling/client.rb +2 -0
  47. data/lib/restforce/upload_io.rb +2 -0
  48. data/lib/restforce/version.rb +3 -1
  49. data/restforce.gemspec +17 -10
  50. data/spec/fixtures/sobject/sobject_describe_success_response.json +48 -1
  51. data/spec/integration/abstract_client_spec.rb +9 -6
  52. data/spec/integration/data/client_spec.rb +24 -5
  53. data/spec/spec_helper.rb +2 -0
  54. data/spec/support/client_integration.rb +2 -0
  55. data/spec/support/concerns.rb +2 -0
  56. data/spec/support/event_machine.rb +2 -0
  57. data/spec/support/fixture_helpers.rb +2 -0
  58. data/spec/support/matchers.rb +2 -0
  59. data/spec/support/middleware.rb +3 -1
  60. data/spec/support/mock_cache.rb +4 -2
  61. data/spec/unit/abstract_client_spec.rb +2 -0
  62. data/spec/unit/attachment_spec.rb +2 -0
  63. data/spec/unit/collection_spec.rb +5 -3
  64. data/spec/unit/concerns/api_spec.rb +30 -11
  65. data/spec/unit/concerns/authentication_spec.rb +4 -2
  66. data/spec/unit/concerns/base_spec.rb +2 -0
  67. data/spec/unit/concerns/caching_spec.rb +2 -0
  68. data/spec/unit/concerns/canvas_spec.rb +3 -1
  69. data/spec/unit/concerns/connection_spec.rb +5 -3
  70. data/spec/unit/concerns/streaming_spec.rb +3 -1
  71. data/spec/unit/config_spec.rb +10 -8
  72. data/spec/unit/data/client_spec.rb +2 -0
  73. data/spec/unit/document_spec.rb +2 -0
  74. data/spec/unit/mash_spec.rb +3 -1
  75. data/spec/unit/middleware/authentication/password_spec.rb +2 -0
  76. data/spec/unit/middleware/authentication/token_spec.rb +2 -0
  77. data/spec/unit/middleware/authentication_spec.rb +3 -1
  78. data/spec/unit/middleware/authorization_spec.rb +2 -0
  79. data/spec/unit/middleware/custom_headers_spec.rb +3 -1
  80. data/spec/unit/middleware/gzip_spec.rb +4 -2
  81. data/spec/unit/middleware/instance_url_spec.rb +2 -0
  82. data/spec/unit/middleware/logger_spec.rb +2 -0
  83. data/spec/unit/middleware/mashify_spec.rb +3 -1
  84. data/spec/unit/middleware/raise_error_spec.rb +2 -0
  85. data/spec/unit/signed_request_spec.rb +2 -0
  86. data/spec/unit/sobject_spec.rb +5 -3
  87. data/spec/unit/tooling/client_spec.rb +2 -0
  88. metadata +35 -19
  89. data/.travis.yml +0 -16
  90. data/Gemfile.travis +0 -8
@@ -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'
@@ -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
@@ -379,11 +382,11 @@ shared_examples_for Restforce::AbstractClient do
379
382
 
380
383
  before do
381
384
  @query = stub_api_request('query\?q=SELECT%20some,%20fields%20FROM%20object').
382
- with(headers: { 'Authorization' => "OAuth #{oauth_token}" }).
383
- to_return(status: 401,
385
+ with(headers: { 'Authorization' => "OAuth #{oauth_token}" }).
386
+ to_return(status: 401,
384
387
  body: fixture('expired_session_response'),
385
388
  headers: { 'Content-Type' => 'application/json' }).then.
386
- to_return(status: 200,
389
+ to_return(status: 200,
387
390
  body: fixture('sobject/query_success_response'),
388
391
  headers: { 'Content-Type' => 'application/json' })
389
392
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  shared_examples_for Restforce::Data::Client do
@@ -8,15 +10,20 @@ shared_examples_for Restforce::Data::Client do
8
10
  context 'when given a picklist field' do
9
11
  subject { client.picklist_values('Account', 'Picklist_Field') }
10
12
  it { should be_an Array }
11
- its(:length) { should eq 3 }
12
- it { should include_picklist_values %w(one two three) }
13
+ its(:length) { should eq 10 }
14
+ it {
15
+ should include_picklist_values %w[
16
+ one two three control_four control_five
17
+ control_six control_seven control_eight control_nine control_ten
18
+ ]
19
+ }
13
20
  end
14
21
 
15
22
  context 'when given a multipicklist field' do
16
23
  subject { client.picklist_values('Account', 'Picklist_Multiselect_Field') }
17
24
  it { should be_an Array }
18
25
  its(:length) { should eq 3 }
19
- it { should include_picklist_values %w(four five six) }
26
+ it { should include_picklist_values %w[four five six] }
20
27
  end
21
28
 
22
29
  describe 'dependent picklists' do
@@ -29,10 +36,22 @@ shared_examples_for Restforce::Data::Client do
29
36
 
30
37
  it { should be_an Array }
31
38
  its(:length) { should eq 2 }
32
- it { should include_picklist_values %w(seven eight) }
39
+ it { should include_picklist_values %w[seven eight] }
33
40
  it { should_not include_picklist_values ['nine'] }
34
41
  end
35
42
 
43
+ context 'when given a picklist field that has a dependency index greater than 8' do
44
+ subject do
45
+ client.picklist_values('Account',
46
+ 'Dependent_Picklist_Field',
47
+ valid_for: 'control_ten')
48
+ end
49
+
50
+ it { should be_an Array }
51
+ its(:length) { should eq 1 }
52
+ it { should include_picklist_values %w[ten] }
53
+ end
54
+
36
55
  context 'when given a picklist field that does not have a dependency' do
37
56
  subject do
38
57
  client.picklist_values('Account', 'Picklist_Field', valid_for: 'one')
@@ -90,7 +109,7 @@ shared_examples_for Restforce::Data::Client do
90
109
  it 'subscribes to each pushtopic' do
91
110
  client.faye.should_receive(:subscribe).with(['/topic/PushTopic1',
92
111
  '/topic/PushTopic2'])
93
- client.subscribe(%w(PushTopic1 PushTopic2))
112
+ client.subscribe(%w[PushTopic1 PushTopic2])
94
113
  end
95
114
  end
96
115
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'simplecov'
2
4
  SimpleCov.start
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ClientIntegrationExampleGroup
2
4
  def self.included(base)
3
5
  base.class_eval do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ConcernsExampleGroup
2
4
  def self.included(base)
3
5
  base.class_eval do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.configure do |config|
2
4
  config.before do
3
5
  EventMachine.stub(:connect) if defined?(EventMachine)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FixtureHelpers
2
4
  module InstanceMethods
3
5
  def stub_api_request(endpoint, options = {})
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec::Matchers.define :include_picklist_values do |expected|
2
4
  match do |actual|
3
5
  actual.all? { |picklist_value| expected.include? picklist_value['value'] }
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiddlewareExampleGroup
2
4
  def self.included(base)
3
5
  base.class_eval do
4
- let(:app) { double('@app', call: nil) }
6
+ let(:app) { double('@app', call: nil) }
5
7
  let(:env) { { request_headers: {}, response_headers: {} } }
6
8
  let(:retries) { 3 }
7
9
  let(:options) { {} }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MockCache
2
4
  def initialize
3
5
  @storage = {}
@@ -11,8 +13,8 @@ class MockCache
11
13
  @storage[key] = value
12
14
  end
13
15
 
14
- def fetch(key, &block)
15
- @storage[key] ||= block.call
16
+ def fetch(key)
17
+ @storage[key] ||= yield
16
18
  end
17
19
 
18
20
  def delete(key)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::AbstractClient do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Attachment do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Collection do
@@ -16,7 +18,7 @@ describe Restforce::Collection do
16
18
  its(:page_size) { should eq 1 }
17
19
 
18
20
  describe 'each record' do
19
- it { should be_all { |record| expect(record).to be_a Restforce::SObject } }
21
+ it { should(be_all { |record| expect(record).to be_a Restforce::SObject }) }
20
22
  end
21
23
  end
22
24
 
@@ -51,11 +53,11 @@ describe Restforce::Collection do
51
53
  end
52
54
 
53
55
  its(:pages) do
54
- should be_all { |page| expect(page).to be_a Restforce::Collection }
56
+ should(be_all { |page| expect(page).to be_a Restforce::Collection })
55
57
  end
56
58
 
57
59
  its(:has_next_page?) { should be_true }
58
- it { should be_all { |record| expect(record).to be_a Restforce::SObject } }
60
+ it { should(be_all { |record| expect(record).to be_a Restforce::SObject }) }
59
61
  its(:next_page) { should be_a Restforce::Collection }
60
62
  end
61
63
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Concerns::API do
@@ -27,7 +29,7 @@ describe Restforce::Concerns::API do
27
29
  it 'returns the body' do
28
30
  start_string = '2002-10-31T00:02:02Z'
29
31
  end_string = '2003-10-31T00:02:02Z'
30
- url = "/sobjects/Whizbang/updated/?start=#{start_string}&end=#{end_string}"
32
+ url = "sobjects/Whizbang/updated/?start=#{start_string}&end=#{end_string}"
31
33
  client.should_receive(:api_get).
32
34
  with(url).
33
35
  and_return(response)
@@ -43,7 +45,7 @@ describe Restforce::Concerns::API do
43
45
  it 'returns the body' do
44
46
  start_string = '2002-10-31T00:02:02Z'
45
47
  end_string = '2003-10-31T00:02:02Z'
46
- url = "/sobjects/Whizbang/deleted/?start=#{start_string}&end=#{end_string}"
48
+ url = "sobjects/Whizbang/deleted/?start=#{start_string}&end=#{end_string}"
47
49
  client.should_receive(:api_get).
48
50
  with(url).
49
51
  and_return(response)
@@ -259,7 +261,7 @@ describe Restforce::Concerns::API do
259
261
  end
260
262
  end
261
263
 
262
- [:create, :update, :upsert, :destroy].each do |method|
264
+ %i[create update upsert destroy].each do |method|
263
265
  describe ".#{method}" do
264
266
  let(:args) { [] }
265
267
  subject(:result) { client.send(method, *args) }
@@ -289,7 +291,7 @@ describe Restforce::Concerns::API do
289
291
 
290
292
  describe '.create!' do
291
293
  let(:sobject) { 'Whizbang' }
292
- let(:attrs) { Hash.new }
294
+ let(:attrs) { {} }
293
295
  subject(:result) { client.create!(sobject, attrs) }
294
296
 
295
297
  it 'send an HTTP POST, and returns the id of the record' do
@@ -303,7 +305,7 @@ describe Restforce::Concerns::API do
303
305
 
304
306
  describe '.update!' do
305
307
  let(:sobject) { 'Whizbang' }
306
- let(:attrs) { Hash.new }
308
+ let(:attrs) { {} }
307
309
  subject(:result) { client.update!(sobject, attrs) }
308
310
 
309
311
  context 'when the id field is present' do
@@ -342,7 +344,7 @@ describe Restforce::Concerns::API do
342
344
 
343
345
  context 'when the record is found and updated' do
344
346
  it 'returns true' do
345
- response.body.stub :[]
347
+ response.stub(:body) { {} }
346
348
  client.should_receive(:api_patch).
347
349
  with('sobjects/Whizbang/External_ID__c/1234', {}).
348
350
  and_return(response)
@@ -352,7 +354,7 @@ describe Restforce::Concerns::API do
352
354
 
353
355
  context 'when the record is found and created' do
354
356
  it 'returns the id of the record' do
355
- response.body.stub(:[]).with('id').and_return('4321')
357
+ response.stub(:body) { { "id" => "4321" } }
356
358
  client.should_receive(:api_patch).
357
359
  with('sobjects/Whizbang/External_ID__c/1234', {}).
358
360
  and_return(response)
@@ -361,7 +363,7 @@ describe Restforce::Concerns::API do
361
363
  end
362
364
 
363
365
  context 'when the external id field is missing from the attrs' do
364
- let(:attrs) { Hash.new }
366
+ let(:attrs) { {} }
365
367
 
366
368
  it 'raises an argument error' do
367
369
  expect { client.upsert!(sobject, field, attrs) }.
@@ -376,7 +378,7 @@ describe Restforce::Concerns::API do
376
378
 
377
379
  context 'and the value for Id is provided' do
378
380
  it 'returns the id of the record, and original record still contains id' do
379
- response.body.stub(:[]).with('id').and_return('4321')
381
+ response.stub(:body) { { "id" => "4321" } }
380
382
  client.should_receive(:api_patch).
381
383
  with('sobjects/Whizbang/Id/4321', {}).
382
384
  and_return(response)
@@ -389,7 +391,7 @@ describe Restforce::Concerns::API do
389
391
  let(:attrs) { { 'External_ID__c' => '1234' } }
390
392
 
391
393
  it 'uses POST to create the record' do
392
- response.body.stub(:[]).with('id').and_return('4321')
394
+ response.stub(:body) { { "id" => "4321" } }
393
395
  client.should_receive(:options).and_return(api_version: 38.0)
394
396
  client.should_receive(:api_post).
395
397
  with('sobjects/Whizbang/Id', attrs).
@@ -415,7 +417,7 @@ describe Restforce::Concerns::API do
415
417
 
416
418
  context 'when the record is found and updated' do
417
419
  it 'returns true' do
418
- response.body.stub :[]
420
+ response.stub(:body) { {} }
419
421
  client.should_receive(:api_patch).
420
422
  with('sobjects/Whizbang/External_ID__c/%E3%81%82', {}).
421
423
  and_return(response)
@@ -423,6 +425,23 @@ describe Restforce::Concerns::API do
423
425
  end
424
426
  end
425
427
  end
428
+
429
+ describe '.upsert! with Fixnum argument' do
430
+ let(:sobject) { 'Whizbang' }
431
+ let(:field) { :External_ID__c }
432
+ let(:attrs) { { 'External_ID__c' => 1234 } }
433
+ subject(:result) { client.upsert!(sobject, field, attrs) }
434
+
435
+ context 'when the record is found and updated' do
436
+ it 'returns true' do
437
+ response.stub(:body) { {} }
438
+ client.should_receive(:api_patch).
439
+ with('sobjects/Whizbang/External_ID__c/1234', {}).
440
+ and_return(response)
441
+ expect(result).to be_true
442
+ end
443
+ end
444
+ end
426
445
  end
427
446
 
428
447
  describe '.destroy!' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Concerns::Authentication do
@@ -54,7 +56,7 @@ describe Restforce::Concerns::Authentication do
54
56
 
55
57
  describe '.username_password?' do
56
58
  subject { client.username_password? }
57
- let(:options) { Hash.new }
59
+ let(:options) { {} }
58
60
 
59
61
  before do
60
62
  client.stub options: options
@@ -78,7 +80,7 @@ describe Restforce::Concerns::Authentication do
78
80
 
79
81
  describe '.oauth_refresh?' do
80
82
  subject { client.oauth_refresh? }
81
- let(:options) { Hash.new }
83
+ let(:options) { {} }
82
84
 
83
85
  before do
84
86
  client.stub options: options
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Concerns::Base do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Concerns::Caching do
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restforce::Concerns::Canvas do
4
- let(:options) { Hash.new }
6
+ let(:options) { {} }
5
7
 
6
8
  before do
7
9
  client.stub options: options