logstash-core 2.1.3-java → 2.2.0-java

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.

Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core.rb +1 -3
  3. data/lib/logstash-core/logstash-core.rb +3 -0
  4. data/lib/logstash-core/version.rb +8 -0
  5. data/lib/logstash/agent.rb +48 -20
  6. data/lib/logstash/codecs/base.rb +2 -2
  7. data/lib/logstash/config/config_ast.rb +8 -3
  8. data/lib/logstash/environment.rb +0 -16
  9. data/lib/logstash/filters/base.rb +9 -5
  10. data/lib/logstash/inputs/base.rb +1 -1
  11. data/lib/logstash/output_delegator.rb +150 -0
  12. data/lib/logstash/outputs/base.rb +37 -40
  13. data/lib/logstash/pipeline.rb +259 -178
  14. data/lib/logstash/pipeline_reporter.rb +114 -0
  15. data/lib/logstash/plugin.rb +1 -1
  16. data/lib/logstash/{shutdown_controller.rb → shutdown_watcher.rb} +10 -37
  17. data/lib/logstash/util.rb +17 -0
  18. data/lib/logstash/util/decorators.rb +14 -7
  19. data/lib/logstash/util/worker_threads_default_printer.rb +4 -4
  20. data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
  21. data/lib/logstash/version.rb +10 -2
  22. data/locales/en.yml +8 -3
  23. data/logstash-core.gemspec +5 -3
  24. data/spec/{core/conditionals_spec.rb → conditionals_spec.rb} +0 -0
  25. data/spec/{core/config_spec.rb → logstash/config/config_ast_spec.rb} +0 -0
  26. data/spec/{core/config_cpu_core_strategy_spec.rb → logstash/config/cpu_core_strategy_spec.rb} +0 -0
  27. data/spec/{core/config_defaults_spec.rb → logstash/config/defaults_spec.rb} +0 -0
  28. data/spec/{core/config_mixin_spec.rb → logstash/config/mixin_spec.rb} +0 -0
  29. data/spec/{core → logstash}/environment_spec.rb +0 -0
  30. data/spec/{filters → logstash/filters}/base_spec.rb +0 -0
  31. data/spec/{inputs → logstash/inputs}/base_spec.rb +0 -0
  32. data/spec/{lib/logstash → logstash}/java_integration_spec.rb +0 -0
  33. data/spec/{util → logstash}/json_spec.rb +0 -0
  34. data/spec/logstash/output_delegator_spec.rb +126 -0
  35. data/spec/logstash/outputs/base_spec.rb +40 -0
  36. data/spec/logstash/pipeline_reporter_spec.rb +85 -0
  37. data/spec/{core → logstash}/pipeline_spec.rb +128 -16
  38. data/spec/{core → logstash}/plugin_spec.rb +47 -1
  39. data/spec/logstash/runner_spec.rb +68 -0
  40. data/spec/{core/shutdown_controller_spec.rb → logstash/shutdown_watcher_spec.rb} +17 -11
  41. data/spec/{util → logstash/util}/buftok_spec.rb +0 -0
  42. data/spec/{util → logstash/util}/charset_spec.rb +0 -0
  43. data/spec/{util → logstash/util}/defaults_printer_spec.rb +4 -4
  44. data/spec/{util → logstash/util}/java_version_spec.rb +0 -0
  45. data/spec/{util → logstash/util}/plugin_version_spec.rb +0 -0
  46. data/spec/{util → logstash/util}/unicode_trimmer_spec.rb +0 -0
  47. data/spec/{util → logstash/util}/worker_threads_default_printer_spec.rb +8 -8
  48. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
  49. data/spec/{util_spec.rb → logstash/util_spec.rb} +0 -0
  50. metadata +74 -81
  51. data/lib/logstash/event.rb +0 -275
  52. data/lib/logstash/patches/bundler.rb +0 -36
  53. data/lib/logstash/sized_queue.rb +0 -8
  54. data/lib/logstash/string_interpolation.rb +0 -140
  55. data/lib/logstash/timestamp.rb +0 -97
  56. data/lib/logstash/util/accessors.rb +0 -123
  57. data/spec/core/event_spec.rb +0 -518
  58. data/spec/core/runner_spec.rb +0 -40
  59. data/spec/core/timestamp_spec.rb +0 -84
  60. data/spec/coverage_helper.rb +0 -24
  61. data/spec/lib/logstash/bundler_spec.rb +0 -121
  62. data/spec/license_spec.rb +0 -67
  63. data/spec/outputs/base_spec.rb +0 -26
  64. data/spec/plugin_manager/install_spec.rb +0 -28
  65. data/spec/plugin_manager/update_spec.rb +0 -39
  66. data/spec/plugin_manager/util_spec.rb +0 -71
  67. data/spec/spec_helper.rb +0 -11
  68. data/spec/util/accessors_spec.rb +0 -170
  69. data/spec/util/compress_spec.rb +0 -121
  70. data/spec/util/gemfile_spec.rb +0 -212
  71. data/spec/util/retryable_spec.rb +0 -139
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+ require 'ostruct'
3
+
4
+ module LogStash; class PipelineReporter
5
+ attr_reader :logger, :pipeline
6
+
7
+ # This is an immutable copy of the pipeline state,
8
+ # It is a proxy to a hash to allow us to add methods dynamically to the hash
9
+ class Snapshot
10
+ def initialize(data)
11
+ @data = data
12
+ end
13
+
14
+ def to_hash
15
+ @data
16
+ end
17
+
18
+ def to_simple_hash
19
+ {"inflight_count" => inflight_count, "stalling_thread_info" => format_threads_by_plugin}
20
+ end
21
+
22
+ def to_str
23
+ to_simple_hash.to_s
24
+ end
25
+ alias_method :to_s, :to_str
26
+
27
+ def method_missing(meth)
28
+ @data[meth]
29
+ end
30
+
31
+ def format_threads_by_plugin
32
+ stalled_plugins = {}
33
+ stalling_threads_info.each do |thr|
34
+ key = (thr.delete("plugin") || "other")
35
+ stalled_plugins[key] ||= []
36
+ stalled_plugins[key] << thr
37
+ end
38
+ stalled_plugins
39
+ end
40
+ end
41
+
42
+ def initialize(logger,pipeline)
43
+ @logger = logger
44
+ @pipeline = pipeline
45
+ end
46
+
47
+ # The main way of accessing data from the reporter,,
48
+ # this provides a (more or less) consistent snapshot of what's going on in the
49
+ # pipeline with some extra decoration
50
+ def snapshot
51
+ Snapshot.new(self.to_hash)
52
+ end
53
+
54
+ def to_hash
55
+ pipeline.inflight_batches_synchronize do |batch_map|
56
+ worker_states_snap = worker_states(batch_map) # We only want to run this once
57
+ inflight_count = worker_states_snap.map {|s| s[:inflight_count] }.reduce(0, :+)
58
+
59
+ {
60
+ :events_filtered => events_filtered,
61
+ :events_consumed => events_consumed,
62
+ :worker_count => pipeline.worker_threads.size,
63
+ :inflight_count => inflight_count,
64
+ :worker_states => worker_states_snap,
65
+ :output_info => output_info,
66
+ :thread_info => pipeline.plugin_threads_info,
67
+ :stalling_threads_info => pipeline.stalling_threads_info
68
+ }
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def events_filtered
75
+ pipeline.events_filtered.value
76
+ end
77
+
78
+ def events_consumed
79
+ pipeline.events_consumed.value
80
+ end
81
+
82
+ def plugin_threads
83
+ pipeline.plugin_threads
84
+ end
85
+
86
+ # Not threadsafe! must be called within an `inflight_batches_synchronize` block
87
+ def worker_states(batch_map)
88
+ pipeline.worker_threads.map.with_index do |thread,idx|
89
+ status = thread.status || "dead"
90
+ inflight_count = batch_map[thread] ? batch_map[thread].size : 0
91
+ {
92
+ :status => status,
93
+ :alive => thread.alive?,
94
+ :index => idx,
95
+ :inflight_count => inflight_count
96
+ }
97
+ end
98
+ end
99
+
100
+ def output_info
101
+ pipeline.outputs.map do |output_delegator|
102
+ is_multi_worker = output_delegator.worker_count > 1
103
+
104
+ {
105
+ :type => output_delegator.config_name,
106
+ :config => output_delegator.config,
107
+ :is_multi_worker => is_multi_worker,
108
+ :events_received => output_delegator.events_received,
109
+ :workers => output_delegator.workers,
110
+ :busy_workers => output_delegator.busy_workers
111
+ }
112
+ end
113
+ end
114
+ end end
@@ -24,7 +24,7 @@ class LogStash::Plugin
24
24
 
