logstash-filter-jdbc_static 1.0.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 +7 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTORS +22 -0
- data/Gemfile +2 -0
- data/LICENSE +13 -0
- data/README.md +94 -0
- data/lib/logstash-filter-jdbc_static_jars.rb +5 -0
- data/lib/logstash/filters/jdbc/basic_database.rb +117 -0
- data/lib/logstash/filters/jdbc/column.rb +38 -0
- data/lib/logstash/filters/jdbc/db_object.rb +103 -0
- data/lib/logstash/filters/jdbc/loader.rb +114 -0
- data/lib/logstash/filters/jdbc/loader_schedule.rb +38 -0
- data/lib/logstash/filters/jdbc/lookup.rb +192 -0
- data/lib/logstash/filters/jdbc/lookup_processor.rb +91 -0
- data/lib/logstash/filters/jdbc/lookup_result.rb +39 -0
- data/lib/logstash/filters/jdbc/read_only_database.rb +57 -0
- data/lib/logstash/filters/jdbc/read_write_database.rb +86 -0
- data/lib/logstash/filters/jdbc/repeating_load_runner.rb +11 -0
- data/lib/logstash/filters/jdbc/single_load_runner.rb +43 -0
- data/lib/logstash/filters/jdbc/validatable.rb +49 -0
- data/lib/logstash/filters/jdbc_static.rb +216 -0
- data/logstash-filter-jdbc_static.gemspec +38 -0
- data/spec/filters/env_helper.rb +10 -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 +76 -0
- data/spec/filters/jdbc/lookup_processor_spec.rb +132 -0
- data/spec/filters/jdbc/lookup_spec.rb +129 -0
- data/spec/filters/jdbc/read_only_database_spec.rb +66 -0
- data/spec/filters/jdbc/read_write_database_spec.rb +89 -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 +70 -0
- data/spec/filters/remote_server_helper.rb +24 -0
- data/spec/filters/shared_helpers.rb +35 -0
- data/spec/helpers/WHY-THIS-JAR.txt +4 -0
- data/spec/helpers/derbyrun.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/derby-10.14.1.0.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/derbyclient-10.14.1.0.jar +0 -0
- metadata +224 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative "single_load_runner"
|
2
|
+
|
3
|
+
module LogStash module Filters module Jdbc
|
4
|
+
class RepeatingLoadRunner < SingleLoadRunner
|
5
|
+
# info - attr_reader :local, :loaders, :preloaders
|
6
|
+
|
7
|
+
def repeated_load
|
8
|
+
local.repopulate_all(loaders)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end end end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'db_object'
|
2
|
+
|
3
|
+
module LogStash module Filters module Jdbc
|
4
|
+
class SingleLoadRunner
|
5
|
+
|
6
|
+
attr_reader :local, :loaders, :preloaders
|
7
|
+
|
8
|
+
def initialize(local, loaders, preloaders)
|
9
|
+
@local = local
|
10
|
+
@loaders = loaders
|
11
|
+
@preloaders = []
|
12
|
+
preloaders.map do |pre|
|
13
|
+
dbo = DbObject.new(pre)
|
14
|
+
@preloaders << dbo
|
15
|
+
hash = dbo.as_temp_table_opts
|
16
|
+
_dbo = DbObject.new(hash)
|
17
|
+
@preloaders << _dbo if _dbo.valid?
|
18
|
+
end
|
19
|
+
@preloaders.sort!
|
20
|
+
end
|
21
|
+
|
22
|
+
def initial_load
|
23
|
+
do_preload
|
24
|
+
local.populate_all(loaders)
|
25
|
+
end
|
26
|
+
|
27
|
+
def repeated_load
|
28
|
+
end
|
29
|
+
|
30
|
+
def call
|
31
|
+
repeated_load
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def do_preload
|
37
|
+
preloaders.each do |db_object|
|
38
|
+
local.build_db_object(db_object)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end end end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module LogStash module Filters module Jdbc
|
4
|
+
class Validatable
|
5
|
+
def self.find_validation_errors(array_of_options)
|
6
|
+
if !array_of_options.is_a?(Array)
|
7
|
+
return "The options must be an Array"
|
8
|
+
end
|
9
|
+
errors = []
|
10
|
+
array_of_options.each do |options|
|
11
|
+
instance = new(options)
|
12
|
+
unless instance.valid?
|
13
|
+
errors << instance.formatted_errors
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return nil if errors.empty?
|
17
|
+
errors.join("; ")
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(options)
|
21
|
+
pre_initialize(options)
|
22
|
+
@options = options
|
23
|
+
@valid = false
|
24
|
+
@option_errors = []
|
25
|
+
parse_options
|
26
|
+
post_initialize
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid?
|
30
|
+
@valid
|
31
|
+
end
|
32
|
+
|
33
|
+
def formatted_errors
|
34
|
+
@option_errors.join(", ")
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def pre_initialize(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def post_initialize
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_options
|
46
|
+
raise "Subclass must implement 'parse_options'"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end end end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash-filter-jdbc_static_jars"
|
3
|
+
require "logstash/filters/base"
|
4
|
+
require "logstash/namespace"
|
5
|
+
require_relative "jdbc/loader"
|
6
|
+
require_relative "jdbc/loader_schedule"
|
7
|
+
require_relative "jdbc/repeating_load_runner"
|
8
|
+
require_relative "jdbc/lookup_processor"
|
9
|
+
|
10
|
+
# This filter can do multiple enhancements to an event in one pass.
|
11
|
+
# Define multiple loader sources and multiple lookup targets.
|
12
|
+
# Currently only one remote database connection is supported.
|
13
|
+
# [source,ruby]
|
14
|
+
|
15
|
+
#
|
16
|
+
module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
|
17
|
+
config_name "jdbc_static"
|
18
|
+
|
19
|
+
# Define the loaders, an Array of Hashes, to fetch remote data and create local tables.
|
20
|
+
# the fetched data will be inserted into the local tables. Make sure that the
|
21
|
+
# local table name, columns and datatypes correspond to the shape of the remote data
|
22
|
+
# being fetched. The default for max_rows is 1 million rows. You may provide an `id`
|
23
|
+
# For example:
|
24
|
+
# loaders => [
|
25
|
+
# {
|
26
|
+
# id => "country_details"
|
27
|
+
# query => "select code, name from WORLD.COUNTRY"
|
28
|
+
# max_rows => 2000
|
29
|
+
# local_table => "country"
|
30
|
+
# },
|
31
|
+
# {
|
32
|
+
# id => "servers_load"
|
33
|
+
# query => "select id, ip, name, location from INTERNAL.SERVERS"
|
34
|
+
# local_table => "servers"
|
35
|
+
# }
|
36
|
+
# ]
|
37
|
+
# This is optional. You can provide a pre-populated local database server then no initial loaders are needed.
|
38
|
+
config :loaders, :required => false, :default => [], :validate => [LogStash::Filters::Jdbc::Loader]
|
39
|
+
|
40
|
+
# Define an array of Database Objects to create when the plugin first starts.
|
41
|
+
# These will usually be the definitions to setup the local in-memory tables.
|
42
|
+
# For example:
|
43
|
+
# local_db_objects => [
|
44
|
+
# {name => "servers", preserve_existing => true, index_columns => ["ip"], columns => [["id", "INTEGER"], ["ip", "varchar(64)"], ["name", "varchar(64)"], ["location", "varchar(64)"]]},
|
45
|
+
# ]
|
46
|
+
# NOTE: Important! use `preserve_existing => true` to keep a table created and filled in a previous Logstash session. It will default to false and is unneeded if the database is not persistent.
|
47
|
+
# NOTE: Important! Tables created here must have the same names as those used in the `loaders` and
|
48
|
+
# `local_lookups` configuration options
|
49
|
+
config :local_db_objects, :required => false, :default => [], :validate => [LogStash::Filters::Jdbc::DbObject]
|
50
|
+
|
51
|
+
# Define the list (Array) of enhancement local_lookups to be applied to an event
|
52
|
+
# Each entry is a hash of the query string, the target field and value and a
|
53
|
+
# parameter hash. Target is overwritten if existing. Target is optional,
|
54
|
+
# if omitted the lookup results will be written to the root of the event like this:
|
55
|
+
# event.set(<column name (or alias)>, <column value>)
|
56
|
+
# Use parameters to have this plugin put values from the event into the query.
|
57
|
+
# The parameter maps the symbol used in the query string to the field name in the event.
|
58
|
+
# NOTE: when using a query string that includes the LIKE keyword make sure that
|
59
|
+
# you provide a Logstash Event sprintf pattern with added wildcards.
|
60
|
+
# For example:
|
61
|
+
# local_lookups => [
|
62
|
+
# {
|
63
|
+
# "query" => "select * from country WHERE code = :code",
|
64
|
+
# "parameters" => {"code" => "country_code"}
|
65
|
+
# "target" => "country_details"
|
66
|
+
# },
|
67
|
+
# {
|
68
|
+
# "query" => "select ip, name from servers WHERE ip LIKE :ip",
|
69
|
+
# "parameters" => {"ip" => "%{[response][ip]}%"}
|
70
|
+
# "target" => "servers"
|
71
|
+
# }
|
72
|
+
# ]
|
73
|
+
config :local_lookups, :required => true, :validate => [LogStash::Filters::Jdbc::LookupProcessor]
|
74
|
+
|
75
|
+
# Schedule of when to periodically run loaders, in Cron format
|
76
|
+
# for example: "* * * * *" (execute query every minute, on the minute)
|
77
|
+
#
|
78
|
+
# There is no schedule by default. If no schedule is given, then the loaders are run
|
79
|
+
# exactly once.
|
80
|
+
config :loader_schedule, :validate => [LogStash::Filters::Jdbc::LoaderSchedule]
|
81
|
+
|
82
|
+
# Append values to the `tags` field if sql error occured
|
83
|
+
# Alternatively, individual `tag_on_failure` arrays can be added to each lookup hash
|
84
|
+
config :tag_on_failure, :validate => :array, :default => ["_jdbcstaticfailure"]
|
85
|
+
|
86
|
+
# Append values to the `tags` field if no record was found and default values were used
|
87
|
+
config :tag_on_default_use, :validate => :array, :default => ["_jdbcstaticdefaultsused"]
|
88
|
+
|
89
|
+
# Remote Load DB Jdbc driver library path to third party driver library.
|
90
|
+
config :jdbc_driver_library, :validate => :path
|
91
|
+
|
92
|
+
# Remote Load DB Jdbc driver class to load, for example "oracle.jdbc.OracleDriver" or "org.apache.derby.jdbc.ClientDriver"
|
93
|
+
config :jdbc_driver_class, :validate => :string, :required => true
|
94
|
+
|
95
|
+
# Remote Load DB Jdbc connection string
|
96
|
+
config :jdbc_connection_string, :validate => :string, :required => true
|
97
|
+
|
98
|
+
# Remote Load DB Jdbc user
|
99
|
+
config :jdbc_user, :validate => :string
|
100
|
+
|
101
|
+
# Remote Load DB Jdbc password
|
102
|
+
config :jdbc_password, :validate => :password
|
103
|
+
|
104
|
+
# NOTE: For the initial release, we are not allowing the user to specify their own local lookup JDBC DB settings.
|
105
|
+
# In the near future we have to consider identical config running in multiple pipelines stomping over each other
|
106
|
+
# when the database names are common across configs because there is only one Derby server in memory per JVM.
|
107
|
+
|
108
|
+
# Local Lookup DB Jdbc driver class to load, for example "org.apache.derby.jdbc.ClientDriver"
|
109
|
+
# config :lookup_jdbc_driver_class, :validate => :string, :required => false
|
110
|
+
|
111
|
+
# Local Lookup DB Jdbc driver library path to third party driver library.
|
112
|
+
# config :lookup_jdbc_driver_library, :validate => :path, :required => false
|
113
|
+
|
114
|
+
# Local Lookup DB Jdbc connection string
|
115
|
+
# config :lookup_jdbc_connection_string, :validate => :string, :required => false
|
116
|
+
|
117
|
+
class << self
|
118
|
+
alias_method :old_validate_value, :validate_value
|
119
|
+
|
120
|
+
def validate_value(value, validator)
|
121
|
+
if validator.is_a?(Array) && validator.first.respond_to?(:find_validation_errors)
|
122
|
+
validation_errors = validator.first.find_validation_errors(value)
|
123
|
+
unless validation_errors.nil?
|
124
|
+
return false, validation_errors
|
125
|
+
end
|
126
|
+
else
|
127
|
+
return old_validate_value(value, validator)
|
128
|
+
end
|
129
|
+
[true, value]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
public
|
134
|
+
|
135
|
+
def register
|
136
|
+
prepare_data_dir
|
137
|
+
prepare_runner
|
138
|
+
@loader_runner.initial_load
|
139
|
+
end
|
140
|
+
|
141
|
+
def filter(event)
|
142
|
+
enhancement_states = @processor.enhance(event)
|
143
|
+
filter_matched(event) if enhancement_states.all?
|
144
|
+
end
|
145
|
+
|
146
|
+
def stop
|
147
|
+
@scheduler.stop if @scheduler
|
148
|
+
@parsed_loaders.each(&:close)
|
149
|
+
@processor.close
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def prepare_data_dir
|
155
|
+
# later, when local persistent databases are allowed set this property to LS_HOME/data/jdbc-static/
|
156
|
+
# must take multi-pipelines into account and more than one config using the same jdbc-static settings
|
157
|
+
java.lang.System.setProperty("derby.system.home", ENV["HOME"])
|
158
|
+
end
|
159
|
+
|
160
|
+
def prepare_runner
|
161
|
+
@parsed_loaders = @loaders.map do |options|
|
162
|
+
add_plugin_configs(options)
|
163
|
+
loader = Jdbc::Loader.new(options)
|
164
|
+
loader.build_remote_db
|
165
|
+
loader
|
166
|
+
end
|
167
|
+
runner_args = [@parsed_loaders, @local_db_objects]
|
168
|
+
@processor = Jdbc::LookupProcessor.new(@local_lookups, global_lookup_options)
|
169
|
+
runner_args.unshift(@processor.local)
|
170
|
+
if @loader_schedule
|
171
|
+
require "rufus/scheduler"
|
172
|
+
args = []
|
173
|
+
@loader_runner = Jdbc::RepeatingLoadRunner.new(*runner_args)
|
174
|
+
|
175
|
+
cronline = Jdbc::LoaderSchedule.new(@loader_schedule)
|
176
|
+
rufus_args = {:max_work_threads => 1, :frequency => cronline.schedule_frequency}
|
177
|
+
|
178
|
+
@scheduler = Rufus::Scheduler.new(rufus_args)
|
179
|
+
@scheduler.cron(cronline.loader_schedule, @loader_runner)
|
180
|
+
@scheduler.join
|
181
|
+
else
|
182
|
+
@loader_runner = Jdbc::SingleLoadRunner.new(*runner_args)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def global_lookup_options(options = Hash.new)
|
187
|
+
if @tag_on_failure && !@tag_on_failure.empty? && !options.key?("tag_on_failure")
|
188
|
+
options["tag_on_failure"] = @tag_on_failure
|
189
|
+
end
|
190
|
+
if @tag_on_default_use && !@tag_on_default_use.empty? && !options.key?("tag_on_default_use")
|
191
|
+
options["tag_on_default_use"] = @tag_on_default_use
|
192
|
+
end
|
193
|
+
options["lookup_jdbc_driver_class"] = @lookup_jdbc_driver_class
|
194
|
+
options["lookup_jdbc_driver_library"] = @lookup_jdbc_driver_library
|
195
|
+
options["lookup_jdbc_connection_string"] = @lookup_jdbc_connection_string
|
196
|
+
options
|
197
|
+
end
|
198
|
+
|
199
|
+
def add_plugin_configs(options)
|
200
|
+
if @jdbc_driver_library
|
201
|
+
options["jdbc_driver_library"] = @jdbc_driver_library
|
202
|
+
end
|
203
|
+
if @jdbc_driver_class
|
204
|
+
options["jdbc_driver_class"] = @jdbc_driver_class
|
205
|
+
end
|
206
|
+
if @jdbc_connection_string
|
207
|
+
options["jdbc_connection_string"] = @jdbc_connection_string
|
208
|
+
end
|
209
|
+
if @jdbc_user
|
210
|
+
options["jdbc_user"] = @jdbc_user
|
211
|
+
end
|
212
|
+
if @jdbc_password
|
213
|
+
options["jdbc_password"] = @jdbc_password
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end end end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'logstash-filter-jdbc_static'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.licenses = ['Apache License (2.0)']
|
5
|
+
s.summary = "This filter executes a SQL query to fetch a SQL query result, store it locally then use a second SQL query to update an event."
|
6
|
+
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
|
7
|
+
s.authors = ["Elastic"]
|
8
|
+
s.email = 'info@elastic.co'
|
9
|
+
s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
|
10
|
+
# to fool jar_dependencies to mimic our other plugin gradle vendor script behaviour
|
11
|
+
# the rake vendor task removes jars dir and jars downloaded to it
|
12
|
+
s.require_paths = ["lib", "jars"]
|
13
|
+
|
14
|
+
# Files
|
15
|
+
s.files = Dir['lib/**/*','vendor/**/*','spec/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
|
16
|
+
# Tests
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
|
19
|
+
# Special flag to let us know this is actually a logstash plugin
|
20
|
+
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
|
21
|
+
|
22
|
+
derby_version = "10.14.1.0"
|
23
|
+
s.requirements << "jar 'org.apache.derby:derby', '#{derby_version}'"
|
24
|
+
s.requirements << "jar 'org.apache.derby:derbyclient', '#{derby_version}'"
|
25
|
+
# we may need 'org.apache.derby:derbynet' in the future, marking this here
|
26
|
+
|
27
|
+
s.add_development_dependency 'jar-dependencies', '~> 0.3'
|
28
|
+
|
29
|
+
# Gem dependencies
|
30
|
+
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
31
|
+
s.add_runtime_dependency 'sequel'
|
32
|
+
s.add_runtime_dependency 'tzinfo'
|
33
|
+
s.add_runtime_dependency 'tzinfo-data'
|
34
|
+
s.add_runtime_dependency 'rufus-scheduler'
|
35
|
+
|
36
|
+
s.add_development_dependency 'logstash-devutils'
|
37
|
+
s.add_development_dependency "childprocess"
|
38
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# use the rspec --require command line option to have this file evaluated before rspec runs
|
4
|
+
# it i
|
5
|
+
|
6
|
+
GEM_BASE_DIR = ::File.expand_path("../../..", __FILE__)
|
7
|
+
BASE_DERBY_DIR = ::File.join(GEM_BASE_DIR, "spec", "helpers")
|
8
|
+
ENV["HOME"] = GEM_BASE_DIR
|
9
|
+
ENV["TEST_DEBUG"] = "true"
|
10
|
+
java.lang.System.setProperty("ls.logs", "console")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/filters/jdbc/column"
|
4
|
+
|
5
|
+
describe LogStash::Filters::Jdbc::Column do
|
6
|
+
let(:invalid_messages) do
|
7
|
+
[
|
8
|
+
"The column options must be an array",
|
9
|
+
"The first column option is the name and must be a string",
|
10
|
+
"The second column option is the datatype and must be a string"
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
context "various invalid non-array arguments" do
|
15
|
+
it "a nil does not validate" do
|
16
|
+
instance = described_class.new(nil)
|
17
|
+
expect(instance.valid?).to be_falsey
|
18
|
+
expect(instance.formatted_errors).to eq(invalid_messages.join(", "))
|
19
|
+
end
|
20
|
+
|
21
|
+
it "a string does not validate" do
|
22
|
+
instance = described_class.new("foo")
|
23
|
+
expect(instance.valid?).to be_falsey
|
24
|
+
expect(instance.formatted_errors).to eq(invalid_messages.values_at(0,2).join(", "))
|
25
|
+
end
|
26
|
+
|
27
|
+
it "a number does not validate" do
|
28
|
+
instance = described_class.new(42)
|
29
|
+
expect(instance.valid?).to be_falsey
|
30
|
+
expect(instance.formatted_errors).to eq(invalid_messages.join(", "))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "various invalid array arguments" do
|
35
|
+
it "a single string element does not validate" do
|
36
|
+
instance = described_class.new(["foo"])
|
37
|
+
expect(instance.valid?).to be_falsey
|
38
|
+
expect(instance.formatted_errors).to eq(invalid_messages.last)
|
39
|
+
end
|
40
|
+
[ [], [1, 2] ].each do |arg|
|
41
|
+
it "do not validate" do
|
42
|
+
instance = described_class.new(arg)
|
43
|
+
expect(instance.valid?).to be_falsey
|
44
|
+
expect(instance.formatted_errors).to eq(invalid_messages.values_at(1,2).join(", "))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
[ ["foo", 3], ["foo", nil] ].each do |arg|
|
48
|
+
it "do not validate" do
|
49
|
+
instance = described_class.new(arg)
|
50
|
+
expect(instance.valid?).to be_falsey
|
51
|
+
expect(instance.formatted_errors).to eq(invalid_messages.last)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
[ [3, "foo"], [nil, "foo"] ].each do |arg|
|
55
|
+
it "do not validate" do
|
56
|
+
instance = described_class.new(arg)
|
57
|
+
expect(instance.valid?).to be_falsey
|
58
|
+
expect(instance.formatted_errors).to eq(invalid_messages[1])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "a valid array argument" do
|
64
|
+
it "does validate" do
|
65
|
+
instance = described_class.new(["foo", "varchar2"])
|
66
|
+
expect(instance.valid?).to be_truthy
|
67
|
+
expect(instance.formatted_errors).to eq("")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/filters/jdbc/db_object"
|
4
|
+
|
5
|
+
describe LogStash::Filters::Jdbc::DbObject do
|
6
|
+
context "various invalid non-hash arguments" do
|
7
|
+
it "a nil does not validate" do
|
8
|
+
instance = described_class.new(nil)
|
9
|
+
expect(instance.valid?).to be_falsey
|
10
|
+
expect(instance.formatted_errors).to eq("DbObject options must be a Hash")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "a string does not validate" do
|
14
|
+
instance = described_class.new("foo")
|
15
|
+
expect(instance.valid?).to be_falsey
|
16
|
+
expect(instance.formatted_errors).to eq("DbObject options must be a Hash")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "a number does not validate" do
|
20
|
+
instance = described_class.new(42)
|
21
|
+
expect(instance.valid?).to be_falsey
|
22
|
+
expect(instance.formatted_errors).to eq("DbObject options must be a Hash")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "various invalid hash arguments" do
|
27
|
+
let(:error_messages) do
|
28
|
+
[
|
29
|
+
"DbObject options must include a 'name' string",
|
30
|
+
"DbObject options for 'foo' must include a 'columns' array"
|
31
|
+
]
|
32
|
+
end
|
33
|
+
"DbObject options must include a 'name' string, DbObject options for 'unnamed' must include a 'columns' array"
|
34
|
+
it "an empty hash does not validate" do
|
35
|
+
instance = described_class.new({})
|
36
|
+
expect(instance.valid?).to be_falsey
|
37
|
+
expect(instance.formatted_errors).to eq(error_messages.values_at(0,1).join(", ").gsub('foo', 'unnamed'))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "a name key value only" do
|
41
|
+
instance = described_class.new({"name" => "foo"})
|
42
|
+
expect(instance.valid?).to be_falsey
|
43
|
+
expect(instance.formatted_errors).to eq(error_messages[1])
|
44
|
+
end
|
45
|
+
|
46
|
+
it "a name and bad columns" do
|
47
|
+
instance = described_class.new({"name" => "foo", "columns" => 42})
|
48
|
+
expect(instance.valid?).to be_falsey
|
49
|
+
expect(instance.formatted_errors).to eq(error_messages[1])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "a name and bad columns - empty array" do
|
53
|
+
instance = described_class.new({"name" => "foo", "columns" => []})
|
54
|
+
expect(instance.valid?).to be_falsey
|
55
|
+
msg = "The columns array for 'foo' is not uniform, it should contain arrays of two strings only"
|
56
|
+
expect(instance.formatted_errors).to eq(msg)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "a name and bad columns - irregular arrays" do
|
60
|
+
instance = described_class.new({"name" => "foo", "columns" => [["ip", "text"], ["name"], ["a", "b", "c"]]})
|
61
|
+
expect(instance.valid?).to be_falsey
|
62
|
+
msg = "The columns array for 'foo' is not uniform, it should contain arrays of two strings only"
|
63
|
+
expect(instance.formatted_errors).to eq(msg)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "a name, good columns and bad index_column" do
|
67
|
+
instance = described_class.new({"name" => "foo_index", "index_columns" => ["bar"], "columns" => [["ip", "text"], ["name", "text"]]})
|
68
|
+
expect(instance.valid?).to be_falsey
|
69
|
+
msg = "The index_columns element: 'bar' must be a column defined in the columns array"
|
70
|
+
expect(instance.formatted_errors).to eq(msg)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "a valid hash argument" do
|
75
|
+
it "does validate" do
|
76
|
+
instance = described_class.new({"name" => "foo", "index_columns" => ["ip"], "columns" => [["ip", "text"], ["name", "text"]]})
|
77
|
+
expect(instance.formatted_errors).to eq("")
|
78
|
+
expect(instance.valid?).to be_truthy
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|