logstash-core 2.2.4.snapshot1
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.
Potentially problematic release.
This version of logstash-core might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/lib/logstash-core.rb +1 -0
- data/lib/logstash-core/logstash-core.rb +3 -0
- data/lib/logstash-core/version.rb +8 -0
- data/lib/logstash/agent.rb +391 -0
- data/lib/logstash/codecs/base.rb +50 -0
- data/lib/logstash/config/config_ast.rb +550 -0
- data/lib/logstash/config/cpu_core_strategy.rb +32 -0
- data/lib/logstash/config/defaults.rb +12 -0
- data/lib/logstash/config/file.rb +39 -0
- data/lib/logstash/config/grammar.rb +3503 -0
- data/lib/logstash/config/mixin.rb +518 -0
- data/lib/logstash/config/registry.rb +13 -0
- data/lib/logstash/environment.rb +98 -0
- data/lib/logstash/errors.rb +12 -0
- data/lib/logstash/filters/base.rb +205 -0
- data/lib/logstash/inputs/base.rb +116 -0
- data/lib/logstash/inputs/threadable.rb +18 -0
- data/lib/logstash/java_integration.rb +116 -0
- data/lib/logstash/json.rb +61 -0
- data/lib/logstash/logging.rb +91 -0
- data/lib/logstash/namespace.rb +13 -0
- data/lib/logstash/output_delegator.rb +172 -0
- data/lib/logstash/outputs/base.rb +91 -0
- data/lib/logstash/patches.rb +5 -0
- data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
- data/lib/logstash/patches/cabin.rb +35 -0
- data/lib/logstash/patches/profile_require_calls.rb +47 -0
- data/lib/logstash/patches/rubygems.rb +38 -0
- data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
- data/lib/logstash/pipeline.rb +499 -0
- data/lib/logstash/pipeline_reporter.rb +114 -0
- data/lib/logstash/plugin.rb +120 -0
- data/lib/logstash/program.rb +14 -0
- data/lib/logstash/runner.rb +124 -0
- data/lib/logstash/shutdown_watcher.rb +100 -0
- data/lib/logstash/util.rb +203 -0
- data/lib/logstash/util/buftok.rb +139 -0
- data/lib/logstash/util/charset.rb +35 -0
- data/lib/logstash/util/decorators.rb +52 -0
- data/lib/logstash/util/defaults_printer.rb +31 -0
- data/lib/logstash/util/filetools.rb +186 -0
- data/lib/logstash/util/java_version.rb +66 -0
- data/lib/logstash/util/password.rb +25 -0
- data/lib/logstash/util/plugin_version.rb +56 -0
- data/lib/logstash/util/prctl.rb +10 -0
- data/lib/logstash/util/retryable.rb +40 -0
- data/lib/logstash/util/socket_peer.rb +7 -0
- data/lib/logstash/util/unicode_trimmer.rb +81 -0
- data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
- data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
- data/lib/logstash/version.rb +14 -0
- data/locales/en.yml +204 -0
- data/logstash-core.gemspec +58 -0
- data/spec/conditionals_spec.rb +429 -0
- data/spec/logstash/agent_spec.rb +85 -0
- data/spec/logstash/config/config_ast_spec.rb +146 -0
- data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
- data/spec/logstash/config/defaults_spec.rb +10 -0
- data/spec/logstash/config/mixin_spec.rb +158 -0
- data/spec/logstash/environment_spec.rb +56 -0
- data/spec/logstash/filters/base_spec.rb +251 -0
- data/spec/logstash/inputs/base_spec.rb +74 -0
- data/spec/logstash/java_integration_spec.rb +304 -0
- data/spec/logstash/json_spec.rb +96 -0
- data/spec/logstash/output_delegator_spec.rb +144 -0
- data/spec/logstash/outputs/base_spec.rb +40 -0
- data/spec/logstash/patches_spec.rb +90 -0
- data/spec/logstash/pipeline_reporter_spec.rb +85 -0
- data/spec/logstash/pipeline_spec.rb +455 -0
- data/spec/logstash/plugin_spec.rb +169 -0
- data/spec/logstash/runner_spec.rb +68 -0
- data/spec/logstash/shutdown_watcher_spec.rb +113 -0
- data/spec/logstash/util/buftok_spec.rb +31 -0
- data/spec/logstash/util/charset_spec.rb +74 -0
- data/spec/logstash/util/defaults_printer_spec.rb +50 -0
- data/spec/logstash/util/java_version_spec.rb +79 -0
- data/spec/logstash/util/plugin_version_spec.rb +64 -0
- data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
- data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
- data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
- data/spec/logstash/util_spec.rb +35 -0
- metadata +364 -0
@@ -0,0 +1,169 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/plugin"
|
4
|
+
|
5
|
+
describe LogStash::Plugin do
|
6
|
+
it "should fail lookup on inexisting type" do
|
7
|
+
expect_any_instance_of(Cabin::Channel).to receive(:debug).once
|
8
|
+
expect { LogStash::Plugin.lookup("badbadtype", "badname") }.to raise_error(LogStash::PluginLoadingError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should fail lookup on inexisting name" do
|
12
|
+
expect_any_instance_of(Cabin::Channel).to receive(:debug).once
|
13
|
+
expect { LogStash::Plugin.lookup("filter", "badname") }.to raise_error(LogStash::PluginLoadingError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should fail on bad plugin class" do
|
17
|
+
LogStash::Filters::BadSuperClass = Class.new
|
18
|
+
expect { LogStash::Plugin.lookup("filter", "bad_super_class") }.to raise_error(LogStash::PluginLoadingError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should fail on missing config_name method" do
|
22
|
+
LogStash::Filters::MissingConfigName = Class.new(LogStash::Filters::Base)
|
23
|
+
expect { LogStash::Plugin.lookup("filter", "missing_config_name") }.to raise_error(LogStash::PluginLoadingError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should lookup an already defined plugin class" do
|
27
|
+
class LogStash::Filters::LadyGaga < LogStash::Filters::Base
|
28
|
+
config_name "lady_gaga"
|
29
|
+
end
|
30
|
+
expect(LogStash::Plugin.lookup("filter", "lady_gaga")).to eq(LogStash::Filters::LadyGaga)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#inspect" do
|
34
|
+
class LogStash::Filters::MyTestFilter < LogStash::Filters::Base
|
35
|
+
config_name "param1"
|
36
|
+
config :num, :validate => :number, :default => 20
|
37
|
+
config :str, :validate => :string, :default => "test"
|
38
|
+
end
|
39
|
+
subject { LogStash::Filters::MyTestFilter.new("num" => 1, "str" => "hello") }
|
40
|
+
|
41
|
+
it "should print the class of the filter" do
|
42
|
+
expect(subject.inspect).to match(/^<LogStash::Filters::MyTestFilter/)
|
43
|
+
end
|
44
|
+
it "should list config options and values" do
|
45
|
+
expect(subject.inspect).to match(/num=>1, str=>"hello"/)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when validating the plugin version" do
|
50
|
+
let(:plugin_name) { 'logstash-filter-stromae' }
|
51
|
+
subject do
|
52
|
+
Class.new(LogStash::Filters::Base) do
|
53
|
+
config_name 'stromae'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "doesn't warn the user if the version is superior or equal to 1.0.0" do
|
58
|
+
allow(Gem::Specification).to receive(:find_by_name)
|
59
|
+
.with(plugin_name)
|
60
|
+
.and_return(double(:version => Gem::Version.new('1.0.0')))
|
61
|
+
|
62
|
+
expect_any_instance_of(Cabin::Channel).not_to receive(:info)
|
63
|
+
subject.validate({})
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'warns the user if the plugin version is between 0.9.x and 1.0.0' do
|
67
|
+
allow(Gem::Specification).to receive(:find_by_name)
|
68
|
+
.with(plugin_name)
|
69
|
+
.and_return(double(:version => Gem::Version.new('0.9.1')))
|
70
|
+
|
71
|
+
expect_any_instance_of(Cabin::Channel).to receive(:info)
|
72
|
+
.with(/Using version 0.9.x/)
|
73
|
+
|
74
|
+
subject.validate({})
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'warns the user if the plugin version is inferior to 0.9.x' do
|
78
|
+
allow(Gem::Specification).to receive(:find_by_name)
|
79
|
+
.with(plugin_name)
|
80
|
+
.and_return(double(:version => Gem::Version.new('0.1.1')))
|
81
|
+
|
82
|
+
expect_any_instance_of(Cabin::Channel).to receive(:info)
|
83
|
+
.with(/Using version 0.1.x/)
|
84
|
+
subject.validate({})
|
85
|
+
end
|
86
|
+
|
87
|
+
it "doesnt show the version notice more than once" do
|
88
|
+
one_notice = Class.new(LogStash::Filters::Base) do
|
89
|
+
config_name "stromae"
|
90
|
+
end
|
91
|
+
|
92
|
+
allow(Gem::Specification).to receive(:find_by_name)
|
93
|
+
.with(plugin_name)
|
94
|
+
.and_return(double(:version => Gem::Version.new('0.1.1')))
|
95
|
+
|
96
|
+
expect_any_instance_of(Cabin::Channel).to receive(:info)
|
97
|
+
.once
|
98
|
+
.with(/Using version 0.1.x/)
|
99
|
+
|
100
|
+
one_notice.validate({})
|
101
|
+
one_notice.validate({})
|
102
|
+
end
|
103
|
+
|
104
|
+
it "warns the user if we can't find a defined version" do
|
105
|
+
expect_any_instance_of(Cabin::Channel).to receive(:warn)
|
106
|
+
.once
|
107
|
+
.with(/plugin doesn't have a version/)
|
108
|
+
|
109
|
+
subject.validate({})
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it 'logs a warning if the plugin use the milestone option' do
|
114
|
+
expect_any_instance_of(Cabin::Channel).to receive(:warn)
|
115
|
+
.with(/stromae plugin is using the 'milestone' method/)
|
116
|
+
|
117
|
+
class LogStash::Filters::Stromae < LogStash::Filters::Base
|
118
|
+
config_name "stromae"
|
119
|
+
milestone 2
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "subclass initialize" do
|
125
|
+
let(:args) { Hash.new }
|
126
|
+
|
127
|
+
[
|
128
|
+
StromaeCodec = Class.new(LogStash::Codecs::Base) do
|
129
|
+
config_name "stromae"
|
130
|
+
config :foo_tag, :validate => :string, :default => "bar"
|
131
|
+
end,
|
132
|
+
StromaeFilter = Class.new(LogStash::Filters::Base) do
|
133
|
+
config_name "stromae"
|
134
|
+
config :foo_tag, :validate => :string, :default => "bar"
|
135
|
+
end,
|
136
|
+
StromaeInput = Class.new(LogStash::Inputs::Base) do
|
137
|
+
config_name "stromae"
|
138
|
+
config :foo_tag, :validate => :string, :default => "bar"
|
139
|
+
end,
|
140
|
+
StromaeOutput = Class.new(LogStash::Outputs::Base) do
|
141
|
+
config_name "stromae"
|
142
|
+
config :foo_tag, :validate => :string, :default => "bar"
|
143
|
+
end
|
144
|
+
].each do |klass|
|
145
|
+
|
146
|
+
it "subclass #{klass.name} does not modify params" do
|
147
|
+
klass.new(args)
|
148
|
+
expect(args).to be_empty
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "codec initialization" do
|
153
|
+
|
154
|
+
class LogStash::Codecs::Noop < LogStash::Codecs::Base
|
155
|
+
config_name "noop"
|
156
|
+
|
157
|
+
config :format, :validate => :string
|
158
|
+
def register; end
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should only register once" do
|
162
|
+
args = { "codec" => LogStash::Codecs::Noop.new("format" => ".") }
|
163
|
+
expect_any_instance_of(LogStash::Codecs::Noop).to receive(:register).once
|
164
|
+
LogStash::Plugin.new(args)
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/runner"
|
4
|
+
require "stud/task"
|
5
|
+
require "stud/trap"
|
6
|
+
|
7
|
+
class NullRunner
|
8
|
+
def run(args); end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe LogStash::Runner do
|
12
|
+
|
13
|
+
context "argument parsing" do
|
14
|
+
it "should run agent" do
|
15
|
+
expect(Stud::Task).to receive(:new).once.and_return(nil)
|
16
|
+
args = ["agent", "-e", ""]
|
17
|
+
expect(subject.run(args)).to eq(nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should run agent help" do
|
21
|
+
expect(subject).to receive(:show_help).once.and_return(nil)
|
22
|
+
args = ["agent", "-h"]
|
23
|
+
expect(subject.run(args).wait).to eq(0)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should show help with no arguments" do
|
27
|
+
expect($stderr).to receive(:puts).once.and_return("No command given")
|
28
|
+
expect($stderr).to receive(:puts).once
|
29
|
+
args = []
|
30
|
+
expect(subject.run(args).wait).to eq(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should show help for unknown commands" do
|
34
|
+
expect($stderr).to receive(:puts).once.and_return("No such command welp")
|
35
|
+
expect($stderr).to receive(:puts).once
|
36
|
+
args = ["welp"]
|
37
|
+
expect(subject.run(args).wait).to eq(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "pipeline settings" do
|
42
|
+
let(:pipeline_string) { "input { stdin {} } output { stdout {} }" }
|
43
|
+
let(:base_pipeline_settings) { { :pipeline_id => "base", :debug_config => false } }
|
44
|
+
let(:pipeline) { double("pipeline") }
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
task = Stud::Task.new { 1 }
|
48
|
+
allow(pipeline).to receive(:run).and_return(task)
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when pipeline workers is not defined by the user" do
|
52
|
+
it "should not pass the value to the pipeline" do
|
53
|
+
expect(LogStash::Pipeline).to receive(:new).with(pipeline_string, base_pipeline_settings).and_return(pipeline)
|
54
|
+
args = ["agent", "-e", pipeline_string]
|
55
|
+
subject.run(args).wait
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when pipeline workers is defined by the user" do
|
60
|
+
it "should pass the value to the pipeline" do
|
61
|
+
base_pipeline_settings[:pipeline_workers] = 2
|
62
|
+
expect(LogStash::Pipeline).to receive(:new).with(pipeline_string, base_pipeline_settings).and_return(pipeline)
|
63
|
+
args = ["agent", "-w", "2", "-e", pipeline_string]
|
64
|
+
subject.run(args).wait
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/shutdown_watcher"
|
4
|
+
|
5
|
+
describe LogStash::ShutdownWatcher do
|
6
|
+
|
7
|
+
let(:check_every) { 0.01 }
|
8
|
+
let(:check_threshold) { 100 }
|
9
|
+
subject { LogStash::ShutdownWatcher.new(pipeline, check_every) }
|
10
|
+
let(:pipeline) { double("pipeline") }
|
11
|
+
let(:reporter) { double("reporter") }
|
12
|
+
let(:reporter_snapshot) { double("reporter snapshot") }
|
13
|
+
report_count = 0
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
allow(pipeline).to receive(:reporter).and_return(reporter)
|
17
|
+
allow(reporter).to receive(:snapshot).and_return(reporter_snapshot)
|
18
|
+
allow(reporter_snapshot).to receive(:o_simple_hash).and_return({})
|
19
|
+
|
20
|
+
allow(subject).to receive(:pipeline_report_snapshot).and_wrap_original do |m, *args|
|
21
|
+
report_count += 1
|
22
|
+
m.call(*args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
after :each do
|
27
|
+
report_count = 0
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when pipeline is stalled" do
|
31
|
+
let(:increasing_count) { (1..5000).to_a }
|
32
|
+
before :each do
|
33
|
+
allow(reporter_snapshot).to receive(:inflight_count).and_return(*increasing_count)
|
34
|
+
allow(reporter_snapshot).to receive(:stalling_threads) { { } }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".unsafe_shutdown = true" do
|
38
|
+
let(:abort_threshold) { subject.abort_threshold }
|
39
|
+
let(:report_every) { subject.report_every }
|
40
|
+
|
41
|
+
before :each do
|
42
|
+
subject.class.unsafe_shutdown = true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should force the shutdown" do
|
46
|
+
expect(subject).to receive(:force_exit).once
|
47
|
+
subject.start
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should do exactly \"abort_threshold\" stall checks" do
|
51
|
+
allow(subject).to receive(:force_exit)
|
52
|
+
expect(subject).to receive(:shutdown_stalled?).exactly(abort_threshold).times.and_call_original
|
53
|
+
subject.start
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should do exactly \"abort_threshold\"*\"report_every\" stall checks" do
|
57
|
+
allow(subject).to receive(:force_exit)
|
58
|
+
expect(subject).to receive(:pipeline_report_snapshot).exactly(abort_threshold*report_every).times.and_call_original
|
59
|
+
subject.start
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe ".unsafe_shutdown = false" do
|
64
|
+
|
65
|
+
before :each do
|
66
|
+
subject.class.unsafe_shutdown = false
|
67
|
+
end
|
68
|
+
|
69
|
+
it "shouldn't force the shutdown" do
|
70
|
+
expect(subject).to_not receive(:force_exit)
|
71
|
+
thread = Thread.new(subject) {|subject| subject.start }
|
72
|
+
sleep 0.1 until report_count > check_threshold
|
73
|
+
thread.kill
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when pipeline is not stalled" do
|
79
|
+
let(:decreasing_count) { (1..5000).to_a.reverse }
|
80
|
+
before :each do
|
81
|
+
allow(reporter_snapshot).to receive(:inflight_count).and_return(*decreasing_count)
|
82
|
+
allow(reporter_snapshot).to receive(:stalling_threads) { { } }
|
83
|
+
end
|
84
|
+
|
85
|
+
describe ".unsafe_shutdown = true" do
|
86
|
+
|
87
|
+
before :each do
|
88
|
+
subject.class.unsafe_shutdown = true
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should force the shutdown" do
|
92
|
+
expect(subject).to_not receive(:force_exit)
|
93
|
+
thread = Thread.new(subject) {|subject| subject.start }
|
94
|
+
sleep 0.1 until report_count > check_threshold
|
95
|
+
thread.kill
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe ".unsafe_shutdown = false" do
|
100
|
+
|
101
|
+
before :each do
|
102
|
+
subject.class.unsafe_shutdown = false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "shouldn't force the shutdown" do
|
106
|
+
expect(subject).to_not receive(:force_exit)
|
107
|
+
thread = Thread.new(subject) {|subject| subject.start }
|
108
|
+
sleep 0.1 until report_count > check_threshold
|
109
|
+
thread.kill
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/util/buftok"
|
4
|
+
|
5
|
+
describe FileWatch::BufferedTokenizer do
|
6
|
+
|
7
|
+
subject { FileWatch::BufferedTokenizer.new }
|
8
|
+
|
9
|
+
it "should tokenize a single token" do
|
10
|
+
expect(subject.extract("foo\n")).to eq(["foo"])
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should merge multiple token" do
|
14
|
+
expect(subject.extract("foo")).to eq([])
|
15
|
+
expect(subject.extract("bar\n")).to eq(["foobar"])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should tokenize multiple token" do
|
19
|
+
expect(subject.extract("foo\nbar\n")).to eq(["foo", "bar"])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should ignore empty payload" do
|
23
|
+
expect(subject.extract("")).to eq([])
|
24
|
+
expect(subject.extract("foo\nbar")).to eq(["foo"])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should tokenize empty payload with newline" do
|
28
|
+
expect(subject.extract("\n")).to eq([""])
|
29
|
+
expect(subject.extract("\n\n\n")).to eq(["", "", ""])
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/util/charset"
|
4
|
+
|
5
|
+
describe LogStash::Util::Charset do
|
6
|
+
let(:logger) { double("logger") }
|
7
|
+
|
8
|
+
context "with valid UTF-8 source encoding" do
|
9
|
+
subject {LogStash::Util::Charset.new("UTF-8")}
|
10
|
+
|
11
|
+
it "should return untouched data" do
|
12
|
+
["foobar", "κόσμε"].each do |data|
|
13
|
+
expect(data.encoding.name).to eq("UTF-8")
|
14
|
+
expect(subject.convert(data)).to eq(data)
|
15
|
+
expect(subject.convert(data).encoding.name).to eq("UTF-8")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "with invalid UTF-8 source encoding" do
|
21
|
+
subject do
|
22
|
+
LogStash::Util::Charset.new("UTF-8").tap do |charset|
|
23
|
+
charset.logger = logger
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should escape invalid sequences" do
|
28
|
+
["foo \xED\xB9\x81\xC3", "bar \xAD"].each do |data|
|
29
|
+
expect(data.encoding.name).to eq("UTF-8")
|
30
|
+
expect(data.valid_encoding?).to eq(false)
|
31
|
+
expect(logger).to receive(:warn).exactly(2).times
|
32
|
+
#logger.should_receive(:warn).twice
|
33
|
+
expect(subject.convert(data)).to eq(data.inspect[1..-2])
|
34
|
+
expect(subject.convert(data).encoding.name).to eq("UTF-8")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with valid non UTF-8 source encoding" do
|
41
|
+
subject {LogStash::Util::Charset.new("ISO-8859-1")}
|
42
|
+
|
43
|
+
it "should encode to UTF-8" do
|
44
|
+
samples = [
|
45
|
+
["foobar", "foobar"],
|
46
|
+
["\xE0 Montr\xE9al", "à Montréal"],
|
47
|
+
]
|
48
|
+
samples.map{|(a, b)| [a.force_encoding("ISO-8859-1"), b]}.each do |(a, b)|
|
49
|
+
expect(a.encoding.name).to eq("ISO-8859-1")
|
50
|
+
expect(b.encoding.name).to eq("UTF-8")
|
51
|
+
expect(a.valid_encoding?).to eq(true)
|
52
|
+
expect(subject.convert(a).encoding.name).to eq("UTF-8")
|
53
|
+
expect(subject.convert(a)).to eq(b)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with invalid non UTF-8 source encoding" do
|
59
|
+
subject {LogStash::Util::Charset.new("ASCII-8BIT")}
|
60
|
+
|
61
|
+
it "should encode to UTF-8 and replace invalid chars" do
|
62
|
+
samples = [
|
63
|
+
["\xE0 Montr\xE9al", "� Montr�al"],
|
64
|
+
["\xCE\xBA\xCF\x8C\xCF\x83\xCE\xBC\xCE\xB5", "����������"],
|
65
|
+
]
|
66
|
+
samples.map{|(a, b)| [a.force_encoding("ASCII-8BIT"), b]}.each do |(a, b)|
|
67
|
+
expect(a.encoding.name).to eq("ASCII-8BIT")
|
68
|
+
expect(b.encoding.name).to eq("UTF-8")
|
69
|
+
expect(subject.convert(a).encoding.name).to eq("UTF-8")
|
70
|
+
expect(subject.convert(a)).to eq(b)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|