logstash-integration-jdbc 5.0.0.alpha1
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 +7 -0
- data/CHANGELOG.md +8 -0
- data/CONTRIBUTORS +22 -0
- data/Gemfile +11 -0
- data/LICENSE +13 -0
- data/NOTICE.TXT +5 -0
- data/README.md +105 -0
- data/docs/filter-jdbc_static.asciidoc +606 -0
- data/docs/filter-jdbc_streaming.asciidoc +317 -0
- data/docs/index.asciidoc +32 -0
- data/docs/input-jdbc.asciidoc +573 -0
- data/lib/logstash/filters/jdbc/basic_database.rb +125 -0
- data/lib/logstash/filters/jdbc/column.rb +39 -0
- data/lib/logstash/filters/jdbc/db_object.rb +101 -0
- data/lib/logstash/filters/jdbc/loader.rb +119 -0
- data/lib/logstash/filters/jdbc/loader_schedule.rb +64 -0
- data/lib/logstash/filters/jdbc/lookup.rb +253 -0
- data/lib/logstash/filters/jdbc/lookup_processor.rb +100 -0
- data/lib/logstash/filters/jdbc/lookup_result.rb +40 -0
- data/lib/logstash/filters/jdbc/read_only_database.rb +57 -0
- data/lib/logstash/filters/jdbc/read_write_database.rb +108 -0
- data/lib/logstash/filters/jdbc/repeating_load_runner.rb +13 -0
- data/lib/logstash/filters/jdbc/single_load_runner.rb +46 -0
- data/lib/logstash/filters/jdbc/validatable.rb +46 -0
- data/lib/logstash/filters/jdbc_static.rb +240 -0
- data/lib/logstash/filters/jdbc_streaming.rb +196 -0
- data/lib/logstash/inputs/jdbc.rb +341 -0
- data/lib/logstash/inputs/tzinfo_jruby_patch.rb +57 -0
- data/lib/logstash/plugin_mixins/jdbc/checked_count_logger.rb +43 -0
- data/lib/logstash/plugin_mixins/jdbc/jdbc.rb +298 -0
- data/lib/logstash/plugin_mixins/jdbc/statement_handler.rb +129 -0
- data/lib/logstash/plugin_mixins/jdbc/value_tracking.rb +140 -0
- data/lib/logstash/plugin_mixins/jdbc_streaming/cache_payload.rb +28 -0
- data/lib/logstash/plugin_mixins/jdbc_streaming/parameter_handler.rb +64 -0
- data/lib/logstash/plugin_mixins/jdbc_streaming/statement_handler.rb +143 -0
- data/lib/logstash/plugin_mixins/jdbc_streaming.rb +100 -0
- data/lib/logstash/plugin_mixins/statement_handler.rb +0 -0
- data/lib/logstash-integration-jdbc_jars.rb +5 -0
- data/logstash-integration-jdbc.gemspec +44 -0
- data/spec/filters/env_helper.rb +10 -0
- data/spec/filters/integration/jdbc_static_spec.rb +154 -0
- data/spec/filters/integration/jdbcstreaming_spec.rb +173 -0
- data/spec/filters/jdbc/column_spec.rb +70 -0
- data/spec/filters/jdbc/db_object_spec.rb +81 -0
- data/spec/filters/jdbc/loader_spec.rb +77 -0
- data/spec/filters/jdbc/lookup_processor_spec.rb +132 -0
- data/spec/filters/jdbc/lookup_spec.rb +253 -0
- data/spec/filters/jdbc/read_only_database_spec.rb +67 -0
- data/spec/filters/jdbc/read_write_database_spec.rb +90 -0
- data/spec/filters/jdbc/repeating_load_runner_spec.rb +24 -0
- data/spec/filters/jdbc/single_load_runner_spec.rb +16 -0
- data/spec/filters/jdbc_static_file_local_spec.rb +83 -0
- data/spec/filters/jdbc_static_spec.rb +162 -0
- data/spec/filters/jdbc_streaming_spec.rb +350 -0
- data/spec/filters/remote_server_helper.rb +24 -0
- data/spec/filters/shared_helpers.rb +34 -0
- data/spec/helpers/WHY-THIS-JAR.txt +4 -0
- data/spec/helpers/derbyrun.jar +0 -0
- data/spec/inputs/integration/integ_spec.rb +78 -0
- data/spec/inputs/jdbc_spec.rb +1431 -0
- data/vendor/jar-dependencies/org/apache/derby/derby/10.14.1.0/derby-10.14.1.0.jar +0 -0
- data/vendor/jar-dependencies/org/apache/derby/derbyclient/10.14.1.0/derbyclient-10.14.1.0.jar +0 -0
- metadata +319 -0
@@ -0,0 +1,350 @@
|
|
1
|
+
require "logstash/devutils/rspec/spec_helper"
|
2
|
+
require "logstash/filters/jdbc_streaming"
|
3
|
+
require 'jdbc/derby'
|
4
|
+
require "sequel"
|
5
|
+
require "sequel/adapters/jdbc"
|
6
|
+
|
7
|
+
module LogStash module Filters
|
8
|
+
class TestJdbcStreaming < JdbcStreaming
|
9
|
+
attr_reader :database
|
10
|
+
end
|
11
|
+
|
12
|
+
describe JdbcStreaming do
|
13
|
+
let!(:jdbc_connection_string) { "jdbc:derby:memory:jdbc_streaming_testdb;create=true"}
|
14
|
+
#Use embedded Derby for tests
|
15
|
+
::Jdbc::Derby.load_driver
|
16
|
+
|
17
|
+
ENV["TZ"] = "Etc/UTC"
|
18
|
+
describe "plugin level execution" do
|
19
|
+
let(:mixin_settings) do
|
20
|
+
{ "jdbc_user" => ENV['USER'], "jdbc_driver_class" => "org.apache.derby.jdbc.EmbeddedDriver",
|
21
|
+
"jdbc_connection_string" => jdbc_connection_string}
|
22
|
+
end
|
23
|
+
let(:plugin) { JdbcStreaming.new(mixin_settings.merge(settings)) }
|
24
|
+
let (:db) do
|
25
|
+
::Sequel.connect(mixin_settings['jdbc_connection_string'], :user=> nil, :password=> nil)
|
26
|
+
end
|
27
|
+
let(:event) { ::LogStash::Event.new("message" => "some text", "ip" => ipaddr) }
|
28
|
+
let(:cache_expiration) { 3.0 }
|
29
|
+
let(:use_cache) { true }
|
30
|
+
let(:cache_size) { 10 }
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
db.create_table :reference_table do
|
34
|
+
String :ip
|
35
|
+
String :name
|
36
|
+
String :location
|
37
|
+
Integer :gcode
|
38
|
+
end
|
39
|
+
db[:reference_table].insert(:ip => "10.1.1.1", :name => "ldn-server-1", :location => "LDN-2-3-4", :gcode => 3)
|
40
|
+
db[:reference_table].insert(:ip => "10.2.1.1", :name => "nyc-server-1", :location => "NYC-5-2-8", :gcode => 1)
|
41
|
+
db[:reference_table].insert(:ip => "10.3.1.1", :name => "mv-server-1", :location => "MV-9-6-4", :gcode => 1)
|
42
|
+
db[:reference_table].insert(:ip => "10.4.1.1", :name => "sf-server-1", :location => "SF-9-5-4", :gcode => 1)
|
43
|
+
db[:reference_table].insert(:ip => "10.4.1.1", :name => "mtl-server-1", :location => "MTL-9-3-4", :gcode => 2)
|
44
|
+
end
|
45
|
+
|
46
|
+
after :each do
|
47
|
+
db.drop_table(:reference_table)
|
48
|
+
end
|
49
|
+
|
50
|
+
context "Normal Mode" do
|
51
|
+
before :each do
|
52
|
+
plugin.register
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:statement) { "SELECT name, location FROM reference_table WHERE ip = :ip" }
|
56
|
+
let(:settings) do
|
57
|
+
{
|
58
|
+
"statement" => statement,
|
59
|
+
"parameters" => {"ip" => "ip"},
|
60
|
+
"target" => "server",
|
61
|
+
"use_cache" => use_cache,
|
62
|
+
"cache_expiration" => cache_expiration,
|
63
|
+
"cache_size" => cache_size,
|
64
|
+
"tag_on_failure" => ["lookup_failed"],
|
65
|
+
"tag_on_default_use" => ["default_used_instead"],
|
66
|
+
"default_hash" => {"name" => "unknown", "location" => "unknown"},
|
67
|
+
"sequel_opts" => {"pool_timeout" => 600}
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "found record - uses row" do
|
72
|
+
let(:ipaddr) { "10.1.1.1" }
|
73
|
+
|
74
|
+
it "fills in the target" do
|
75
|
+
plugin.filter(event)
|
76
|
+
expect(event.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
77
|
+
expect(event.get("tags") || []).not_to include("lookup_failed")
|
78
|
+
expect(event.get("tags") || []).not_to include("default_used_instead")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "missing record - uses default" do
|
83
|
+
let(:ipaddr) { "192.168.1.1" }
|
84
|
+
|
85
|
+
it "fills in the target with the default" do
|
86
|
+
plugin.filter(event)
|
87
|
+
expect(event.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
88
|
+
expect(event.get("tags") & ["lookup_failed", "default_used_instead"]).to eq(["default_used_instead"])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "database error - uses default" do
|
93
|
+
let(:ipaddr) { "10.1.1.1" }
|
94
|
+
let(:statement) { "SELECT name, location FROM reference_table WHERE ip = :address" }
|
95
|
+
it "fills in the target with the default" do
|
96
|
+
plugin.filter(event)
|
97
|
+
expect(event.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
98
|
+
expect(event.get("tags") & ["lookup_failed", "default_used_instead"]).to eq(["lookup_failed", "default_used_instead"])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when fetching from cache" do
|
103
|
+
let(:plugin) { TestJdbcStreaming.new(mixin_settings.merge(settings)) }
|
104
|
+
let(:events) do
|
105
|
+
5.times.map{|i| ::LogStash::Event.new("message" => "some other text #{i}", "ip" => ipaddr) }
|
106
|
+
end
|
107
|
+
let(:call_count) { 1 }
|
108
|
+
before(:each) do
|
109
|
+
expect(plugin.database).to receive(:[]).exactly(call_count).times.and_call_original
|
110
|
+
plugin.filter(event)
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "found record - caches row" do
|
114
|
+
let(:ipaddr) { "10.1.1.1" }
|
115
|
+
it "calls the database once then uses the cache" do
|
116
|
+
expect(event.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
117
|
+
expect(event.get("tags") || []).not_to include("lookup_failed")
|
118
|
+
expect(event.get("tags") || []).not_to include("default_used_instead")
|
119
|
+
events.each do |evt|
|
120
|
+
plugin.filter(evt)
|
121
|
+
expect(evt.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "missing record - uses default" do
|
127
|
+
let(:ipaddr) { "10.10.1.1" }
|
128
|
+
it "calls the database once then uses the cache" do
|
129
|
+
expect(event.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
130
|
+
expect(event.get("tags") & ["lookup_failed", "default_used_instead"]).to eq(["default_used_instead"])
|
131
|
+
events.each do |evt|
|
132
|
+
plugin.filter(evt)
|
133
|
+
expect(evt.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "extremely small cache expiration" do
|
139
|
+
describe "found record - cache always expires" do
|
140
|
+
let(:ipaddr) { "10.1.1.1" }
|
141
|
+
let(:call_count) { 6 }
|
142
|
+
let(:cache_expiration) { 0.0000001 }
|
143
|
+
it "calls the database each time because cache entry expired" do
|
144
|
+
expect(event.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
145
|
+
expect(event.get("tags") || []).not_to include("lookup_failed")
|
146
|
+
expect(event.get("tags") || []).not_to include("default_used_instead")
|
147
|
+
events.each do |evt|
|
148
|
+
plugin.filter(evt)
|
149
|
+
expect(evt.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "when cache is disabled" do
|
156
|
+
let(:call_count) { 6 }
|
157
|
+
let(:use_cache) { false }
|
158
|
+
describe "database is always called" do
|
159
|
+
let(:ipaddr) { "10.1.1.1" }
|
160
|
+
it "calls the database each time" do
|
161
|
+
expect(event.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
162
|
+
expect(event.get("tags") || []).not_to include("lookup_failed")
|
163
|
+
expect(event.get("tags") || []).not_to include("default_used_instead")
|
164
|
+
events.each do |evt|
|
165
|
+
plugin.filter(evt)
|
166
|
+
expect(evt.get("server")).to eq([{"name" => "ldn-server-1", "location" => "LDN-2-3-4"}])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "database is always called but record is missing and default is used" do
|
172
|
+
let(:ipaddr) { "10.11.1.1" }
|
173
|
+
it "calls the database each time" do
|
174
|
+
expect(event.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
175
|
+
expect(event.get("tags") & ["lookup_failed", "default_used_instead"]).to eq(["default_used_instead"])
|
176
|
+
events.each do |evt|
|
177
|
+
plugin.filter(evt)
|
178
|
+
expect(evt.get("server")).to eq([{"name" => "unknown", "location" => "unknown"}])
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "Prepared Statement Mode" do
|
187
|
+
let(:statement) { "SELECT name, location FROM reference_table WHERE (ip = ?) AND (gcode = ?)" }
|
188
|
+
let(:settings) do
|
189
|
+
{
|
190
|
+
"statement" => statement,
|
191
|
+
"use_prepared_statements" => true,
|
192
|
+
"prepared_statement_name" => "lookup_ip",
|
193
|
+
"prepared_statement_bind_values" => ["[ip]", 2],
|
194
|
+
"target" => "server",
|
195
|
+
"use_cache" => use_cache,
|
196
|
+
"cache_expiration" => cache_expiration,
|
197
|
+
"cache_size" => cache_size,
|
198
|
+
"tag_on_failure" => ["lookup_failed"],
|
199
|
+
"tag_on_default_use" => ["default_used_instead"],
|
200
|
+
"default_hash" => {"name" => "unknown", "location" => "unknown"},
|
201
|
+
"sequel_opts" => {"pool_timeout" => 600}
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "using one variable and one constant, found record - uses row" do
|
206
|
+
let(:ipaddr) { "10.4.1.1" }
|
207
|
+
|
208
|
+
it "fills in the target" do
|
209
|
+
plugin.register
|
210
|
+
expect(plugin.prepared_statement_constant_warned).to be_falsey
|
211
|
+
plugin.filter(event)
|
212
|
+
expect(event.get("server")).to eq([{"name" => "mtl-server-1", "location" => "MTL-9-3-4"}])
|
213
|
+
expect(event.get("tags") || []).not_to include("lookup_failed")
|
214
|
+
expect(event.get("tags") || []).not_to include("default_used_instead")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "fails empty name validation" do
|
219
|
+
before :each do
|
220
|
+
settings["prepared_statement_name"] = ""
|
221
|
+
end
|
222
|
+
it "should fail to register" do
|
223
|
+
expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe "fails parameter mismatch validation" do
|
228
|
+
before :each do
|
229
|
+
settings["prepared_statement_bind_values"] = ["[ip]"]
|
230
|
+
end
|
231
|
+
it "should fail to register" do
|
232
|
+
expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "warns on constant usage" do
|
237
|
+
before :each do
|
238
|
+
settings["prepared_statement_bind_values"] = ["ip", 2]
|
239
|
+
end
|
240
|
+
it "should set the warning logged flag" do
|
241
|
+
plugin.register
|
242
|
+
expect(plugin.prepared_statement_constant_warned).to be_truthy
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "All default - Retrieve a value from database" do
|
249
|
+
let(:config) do <<-CONFIG
|
250
|
+
filter {
|
251
|
+
jdbc_streaming {
|
252
|
+
jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
|
253
|
+
jdbc_connection_string => "#{jdbc_connection_string}"
|
254
|
+
statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1"
|
255
|
+
target => "new_field"
|
256
|
+
}
|
257
|
+
}
|
258
|
+
CONFIG
|
259
|
+
end
|
260
|
+
|
261
|
+
sample("message" => "some text") do
|
262
|
+
expect(subject.get('new_field')).to eq([{"1" => 'from_database'}])
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe "Named column - Retrieve a value from database" do
|
267
|
+
let(:config) do <<-CONFIG
|
268
|
+
filter {
|
269
|
+
jdbc_streaming {
|
270
|
+
jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
|
271
|
+
jdbc_connection_string => "#{jdbc_connection_string}"
|
272
|
+
statement => "SELECT 'from_database' as col_1 FROM SYSIBM.SYSDUMMY1"
|
273
|
+
target => "new_field"
|
274
|
+
}
|
275
|
+
}
|
276
|
+
CONFIG
|
277
|
+
end
|
278
|
+
|
279
|
+
sample("message" => "some text") do
|
280
|
+
expect(subject.get('new_field')).to eq([{"col_1" => 'from_database'}])
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe "Using string parameters - Retrieve a value from database" do
|
285
|
+
let(:config) do <<-CONFIG
|
286
|
+
filter {
|
287
|
+
jdbc_streaming {
|
288
|
+
jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
|
289
|
+
jdbc_connection_string => "#{jdbc_connection_string}"
|
290
|
+
statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE '1' = :param"
|
291
|
+
parameters => { "param" => "param_field"}
|
292
|
+
target => "new_field"
|
293
|
+
}
|
294
|
+
}
|
295
|
+
CONFIG
|
296
|
+
end
|
297
|
+
|
298
|
+
sample("message" => "some text", "param_field" => "1") do
|
299
|
+
expect(subject.get('new_field')).to eq([{"1" => 'from_database'}])
|
300
|
+
end
|
301
|
+
|
302
|
+
sample("message" => "some text", "param_field" => "2") do
|
303
|
+
expect(subject.get('new_field').nil?)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe "Using integer parameters" do
|
308
|
+
let(:config) do <<-CONFIG
|
309
|
+
filter {
|
310
|
+
jdbc_streaming {
|
311
|
+
jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
|
312
|
+
jdbc_connection_string => "#{jdbc_connection_string}"
|
313
|
+
statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE 1 = :param"
|
314
|
+
parameters => { "param" => "param_field"}
|
315
|
+
target => "new_field"
|
316
|
+
}
|
317
|
+
}
|
318
|
+
CONFIG
|
319
|
+
end
|
320
|
+
|
321
|
+
sample("message" => "some text", "param_field" => 1) do
|
322
|
+
expect(subject.get('new_field')).to eq([{"1" => 'from_database'}])
|
323
|
+
end
|
324
|
+
|
325
|
+
sample("message" => "some text", "param_field" => "1") do
|
326
|
+
expect(subject.get('new_field').nil?)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "Using timestamp parameter" do
|
331
|
+
let(:config) do <<-CONFIG
|
332
|
+
filter {
|
333
|
+
jdbc_streaming {
|
334
|
+
jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
|
335
|
+
jdbc_connection_string => "#{jdbc_connection_string}"
|
336
|
+
statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE {fn TIMESTAMPDIFF( SQL_TSI_DAY, {t :param}, current_timestamp)} = 0"
|
337
|
+
parameters => { "param" => "@timestamp"}
|
338
|
+
target => "new_field"
|
339
|
+
}
|
340
|
+
}
|
341
|
+
CONFIG
|
342
|
+
end
|
343
|
+
|
344
|
+
sample("message" => "some text") do
|
345
|
+
expect(subject.get('new_field')).to eq([{"1" => 'from_database'}])
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
end end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "childprocess"
|
3
|
+
|
4
|
+
module ServerProcessHelpers
|
5
|
+
def self.jdbc_static_start_derby_server()
|
6
|
+
# client_out = Stud::Temporary.file
|
7
|
+
# client_out.sync
|
8
|
+
ChildProcess.posix_spawn = true
|
9
|
+
cmd = ["java", "-jar", "#{BASE_DERBY_DIR}/derbyrun.jar", "server", "start"]
|
10
|
+
process = ChildProcess.build(*cmd)
|
11
|
+
process.start
|
12
|
+
|
13
|
+
sleep(0.1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.jdbc_static_stop_derby_server(test_db)
|
17
|
+
cmd = ["java", "-jar", "#{BASE_DERBY_DIR}/derbyrun.jar", "server", "shutdown"]
|
18
|
+
process = ChildProcess.build(*cmd)
|
19
|
+
ChildProcess.posix_spawn = true
|
20
|
+
process.start
|
21
|
+
process.wait
|
22
|
+
`rm -rf #{::File.join(GEM_BASE_DIR, test_db)}`
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/filters/jdbc/db_object"
|
3
|
+
|
4
|
+
RSpec.shared_examples "a single load runner" do
|
5
|
+
|
6
|
+
context "with local db objects" do
|
7
|
+
let(:local_db_objects) do
|
8
|
+
[
|
9
|
+
{"name" => "servers", "index_columns" => ["ip"], "columns" => [%w(ip text), %w(name text), %w(location text)]},
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "builds local db objects and populates the local db" do
|
14
|
+
expect(local_db).to receive(:populate_all).once.with(loaders)
|
15
|
+
expect(local_db).to receive(:build_db_object).once.with(instance_of(LogStash::Filters::Jdbc::DbObject))
|
16
|
+
runner.initial_load
|
17
|
+
expect(runner.preloaders).to be_a(Array)
|
18
|
+
expect(runner.preloaders.size).to eq(1)
|
19
|
+
expect(runner.preloaders[0].name).to eq(:servers)
|
20
|
+
expect(runner.local).to eq(local_db)
|
21
|
+
expect(runner.loaders).to eq(loaders)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "without local db objects" do
|
26
|
+
it "populates the local db" do
|
27
|
+
expect(local_db).to receive(:populate_all).once.with(loaders)
|
28
|
+
runner.initial_load
|
29
|
+
expect(runner.preloaders).to eq([])
|
30
|
+
expect(runner.local).to eq(local_db)
|
31
|
+
expect(runner.loaders).to eq(loaders)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
Binary file
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "logstash/devutils/rspec/spec_helper"
|
2
|
+
require "logstash/inputs/jdbc"
|
3
|
+
require "sequel"
|
4
|
+
require "sequel/adapters/jdbc"
|
5
|
+
|
6
|
+
# This test requires: Firebird installed to Mac OSX, it uses the built-in example database `employee`
|
7
|
+
|
8
|
+
describe LogStash::Inputs::Jdbc, :integration => true do
|
9
|
+
# This is a necessary change test-wide to guarantee that no local timezone
|
10
|
+
# is picked up. It could be arbitrarily set to any timezone, but then the test
|
11
|
+
# would have to compensate differently. That's why UTC is chosen.
|
12
|
+
ENV["TZ"] = "Etc/UTC"
|
13
|
+
# For Travis and CI based on docker, we source from ENV
|
14
|
+
jdbc_connection_string = ENV.fetch("PG_CONNECTION_STRING",
|
15
|
+
"jdbc:postgresql://postgresql:5432") + "/jdbc_input_db?user=postgres"
|
16
|
+
|
17
|
+
let(:settings) do
|
18
|
+
{ "jdbc_driver_class" => "org.postgresql.Driver",
|
19
|
+
"jdbc_connection_string" => jdbc_connection_string,
|
20
|
+
"jdbc_driver_library" => "/usr/share/logstash/postgresql.jar",
|
21
|
+
"jdbc_user" => "postgres",
|
22
|
+
"statement" => 'SELECT FIRST_NAME, LAST_NAME FROM "employee" WHERE EMP_NO = 2'
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:plugin) { LogStash::Inputs::Jdbc.new(settings) }
|
27
|
+
let(:queue) { Queue.new }
|
28
|
+
|
29
|
+
context "when connecting to a postgres instance" do
|
30
|
+
before do
|
31
|
+
plugin.register
|
32
|
+
end
|
33
|
+
|
34
|
+
after do
|
35
|
+
plugin.stop
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should populate the event with database entries" do
|
39
|
+
plugin.run(queue)
|
40
|
+
event = queue.pop
|
41
|
+
expect(event.get('first_name')).to eq("Mark")
|
42
|
+
expect(event.get('last_name')).to eq("Guckenheimer")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when supplying a non-existent library" do
|
47
|
+
let(:settings) do
|
48
|
+
super.merge(
|
49
|
+
"jdbc_driver_library" => "/no/path/to/postgresql.jar"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not register correctly" do
|
54
|
+
plugin.register
|
55
|
+
q = Queue.new
|
56
|
+
expect do
|
57
|
+
plugin.run(q)
|
58
|
+
end.to raise_error(::LogStash::PluginLoadingError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when connecting to a non-existent server" do
|
63
|
+
let(:settings) do
|
64
|
+
super.merge(
|
65
|
+
"jdbc_connection_string" => "jdbc:postgresql://localhost:65000/somedb"
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not register correctly" do
|
70
|
+
plugin.register
|
71
|
+
q = Queue.new
|
72
|
+
expect do
|
73
|
+
plugin.run(q)
|
74
|
+
end.to raise_error(::Sequel::DatabaseConnectionError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|