25
25
  public
26
26
  def initialize(params=nil)
27
- @params = params
27
+ @params = LogStash::Util.deep_clone(params)
28
28
  @logger = Cabin::Channel.get(LogStash)
29
29
  end
30
30
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module LogStash
4
- class ShutdownController
4
+ class ShutdownWatcher
5
5
 
6
6
  CHECK_EVERY = 1 # second
7
7
  REPORT_EVERY = 5 # checks
@@ -34,8 +34,8 @@ module LogStash
34
34
  end
35
35
 
36
36
  def self.start(pipeline, cycle_period=CHECK_EVERY, report_every=REPORT_EVERY, abort_threshold=ABORT_AFTER)
37
- controller = self.new(pipeline, cycle_period, report_every, abort_threshold)
38
- Thread.new(controller) { |controller| controller.start }
37
+ watcher = self.new(pipeline, cycle_period, report_every, abort_threshold)
38
+ Thread.new(watcher) { |watcher| watcher.start }
39
39
  end
40
40
 
41
41
  def logger
@@ -47,10 +47,10 @@ module LogStash
47
47
  cycle_number = 0
48
48
  stalled_count = 0
49
49
  Stud.interval(@cycle_period) do
50
- @reports << Report.from_pipeline(@pipeline)
50
+ @reports << pipeline_report_snapshot
51
51
  @reports.delete_at(0) if @reports.size > @report_every # expire old report
