bulkforce 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ #encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Bulkforce::Connection do
5
+ let(:subject) do
6
+ described_class.new(
7
+ session_id: session_id,
8
+ instance: instance,
9
+ api_version: api_version,
10
+ )
11
+ end
12
+
13
+ let(:session_id) { "org_id!session_id" }
14
+ let(:instance) { "eu2" }
15
+ let(:api_version) { "33.0" }
16
+
17
+ {
18
+ login: 0,
19
+ create_job: 4,
20
+ close_job: 1,
21
+ query_batch: 2,
22
+ query_batch_result_id: 2,
23
+ query_batch_result_data: 3,
24
+ }.each do |method_name, num_of_params|
25
+ describe "##{method_name}" do
26
+ it "delegates correctly to Http class" do
27
+ allow(Bulkforce::Helper).to receive(:parse_csv).and_return([])
28
+ expect(Bulkforce::Http)
29
+ .to receive(method_name)
30
+ .and_return({})
31
+ subject.send(method_name, *Array.new(num_of_params))
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#add_query" do
37
+ it "delegates correctly to Http class" do
38
+ expect(Bulkforce::Http).to receive(:add_batch)
39
+ .and_return({})
40
+ subject.add_query(nil, nil)
41
+ end
42
+ end
43
+
44
+ describe "#org_id" do
45
+ let(:org_id) { "00D50000000IehZ" }
46
+ let(:session_id) { "#{org_id}!AQcAQH0dMHZfz972Szmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1E6LYUfiDUkWe6H34r1AAwOR8B8fLEz6n04NPGRrq0FM" }
47
+
48
+ it "returns correct OrgId" do
49
+ expect(subject.org_id).to eq(org_id)
50
+ end
51
+ end
52
+
53
+ describe "#add_batch" do
54
+ it "delegates correctly to underlying classes" do
55
+ expect(Bulkforce::Http).to receive(:add_batch)
56
+ .and_return({})
57
+ expect(Bulkforce::Helper).to receive(:records_to_csv)
58
+ .and_return("My,Awesome,CSV")
59
+ subject.add_batch(nil, [{"non_emtpy" => "records"}])
60
+ end
61
+
62
+ it "returns -1 for nil input" do
63
+ return_code = subject.add_batch(nil, nil)
64
+ expect(return_code).to eq(-1)
65
+ end
66
+
67
+ it "returns -1 for empty input" do
68
+ return_code = subject.add_batch(nil, [])
69
+ expect(return_code).to eq(-1)
70
+ end
71
+ end
72
+
73
+ describe "#query_batch_result_id" do
74
+ let(:job_id) {"12345"}
75
+ let(:batch_id) {"67890"}
76
+
77
+ context "with a single page of results" do
78
+ let(:single_result) {{:result=>"M75200000001Vgt", :@xmlns=>"http://www.force.com/2009/06/asyncapi/dataload"}}
79
+ it "returns the result_id as a string" do
80
+ expect(Bulkforce::Http).to receive(:query_batch_result_id).
81
+ with(instance, session_id, job_id, batch_id, api_version).
82
+ and_return(single_result)
83
+
84
+ expect(subject.query_batch_result_id(job_id, batch_id)).to eq(single_result)
85
+ end
86
+ end
87
+
88
+ context "with an array of page of results" do
89
+ let(:multiple_result) {{:result=>["752M00000001Vgt", "752M00000001Vgy"], :@xmlns=>"http://www.force.com/2009/06/asyncapi/dataload"}}
90
+ it "returns the result_id as a string" do
91
+ expect(Bulkforce::Http).to receive(:query_batch_result_id).
92
+ with(instance, session_id, job_id, batch_id, api_version).
93
+ and_return(multiple_result)
94
+
95
+ expect(subject.query_batch_result_id(job_id, batch_id)).to eq(multiple_result)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,249 @@
1
+ #encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Bulkforce::Helper do
5
+ describe ".records_to_csv" do
6
+ it "returns valid csv for single record" do
7
+ input = [
8
+ {"Title" => "Awesome Title", "Name" => "A name"},
9
+ ]
10
+
11
+ expected_csv = "\"Title\",\"Name\"\n" \
12
+ "\"Awesome Title\",\"A name\"\n"
13
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
14
+ end
15
+
16
+ it "returns valid csv for basic records" do
17
+ input = [
18
+ {"Title" => "Awesome Title", "Name" => "A name"},
19
+ {"Title" => "A second Title", "Name" => "A second name"},
20
+ ]
21
+
22
+ expected_csv = "\"Title\",\"Name\"\n" \
23
+ "\"Awesome Title\",\"A name\"\n" \
24
+ "\"A second Title\",\"A second name\"\n"
25
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
26
+ end
27
+
28
+ it "returns valid csv when first row misses a key" do
29
+ input = [
30
+ {"Title" => "Awesome Title", "Name" => "A name"},
31
+ {"Title" => "A second Title", "Name" => "A second name", "Something" => "Else"},
32
+ ]
33
+
34
+ expected_csv = "\"Title\",\"Name\",\"Something\"\n" \
35
+ "\"Awesome Title\",\"A name\",\"\"\n" \
36
+ "\"A second Title\",\"A second name\",\"Else\"\n"
37
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
38
+ end
39
+
40
+ it "correctly converts Array to Multi-Picklist" do
41
+ input = [
42
+ {"Title" => "Awesome Title", "Picklist" => ["Several", "Values"]},
43
+ {"Title" => "A second Title", "Picklist" => ["SingleValue"]},
44
+ ]
45
+
46
+ expected_csv = "\"Title\",\"Picklist\"\n" \
47
+ "\"Awesome Title\",\"Several;Values\"\n" \
48
+ "\"A second Title\",\"SingleValue\"\n"
49
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
50
+ end
51
+
52
+ it "returns valid csv when order of keys varies" do
53
+ input = [
54
+ {"Title" => "Awesome Title", "Name" => "A name"},
55
+ {"Name" => "A second name", "Title" => "A second Title"},
56
+ ]
57
+
58
+ expected_csv = "\"Title\",\"Name\"\n" \
59
+ "\"Awesome Title\",\"A name\"\n" \
60
+ "\"A second Title\",\"A second name\"\n"
61
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
62
+ end
63
+
64
+ it "correctly converts empty arrays, nil values and blank strings to #N/A" do
65
+ input = [
66
+ {"Title" => nil, "Picklist" => ["Several", "Values"]},
67
+ {"Title" => "", "Picklist" => []},
68
+ ]
69
+
70
+ expected_csv = "\"Title\",\"Picklist\"\n" \
71
+ "\"#N/A\",\"Several;Values\"\n" \
72
+ "\"#N/A\",\"#N/A\"\n"
73
+ expect(described_class.records_to_csv(input)).to eq(expected_csv)
74
+ end
75
+ end
76
+
77
+ describe ".fetch_instance_from_server_url" do
78
+ let(:basic_api_server_url) {
79
+ "https://cs7-api.salesforce.com/services/Soap/u/28.0/00CS00000095Y5b"
80
+ }
81
+
82
+ let(:basic_server_url) {
83
+ "https://eu1.salesforce.com/services/Soap/u/28.0/00EU00000096Y8c"
84
+ }
85
+
86
+ let(:named_server_url) {
87
+ "https://supercustomname.my.salesforce.com/services/Soap/u/28.0/00EH0000001jNQu"
88
+ }
89
+
90
+ it "returns correct instance for regular salesforce server url" do
91
+ expect(described_class.fetch_instance_from_server_url(basic_server_url))
92
+ .to eq("eu1")
93
+ end
94
+
95
+ it "returns correct instance for api salesforce server url" do
96
+ expect(described_class.fetch_instance_from_server_url(basic_api_server_url))
97
+ .to eq("cs7")
98
+ end
99
+
100
+ it "returns correct instance for named salesforce server url" do
101
+ expect(described_class.fetch_instance_from_server_url(named_server_url))
102
+ .to eq("supercustomname.my")
103
+ end
104
+ end
105
+
106
+ describe ".attachment_keys" do
107
+ let(:records_with_attachment) do
108
+ prefix = Dir.tmpdir
109
+ FileUtils.touch("#{prefix}/attachment.pdf")
110
+ [
111
+ {
112
+ "normal_key" => "normal_value1",
113
+ "attachment_key" => nil,
114
+ },
115
+ {
116
+ "normal_key" => "normal_value2",
117
+ "attachment_key" => File.new("#{prefix}/attachment.pdf"),
118
+ }
119
+ ]
120
+ end
121
+
122
+ let(:records_with_multiple_attachment) do
123
+ prefix = Dir.tmpdir
124
+ FileUtils.touch("#{prefix}/attachment1.pdf")
125
+ FileUtils.touch("#{prefix}/attachment2.pdf")
126
+ FileUtils.touch("#{prefix}/attachment3.pdf")
127
+ [
128
+ {
129
+ "normal_key" => "normal_value1",
130
+ "attachment_key" => File.new("#{prefix}/attachment1.pdf"),
131
+ "another_attachment_key" => File.new("#{prefix}/attachment2.pdf"),
132
+ },
133
+ {
134
+ "normal_key" => "normal_value2",
135
+ "attachment_key" => File.new("#{prefix}/attachment3.pdf"),
136
+ }
137
+ ]
138
+ end
139
+
140
+ let(:records_without_attachment) do
141
+ [
142
+ {
143
+ "normal_key" => "normal_value1",
144
+ "another_normal_key" => "another_normal_value1",
145
+ },
146
+ {
147
+ "normal_key" => "normal_value2",
148
+ "another_normal_key" => "another_normal_value2",
149
+ }
150
+ ]
151
+ end
152
+
153
+ it "returns correct keys for single attachment key" do
154
+ expect(described_class.attachment_keys(records_with_attachment))
155
+ .to eq(["attachment_key"])
156
+ end
157
+
158
+ it "returns correct keys for multiple attachment keys" do
159
+ expect(described_class.attachment_keys(records_with_multiple_attachment))
160
+ .to eq(["attachment_key", "another_attachment_key"])
161
+ end
162
+
163
+ it "returns false for no attachment" do
164
+ expect(described_class.attachment_keys(records_without_attachment))
165
+ .to eq([])
166
+ end
167
+ end
168
+
169
+ describe ".transform_values!" do
170
+ let(:records_with_attachment) do
171
+ prefix = Dir.tmpdir
172
+ FileUtils.touch("#{prefix}/attachment.pdf")
173
+ [
174
+ {
175
+ "normal_key" => "normal_value1",
176
+ "attachment_key" => nil,
177
+ },
178
+ {
179
+ "normal_key" => "normal_value2",
180
+ "attachment_key" => File.new("#{prefix}/attachment.pdf"),
181
+ }
182
+ ]
183
+ end
184
+
185
+ it "transforms values correctly" do
186
+ expect(File).to receive(:absolute_path).and_return("/an/absolute/path")
187
+ expected_output = [
188
+ {
189
+ "normal_key" => "normal_value1",
190
+ "attachment_key" => nil,
191
+ },
192
+ {
193
+ "normal_key" => "normal_value2",
194
+ "attachment_key" => "#an/absolute/path",
195
+ }
196
+ ]
197
+
198
+ input = records_with_attachment
199
+ described_class.transform_values!(input,["attachment_key"])
200
+ expect(input).to eq(expected_output)
201
+ end
202
+
203
+ it "yields absolute path" do
204
+ expect(File).to receive(:absolute_path).and_return("/an/absolute/path")
205
+ input = records_with_attachment
206
+ expect do |blk|
207
+ described_class.transform_values!(input,["attachment_key"], &blk)
208
+ end.to yield_with_args("/an/absolute/path")
209
+ end
210
+ end
211
+
212
+ describe ".absolute_to_relative_path" do
213
+ let(:unix_path) { "/a/unix/path" }
214
+ let(:windows_path_backslash) { "C:\\a\\backslash\\path" }
215
+ let(:windows_path_forwardslash) { "C:/a/forwardslash/path" }
216
+
217
+ it "strips unix path correctly" do
218
+ expect(described_class.absolute_to_relative_path(unix_path,"")).
219
+ to eq("a/unix/path")
220
+ end
221
+
222
+ it "strips windows path with backslash correctly" do
223
+ expect(described_class.absolute_to_relative_path(windows_path_backslash,"")).
224
+ to eq("a\\backslash\\path")
225
+ end
226
+
227
+ it "strips windows path with forwardslash correctly" do
228
+ expect(described_class.absolute_to_relative_path(windows_path_forwardslash,"")).
229
+ to eq("a/forwardslash/path")
230
+ end
231
+ end
232
+
233
+ describe ".parse_csv" do
234
+ let(:csv_string) {
235
+ "Id,my_external_id__c\n" \
236
+ "003M000057GH39aIAD,K-00J799\n" \
237
+ "003M001200KO82cIAD,K-015699"
238
+ }
239
+ let(:expected_result) {
240
+ [
241
+ { "Id" => "003M000057GH39aIAD", "my_external_id__c" => "K-00J799" },
242
+ { "Id" => "003M001200KO82cIAD", "my_external_id__c" => "K-015699" },
243
+ ]
244
+ }
245
+ it "correctly transforms csv string" do
246
+ expect(described_class.parse_csv(csv_string)).to eq(expected_result)
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,375 @@
1
+ #encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Bulkforce::Http do
5
+ describe "#process_http_request" do
6
+ let(:post_request) do
7
+ Bulkforce::Http::Request.new(
8
+ :post,
9
+ "test.host",
10
+ "/",
11
+ "post body",
12
+ {"X-SFDC-Session" => "super_secret"})
13
+ end
14
+
15
+ let(:get_request) do
16
+ Bulkforce::Http::Request.new(:get, "test.host", "/", "", [])
17
+ end
18
+
19
+ it "returns a response object" do
20
+ expected_body = "correct result"
21
+ stub_request(:post, "https://test.host")
22
+ .with(
23
+ body: post_request.body,
24
+ headers: post_request.headers)
25
+ .to_return(:body => expected_body)
26
+ res = Bulkforce::Http.process_http_request(post_request)
27
+ expect(res).to eq(expected_body)
28
+ end
29
+ end
30
+
31
+ describe "#login" do
32
+ let(:login_error_message) do
33
+ "INVALID_LOGIN: Invalid username, password, security token;" \
34
+ "or user locked out."
35
+ end
36
+
37
+ let(:sf_instance) {"cs7"}
38
+
39
+ let(:login_success) do
40
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
41
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
42
+ <soapenv:Body>
43
+ <loginResponse>
44
+ <result>
45
+ <metadataServerUrl>https://#{sf_instance}-api.salesforce.com/services/Soap/m/27.0/00EU00000095Y5b</metadataServerUrl>
46
+ <passwordExpired>false</passwordExpired>
47
+ <sandbox>true</sandbox>
48
+ <serverUrl>https://#{sf_instance}-api.salesforce.com/services/Soap/u/27.0/00EU00000095Y5b</serverUrl>
49
+ <sessionId>00DM00000099X9a!AQ7AQJ9BjrYfF2h_G9_VERsCRVjTMAPaWjz2zuqqRBduYvKCmHexVbKdtxFMrgTnV9Xi.M80AhIkjnwuEVxI00ChG09._Q_X</sessionId>
50
+ <userId>005K001100243YPIAY</userId>
51
+ <userInfo>
52
+ <accessibilityMode>false</accessibilityMode>
53
+ <currencySymbol xsi:nil="true"/>
54
+ <orgAttachmentFileSizeLimit>2621440</orgAttachmentFileSizeLimit>
55
+ <orgDefaultCurrencyIsoCode xsi:nil="true"/>
56
+ <orgDisallowHtmlAttachments>false</orgDisallowHtmlAttachments>
57
+ <orgHasPersonAccounts>false</orgHasPersonAccounts>
58
+ <organizationId>00ID0000OrgFoo</organizationId>
59
+ <organizationMultiCurrency>true</organizationMultiCurrency>
60
+ <organizationName>Hinz &amp; Kunz</organizationName>
61
+ <profileId>00eA0000000nJEY</profileId>
62
+ <roleId xsi:nil="true"/>
63
+ <sessionSecondsValid>3600</sessionSecondsValid>
64
+ <userDefaultCurrencyIsoCode>EUR</userDefaultCurrencyIsoCode>
65
+ <userEmail>theadmin@example.com</userEmail>
66
+ <userFullName>John Doe</userFullName>
67
+ <userId>005D0000002b3SPIAY</userId>
68
+ <userLanguage>de</userLanguage>
69
+ <userLocale>de_DE_EURO</userLocale>
70
+ <userName>theadmin@exammple.com.euvconfig</userName>
71
+ <userTimeZone>Europe/Berlin</userTimeZone>
72
+ <userType>Standard</userType>
73
+ <userUiSkin>Theme42</userUiSkin>
74
+ </userInfo>
75
+ </result>
76
+ </loginResponse>
77
+ </soapenv:Body>
78
+ </soapenv:Envelope>}
79
+ end
80
+
81
+ let(:login_success_new) do
82
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
83
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
84
+ <soapenv:Body>
85
+ <loginResponse>
86
+ <result>
87
+ <metadataServerUrl>https://#{sf_instance}.salesforce.com/services/Soap/m/27.0/00EU00000095Y5b</metadataServerUrl>
88
+ <passwordExpired>false</passwordExpired>
89
+ <sandbox>true</sandbox>
90
+ <serverUrl>https://#{sf_instance}.salesforce.com/services/Soap/u/27.0/00EU00000095Y5b</serverUrl>
91
+ <sessionId>00DM00000099X9a!AQ7AQJ9BjrYfF2h_G9_VERsCRVjTMAPaWjz2zuqqRBduYvKCmHexVbKdtxFMrgTnV9Xi.M80AhIkjnwuEVxI00ChG09._Q_X</sessionId>
92
+ <userId>005K001100243YPIAY</userId>
93
+ <userInfo>
94
+ <accessibilityMode>false</accessibilityMode>
95
+ <currencySymbol xsi:nil="true"/>
96
+ <orgAttachmentFileSizeLimit>2621440</orgAttachmentFileSizeLimit>
97
+ <orgDefaultCurrencyIsoCode xsi:nil="true"/>
98
+ <orgDisallowHtmlAttachments>false</orgDisallowHtmlAttachments>
99
+ <orgHasPersonAccounts>false</orgHasPersonAccounts>
100
+ <organizationId>00ID0000OrgFoo</organizationId>
101
+ <organizationMultiCurrency>true</organizationMultiCurrency>
102
+ <organizationName>Hinz &amp; Kunz</organizationName>
103
+ <profileId>00eA0000000nJEY</profileId>
104
+ <roleId xsi:nil="true"/>
105
+ <sessionSecondsValid>3600</sessionSecondsValid>
106
+ <userDefaultCurrencyIsoCode>EUR</userDefaultCurrencyIsoCode>
107
+ <userEmail>theadmin@example.com</userEmail>
108
+ <userFullName>John Doe</userFullName>
109
+ <userId>005D0000002b3SPIAY</userId>
110
+ <userLanguage>de</userLanguage>
111
+ <userLocale>de_DE_EURO</userLocale>
112
+ <userName>theadmin@exammple.com.euvconfig</userName>
113
+ <userTimeZone>Europe/Berlin</userTimeZone>
114
+ <userType>Standard</userType>
115
+ <userUiSkin>Theme42</userUiSkin>
116
+ </userInfo>
117
+ </result>
118
+ </loginResponse>
119
+ </soapenv:Body>
120
+ </soapenv:Envelope>}
121
+ end
122
+
123
+ let(:login_error) do
124
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
125
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
126
+ xmlns:sf="urn:fault.partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
127
+ <soapenv:Body>
128
+ <soapenv:Fault>
129
+ <faultcode>INVALID_LOGIN</faultcode>
130
+ <faultstring>#{login_error_message}</faultstring>
131
+ <detail>
132
+ <sf:LoginFault xsi:type="sf:LoginFault">
133
+ <sf:exceptionCode>INVALID_LOGIN</sf:exceptionCode>
134
+ <sf:exceptionMessage>Invalid username, password, │Your bundle is complete!security token; or user locked out.
135
+ </sf:exceptionMessage>
136
+ </sf:LoginFault>
137
+ </detail>
138
+ </soapenv:Fault>
139
+ </soapenv:Body>
140
+ </soapenv:Envelope>}
141
+ end
142
+
143
+ it "raises an error for faulty login" do
144
+ expect(Bulkforce::Http).to receive(:process_http_request)
145
+ .and_return(login_error)
146
+ expect{ Bulkforce::Http.login("a","b","c", "d") }
147
+ .to raise_error(RuntimeError, login_error_message)
148
+ end
149
+
150
+ it "returns hash for correct login" do
151
+ [login_success, login_success_new].each do |login_response|
152
+ expect(Bulkforce::Http).to receive(:process_http_request)
153
+ .and_return(login_response)
154
+ result = Bulkforce::Http.login("a","b","c", "d")
155
+ expect(result).to be_a(Hash)
156
+ expect(result).to have_key(:session_id)
157
+ expect(result).to have_key(:server_url)
158
+ expect(result[:instance]).to eq(sf_instance)
159
+ end
160
+ end
161
+ end
162
+
163
+ describe "#oauth_login" do
164
+ let(:login_error) do
165
+ %Q{<OAuth>
166
+ <error_description>invalid client credentials</error_description>
167
+ <error>invalid_client</error>
168
+ </OAuth>}
169
+ end
170
+
171
+ let(:login_error_message) { "invalid_client: invalid client credentials" }
172
+
173
+ let(:sf_instance) {"eu2"}
174
+
175
+ let(:login_success) do
176
+ %Q{<OAuth>
177
+ <id>https://login.salesforce.com/id/00Db0000000bHH3EAM/005b0000000K44BAAS</id>
178
+ <issued_at>1435621555861</issued_at>
179
+ <scope>full</scope>
180
+ <instance_url>https://eu2.salesforce.com</instance_url>
181
+ <token_type>Bearer</token_type>
182
+ <signature>mbfZerj8DRVXVF9WD28kM/p8j6d74fE29RRGleTxELE=</signature>
183
+ <access_token>00Db0000000bHH3!AREAQFjvfelEv7D6TM3QqoqhWAJ52sUPSw.yMuIJ0x4NExqxey7xwvezoTG6DgUypEp8.FW_l6LdyK.viB4kxZY.Tn63oRP5</access_token>
184
+ </OAuth>}
185
+ end
186
+
187
+ it "raises an error for faulty login" do
188
+ expect(Bulkforce::Http).to receive(:process_http_request)
189
+ .and_return(login_error)
190
+ expect{ Bulkforce::Http.oauth_login("a","b","c", "d") }
191
+ .to raise_error(RuntimeError, login_error_message)
192
+ end
193
+
194
+ it "returns hash for correct login" do
195
+ expect(Bulkforce::Http).to receive(:process_http_request).and_return(login_success)
196
+ result = Bulkforce::Http.oauth_login("a","b","c", "d")
197
+ expect(result).to be_a(Hash)
198
+ expect(result).to have_key(:session_id)
199
+ expect(result).to have_key(:server_url)
200
+ expect(result[:instance]).to eq(sf_instance)
201
+ end
202
+ end
203
+
204
+ describe "#create_job" do
205
+ let(:create_job_success) do
206
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
207
+ <jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
208
+ <id>750D0000000002lIAA</id>
209
+ <operation>upsert</operation>
210
+ <object>Contact</object>
211
+ <createdById>005D0000001ALVFIA4</createdById>
212
+ <createdDate>2013-04-10T15:52:02.000Z</createdDate>
213
+ <systemModstamp>2013-04-10T15:52:02.000Z</systemModstamp>
214
+ <state>Open</state>
215
+ <externalIdFieldName>my_external_field__c</externalIdFieldName>
216
+ <concurrencyMode>Parallel</concurrencyMode>
217
+ <contentType>CSV</contentType>
218
+ <numberBatchesQueued>0</numberBatchesQueued>
219
+ <numberBatchesInProgress>0</numberBatchesInProgress>
220
+ <numberBatchesCompleted>0</numberBatchesCompleted>
221
+ <numberBatchesFailed>0</numberBatchesFailed>
222
+ <numberBatchesTotal>0</numberBatchesTotal>
223
+ <numberRecordsProcessed>0</numberRecordsProcessed>
224
+ <numberRetries>0</numberRetries>
225
+ <apiVersion>27.0</apiVersion>
226
+ <numberRecordsFailed>0</numberRecordsFailed>
227
+ <totalProcessingTime>0</totalProcessingTime>
228
+ <apiActiveProcessingTime>0</apiActiveProcessingTime>
229
+ <apexProcessingTime>0</apexProcessingTime>
230
+ </jobInfo>}
231
+ end
232
+
233
+ it "returns hash for creating job" do
234
+ expect(Bulkforce::Http).to receive(:process_http_request)
235
+ .and_return(create_job_success)
236
+ result = Bulkforce::Http.create_job("a","b","c","d", "e", "f")
237
+ expect(result).to be_a(Hash)
238
+ expect(result).to have_key(:id)
239
+ expect(result).to have_key(:operation)
240
+ end
241
+ end
242
+
243
+ describe "#add_batch" do
244
+ let(:add_batch_success) do
245
+ %Q{
246
+ <?xml version="1.0" encoding="UTF-8"?>
247
+ <batchInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
248
+ <id>750M0000000B1Z6IAL</id>
249
+ <jobId>751K00000009x71IAA</jobId>
250
+ <state>Queued</state>
251
+ <createdDate>2013-04-10T15:53:46.000Z</createdDate>
252
+ <systemModstamp>2013-04-10T15:53:46.000Z</systemModstamp>
253
+ <numberRecordsProcessed>0</numberRecordsProcessed>
254
+ <numberRecordsFailed>0</numberRecordsFailed>
255
+ <totalProcessingTime>0</totalProcessingTime>
256
+ <apiActiveProcessingTime>0</apiActiveProcessingTime>
257
+ <apexProcessingTime>0</apexProcessingTime>
258
+ </batchInfo>
259
+ }
260
+ end
261
+
262
+ it "returns hash for adding batch" do
263
+ expect(Bulkforce::Http).to receive(:process_http_request)
264
+ .and_return(add_batch_success)
265
+ result = Bulkforce::Http.add_batch(:post,"a","b","c","d")
266
+ expect(result).to be_a(Hash)
267
+ expect(result).to have_key(:id)
268
+ expect(result).to have_key(:job_id)
269
+ expect(result).to have_key(:state)
270
+ end
271
+ end
272
+
273
+ describe "#close_job" do
274
+ let(:close_job_success) do
275
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
276
+ <jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
277
+ <id>750D0000000002jIAA</id>
278
+ <operation>upsert</operation>
279
+ <object>Contact</object>
280
+ <createdById>005D0000002b3SPIAY</createdById>
281
+ <createdDate>2013-04-10T16:27:56.000Z</createdDate>
282
+ <systemModstamp>2013-04-10T16:27:56.000Z</systemModstamp>
283
+ <state>Closed</state>
284
+ <externalIdFieldName>my_external_id__c</externalIdFieldName>
285
+ <concurrencyMode>Parallel</concurrencyMode>
286
+ <contentType>CSV</contentType>
287
+ <numberBatchesQueued>0</numberBatchesQueued>
288
+ <numberBatchesInProgress>0</numberBatchesInProgress>
289
+ <numberBatchesCompleted>1</numberBatchesCompleted>
290
+ <numberBatchesFailed>0</numberBatchesFailed>
291
+ <numberBatchesTotal>1</numberBatchesTotal>
292
+ <numberRecordsProcessed>4</numberRecordsProcessed>
293
+ <numberRetries>0</numberRetries>
294
+ <apiVersion>27.0</apiVersion>
295
+ <numberRecordsFailed>0</numberRecordsFailed>
296
+ <totalProcessingTime>838</totalProcessingTime>
297
+ <apiActiveProcessingTime>355</apiActiveProcessingTime>
298
+ <apexProcessingTime>253</apexProcessingTime>
299
+ </jobInfo>}
300
+ end
301
+
302
+ it "returns hash for closing job" do
303
+ expect(Bulkforce::Http).to receive(:process_http_request)
304
+ .and_return(close_job_success)
305
+ result = Bulkforce::Http.close_job("a","b","c","d")
306
+ expect(result).to be_a(Hash)
307
+ expect(result).to have_key(:id)
308
+ expect(result).to have_key(:object)
309
+ expect(result).to have_key(:operation)
310
+ expect(result).to have_key(:state)
311
+ expect(result).to have_key(:content_type)
312
+ end
313
+ end
314
+
315
+ describe "#add_batch" do
316
+ let(:invalid_session_id) do
317
+ %Q{<?xml version="1.0" encoding="UTF-8"?>
318
+ <error xmlns="http://www.force.com/2009/06/asyncapi/dataload">
319
+ <exceptionCode>InvalidSessionId</exceptionCode>
320
+ <exceptionMessage>Invalid session id</exceptionMessage>
321
+ </error>}
322
+ end
323
+
324
+ it "raises an exception on faulty authorization" do
325
+ expect(Bulkforce::Http).to receive(:process_http_request)
326
+ .and_return(invalid_session_id)
327
+ expect{Bulkforce::Http.query_batch("a","b","c","d","e")}
328
+ .to raise_error(RuntimeError, "InvalidSessionId: Invalid session id")
329
+ end
330
+ end
331
+
332
+ describe "#query_batch_result_id" do
333
+ let(:batch_result_success) do
334
+ %Q{<result-list xmlns="http://www.force.com/2009/06/asyncapi/dataload">
335
+ <result>750D0000002jIAA</result>
336
+ </result-list>}
337
+ end
338
+
339
+ it "returns hash including the result id" do
340
+ expect(Bulkforce::Http).to receive(:process_http_request)
341
+ .and_return(batch_result_success)
342
+ result = Bulkforce::Http.query_batch_result_id("a","b","c","d","e")
343
+ expect(result).to be_a(Hash)
344
+ expect(result).to have_key(:result)
345
+ end
346
+ end
347
+
348
+ describe "#query_batch_result_data" do
349
+ let(:batch_result_data_success) do
350
+ %Q{"Id","my_external_id__c"
351
+ "003M000057GH39aIAD","K-00J799"
352
+ "003M001200KO82cIAD","K-015699"}
353
+ end
354
+
355
+ let(:batch_result_data_with_spaces_success) do
356
+ %Q{"Id","Name"
357
+ "003K000057GH39aIAD","Master of Disaster"
358
+ "003K001200KO82cIAD","King of the Hill"}
359
+ end
360
+
361
+ it "returns a correctly formatted CSV string" do
362
+ expect(Bulkforce::Http).to receive(:process_http_request)
363
+ .and_return(batch_result_data_success)
364
+ result = Bulkforce::Http.query_batch_result_data("a","b","c","d","e","f")
365
+ expect(result).to eq(batch_result_data_success.gsub(/^\s+/, ""))
366
+ end
367
+
368
+ it "returns a correctly formatted CSV string including spaces" do
369
+ expect(Bulkforce::Http).to receive(:process_http_request)
370
+ .and_return(batch_result_data_with_spaces_success)
371
+ result = Bulkforce::Http.query_batch_result_data("a","b","c","d","e","f")
372
+ expect(result).to eq(batch_result_data_with_spaces_success.gsub(/^\s+/, ""))
373
+ end
374
+ end
375
+ end