force 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +107 -0
- data/Guardfile +8 -0
- data/LICENSE +22 -0
- data/README.md +421 -0
- data/Rakefile +10 -0
- data/coverage/assets/0.7.1/application.css +1110 -0
- data/coverage/assets/0.7.1/application.js +626 -0
- data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
- data/coverage/assets/0.7.1/favicon_green.png +0 -0
- data/coverage/assets/0.7.1/favicon_red.png +0 -0
- data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
- data/coverage/assets/0.7.1/loading.gif +0 -0
- data/coverage/assets/0.7.1/magnify.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +19808 -0
- data/force.gemspec +27 -0
- data/lib/force.rb +74 -0
- data/lib/force/abstract_client.rb +9 -0
- data/lib/force/attachment.rb +21 -0
- data/lib/force/client.rb +3 -0
- data/lib/force/collection.rb +45 -0
- data/lib/force/concerns/api.rb +321 -0
- data/lib/force/concerns/authentication.rb +39 -0
- data/lib/force/concerns/base.rb +59 -0
- data/lib/force/concerns/caching.rb +24 -0
- data/lib/force/concerns/canvas.rb +10 -0
- data/lib/force/concerns/connection.rb +74 -0
- data/lib/force/concerns/picklists.rb +87 -0
- data/lib/force/concerns/streaming.rb +31 -0
- data/lib/force/concerns/verbs.rb +67 -0
- data/lib/force/config.rb +140 -0
- data/lib/force/data/client.rb +18 -0
- data/lib/force/mash.rb +66 -0
- data/lib/force/middleware.rb +27 -0
- data/lib/force/middleware/authentication.rb +73 -0
- data/lib/force/middleware/authentication/password.rb +17 -0
- data/lib/force/middleware/authentication/token.rb +15 -0
- data/lib/force/middleware/authorization.rb +15 -0
- data/lib/force/middleware/caching.rb +22 -0
- data/lib/force/middleware/gzip.rb +31 -0
- data/lib/force/middleware/instance_url.rb +14 -0
- data/lib/force/middleware/logger.rb +40 -0
- data/lib/force/middleware/mashify.rb +16 -0
- data/lib/force/middleware/multipart.rb +55 -0
- data/lib/force/middleware/raise_error.rb +25 -0
- data/lib/force/signed_request.rb +48 -0
- data/lib/force/sobject.rb +68 -0
- data/lib/force/tooling/client.rb +11 -0
- data/lib/force/upload_io.rb +20 -0
- data/lib/force/version.rb +3 -0
- data/spec/fixtures/auth_error_response.json +4 -0
- data/spec/fixtures/auth_success_response.json +7 -0
- data/spec/fixtures/blob.jpg +0 -0
- data/spec/fixtures/expired_session_response.json +6 -0
- data/spec/fixtures/reauth_success_response.json +7 -0
- data/spec/fixtures/refresh_error_response.json +4 -0
- data/spec/fixtures/refresh_success_response.json +7 -0
- data/spec/fixtures/services_data_success_response.json +12 -0
- data/spec/fixtures/sobject/create_success_response.json +5 -0
- data/spec/fixtures/sobject/delete_error_response.json +1 -0
- data/spec/fixtures/sobject/describe_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/list_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/org_query_response.json +11 -0
- data/spec/fixtures/sobject/query_aggregate_success_response.json +23 -0
- data/spec/fixtures/sobject/query_empty_response.json +5 -0
- data/spec/fixtures/sobject/query_error_response.json +6 -0
- data/spec/fixtures/sobject/query_paginated_first_page_response.json +14 -0
- data/spec/fixtures/sobject/query_paginated_last_page_response.json +13 -0
- data/spec/fixtures/sobject/query_success_response.json +38 -0
- data/spec/fixtures/sobject/recent_success_response.json +18 -0
- data/spec/fixtures/sobject/search_error_response.json +6 -0
- data/spec/fixtures/sobject/search_success_response.json +16 -0
- data/spec/fixtures/sobject/sobject_describe_error_response.json +6 -0
- data/spec/fixtures/sobject/sobject_describe_success_response.json +1429 -0
- data/spec/fixtures/sobject/sobject_find_error_response.json +6 -0
- data/spec/fixtures/sobject/sobject_find_success_response.json +29 -0
- data/spec/fixtures/sobject/upsert_created_success_response.json +5 -0
- data/spec/fixtures/sobject/upsert_error_response.json +6 -0
- data/spec/fixtures/sobject/upsert_multiple_error_response.json +4 -0
- data/spec/fixtures/sobject/upsert_updated_success_response.json +0 -0
- data/spec/fixtures/sobject/write_error_response.json +6 -0
- data/spec/integration/abstract_client_spec.rb +306 -0
- data/spec/integration/data/client_spec.rb +90 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/client_integration.rb +45 -0
- data/spec/support/concerns.rb +18 -0
- data/spec/support/event_machine.rb +14 -0
- data/spec/support/fixture_helpers.rb +45 -0
- data/spec/support/matchers.rb +11 -0
- data/spec/support/middleware.rb +76 -0
- data/spec/support/mock_cache.rb +13 -0
- data/spec/unit/abstract_client_spec.rb +11 -0
- data/spec/unit/attachment_spec.rb +15 -0
- data/spec/unit/collection_spec.rb +52 -0
- data/spec/unit/concerns/api_spec.rb +244 -0
- data/spec/unit/concerns/authentication_spec.rb +98 -0
- data/spec/unit/concerns/base_spec.rb +42 -0
- data/spec/unit/concerns/caching_spec.rb +29 -0
- data/spec/unit/concerns/canvas_spec.rb +30 -0
- data/spec/unit/concerns/connection_spec.rb +22 -0
- data/spec/unit/config_spec.rb +99 -0
- data/spec/unit/data/client_spec.rb +10 -0
- data/spec/unit/mash_spec.rb +36 -0
- data/spec/unit/middleware/authentication/password_spec.rb +31 -0
- data/spec/unit/middleware/authentication/token_spec.rb +24 -0
- data/spec/unit/middleware/authentication_spec.rb +67 -0
- data/spec/unit/middleware/authorization_spec.rb +11 -0
- data/spec/unit/middleware/gzip_spec.rb +66 -0
- data/spec/unit/middleware/instance_url_spec.rb +24 -0
- data/spec/unit/middleware/logger_spec.rb +19 -0
- data/spec/unit/middleware/mashify_spec.rb +11 -0
- data/spec/unit/middleware/raise_error_spec.rb +32 -0
- data/spec/unit/signed_request_spec.rb +24 -0
- data/spec/unit/sobject_spec.rb +86 -0
- data/spec/unit/tooling/client_spec.rb +7 -0
- data/tmp/rspec_guard_result +1 -0
- metadata +383 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"attributes": {
|
3
|
+
"type": "Whizbang",
|
4
|
+
"url": "/services/data/v20.0/sobjects/Whizbang/23foo"
|
5
|
+
},
|
6
|
+
"Id": "23foo",
|
7
|
+
"OwnerId": "owner_id",
|
8
|
+
"IsDeleted": false,
|
9
|
+
"Name": "My First Whizbang",
|
10
|
+
"CreatedById": "created_by_id",
|
11
|
+
"LastModifiedById": "last_modified_by_id",
|
12
|
+
"Auto_Number": "A-1",
|
13
|
+
"Checkbox_Label": true,
|
14
|
+
"Currency_Label": 23.0,
|
15
|
+
"Date_Label": "2010-01-01",
|
16
|
+
"DateTime_Label": "2011-07-07T00:37:00.000+0000",
|
17
|
+
"OtherDateTime_Label": null,
|
18
|
+
"Email_Label": "danny@example.com",
|
19
|
+
"Number_Label": 23.0,
|
20
|
+
"Percent_Label": 33.0,
|
21
|
+
"Phone_Label": "(415) 555-1212",
|
22
|
+
"Picklist_Label": "one",
|
23
|
+
"Picklist_Multiselect_Label": "four;six",
|
24
|
+
"Text_Label": "some text",
|
25
|
+
"TextArea_Label": "a text area",
|
26
|
+
"TextAreaLong_Label": "a loooooooooooooong text area",
|
27
|
+
"TextAreaRich_Label": "Rich <strong>text</strong>",
|
28
|
+
"URL_Label": "http://pivotallabs.com"
|
29
|
+
}
|
File without changes
|
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for Force::AbstractClient do
|
4
|
+
describe '.list_sobjects' do
|
5
|
+
requests :sobjects, :fixture => 'sobject/describe_sobjects_success_response'
|
6
|
+
|
7
|
+
subject { client.list_sobjects }
|
8
|
+
it { should be_an Array }
|
9
|
+
it { should eq ['Account'] }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.describe' do
|
13
|
+
context 'with no arguments' do
|
14
|
+
requests :sobjects, :fixture => 'sobject/describe_sobjects_success_response'
|
15
|
+
|
16
|
+
subject { client.describe }
|
17
|
+
it { should be_an Array }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with an argument' do
|
21
|
+
requests 'sobjects/Whizbang/describe', :fixture => 'sobject/sobject_describe_success_response'
|
22
|
+
|
23
|
+
subject { client.describe('Whizbang') }
|
24
|
+
its(['name']) { should eq 'Whizbang' }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.query' do
|
29
|
+
requests 'query\?q=SELECT%20some,%20fields%20FROM%20object', :fixture => 'sobject/query_success_response'
|
30
|
+
|
31
|
+
subject { client.query('SELECT some, fields FROM object') }
|
32
|
+
it { should be_an Enumerable }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.search' do
|
36
|
+
requests 'search\?q=FIND%20%7Bbar%7D', :fixture => 'sobject/search_success_response'
|
37
|
+
|
38
|
+
subject { client.search('FIND {bar}') }
|
39
|
+
it { should be_an Array }
|
40
|
+
its(:size) { should eq 2 }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '.org_id' do
|
44
|
+
requests 'query\?q=select%20id%20from%20Organization', :fixture => 'sobject/org_query_response'
|
45
|
+
|
46
|
+
subject { client.org_id }
|
47
|
+
it { should eq '00Dx0000000BV7z' }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.create' do
|
51
|
+
context 'without multipart' do
|
52
|
+
requests 'sobjects/Account',
|
53
|
+
:method => :post,
|
54
|
+
:with_body => "{\"Name\":\"Foobar\"}",
|
55
|
+
:fixture => 'sobject/create_success_response'
|
56
|
+
|
57
|
+
subject { client.create('Account', :Name => 'Foobar') }
|
58
|
+
it { should eq 'some_id' }
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with multipart' do
|
62
|
+
requests 'sobjects/Account',
|
63
|
+
:method => :post,
|
64
|
+
:with_body => %r(----boundary_string\r\nContent-Disposition: form-data; name=\"entity_content\";\r\nContent-Type: application/json\r\n\r\n{\"Name\":\"Foobar\"}\r\n----boundary_string\r\nContent-Disposition: form-data; name=\"Blob\"; filename=\"blob.jpg\"\r\nContent-Length: 42171\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary),
|
65
|
+
:fixture => 'sobject/create_success_response'
|
66
|
+
|
67
|
+
subject { client.create('Account', :Name => 'Foobar', :Blob => Force::UploadIO.new(File.expand_path('../../fixtures/blob.jpg', __FILE__), 'image/jpeg')) }
|
68
|
+
it { should eq 'some_id' }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '.update!' do
|
73
|
+
context 'with invalid Id' do
|
74
|
+
requests 'sobjects/Account/001D000000INjVe',
|
75
|
+
:method => :patch,
|
76
|
+
:with_body => "{\"Name\":\"Foobar\"}",
|
77
|
+
:status => 404,
|
78
|
+
:fixture => 'sobject/delete_error_response'
|
79
|
+
|
80
|
+
subject { lambda { client.update!('Account', :Id => '001D000000INjVe', :Name => 'Foobar') } }
|
81
|
+
it { should raise_error Faraday::Error::ResourceNotFound }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '.update' do
|
86
|
+
context 'with missing Id' do
|
87
|
+
subject { lambda { client.update('Account', :Name => 'Foobar') } }
|
88
|
+
it { should raise_error ArgumentError, 'Id field missing from attrs.' }
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with invalid Id' do
|
92
|
+
requests 'sobjects/Account/001D000000INjVe',
|
93
|
+
:method => :patch,
|
94
|
+
:with_body => "{\"Name\":\"Foobar\"}",
|
95
|
+
:status => 404,
|
96
|
+
:fixture => 'sobject/delete_error_response'
|
97
|
+
|
98
|
+
subject { client.update('Account', :Id => '001D000000INjVe', :Name => 'Foobar') }
|
99
|
+
it { should be_false }
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'with success' do
|
103
|
+
requests 'sobjects/Account/001D000000INjVe',
|
104
|
+
:method => :patch,
|
105
|
+
:with_body => "{\"Name\":\"Foobar\"}"
|
106
|
+
|
107
|
+
[:Id, :id, 'Id', 'id'].each do |key|
|
108
|
+
context "with #{key.inspect} as the key" do
|
109
|
+
subject { client.update('Account', key => '001D000000INjVe', :Name => 'Foobar') }
|
110
|
+
it { should be_true }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '.upsert!' do
|
117
|
+
context 'when updated' do
|
118
|
+
requests 'sobjects/Account/External__c/foobar',
|
119
|
+
:method => :patch,
|
120
|
+
:with_body => "{\"Name\":\"Foobar\"}"
|
121
|
+
|
122
|
+
context 'with symbol external Id key' do
|
123
|
+
subject { client.upsert!('Account', 'External__c', :External__c => 'foobar', :Name => 'Foobar') }
|
124
|
+
it { should be_true }
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'with string external Id key' do
|
128
|
+
subject { client.upsert!('Account', 'External__c', 'External__c' => 'foobar', 'Name' => 'Foobar') }
|
129
|
+
it { should be_true }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when created' do
|
134
|
+
requests 'sobjects/Account/External__c/foobar',
|
135
|
+
:method => :patch,
|
136
|
+
:with_body => "{\"Name\":\"Foobar\"}",
|
137
|
+
:fixture => 'sobject/upsert_created_success_response'
|
138
|
+
|
139
|
+
[:External__c, 'External__c', :external__c, 'external__c'].each do |key|
|
140
|
+
context "with #{key.inspect} as the external id" do
|
141
|
+
subject { client.upsert!('Account', 'External__c', key => 'foobar', :Name => 'Foobar') }
|
142
|
+
it { should eq 'foo' }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '.destroy!' do
|
149
|
+
subject(:destroy!) { client.destroy!('Account', '001D000000INjVe') }
|
150
|
+
|
151
|
+
context 'with invalid Id' do
|
152
|
+
requests 'sobjects/Account/001D000000INjVe',
|
153
|
+
:fixture => 'sobject/delete_error_response',
|
154
|
+
:method => :delete,
|
155
|
+
:status => 404
|
156
|
+
|
157
|
+
subject { lambda { destroy! } }
|
158
|
+
it { should raise_error Faraday::Error::ResourceNotFound }
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'with success' do
|
162
|
+
requests 'sobjects/Account/001D000000INjVe', :method => :delete
|
163
|
+
|
164
|
+
it { should be_true }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '.destroy' do
|
169
|
+
subject { client.destroy('Account', '001D000000INjVe') }
|
170
|
+
|
171
|
+
context 'with invalid Id' do
|
172
|
+
requests 'sobjects/Account/001D000000INjVe',
|
173
|
+
:fixture => 'sobject/delete_error_response',
|
174
|
+
:method => :delete,
|
175
|
+
:status => 404
|
176
|
+
|
177
|
+
it { should be_false }
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'with success' do
|
181
|
+
requests 'sobjects/Account/001D000000INjVe', :method => :delete
|
182
|
+
|
183
|
+
it { should be_true }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '.find' do
|
188
|
+
context 'with no external id passed' do
|
189
|
+
requests 'sobjects/Account/001D000000INjVe',
|
190
|
+
:fixture => 'sobject/sobject_find_success_response'
|
191
|
+
|
192
|
+
subject { client.find('Account', '001D000000INjVe') }
|
193
|
+
it { should be_a Hash }
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when an external id is passed' do
|
197
|
+
requests 'sobjects/Account/External_Field__c/1234',
|
198
|
+
:fixture => 'sobject/sobject_find_success_response'
|
199
|
+
|
200
|
+
subject { client.find('Account', '1234', 'External_Field__c') }
|
201
|
+
it { should be_a Hash }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe '.authenticate!' do
|
206
|
+
subject(:authenticate!) { client.authenticate! }
|
207
|
+
|
208
|
+
context 'when successful' do
|
209
|
+
before do
|
210
|
+
@request = stub_login_request(:with_body => "grant_type=password&client_id=client_id&client_secret=" \
|
211
|
+
"client_secret&username=foo&password=barsecurity_token").
|
212
|
+
to_return(:status => 200, :body => fixture(:auth_success_response))
|
213
|
+
end
|
214
|
+
|
215
|
+
after do
|
216
|
+
expect(@request).to have_been_requested
|
217
|
+
end
|
218
|
+
|
219
|
+
it { should be_a Hash }
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'when no authentication middleware is present' do
|
223
|
+
before do
|
224
|
+
client.stub(:authentication_middleware).and_return(nil)
|
225
|
+
end
|
226
|
+
|
227
|
+
subject { lambda { authenticate! } }
|
228
|
+
it { should raise_error Force::AuthenticationError, 'No authentication middleware present'}
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe '.without_caching' do
|
233
|
+
requests 'query\?q=SELECT%20some,%20fields%20FROM%20object',
|
234
|
+
:fixture => 'sobject/query_success_response'
|
235
|
+
|
236
|
+
before do
|
237
|
+
cache.should_receive(:delete).and_call_original
|
238
|
+
cache.should_receive(:fetch).and_call_original
|
239
|
+
end
|
240
|
+
|
241
|
+
let(:cache) { MockCache.new }
|
242
|
+
subject { client.without_caching { client.query('SELECT some, fields FROM object') } }
|
243
|
+
it { should be_an Enumerable }
|
244
|
+
end
|
245
|
+
|
246
|
+
describe 'authentication retries' do
|
247
|
+
context 'when retries reaches 0' do
|
248
|
+
before do
|
249
|
+
@auth_request = stub_api_request('query\?q=SELECT%20some,%20fields%20FROM%20object',
|
250
|
+
:status => 401,
|
251
|
+
:fixture => 'expired_session_response')
|
252
|
+
@query_request = stub_login_request(:with_body => "grant_type=password&client_id=client_id&client_secret=" \
|
253
|
+
"client_secret&username=foo&password=barsecurity_token").
|
254
|
+
to_return(:status => 200, :body => fixture(:auth_success_response))
|
255
|
+
end
|
256
|
+
|
257
|
+
subject { lambda { client.query('SELECT some, fields FROM object') } }
|
258
|
+
it { should raise_error Force::UnauthorizedError }
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe '.query with caching' do
|
263
|
+
let(:cache) { MockCache.new }
|
264
|
+
|
265
|
+
before do
|
266
|
+
@query = stub_api_request('query\?q=SELECT%20some,%20fields%20FROM%20object').
|
267
|
+
with(:headers => { 'Authorization' => "OAuth #{oauth_token}" }).
|
268
|
+
to_return(:status => 401, :body => fixture('expired_session_response'), :headers => { 'Content-Type' => 'application/json' }).then.
|
269
|
+
to_return(:status => 200, :body => fixture('sobject/query_success_response'), :headers => { 'Content-Type' => 'application/json' })
|
270
|
+
|
271
|
+
@login = stub_login_request(:with_body => "grant_type=password&client_id=client_id&client_secret=" \
|
272
|
+
"client_secret&username=foo&password=barsecurity_token").
|
273
|
+
to_return(:status => 200, :body => fixture(:auth_success_response))
|
274
|
+
end
|
275
|
+
|
276
|
+
after do
|
277
|
+
expect(@query).to have_been_made.times(2)
|
278
|
+
expect(@login).to have_been_made
|
279
|
+
end
|
280
|
+
|
281
|
+
subject { client.query('SELECT some, fields FROM object') }
|
282
|
+
it { should be_an Enumerable }
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe Force::AbstractClient do
|
287
|
+
describe 'with mashify' do
|
288
|
+
it_behaves_like Force::AbstractClient
|
289
|
+
|
290
|
+
describe '.query' do
|
291
|
+
context 'with pagination' do
|
292
|
+
subject { client.query('SELECT some, fields FROM object').next_page }
|
293
|
+
|
294
|
+
requests 'query\?q', :fixture => 'sobject/query_paginated_first_page_response'
|
295
|
+
requests 'query/01gD', :fixture => 'sobject/query_paginated_last_page_response'
|
296
|
+
|
297
|
+
it { should be_a Force::Collection }
|
298
|
+
its('first.Text_Label') { should eq 'Last Page'}
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe 'without mashify', :mashify => false do
|
304
|
+
it_behaves_like Force::AbstractClient
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for Force::Data::Client do
|
4
|
+
describe '.picklist_values' do
|
5
|
+
requests 'sobjects/Account/describe',
|
6
|
+
:fixture => 'sobject/sobject_describe_success_response'
|
7
|
+
|
8
|
+
context 'when given a picklist field' do
|
9
|
+
subject { client.picklist_values('Account', 'Picklist_Field') }
|
10
|
+
it { should be_an Array }
|
11
|
+
its(:length) { should eq 3 }
|
12
|
+
it { should include_picklist_values ['one', 'two', 'three'] }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when given a multipicklist field' do
|
16
|
+
subject { client.picklist_values('Account', 'Picklist_Multiselect_Field') }
|
17
|
+
it { should be_an Array }
|
18
|
+
its(:length) { should eq 3 }
|
19
|
+
it { should include_picklist_values ['four', 'five', 'six'] }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'dependent picklists' do
|
23
|
+
context 'when given a picklist field that has a dependency' do
|
24
|
+
subject { client.picklist_values('Account', 'Dependent_Picklist_Field', :valid_for => 'one') }
|
25
|
+
it { should be_an Array }
|
26
|
+
its(:length) { should eq 2 }
|
27
|
+
it { should include_picklist_values ['seven', 'eight'] }
|
28
|
+
it { should_not include_picklist_values ['nine'] }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when given a picklist field that does not have a dependency' do
|
32
|
+
subject { client.picklist_values('Account', 'Picklist_Field', :valid_for => 'one') }
|
33
|
+
it 'raises an exception' do
|
34
|
+
expect { subject }.to raise_error(/Picklist_Field is not a dependent picklist/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.faye', :event_machine => true do
|
41
|
+
subject { client.faye }
|
42
|
+
|
43
|
+
context 'with missing instance url' do
|
44
|
+
let(:instance_url) { nil }
|
45
|
+
specify { expect { subject }.to raise_error RuntimeError, 'Instance URL missing. Call .authenticate! first.' }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with oauth token and instance url' do
|
49
|
+
let(:instance_url) { 'http://google.com' }
|
50
|
+
let(:oauth_token) { 'bar' }
|
51
|
+
specify { expect { subject }.to_not raise_error }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when the connection goes down' do
|
55
|
+
it 'should reauthenticate' do
|
56
|
+
access_token = double('access token')
|
57
|
+
access_token.stub(:access_token).and_return('token')
|
58
|
+
client.should_receive(:authenticate!).and_return(access_token)
|
59
|
+
client.faye.should_receive(:set_header).with('Authorization', "OAuth token")
|
60
|
+
client.faye.trigger('transport:down')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '.subcribe', :event_machine => true do
|
66
|
+
context 'when given a single pushtopic' do
|
67
|
+
it 'subscribes to the pushtopic' do
|
68
|
+
client.faye.should_receive(:subscribe).with(['/topic/PushTopic'])
|
69
|
+
client.subscribe('PushTopic')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when given an array of pushtopics' do
|
74
|
+
it 'subscribes to each pushtopic' do
|
75
|
+
client.faye.should_receive(:subscribe).with(['/topic/PushTopic1', '/topic/PushTopic2'])
|
76
|
+
client.subscribe(['PushTopic1', 'PushTopic2'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe Force::Data::Client do
|
83
|
+
describe 'with mashify' do
|
84
|
+
it_behaves_like Force::Client
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'without mashify', :mashify => false do
|
88
|
+
it_behaves_like Force::Client
|
89
|
+
end
|
90
|
+
end
|