52
52
  if cycle_number == (@report_every - 1) # it's report time!
53
- logger.warn(@reports.last.to_hash)
53
+ logger.warn(@reports.last)
54
54
 
55
55
  if shutdown_stalled?
56
56
  logger.error("The shutdown process appears to be stalled due to busy or blocked plugins. Check the logs for more information.") if stalled_count == 0
@@ -69,6 +69,10 @@ module LogStash
69
69
  end
70
70
  end
71
71
 
72
+ def pipeline_report_snapshot
73
+ @pipeline.reporter.snapshot
74
+ end
75
+
72
76
  # A pipeline shutdown is stalled if
73
77
  # * at least REPORT_EVERY reports have been created
74
78
  # * the inflight event count is in monotonically increasing
@@ -78,7 +82,7 @@ module LogStash
78
82
  return false unless @reports.size == @report_every #
79
83
  # is stalled if inflight count is either constant or increasing
80
84
  stalled_event_count = @reports.each_cons(2).all? do |prev_report, next_report|
81
- prev_report.inflight_count["total"] <= next_report.inflight_count["total"]
85
+ prev_report.inflight_count <= next_report.inflight_count
82
86
  end
83
87
  if stalled_event_count
84
88
  @reports.each_cons(2).all? do |prev_report, next_report|
@@ -93,35 +97,4 @@ module LogStash
93
97
  exit(-1)
94
98
  end
95
99
  end
96
-
97
- class Report
98
-
99
- attr_reader :inflight_count, :stalling_threads
100
-
101
- def self.from_pipeline(pipeline)
102
- new(pipeline.inflight_count, pipeline.stalling_threads)
103
- end
104
-
105
- def initialize(inflight_count, stalling_threads)
106
- @inflight_count = inflight_count
107
- @stalling_threads = format_threads_by_plugin(stalling_threads)
108
- end
109
-
110
- def to_hash
111
- {
112
- "INFLIGHT_EVENT_COUNT" => @inflight_count,
113
- "STALLING_THREADS" => @stalling_threads
114
- }
115
- end
116
-
117
- def format_threads_by_plugin(stalling_threads)
118
- stalled_plugins = {}
119
- stalling_threads.each do |thr|
120
- key = (thr.delete("plugin") || "other")
121
- stalled_plugins[key] ||= []
122
- stalled_plugins[key] << thr
123
- end
124
- stalled_plugins
125
- end
126
- end
127
100
  end
@@ -183,4 +183,21 @@ module LogStash::Util
183
183
  o
