logstash-input-salesforce 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +50 -9
- data/docs/index.asciidoc +138 -27
- data/lib/logstash/inputs/salesforce.rb +120 -21
- data/logstash-input-salesforce.gemspec +2 -2
- data/spec/fixtures/vcr_cassettes/load_some_lead_objects_order_by_lastmodifieddate.yml +124 -0
- data/spec/fixtures/vcr_cassettes/load_some_lead_objects_twice.yml +161 -0
- data/spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter.yml +123 -0
- data/spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate.yml +123 -0
- data/spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate_no_filters.yml +123 -0
- data/spec/inputs/salesforce_spec.rb +264 -4
- metadata +30 -24
- data/DEVELOPER.md +0 -2
@@ -0,0 +1,123 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://login.salesforce.com/services/oauth2/token
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: grant_type=password&client_id=xxxx&client_secret=xxxx&username=xxxx&password=xxxx
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.1
|
12
|
+
Content-Type:
|
13
|
+
- application/x-www-form-urlencoded
|
14
|
+
Accept:
|
15
|
+
- '*/*'
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Date:
|
22
|
+
- Thu, 27 Aug 2015 23:57:42 GMT
|
23
|
+
Set-Cookie:
|
24
|
+
- BrowserId=xxxx;Path=/;Domain=.salesforce.com;Expires=Mon, 26-Oct-2015 23:57:42 GMT
|
25
|
+
Expires:
|
26
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
27
|
+
Pragma:
|
28
|
+
- no-cache
|
29
|
+
Cache-Control:
|
30
|
+
- no-cache, no-store
|
31
|
+
Content-Type:
|
32
|
+
- application/json;charset=UTF-8
|
33
|
+
Transfer-Encoding:
|
34
|
+
- chunked
|
35
|
+
body:
|
36
|
+
encoding: US-ASCII
|
37
|
+
string: '{"id":"https://login.salesforce.com/id/xxxx/xxxx","issued_at":"1440719862904","token_type":"Bearer","instance_url":"https://eu2.salesforce.com","signature":"xxxx","access_token":"xxxx"}'
|
38
|
+
http_version:
|
39
|
+
recorded_at: Thu, 27 Aug 2015 23:57:43 GMT
|
40
|
+
- request:
|
41
|
+
method: get
|
42
|
+
uri: https://eu2.salesforce.com/services/data/v26.0/sobjects/Lead/describe
|
43
|
+
body:
|
44
|
+
encoding: US-ASCII
|
45
|
+
string: ''
|
46
|
+
headers:
|
47
|
+
User-Agent:
|
48
|
+
- Faraday v0.9.1
|
49
|
+
Authorization:
|
50
|
+
- OAuth xxxx
|
51
|
+
Accept-Encoding:
|
52
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
53
|
+
Accept:
|
54
|
+
- '*/*'
|
55
|
+
response:
|
56
|
+
status:
|
57
|
+
code: 200
|
58
|
+
message: OK
|
59
|
+
headers:
|
60
|
+
Date:
|
61
|
+
- Thu, 27 Aug 2015 23:57:44 GMT
|
62
|
+
Set-Cookie:
|
63
|
+
- BrowserId=xxxx;Path=/;Domain=.salesforce.com;Expires=Mon, 26-Oct-2015 23:57:44 GMT
|
64
|
+
Expires:
|
65
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
66
|
+
Sforce-Limit-Info:
|
67
|
+
- api-usage=211068/451000
|
68
|
+
Org.eclipse.jetty.server.include.etag:
|
69
|
+
- 5fb54cb6
|
70
|
+
Last-Modified:
|
71
|
+
- Thu, 27 Aug 2015 22:36:55 GMT
|
72
|
+
Content-Type:
|
73
|
+
- application/json;charset=UTF-8
|
74
|
+
Etag:
|
75
|
+
- 5fb54cb-gzip"
|
76
|
+
Transfer-Encoding:
|
77
|
+
- chunked
|
78
|
+
body:
|
79
|
+
encoding: UTF-8
|
80
|
+
string: '{"activateable":false,"childRelationships":[],"createable":true,"custom":false,"customSetting":false,"deletable":true,"deprecatedAndHidden":false,"feedEnabled":true,"fields":[{"autoNumber":false,"byteLength":18,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"controllerName":null,"createable":false,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":true,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"externalId":false,"filterable":true,"groupable":true,"htmlFormatted":false,"idLookup":true,"inlineHelpText":null,"label":"Lead
|
81
|
+
ID","length":18,"name":"Id","nameField":false,"namePointing":false,"nillable":false,"permissionable":false,"picklistValues":[],"precision":0,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"soapType":"tns:ID","sortable":true,"type":"id","unique":false,"updateable":false,"writeRequiresMasterRead":false},{"autoNumber":false,"byteLength":0,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"controllerName":null,"createable":false,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":true,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"externalId":false,"filterable":true,"groupable":true,"htmlFormatted":false,"idLookup":false,"inlineHelpText":null,"label":"Deleted","length":0,"name":"IsDeleted","nameField":false,"namePointing":false,"nillable":false,"permissionable":false,"picklistValues":[],"precision":0,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"soapType":"xsd:boolean","sortable":true,"type":"boolean","unique":false,"updateable":false,"writeRequiresMasterRead":false},{"autoNumber":false,"byteLength":240,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"controllerName":null,"createable":true,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"externalId":false,"filterable":true,"groupable":true,"htmlFormatted":false,"idLookup":false,"inlineHelpText":null,"label":"Last
|
82
|
+
Name","length":80,"name":"LastName","nameField":false,"namePointing":false,"nillable":false,"permissionable":false,"picklistValues":[],"precision":0,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"soapType":"xsd:string","sortable":true,"type":"string","unique":false,"updateable":true,"writeRequiresMasterRead":false},{"autoNumber":false,"byteLength":120,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"controllerName":null,"createable":true,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"externalId":false,"filterable":true,"groupable":true,"htmlFormatted":false,"idLookup":false,"inlineHelpText":null,"label":"First
|
83
|
+
Name","length":40,"name":"FirstName","nameField":false,"namePointing":false,"nillable":true,"permissionable":false,"picklistValues":[],"precision":0,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"soapType":"xsd:string","sortable":true,"type":"string","unique":false,"updateable":true,"writeRequiresMasterRead":false},{"autoNumber":false,"byteLength":120,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"controllerName":null,"createable":true,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"externalId":false,"filterable":true,"groupable":true,"htmlFormatted":false,"idLookup":false,"inlineHelpText":null,"label":"Salutation","length":40,"name":"Salutation","nameField":false,"namePointing":false,"nillable":true,"permissionable":false,"picklistValues":[{"active":true,"defaultValue":false,"label":"Mr.","validFor":null,"value":"Mr."},{"active":true,"defaultValue":false,"label":"Ms.","validFor":null,"value":"Ms."},{"active":true,"defaultValue":false,"label":"Mrs.","validFor":null,"value":"Mrs."},{"active":true,"defaultValue":false,"label":"Dr.","validFor":null,"value":"Dr."},{"active":true,"defaultValue":false,"label":"Prof.","validFor":null,"value":"Prof."}],"precision":0,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"soapType":"xsd:string","sortable":true,"type":"picklist","unique":false,"updateable":true,"writeRequiresMasterRead":false}],"keyPrefix":"00Q","label":"Lead","labelPlural":"Leads","layoutable":true,"listviewable":null,"lookupLayoutable":null,"mergeable":true,"name":"Lead","queryable":true,"recordTypeInfos":[{"available":true,"defaultRecordTypeMapping":true,"name":"Marketing","recordTypeId":"xxxx"},{"available":true,"defaultRecordTypeMapping":false,"name":"Partner
|
84
|
+
Deal","recordTypeId":"xxxx"},{"available":true,"defaultRecordTypeMapping":false,"name":"Sales","recordTypeId":"xxxx"},{"available":true,"defaultRecordTypeMapping":false,"name":"Master","recordTypeId":"xxxx"}],"replicateable":true,"retrieveable":true,"searchLayoutable":null,"searchable":true,"triggerable":true,"undeletable":true,"updateable":true,"urls":{"uiEditTemplate":"https://xxx.salesforce.com/{ID}/e","sobject":"/services/data/v26.0/sobjects/Lead","uiDetailTemplate":"https://xxx.salesforce.com/{ID}","describe":"/services/data/v26.0/sobjects/Lead/describe","rowTemplate":"/services/data/v26.0/sobjects/Lead/{ID}","uiNewRecord":"https://xxx.salesforce.com/00Q/e"}}'
|
85
|
+
http_version:
|
86
|
+
recorded_at: Thu, 27 Aug 2015 23:57:44 GMT
|
87
|
+
- request:
|
88
|
+
method: get
|
89
|
+
uri: https://eu2.salesforce.com/services/data/v26.0/query?q=SELECT%20Id,IsDeleted,LastName,FirstName,Salutation,LastModifiedDate%20FROM%20Lead%20WHERE%20LastModifiedDate%20%3E%202025-05-07T14:32:17Z%20ORDER%20BY%20LastModifiedDate%20ASC
|
90
|
+
body:
|
91
|
+
encoding: US-ASCII
|
92
|
+
string: ''
|
93
|
+
headers:
|
94
|
+
User-Agent:
|
95
|
+
- Faraday v0.9.1
|
96
|
+
Authorization:
|
97
|
+
- OAuth xxx
|
98
|
+
Accept-Encoding:
|
99
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
100
|
+
Accept:
|
101
|
+
- '*/*'
|
102
|
+
response:
|
103
|
+
status:
|
104
|
+
code: 200
|
105
|
+
message: OK
|
106
|
+
headers:
|
107
|
+
Date:
|
108
|
+
- Thu, 27 Aug 2015 23:57:45 GMT
|
109
|
+
Set-Cookie:
|
110
|
+
- BrowserId=xxxx;Path=/;Domain=.salesforce.com;Expires=Mon, 26-Oct-2015 23:57:45 GMT
|
111
|
+
Expires:
|
112
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
113
|
+
Sforce-Limit-Info:
|
114
|
+
- api-usage=211063/451000
|
115
|
+
Content-Type:
|
116
|
+
- application/json;charset=UTF-8
|
117
|
+
Transfer-Encoding:
|
118
|
+
- chunked
|
119
|
+
body:
|
120
|
+
encoding: UTF-8
|
121
|
+
string: '{"totalSize":3,"done":true,"records":[{"attributes":{"type":"Lead","url":"/services/data/v26.0/sobjects/Lead/xxxx"},"Id":"xxxx","IsDeleted":false,"LastName":"Katz","FirstName":"Aaron","Salutation":"Mr."},{"attributes":{"type":"Lead","url":"/services/data/v26.0/sobjects/Lead/xxxx"},"Id":"xxxx","IsDeleted":false,"LastName":"Grand","FirstName":"Adrien","Salutation":"Dr."},{"attributes":{"type":"Lead","url":"/services/data/v26.0/sobjects/Lead/xxxx"},"Id":"xxxx","IsDeleted":false,"LastName":"Hardy","FirstName":"Alan","Salutation":"Overlord"}]}'
|
122
|
+
http_version:
|
123
|
+
recorded_at: Thu, 27 Aug 2015 23:57:45 GMT
|
@@ -84,7 +84,7 @@ RSpec.describe LogStash::Inputs::Salesforce do
|
|
84
84
|
["Salutation", "picklist"]] }
|
85
85
|
subject { input }
|
86
86
|
it "loads the Lead object fields" do
|
87
|
-
VCR.use_cassette("
|
87
|
+
VCR.use_cassette("describe lead object",:decode_compressed_response => true) do
|
88
88
|
subject.register
|
89
89
|
expect(subject.instance_variable_get(:@sfdc_field_types)).to match_array(expected_types_result)
|
90
90
|
expect(subject.instance_variable_get(:@sfdc_fields)).to match_array(expected_fields_result)
|
@@ -107,7 +107,7 @@ RSpec.describe LogStash::Inputs::Salesforce do
|
|
107
107
|
subject { input }
|
108
108
|
let(:queue) { [] }
|
109
109
|
it "loads some lead records" do
|
110
|
-
VCR.use_cassette("load some lead objects"
|
110
|
+
VCR.use_cassette("load some lead objects", :decode_compressed_response => true) do
|
111
111
|
subject.register
|
112
112
|
subject.run(queue)
|
113
113
|
expect(queue.length).to eq(3)
|
@@ -155,7 +155,7 @@ RSpec.describe LogStash::Inputs::Salesforce do
|
|
155
155
|
["Salutation", "picklist"]] }
|
156
156
|
subject { input }
|
157
157
|
it "logs into sfdc instance url" do
|
158
|
-
VCR.use_cassette("
|
158
|
+
VCR.use_cassette("login into mydomain", :decode_compressed_response => true) do
|
159
159
|
subject.register
|
160
160
|
expect(subject.instance_variable_get(:@sfdc_field_types)).to match_array(expected_types_result)
|
161
161
|
expect(subject.instance_variable_get(:@sfdc_fields)).to match_array(expected_fields_result)
|
@@ -211,11 +211,271 @@ RSpec.describe LogStash::Inputs::Salesforce do
|
|
211
211
|
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
212
212
|
subject { input }
|
213
213
|
it "should use the Tooling Api Query resource path" do
|
214
|
-
VCR.use_cassette("
|
214
|
+
VCR.use_cassette("describe apex test run result object", :decode_compressed_response => true) do
|
215
215
|
subject.register
|
216
216
|
expect(subject.send(:client).send(:api_path, "query")).to eq('/services/data/v52.0/tooling/query')
|
217
217
|
end
|
218
218
|
end
|
219
219
|
end
|
220
|
+
|
221
|
+
context "run continuously at interval" do
|
222
|
+
VCR.configure do |config|
|
223
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
224
|
+
config.hook_into :webmock
|
225
|
+
config.before_record do |i|
|
226
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
227
|
+
# required because sfdc doesn't send back the content encoding and it
|
228
|
+
# confuses the yaml parser
|
229
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
230
|
+
i.response.body = json_body.to_json
|
231
|
+
i.response.update_content_length_header
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
let(:options) do
|
236
|
+
{
|
237
|
+
"client_id" => "",
|
238
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
239
|
+
"username" => "",
|
240
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
241
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
242
|
+
"use_tooling_api" => false,
|
243
|
+
"sfdc_object_name" => "Lead",
|
244
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
245
|
+
"sfdc_filters" => "Email LIKE '%@elastic.co'",
|
246
|
+
"interval" => 3
|
247
|
+
}
|
248
|
+
end
|
249
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
250
|
+
subject { input }
|
251
|
+
let(:queue) { [] }
|
252
|
+
it "loads some lead records" do
|
253
|
+
VCR.use_cassette("load some lead objects twice", :decode_compressed_response => true) do
|
254
|
+
subject.register
|
255
|
+
# Run a background thread to set the stop flag after 7 seconds, i.e. after the second run of the plugin
|
256
|
+
thr = Thread.new {
|
257
|
+
sleep(4) # more than 3, less than 6
|
258
|
+
subject.do_stop
|
259
|
+
}
|
260
|
+
subject.run(queue)
|
261
|
+
thr.join
|
262
|
+
expect(queue.length).to eq(8) # 3 + 5
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context "run with last modified time from range field file" do
|
268
|
+
VCR.configure do |config|
|
269
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
270
|
+
config.hook_into :webmock
|
271
|
+
config.before_record do |i|
|
272
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
273
|
+
# required because sfdc doesn't send back the content encoding and it
|
274
|
+
# confuses the yaml parser
|
275
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
276
|
+
i.response.body = json_body.to_json
|
277
|
+
i.response.update_content_length_header
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
let(:options) do
|
282
|
+
{
|
283
|
+
"client_id" => "",
|
284
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
285
|
+
"username" => "",
|
286
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
287
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
288
|
+
"use_tooling_api" => false,
|
289
|
+
"sfdc_object_name" => "Lead",
|
290
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
291
|
+
"sfdc_filters" => "Email LIKE '%@elastic.co'",
|
292
|
+
"changed_data_filter" => "LastModifiedDate > %{last_tracking_field_value}",
|
293
|
+
"tracking_field_value_file" => "last_tracking_field_value.txt"
|
294
|
+
}
|
295
|
+
end
|
296
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
297
|
+
subject { input }
|
298
|
+
let(:queue) { [] }
|
299
|
+
it "loads some lead records modified after 2025-05-07 14:32:17 UTC" do
|
300
|
+
VCR.use_cassette("load some lead objects with lastmodifieddate filter", :decode_compressed_response => true) do
|
301
|
+
subject.register
|
302
|
+
File.write("last_tracking_field_value.txt", "2025-05-07T14:32:17Z")
|
303
|
+
subject.run(queue)
|
304
|
+
expect(queue.length).to eq(3)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context "run with last modified time from range field file when file doesn't yet exist" do
|
310
|
+
VCR.configure do |config|
|
311
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
312
|
+
config.hook_into :webmock
|
313
|
+
config.before_record do |i|
|
314
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
315
|
+
# required because sfdc doesn't send back the content encoding and it
|
316
|
+
# confuses the yaml parser
|
317
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
318
|
+
i.response.body = json_body.to_json
|
319
|
+
i.response.update_content_length_header
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
let(:options) do
|
324
|
+
{
|
325
|
+
"client_id" => "",
|
326
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
327
|
+
"username" => "",
|
328
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
329
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
330
|
+
"use_tooling_api" => false,
|
331
|
+
"sfdc_object_name" => "Lead",
|
332
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
333
|
+
"sfdc_filters" => "Email LIKE '%@elastic.co'",
|
334
|
+
"changed_data_filter" => "LastModifiedDate > %{last_tracking_field_value}",
|
335
|
+
"tracking_field_value_file" => "last_tracking_field_value.txt"
|
336
|
+
}
|
337
|
+
end
|
338
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
339
|
+
subject { input }
|
340
|
+
let(:queue) { [] }
|
341
|
+
it "loads some lead records" do
|
342
|
+
VCR.use_cassette("load some lead objects", :decode_compressed_response => true) do
|
343
|
+
subject.register
|
344
|
+
File.exist?("last_tracking_field_value.txt") && File.delete("last_tracking_field_value.txt")
|
345
|
+
subject.run(queue)
|
346
|
+
expect(queue.length).to eq(3)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context "run with last modified time from range field file with range field" do
|
352
|
+
VCR.configure do |config|
|
353
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
354
|
+
config.hook_into :webmock
|
355
|
+
config.before_record do |i|
|
356
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
357
|
+
# required because sfdc doesn't send back the content encoding and it
|
358
|
+
# confuses the yaml parser
|
359
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
360
|
+
i.response.body = json_body.to_json
|
361
|
+
i.response.update_content_length_header
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
let(:options) do
|
366
|
+
{
|
367
|
+
"client_id" => "",
|
368
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
369
|
+
"username" => "",
|
370
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
371
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
372
|
+
"use_tooling_api" => false,
|
373
|
+
"sfdc_object_name" => "Lead",
|
374
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
375
|
+
"sfdc_filters" => "Email LIKE '%@elastic.co'",
|
376
|
+
"tracking_field" => "LastModifiedDate",
|
377
|
+
"changed_data_filter" => "LastModifiedDate > %{last_tracking_field_value}",
|
378
|
+
"tracking_field_value_file" => "last_tracking_field_value.txt"
|
379
|
+
}
|
380
|
+
end
|
381
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
382
|
+
subject { input }
|
383
|
+
let(:queue) { [] }
|
384
|
+
it "loads some lead records modified after 2025-05-07 14:32:17 UTC" do
|
385
|
+
VCR.use_cassette("load some lead objects with lastmodifieddate filter order by lastmodifieddate", :decode_compressed_response => true) do
|
386
|
+
subject.register
|
387
|
+
File.write("last_tracking_field_value.txt", "2025-05-07T14:32:17Z")
|
388
|
+
subject.run(queue)
|
389
|
+
expect(queue.length).to eq(3)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
context "run with last modified time from range field file with range field and no other filters" do
|
395
|
+
VCR.configure do |config|
|
396
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
397
|
+
config.hook_into :webmock
|
398
|
+
config.before_record do |i|
|
399
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
400
|
+
# required because sfdc doesn't send back the content encoding and it
|
401
|
+
# confuses the yaml parser
|
402
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
403
|
+
i.response.body = json_body.to_json
|
404
|
+
i.response.update_content_length_header
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
let(:options) do
|
409
|
+
{
|
410
|
+
"client_id" => "",
|
411
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
412
|
+
"username" => "",
|
413
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
414
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
415
|
+
"use_tooling_api" => false,
|
416
|
+
"sfdc_object_name" => "Lead",
|
417
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
418
|
+
"tracking_field" => "LastModifiedDate",
|
419
|
+
"changed_data_filter" => "LastModifiedDate > %{last_tracking_field_value}",
|
420
|
+
"tracking_field_value_file" => "last_tracking_field_value.txt"
|
421
|
+
}
|
422
|
+
end
|
423
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
424
|
+
subject { input }
|
425
|
+
let(:queue) { [] }
|
426
|
+
it "loads some lead records modified after 2025-05-07 14:32:17 UTC" do
|
427
|
+
VCR.use_cassette("load some lead objects with lastmodifieddate filter order by lastmodifieddate no filters", :decode_compressed_response => true) do
|
428
|
+
subject.register
|
429
|
+
File.write("last_tracking_field_value.txt", "2025-05-07T14:32:17Z")
|
430
|
+
subject.run(queue)
|
431
|
+
expect(queue.length).to eq(3)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
context "run with last modified time from range field file when file doesn't yet exist with range field" do
|
437
|
+
VCR.configure do |config|
|
438
|
+
config.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes')
|
439
|
+
config.hook_into :webmock
|
440
|
+
config.before_record do |i|
|
441
|
+
if i.response.body.encoding.to_s == 'ASCII-8BIT'
|
442
|
+
# required because sfdc doesn't send back the content encoding and it
|
443
|
+
# confuses the yaml parser
|
444
|
+
json_body = JSON.load(i.response.body.encode("ASCII-8BIT").force_encoding("utf-8"))
|
445
|
+
i.response.body = json_body.to_json
|
446
|
+
i.response.update_content_length_header
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
let(:options) do
|
451
|
+
{
|
452
|
+
"client_id" => "",
|
453
|
+
"client_secret" => ::LogStash::Util::Password.new("secret-key"),
|
454
|
+
"username" => "",
|
455
|
+
"password" => ::LogStash::Util::Password.new("secret-password"),
|
456
|
+
"security_token" => ::LogStash::Util::Password.new("secret-token"),
|
457
|
+
"use_tooling_api" => false,
|
458
|
+
"sfdc_object_name" => "Lead",
|
459
|
+
"sfdc_fields" => ["Id", "IsDeleted", "LastName", "FirstName", "Salutation"],
|
460
|
+
"sfdc_filters" => "Email LIKE '%@elastic.co'",
|
461
|
+
"tracking_field" => "LastModifiedDate",
|
462
|
+
"changed_data_filter" => "LastModifiedDate > %{last_tracking_field_value}",
|
463
|
+
"tracking_field_value_file" => "last_tracking_field_value.txt"
|
464
|
+
}
|
465
|
+
end
|
466
|
+
let(:input) { LogStash::Inputs::Salesforce.new(options) }
|
467
|
+
subject { input }
|
468
|
+
let(:queue) { [] }
|
469
|
+
it "loads some lead records" do
|
470
|
+
VCR.use_cassette("load some lead objects order by lastmodifieddate", :decode_compressed_response => true) do
|
471
|
+
subject.register
|
472
|
+
File.exist?("last_tracking_field_value.txt") && File.delete("last_tracking_field_value.txt")
|
473
|
+
subject.run(queue)
|
474
|
+
expect(queue.length).to eq(3)
|
475
|
+
tracking_field_value = File.read("last_tracking_field_value.txt")
|
476
|
+
expect(tracking_field_value).to eq("2025-05-07T14:32:17Z")
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
220
480
|
end
|
221
481
|
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-salesforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Russ Savage
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-05-14 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
13
|
+
name: logstash-core-plugin-api
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
@@ -19,9 +19,8 @@ dependencies:
|
|
19
19
|
- - "<="
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '2.99'
|
22
|
-
name: logstash-core-plugin-api
|
23
|
-
prerelease: false
|
24
22
|
type: :runtime
|
23
|
+
prerelease: false
|
25
24
|
version_requirements: !ruby/object:Gem::Requirement
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
@@ -31,20 +30,21 @@ dependencies:
|
|
31
30
|
- !ruby/object:Gem::Version
|
32
31
|
version: '2.99'
|
33
32
|
- !ruby/object:Gem::Dependency
|
33
|
+
name: logstash-codec-plain
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
requirements:
|
36
36
|
- - ">="
|
37
37
|
- !ruby/object:Gem::Version
|
38
38
|
version: '0'
|
39
|
-
name: logstash-codec-plain
|
40
|
-
prerelease: false
|
41
39
|
type: :runtime
|
40
|
+
prerelease: false
|
42
41
|
version_requirements: !ruby/object:Gem::Requirement
|
43
42
|
requirements:
|
44
43
|
- - ">="
|
45
44
|
- !ruby/object:Gem::Version
|
46
45
|
version: '0'
|
47
46
|
- !ruby/object:Gem::Dependency
|
47
|
+
name: restforce
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
requirements:
|
50
50
|
- - ">="
|
@@ -53,9 +53,8 @@ dependencies:
|
|
53
53
|
- - "<"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '5.2'
|
56
|
-
name: restforce
|
57
|
-
prerelease: false
|
58
56
|
type: :runtime
|
57
|
+
prerelease: false
|
59
58
|
version_requirements: !ruby/object:Gem::Requirement
|
60
59
|
requirements:
|
61
60
|
- - ">="
|
@@ -65,70 +64,70 @@ dependencies:
|
|
65
64
|
- !ruby/object:Gem::Version
|
66
65
|
version: '5.2'
|
67
66
|
- !ruby/object:Gem::Dependency
|
67
|
+
name: logstash-devutils
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
69
69
|
requirements:
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '0'
|
73
|
-
name: logstash-devutils
|
74
|
-
prerelease: false
|
75
73
|
type: :development
|
74
|
+
prerelease: false
|
76
75
|
version_requirements: !ruby/object:Gem::Requirement
|
77
76
|
requirements:
|
78
77
|
- - ">="
|
79
78
|
- !ruby/object:Gem::Version
|
80
79
|
version: '0'
|
81
80
|
- !ruby/object:Gem::Dependency
|
81
|
+
name: vcr
|
82
82
|
requirement: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
|
-
name: vcr
|
88
|
-
prerelease: false
|
89
87
|
type: :development
|
88
|
+
prerelease: false
|
90
89
|
version_requirements: !ruby/object:Gem::Requirement
|
91
90
|
requirements:
|
92
91
|
- - ">="
|
93
92
|
- !ruby/object:Gem::Version
|
94
93
|
version: '0'
|
95
94
|
- !ruby/object:Gem::Dependency
|
95
|
+
name: webmock
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
98
|
- - ">="
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
|
-
name: webmock
|
102
|
-
prerelease: false
|
103
101
|
type: :development
|
102
|
+
prerelease: false
|
104
103
|
version_requirements: !ruby/object:Gem::Requirement
|
105
104
|
requirements:
|
106
105
|
- - ">="
|
107
106
|
- !ruby/object:Gem::Version
|
108
107
|
version: '0'
|
109
108
|
- !ruby/object:Gem::Dependency
|
109
|
+
name: json
|
110
110
|
requirement: !ruby/object:Gem::Requirement
|
111
111
|
requirements:
|
112
112
|
- - ">="
|
113
113
|
- !ruby/object:Gem::Version
|
114
114
|
version: '0'
|
115
|
-
name: json
|
116
|
-
prerelease: false
|
117
115
|
type: :development
|
116
|
+
prerelease: false
|
118
117
|
version_requirements: !ruby/object:Gem::Requirement
|
119
118
|
requirements:
|
120
119
|
- - ">="
|
121
120
|
- !ruby/object:Gem::Version
|
122
121
|
version: '0'
|
123
122
|
- !ruby/object:Gem::Dependency
|
123
|
+
name: public_suffix
|
124
124
|
requirement: !ruby/object:Gem::Requirement
|
125
125
|
requirements:
|
126
126
|
- - ">="
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: '1.4'
|
129
|
-
name: public_suffix
|
130
|
-
prerelease: false
|
131
129
|
type: :development
|
130
|
+
prerelease: false
|
132
131
|
version_requirements: !ruby/object:Gem::Requirement
|
133
132
|
requirements:
|
134
133
|
- - ">="
|
@@ -143,7 +142,6 @@ extensions: []
|
|
143
142
|
extra_rdoc_files: []
|
144
143
|
files:
|
145
144
|
- CHANGELOG.md
|
146
|
-
- DEVELOPER.md
|
147
145
|
- Gemfile
|
148
146
|
- LICENSE
|
149
147
|
- NOTICE.TXT
|
@@ -154,16 +152,20 @@ files:
|
|
154
152
|
- spec/fixtures/vcr_cassettes/describe_apex_test_run_result_object.yml
|
155
153
|
- spec/fixtures/vcr_cassettes/describe_lead_object.yml
|
156
154
|
- spec/fixtures/vcr_cassettes/load_some_lead_objects.yml
|
155
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_order_by_lastmodifieddate.yml
|
156
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_twice.yml
|
157
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter.yml
|
158
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate.yml
|
159
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate_no_filters.yml
|
157
160
|
- spec/fixtures/vcr_cassettes/login_into_mydomain.yml
|
158
161
|
- spec/inputs/salesforce_spec.rb
|
159
162
|
- spec/spec_helper.rb
|
160
163
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
161
164
|
licenses:
|
162
|
-
-
|
165
|
+
- apache-2.0
|
163
166
|
metadata:
|
164
167
|
logstash_plugin: 'true'
|
165
168
|
logstash_group: input
|
166
|
-
post_install_message:
|
167
169
|
rdoc_options: []
|
168
170
|
require_paths:
|
169
171
|
- lib
|
@@ -178,14 +180,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
180
|
- !ruby/object:Gem::Version
|
179
181
|
version: '0'
|
180
182
|
requirements: []
|
181
|
-
rubygems_version: 3.
|
182
|
-
signing_key:
|
183
|
+
rubygems_version: 3.6.3
|
183
184
|
specification_version: 4
|
184
185
|
summary: Creates events based on a Salesforce SOQL query
|
185
186
|
test_files:
|
186
187
|
- spec/fixtures/vcr_cassettes/describe_apex_test_run_result_object.yml
|
187
188
|
- spec/fixtures/vcr_cassettes/describe_lead_object.yml
|
188
189
|
- spec/fixtures/vcr_cassettes/load_some_lead_objects.yml
|
190
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_order_by_lastmodifieddate.yml
|
191
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_twice.yml
|
192
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter.yml
|
193
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate.yml
|
194
|
+
- spec/fixtures/vcr_cassettes/load_some_lead_objects_with_lastmodifieddate_filter_order_by_lastmodifieddate_no_filters.yml
|
189
195
|
- spec/fixtures/vcr_cassettes/login_into_mydomain.yml
|
190
196
|
- spec/inputs/salesforce_spec.rb
|
191
197
|
- spec/spec_helper.rb
|
data/DEVELOPER.md
DELETED