184
184
  end
185
185
  end
186
+
187
+ def self.deep_clone(o)
188
+ case o
189
+ when Hash
190
+ o.inject({}) {|h, (k,v)| h[k] = deep_clone(v); h }
191
+ when Array
192
+ o.map {|v| deep_clone(v) }
193
+ when Fixnum, Symbol, IO, TrueClass, FalseClass, NilClass
194
+ o
195
+ when LogStash::Codecs::Base
196
+ o.clone
197
+ when String
198
+ o.clone #need to keep internal state e.g. frozen
199
+ else
200
+ Marshal.load(Marshal.dump(o))
201
+ end
202
+ end
186
203
  end # module LogStash::Util
@@ -19,13 +19,16 @@ module LogStash::Util
19
19
  value.each do |v|
20
20
  v = event.sprintf(v)
21
21
  if event.include?(field)
22
- event[field] = Array(event[field])
23
- event[field] << v
22
+ # note below that the array field needs to be updated then reassigned to the event.
23
+ # this is important because a construct like event[field] << v will not work
24
+ # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
25
+ a = Array(event[field])
26
+ a << v
27
+ event[field] = a
24
28
  else
25
29
  event[field] = v
26
30
  end
27
- @logger.debug? and @logger.debug("#{pluginname}: adding value to field",
28
- :field => field, :value => value)
31
+ @logger.debug? and @logger.debug("#{pluginname}: adding value to field", :field => field, :value => value)
29
32
  end
30
33
  end
31
34
  end
@@ -34,9 +37,13 @@ module LogStash::Util
34
37
  def add_tags(tags, event, pluginname)
35
38
  tags.each do |tag|
36
39
  tag = event.sprintf(tag)
37
- @logger.debug? and @logger.debug("#{pluginname}: adding tag",
38
- :tag => tag)
39
- (event["tags"] ||= []) << tag
40
+ @logger.debug? and @logger.debug("#{pluginname}: adding tag", :tag => tag)
41
+ # note below that the tags array field needs to be updated then reassigned to the event.
42
+ # this is important because a construct like event["tags"] << tag will not work
43
+ # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
44
+ tags = event["tags"] || []
45
+ tags << tag
46
+ event["tags"] = tags
40
47
  end
41
48
  end
42
49
 
@@ -6,8 +6,8 @@ require "logstash/util"
6
6
  module LogStash module Util class WorkerThreadsDefaultPrinter
7
7
 
8
8
  def initialize(settings)
9
- @setting = settings.fetch('filter-workers', 0)
10
- @default = settings.fetch('default-filter-workers', 0)
9
+ @setting = settings.fetch(:pipeline_workers, 0)
10
+ @default = settings.fetch(:default_pipeline_workers, 0)
11
11
  end
12
12
 
13
13
  def visit(collector)
@@ -17,12 +17,12 @@ module LogStash module Util class WorkerThreadsDefaultPrinter
17
17
 
18
18
  def visit_setting(collector)
19
19
  return if @setting == 0
20
- collector.push("User set filter workers: #{@setting}")
20
+ collector.push("User set pipeline workers: #{@setting}")
21
21
  end
22
22
 
23
23
  def visit_default(collector)
24
24
  return if @default == 0
25
- collector.push "Default filter workers: #{@default}"
25
+ collector.push "Default pipeline workers: #{@default}"
26
26
  end
27
27
 
28
28
  end end end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module LogStash; module Util
4
+ class WrappedSynchronousQueue
5
+ java_import java.util.concurrent.SynchronousQueue
6
+ java_import java.util.concurrent.TimeUnit
7
+
8
+ def initialize()
9
+ @queue = java.util.concurrent.SynchronousQueue.new()
10
+ end
11
+
12
+ # Push an object to the queue if the queue is full
13
+ # it will block until the object can be added to the queue.
14
+ #
15
+ # @param [Object] Object to add to the queue
16
+ def push(obj)
17
+ @queue.put(obj)
18
+ end
19
+ alias_method(:<<, :push)
20
+
21
+ # Offer an object to the queue, wait for the specified amout of time.
22
+ # If adding to the queue was successfull it wil return true, false otherwise.
23
+ #
24
+ # @param [Object] Object to add to the queue
25
+ # @param [Integer] Time in milliseconds to wait before giving up
26
+ # @return [Boolean] True if adding was successfull if not it return false
27
+ def offer(obj, timeout_ms)
28
+ @queue.offer(obj, timeout_ms, TimeUnit::MILLISECONDS)
29
+ end
30
+
31
+ # Blocking
32
+ def take
33
+ @queue.take()
34
+ end
35
+
36
+ # Block for X millis
37
+ def poll(millis)
38
+ @queue.poll(millis, TimeUnit::MILLISECONDS)
39
+ end
40
+ end
41
+ end end
@@ -1,6 +1,14 @@
1
1
  # encoding: utf-8
2
- # The version of logstash.
3
- LOGSTASH_VERSION = "2.1.3"
4
2
 
3
+ # The version of the logstash package (not the logstash-core gem version).
4
+ #
5
5
  # Note to authors: this should not include dashes because 'gem' barfs if
6
6
  # you include a dash in the version string.
7
+
8
+ # TODO: (colin) the logstash-core gem uses it's own version number in logstash-core/lib/logstash-core/version.rb
9
+ # there are some dependencies in logstash-core on the LOGSTASH_VERSION constant this is why
10
+ # the logstash version is currently defined here in logstash-core/lib/logstash/version.rb but
11
+ # eventually this file should be in the root logstash lib fir and dependencies in logstash-core should be
12
+ # fixed.
13
+
14
+ LOGSTASH_VERSION = "2.2.0"
@@ -37,7 +37,7 @@ en:
37
37
  output-worker-unsupported-with-message: >-
38
38
  %{plugin} output plugin: setting 'workers => %{worker_count}' is not
39
39
  supported by this plugin. I will continue working as if you had not set
40
- this setting.
40
+ this setting. Reason: %{message}
41
41
  plugin:
42
42
  deprecated_milestone: >-
43
43
  %{plugin} plugin is using the 'milestone' method to declare the version
@@ -155,8 +155,13 @@ en:
155
155
  the empty string for the '-e' flag.
156
156
  configtest: |+
157
157
  Check configuration for valid syntax and then exit.
158
- filterworkers: |+
159
- Sets the number of filter workers to run.
158
+ pipeline-workers: |+
159
+ Sets the number of pipeline workers to run.
160
+ pipeline-batch-size: |+
161
+ Size of batches the pipeline is to work in.
162
+ pipeline-batch-delay: |+
163
+ When creating pipeline batches, how long to wait while polling
164
+ for the next event.
160
165
  log: |+
161
166
  Write logstash internal logs to the given
162
167
  file. Without this flag, logstash will emit
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'logstash/version'
4
+ require 'logstash-core/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.authors = ["Jordan Sissel", "Pete Fritchman", "Elasticsearch"]
@@ -11,11 +11,13 @@ Gem::Specification.new do |gem|
11
11
  gem.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
12
12
  gem.license = "Apache License (2.0)"
13
13
 
14
- gem.files = Dir.glob(["logstash-core.gemspec", "lib/logstash-core.rb", "lib/logstash/**/*.rb", "spec/**/*.rb", "locales/*"])
14
+ gem.files = Dir.glob(["logstash-core.gemspec", "lib/**/*.rb", "spec/**/*.rb", "locales/*"])
15
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
16
  gem.name = "logstash-core"
17
17
  gem.require_paths = ["lib"]
18
- gem.version = LOGSTASH_VERSION.gsub(/-/, '.')
18
+ gem.version = LOGSTASH_CORE_VERSION
19
+
20
+ gem.add_runtime_dependency "logstash-core-event", "~> 2.2.0"
19
21
 
20
22
  gem.add_runtime_dependency "cabin", "~> 0.7.0" #(Apache 2.0 license)
21
23
  gem.add_runtime_dependency "pry", "~> 0.10.1" #(Ruby license)
File without changes
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe LogStash::OutputDelegator do
5
+ let(:logger) { double("logger") }
6
+ let(:events) { 7.times.map { LogStash::Event.new }}
7
+ let(:default_worker_count) { 1 }
8
+
9
+ subject { described_class.new(logger, out_klass, default_worker_count) }
10
+
11
+ context "with a plain output plugin" do
12
+ let(:out_klass) { double("output klass") }
13
+ let(:out_inst) { double("output instance") }
14
+
15
+ before do
16
+ allow(out_klass).to receive(:new).with(any_args).and_return(out_inst)
17
+ allow(out_klass).to receive(:threadsafe?).and_return(false)
18
+ allow(out_klass).to receive(:workers_not_supported?).and_return(false)
19
+ allow(out_inst).to receive(:register)
20
+ allow(out_inst).to receive(:multi_receive)
21
+ allow(logger).to receive(:debug).with(any_args)
22
+ end
23
+
24
+ it "should initialize cleanly" do
25
+ expect { subject }.not_to raise_error
26
+ end
27
+
28
+ context "after having received a batch of events" do
29
+ before do
30
+ subject.multi_receive(events)
31
+ end
32
+
33
+ it "should pass the events through" do
34
+ expect(out_inst).to have_received(:multi_receive).with(events)
35
+ end
36
+
37
+ it "should increment the number of events received" do
38
+ expect(subject.events_received).to eql(events.length)
39
+ end
40
+ end
41
+
42
+ it "should register all workers on register" do
43
+ expect(out_inst).to receive(:register)
44
+ subject.register
45
+ end
46
+
47
+ it "should close all workers when closing" do
48
+ expect(out_inst).to receive(:do_close)
49
+ subject.do_close
50
+ end
51
+
52
+ describe "concurrency and worker support" do
53
+ describe "non-threadsafe outputs that allow workers" do
54
+ let(:default_worker_count) { 3 }
55
+
56
+ before do
57
+ allow(out_klass).to receive(:threadsafe?).and_return(false)
58
+ allow(out_klass).to receive(:workers_not_supported?).and_return(false)
59
+ end
60
+
61
+ it "should instantiate multiple workers" do
62
+ expect(subject.workers.length).to eql(default_worker_count)
63
+ end
64
+
65
+ it "should send received events to the worker" do
66
+ expect(out_inst).to receive(:multi_receive).with(events)
67
+ subject.multi_receive(events)
68
+ end
69
+ end
70
+
71
+ describe "threadsafe outputs" do
72
+ before do
73
+ allow(out_klass).to receive(:threadsafe?).and_return(true)
74
+ allow(out_klass).to receive(:workers_not_supported?).and_return(false)
75
+ end
76
+
77
+ it "should return true when threadsafe? is invoked" do
78
+ expect(subject.threadsafe?).to eql(true)
79
+ end
80
+
81
+ it "should define a threadsafe_worker" do
82
+ expect(subject.send(:threadsafe_worker)).to eql(out_inst)
83
+ end
84
+
85
+ it "should utilize threadsafe_multi_receive" do
86
+ expect(subject.send(:threadsafe_worker)).to receive(:multi_receive).with(events)
87
+ subject.multi_receive(events)
88
+ end
89
+
90
+ it "should not utilize the worker queue" do
91
+ expect(subject.send(:worker_queue)).not_to receive(:pop)
92
+ subject.multi_receive(events)
93
+ end
94
+
95
+ it "should send received events to the worker" do
96
+ expect(out_inst).to receive(:multi_receive).with(events)
97
+ subject.multi_receive(events)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # This may seem suspiciously similar to the class in outputs/base_spec
104
+ # but, in fact, we need a whole new class because using this even once
105
+ # will immutably modify the base class
106
+ class LogStash::Outputs::NOOPDelLegacyNoWorkers < ::LogStash::Outputs::Base
107
+ LEGACY_WORKERS_NOT_SUPPORTED_REASON = "legacy reason"
108
+
109
+ def register
110
+ workers_not_supported(LEGACY_WORKERS_NOT_SUPPORTED_REASON)
111
+ end
112
+ end
113
+
114
+ describe "legacy output workers_not_supported" do
115
+ let(:default_worker_count) { 2 }
116
+ let(:out_klass) { LogStash::Outputs::NOOPDelLegacyNoWorkers }
117
+
118
+ before do
119
+ allow(logger).to receive(:debug).with(any_args)
120
+ end
121
+
122
+ it "should only setup one worker" do
123
+ expect(subject.worker_count).to eql(1)
124
+ end
125
+ end
126
+ end