logstash-mixin-ecs_compatibility_support 1.0.0-java → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba10e5399ac0d62b035fb98cbb351e9e3c2cc857a25fa541a18998072e40b20c
4
- data.tar.gz: e303a40b0d20f12de4bf57639957c59f12ca30db8e568b99136863e2246e3480
3
+ metadata.gz: 8a64fc499677faca675d99eccc08d8d397f6d1330b6073ce31ab1570a0e750d1
4
+ data.tar.gz: 6a4c3df642e4dc252d545069b4a7b301ecf246c2655b893409f1898643507353
5
5
  SHA512:
6
- metadata.gz: 65f069880870f66b57b018108fad026d440d665a8fc06fc49c14aeeca1f3e8c4c93e1abfbb2227e2bb87a61a85d8c6bdf220c4efb093e4781f398f5c4334a6da
7
- data.tar.gz: 9281a716c7101934d7803baf628b165cfed31716517eeaa8043e585710cb8ade34799b47891ef5679cfaa1342bbc79c107a52187178edf1873c50b77f125624b
6
+ metadata.gz: b84794d3a79993ecb23464e8293ee9f44d2430f6901c5f92f5dfcaa46e45fe09b5ee6f353afe8a8b36afa976f1bcc8b4ee69e123d2b665e5cb2b1228c9aea445
7
+ data.tar.gz: bb9d04088b8dcdd81a1ffefeb9ef1e5eec02e4fd24491684630e5c7e5c9a007121604c5b3435433f6a971b8e42eb2b0e926b1355fc0021e22f53a8de899cd433
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
- # 1.0.0
1
+ # 1.3.0
2
+ - Feat: introduce a target check helper [#6](https://github.com/logstash-plugins/logstash-mixin-ecs_compatibility_support/pull/6)
3
+
4
+ # 1.2.0
5
+ - Added support for resolution aliases, allowing a plugin that uses `ecs_select` to support multiple ECS versions with a single declaration.
2
6
 
7
+ # 1.1.0
8
+ - Added support for `ecs_select` helper, allowing plugins to declare mappings that are selected during plugin instantiation.
9
+
10
+ # 1.0.0
3
11
  - Support Mixin for ensuring a plugin has an `ecs_compatibility` method that is configurable from an `ecs_compatibility` option that accepts the literal `disabled` or a v-prefixed integer representing a major ECS version (e.g., `v1`), using the implementation from Logstash core if available.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ECS Compatibility Support Mixin
2
2
 
3
- [![Build Status](https://travis-ci.org/logstash-plugins/logstash-mixin-ecs_compatibility_support.svg?branch=master)](https://travis-ci.org/logstash-plugins/logstash-mixin-ecs_compatibility_support)
3
+ [![Build Status](https://travis-ci.com/logstash-plugins/logstash-mixin-ecs_compatibility_support.svg?branch=master)](https://travis-ci.com/logstash-plugins/logstash-mixin-ecs_compatibility_support)
4
4
 
5
5
  This gem provides an API-compatible implementation of ECS-compatiblity mode,
6
6
  allowing plugins to be explicitly configured with `ecs_compatibility` in a way
@@ -8,7 +8,7 @@ that respects pipeline- and process-level settings where they are available.
8
8
  It can be added as a dependency of any plugin that wishes to implement one or
9
9
  more ECS-compatibility modes while still supporting older Logstash versions.
10
10
 
11
- ## Usage
11
+ ## Usage (simple)
12
12
 
13
13
  1. Add version `~>1.0` of this gem as a runtime dependency of your Logstash plugin's `gemspec`:
14
14
 
@@ -57,8 +57,79 @@ more ECS-compatibility modes while still supporting older Logstash versions.
57
57
  end
58
58
  ~~~
59
59
 
60
+ ## Usage (advanced)
61
+
62
+ Release 1.1 of this support gem includes support for constraining a plugin
63
+ to only operate in specified ECS-Compatibility modes, and advanced support for
64
+ runtime selectors that provide developers a way to provide alternate _values_
65
+ during initialization based on the instantiated plugin's effective
66
+ `ecs_compatibility` mode. This is helpful in plugins that define large field
67
+ mappings, because it allows those mappings to be side-by-side where they are
68
+ unlikely to diverge and introduce bugs.
69
+
70
+ 1. Add version `~>1.2` of this gem as a runtime dependency of your Logstash plugin's `gemspec`:
71
+
72
+ ~~~ ruby
73
+ Gem::Specification.new do |s|
74
+ # ...
75
+
76
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
77
+ end
78
+ ~~~
79
+
80
+ 2. In your plugin code, require this library and include it into your plugin class
81
+ that already inherits `LogStash::Plugin`, but this time specify which versions
82
+ of ECS your plugin supports:
83
+
84
+ ~~~ ruby
85
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
86
+
87
+ class LogStash::Inputs::Foo < Logstash::Inputs::Base
88
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1)
89
+
90
+ # ...
91
+ end
92
+ ~~~
93
+
94
+ This prevents the plugin from being instantiated with an unsupported mode,
95
+ whether that mode was explicitly defined for the plugin instance or implictly
96
+ defined by the pipeline in which the plugin is run.
97
+
98
+ You can also optionally provide an alias mapping, for when your plugin supports
99
+ multiple versions of ECS that are largely identical to each other. This can be
100
+ especially helpful when using `ecs_select`.
101
+
102
+ ~~~ ruby
103
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
104
+
105
+ class LogStash::Inputs::Foo < Logstash::Inputs::Base
106
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1,:v8 => :v1)
107
+
108
+ # ...
109
+ end
110
+ ~~~
111
+
112
+ 3. As in the simple usage example, you can use the `ecs_compatibility` method.
113
+
114
+ But when supported versions are specified, you can also use the `ecs_select`
115
+ method to define alternates in-line. At runtime, the correct value will be
116
+ selected based on the current effective `ecs_compatibility` mode.
117
+
118
+ ~~~ ruby
119
+ def register
120
+ @field_hostname = ecs_select[disabled: "hostname", v1: "[host][name]"]
121
+ @field_hostip = ecs_select[disabled: "ip", v1: "[host][ip]" ]
122
+ end
123
+ ~~~
124
+
125
+ If you initialized the mixin with an alias mapping, missing values will
126
+ be resolved by their alias.
127
+
128
+ NOTE: `ecs_select` should only be used during plugin initialization and
129
+ not during event-by-event processing.
130
+
60
131
  ## Development
61
132
 
62
133
  This gem:
63
134
  - *MUST* remain API-stable at 1.x
64
- - *MUST NOT* introduce additional runtime dependencies
135
+ - *MUST NOT* introduce additional runtime dependencies
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../ecs_compatibility_support'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ECSCompatibilitySupport
8
+ # A `ECSCompatibilitySupport::Selector` is a `Module` that can be included into any `LogStash::Plugin`
9
+ # to constrain instances to a specific set of supported `ecs_compatibility` modes.
10
+ #
11
+ # It also provides an `ecs_select` that allows plugin developers to specify ECS alternatives
12
+ # in-line with their existing code.
13
+ #
14
+ # @api private
15
+ # @see ECSCompatibilitySupport()
16
+ class Selector < Module
17
+
18
+ ##
19
+ # @api internal (use: `LogStash::Plugin::include`)
20
+ # @param base [Class]: a class that inherits `LogStash::Plugin`, typically one
21
+ # descending from one of the four plugin base classes
22
+ # (e.g., `LogStash::Inputs::Base`)
23
+ # @return [void]
24
+ def included(base)
25
+ fail(ArgumentError, "`#{base}` must inherit LogStash::Plugin") unless base < LogStash::Plugin
26
+ base.include(ECSCompatibilitySupport)
27
+ end
28
+
29
+ EMPTY_HASH = {}.freeze
30
+ private_constant :EMPTY_HASH
31
+
32
+ ##
33
+ # @api private
34
+ # @see ECSCompatibilitySupport()
35
+ # @param ecs_modes_supported
36
+ def initialize(*ecs_modes_and_optional_alias_map)
37
+ selector_module = self
38
+
39
+ alias_mapping = ecs_modes_and_optional_alias_map.last.kind_of?(Hash) ? ecs_modes_and_optional_alias_map.pop.dup.freeze : EMPTY_HASH
40
+ ecs_modes_supported = ecs_modes_and_optional_alias_map.dup
41
+
42
+ fail(ArgumentError, "one or more ecs_modes_supported required") if ecs_modes_supported.empty?
43
+ fail(ArgumentError, "ecs_modes_supported must only contain symbols") unless ecs_modes_supported.all? { |s| s.kind_of?(Symbol) }
44
+
45
+ fail(ArgumentError, "alias names must be symbols") unless alias_mapping.keys.all? { |v| v.kind_of?(Symbol) }
46
+ fail(ArgumentError, "alias targets must be symbols") unless alias_mapping.values.all? { |v| v.kind_of?(Symbol) }
47
+ fail(ArgumentError, "alias must not redefine") if alias_mapping.keys.any? {|v| ecs_modes_supported.include?(v) }
48
+ fail(ArgumentError, "alias map must not have circular references") if circular_references_present?(alias_mapping)
49
+
50
+ ecs_modes_supported |= alias_mapping.keys
51
+
52
+ fail(ArgumentError, "alias target doesn't exist") if alias_mapping.values.any? { |v| !ecs_modes_supported.include?(v) }
53
+
54
+ ecs_modes_supported.freeze
55
+
56
+ ##
57
+ # Hooks initialization to throw a configuration error if plugin is initialized with
58
+ # an unsupported `ecs_compatibility` mode.
59
+ # @method initialize
60
+ define_method(:initialize) do |*args|
61
+ super(*args) # Plugin#initialize
62
+
63
+ effective_ecs_mode = ecs_compatibility
64
+ if !ecs_modes_supported.include?(effective_ecs_mode)
65
+ message = "#{config_name} #{@plugin_type} plugin does not support `ecs_compatibility => #{effective_ecs_mode}`. "+
66
+ "Supported modes are: #{ecs_modes_supported}"
67
+ fail(LogStash::ConfigurationError, message)
68
+ end
69
+ @_ecs_select = selector_module.state_for(effective_ecs_mode)
70
+ end
71
+
72
+ ##
73
+ # @method ecs_select
74
+ # @return [State]
75
+ define_method(:ecs_select) { @_ecs_select }
76
+
77
+ define_singleton_method(:ecs_modes_supported) { ecs_modes_supported }
78
+
79
+ define_singleton_method(:state_for) do |selected_value|
80
+ unless ecs_modes_supported.include?(selected_value)
81
+ fail(NotImplementedError, "Unsupported state `#{selected_value}` (expected one of #{ecs_modes_supported})")
82
+ end
83
+ State.new(ecs_modes_supported, selected_value, alias_mapping)
84
+ end
85
+ end
86
+
87
+ ##
88
+ # @return [String]
89
+ def name
90
+ "#{Selector}(#{ecs_modes_supported.join(',')})"
91
+ end
92
+
93
+ private
94
+
95
+ def circular_references_present?(alias_candidates)
96
+ alias_candidates.each do |candidate, target|
97
+ current = target
98
+ (alias_candidates.size + 1).times do
99
+ return true if current == candidate
100
+ break unless alias_candidates.include?(current)
101
+ current = alias_candidates.fetch(current)
102
+ end
103
+ end
104
+
105
+ false
106
+ end
107
+
108
+ ##
109
+ # A `State` contains the active mode and a list of all supported modes.
110
+ #
111
+ # It allows a developer to safely define mappings of alternative values, exactly
112
+ # one of which will be selected based on the effective mode.
113
+ #
114
+ # It is _NOT_ designed for performance, but may be helpful during instantiation.
115
+ #
116
+ # @api private
117
+ class State
118
+ ##
119
+ # @api private -- Use Selector#state_for(current_value)
120
+ # @param supported_modes [Array<Symbol>]
121
+ # @param active_mode [Symbol]
122
+ def initialize(supported_modes, active_mode, alias_map=EMPTY_HASH)
123
+ fail(ArgumentError, "invalid alias mapping") unless alias_map.flatten.all? {|v| supported_modes.include?(v) }
124
+
125
+ @supported_modes = supported_modes
126
+ @active_mode = active_mode
127
+ @alias_map = alias_map
128
+ end
129
+
130
+ attr_reader :active_mode
131
+ attr_reader :supported_modes
132
+
133
+ # With the active mode, select one of the provided options.
134
+ # @param defined_choices [Hash{Symbol=>Object}]: the options to chose between.
135
+ # it is an `ArgumentError` to provide a different set of
136
+ # options than those this `State` was initialized with.
137
+ # This ensures that all reachable code implements all
138
+ # supported options.
139
+ # @return [Object]
140
+ def value_from(defined_choices)
141
+ fail(ArgumentError, "defined_choices must be a Hash") unless defined_choices.kind_of?(Hash)
142
+ fail(ArgumentError, "defined_choices cannot be empty") if defined_choices.empty?
143
+ fail(ArgumentError, "defined_choices must have Symbol keys") unless defined_choices.keys.all? { |k| k.kind_of?(Symbol) }
144
+
145
+ fail(ArgumentError, "at least one choice must be defined") if defined_choices.empty?
146
+
147
+ missing = @supported_modes - (defined_choices.keys + @alias_map.keys)
148
+ fail(ArgumentError, "missing one or more required choice definition #{missing}") if missing.any?
149
+
150
+ unknown = defined_choices.keys - @supported_modes
151
+ fail(ArgumentError, "unknown choices #{unknown}; valid choices are #{@supported_modes}") if unknown.any?
152
+
153
+ # resolve aliases of missing choices
154
+ effective_mode = @active_mode
155
+ @alias_map.size.times do # theoretical upper limit of alias chain
156
+ break if defined_choices.include?(effective_mode)
157
+ effective_mode = @alias_map.fetch(effective_mode)
158
+ end
159
+
160
+ defined_choices.fetch(effective_mode)
161
+ end
162
+ alias_method :[], :value_from
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'selector'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ECSCompatibilitySupport
8
+ # The `SpecHelper` is meant to be extended into an rspec context to provide it with
9
+ # tools for vaidating the ecs_compatibility matrix.
10
+ #
11
+ # It creates one sub-context per provided mode, and yields a Selector::State
12
+ # to the provided block primed with the list of supported supported_modes and the active mode.
13
+ #
14
+ # It also memoizes an `ecs_compatibility` set to the active mode. It is up to the user
15
+ # to plumb this into the initialization of your plugin.
16
+ #
17
+ # ~~~ ruby
18
+ # require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
19
+ #
20
+ # describe YourClass, :ecs_compatibility_support
21
+ # ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
22
+ # context "#description" do
23
+ # subject(:result) { instance.description }
24
+ # it { is_expected.to eq ecs_select[disabled: "legacy", v1: "novel"] }
25
+ # end
26
+ # end
27
+ # end
28
+ # ~~~
29
+ module SpecHelper
30
+ def ecs_compatibility_matrix(*supported_modes,&block)
31
+ ecs_selector = Selector.new(*supported_modes)
32
+
33
+ ecs_selector.ecs_modes_supported.each do |active_mode|
34
+ context "`ecs_compatibility => #{active_mode}`" do
35
+ let(:ecs_compatibility) { active_mode }
36
+
37
+ ecs_select = ecs_selector.state_for(active_mode)
38
+ instance_exec(ecs_select, &block)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ ::RSpec.configure { |c| c.extend(SpecHelper, :ecs_compatibility_support) } if defined?(::RSpec)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../ecs_compatibility_support'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ECSCompatibilitySupport
8
+ # A target option check that can be included into any `LogStash::Plugin`.
9
+ #
10
+ # @see ECSCompatibilitySupport()
11
+ module TargetCheck
12
+ ##
13
+ # @api internal (use: `LogStash::Plugin::include`)
14
+ # @param base [Class]: a class that inherits `LogStash::Plugin`, typically one
15
+ # descending from one of the four plugin base classes
16
+ # (e.g., `LogStash::Inputs::Base`)
17
+ # @return [void]
18
+ def self.included(base)
19
+ fail(ArgumentError, "`#{base}` must inherit LogStash::Plugin") unless base < LogStash::Plugin
20
+ fail(ArgumentError, "`#{base}` must include #{ECSCompatibilitySupport}") unless base < ECSCompatibilitySupport
21
+ base.prepend(RegisterDecorator)
22
+ end
23
+
24
+ TARGET_NOT_SET_MESSAGE = ("ECS compatibility is enabled but `target` option was not specified. " +
25
+ "This may cause fields to be set at the top-level of the event where they are likely to clash with the Elastic Common Schema. " +
26
+ "It is recommended to set the `target` option to avoid potential schema conflicts (if your data is ECS compliant " +
27
+ "or non-conflicting, feel free to ignore this message)").freeze
28
+
29
+ private
30
+
31
+ ##
32
+ # Check whether `target` is specified.
33
+ #
34
+ # @return [nil] if target is unspecified and ECS compatibility is disabled
35
+ # @return [true, false]
36
+ def target_set?
37
+ return true unless target.nil?
38
+ return nil if ecs_compatibility == :disabled
39
+ false # target isn't set
40
+ end
41
+
42
+ module RegisterDecorator
43
+
44
+ ##
45
+ # Logs an info message when ecs_compatibility is enabled but plugin has no `target` configuration specified.
46
+ # @override
47
+ def register
48
+ super.tap do
49
+ logger.info(TARGET_NOT_SET_MESSAGE) if target_set? == false
50
+ end
51
+ end
52
+
53
+ end
54
+ private_constant :RegisterDecorator
55
+ end
56
+ end
57
+ end
58
+ end
@@ -17,9 +17,9 @@ module LogStash
17
17
  module ECSCompatibilitySupport
18
18
  ##
19
19
  # @api internal (use: `LogStash::Plugin::include`)
20
- # @param: a class that inherits `LogStash::Plugin`, typically one
21
- # descending from one of the four plugin base classes (e.g.,
22
- # `LogStash::Inputs::Base`)
20
+ # @param base [Class]: a class that inherits `LogStash::Plugin`, typically one
21
+ # descending from one of the four plugin base classes
22
+ # (e.g., `LogStash::Inputs::Base`)
23
23
  # @return [void]
24
24
  def self.included(base)
25
25
  fail(ArgumentError, "`#{base}` must inherit LogStash::Plugin") unless base < LogStash::Plugin
@@ -100,5 +100,16 @@ module LogStash
100
100
  end
101
101
  end
102
102
  end
103
+
104
+ ##
105
+ # @override ECSCompatibilitySupport(*supported_versions, alias_map={})
106
+ # @param supported_versions [Array[Symbol]]: the supported ECS versions
107
+ # @param alias_map [Hash{Symbol=>Symbol}]: an optional mapping of aliases (keys) to supported version (values)
108
+ def self.ECSCompatibilitySupport(*supported_versions)
109
+ return ECSCompatibilitySupport if supported_versions.empty?
110
+
111
+ require_relative "ecs_compatibility_support/selector"
112
+ ECSCompatibilitySupport::Selector.new(*supported_versions)
113
+ end
103
114
  end
104
115
  end
@@ -0,0 +1,153 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/its'
4
+
5
+ require "logstash-core"
6
+
7
+ require 'logstash/inputs/base'
8
+ require 'logstash/filters/base'
9
+ require 'logstash/codecs/base'
10
+ require 'logstash/outputs/base'
11
+
12
+ require "logstash/plugin_mixins/ecs_compatibility_support/selector"
13
+
14
+ describe LogStash::PluginMixins::ECSCompatibilitySupport::Selector do
15
+ context 'initialize' do
16
+ it 'rejects zero arguments' do
17
+ expect { described_class.new }.to raise_error(ArgumentError, /one or more/)
18
+ end
19
+ it 'rejects non-symbol arguments' do
20
+ expect { described_class.new("v1") }.to raise_error(ArgumentError, /symbol/)
21
+ end
22
+ it 'accepts one symbol argument'do
23
+ selector_mod = described_class.new(:disabled)
24
+ aggregate_failures do
25
+ expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled)
26
+ expect(selector_mod.name).to include('disabled')
27
+ end
28
+ end
29
+ it 'accepts many symbol arguments'do
30
+ selector_mod = described_class.new(:disabled, :v1)
31
+ aggregate_failures do
32
+ expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled, :v1)
33
+ expect(selector_mod.name).to include('disabled')
34
+ expect(selector_mod.name).to include('v1')
35
+ end
36
+ end
37
+ it 'accepts an alias list' do
38
+ selector_mod = described_class.new(:disabled, :v1, :v8 => :v1)
39
+ aggregate_failures do
40
+ expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled, :v1, :v8)
41
+ expect(selector_mod.name).to include('disabled')
42
+ expect(selector_mod.name).to include('v1')
43
+ expect(selector_mod.name).to include('v8')
44
+ end
45
+ end
46
+ it 'rejects alias list that doesnt resolve' do
47
+ expect { described_class.new(:disabled, :v1, :v8 => :v2) }.to raise_error(ArgumentError, /alias target/)
48
+ end
49
+ it 'rejects tight circular aliases' do
50
+ expect { described_class.new(:disabled, :v1, :v8 => :v8) }.to raise_error(ArgumentError, /circular/)
51
+ end
52
+ it 'rejects loose circular aliases' do
53
+ expect { described_class.new(:disabled, :v1, :v8 => :v7, :v7 => :v6, :v6 => :v8) }.to raise_error(ArgumentError, /circular/)
54
+ end
55
+ it 'rejects alias that redefines concrete definition' do
56
+ expect { described_class.new(:disabled, :v1, :v1 => :disabled) }.to raise_error(ArgumentError, /redefine/)
57
+ end
58
+ end
59
+ context 'included into a class' do
60
+ let(:ecs_compatibility_support) { LogStash::PluginMixins::ECSCompatibilitySupport }
61
+ let(:selector_module) { described_class.new(:disabled,:v1) }
62
+ context 'that does not inherit from LogStash::Plugin' do
63
+ let(:plugin_class) { Class.new }
64
+ it 'fails with an ArgumentError' do
65
+ expect do
66
+ plugin_class.send(:include, selector_module)
67
+ end.to raise_error(ArgumentError, /LogStash::Plugin/)
68
+ end
69
+ end
70
+
71
+ [
72
+ LogStash::Inputs::Base,
73
+ LogStash::Filters::Base,
74
+ LogStash::Codecs::Base,
75
+ LogStash::Outputs::Base
76
+ ].each do |base_class|
77
+ context "that inherits from `#{base_class}`" do
78
+ let(:ecs_supported_modes) { [:disabled, :v1] }
79
+ let(:selector_module) { described_class.new(*ecs_supported_modes) }
80
+ let(:plugin_base_class) { base_class }
81
+ subject(:plugin_class) do
82
+ klass = Class.new(plugin_base_class) do
83
+ config_name 'test'
84
+ end
85
+ klass.send(:include, selector_module)
86
+ klass
87
+ end
88
+ context 'the result' do
89
+ its(:ancestors) { is_expected.to include(ecs_compatibility_support) }
90
+ its(:instance_methods) { is_expected.to include(:ecs_select) }
91
+ end
92
+ context '#ecs_select' do
93
+ let(:plugin_options) { Hash.new }
94
+ let(:plugin_instance) { plugin_class.new(plugin_options) }
95
+ let(:ecs_effective_mode) { :v1 }
96
+
97
+ before(:each) do
98
+ # occurs during initialization, before we can get a reference to the instance.
99
+ # our plugin_class is generated per-spec and not reused.
100
+ allow_any_instance_of(plugin_class).to receive(:ecs_compatibility).and_return(ecs_effective_mode)
101
+ end
102
+
103
+ subject(:ecs_select) { plugin_instance.ecs_select }
104
+
105
+ it { is_expected.to be_a_kind_of described_class::State }
106
+ it { is_expected.to respond_to :[] }
107
+
108
+ context 'when effective ecs_compatibility is not supported' do
109
+ let(:ecs_supported_modes) { [:disabled,:v1,:v2] }
110
+ let(:ecs_effective_mode) { :v3 }
111
+ it 'raises a configuration error' do
112
+ expect { plugin_instance.ecs_select }.to raise_error(LogStash::ConfigurationError)
113
+ end
114
+ end
115
+
116
+ context '#[]' do
117
+ it 'rejects empty options' do
118
+ expect { ecs_select[{}] }.to raise_error(ArgumentError, /empty/)
119
+ end
120
+ it 'rejects unknown options' do
121
+ expect { ecs_select[disabled: "nope", v1: "no", bananas: "monkey"] }.to raise_error(ArgumentError, /unknown/)
122
+ end
123
+ it 'rejects missing options' do
124
+ expect { ecs_select[disabled: "nope"] }.to raise_error(ArgumentError, /missing/)
125
+ end
126
+ it 'rejects non-hash options' do
127
+ expect { ecs_select["bananas"] }.to raise_error(ArgumentError, /Hash/)
128
+ end
129
+ it 'requires symbol keys' do
130
+ expect { ecs_select["bananas"=>"apes"] }.to raise_error(ArgumentError, /Symbol keys/)
131
+ end
132
+ it 'selects the correct effective value' do
133
+ expect(ecs_select[disabled: "nope", v1: "winner"]).to eq("winner")
134
+ end
135
+ context 'when aliases are given' do
136
+ let(:ecs_supported_modes) { [:disabled, :v1, :v8 => :v2, :v2 => :v1 ] }
137
+ let(:ecs_effective_mode) { :v8 }
138
+ it 'selects a given value' do
139
+ expect(ecs_select[disabled: "nope", v1: "nah", v8: "hooray"]).to eq("hooray")
140
+ end
141
+ it 'resolves the deepest alias of a missing value' do
142
+ expect(ecs_select[disabled: "sad-trombone", v1: "wahoo"]).to eq("wahoo")
143
+ end
144
+ it 'resolves the intermediate alias of a missing value' do
145
+ expect(ecs_select[disabled: "sad-trombone", v1: "oh-no", v2: "nice"]).to eq("nice")
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/its'
4
+
5
+ require "logstash/plugin_mixins/ecs_compatibility_support/spec_helper"
6
+
7
+ describe LogStash::PluginMixins::ECSCompatibilitySupport::SpecHelper, :ecs_compatibility_support do
8
+ context '::ecs_compatibility_matrix(*modes)' do
9
+ ecs_compatibility_matrix(:disabled,:v1,:v8 => :v1) do |ecs_select|
10
+ it("sets `ecs_compatibility` with the current active mode `#{ecs_select.active_mode}`") do
11
+ expect(ecs_compatibility).to eq(ecs_select.active_mode)
12
+ end
13
+ context 'the yielded value' do
14
+ subject { ecs_select }
15
+ it { is_expected.to be_a_kind_of LogStash::PluginMixins::ECSCompatibilitySupport::Selector::State }
16
+ its(:supported_modes) { is_expected.to contain_exactly(:disabled,:v1,:v8) }
17
+ its(:active_mode) { is_expected.to be ecs_compatibility }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash-core"
4
+
5
+ require 'logstash/inputs/base'
6
+ require 'logstash/filters/base'
7
+ require 'logstash/codecs/base'
8
+ require 'logstash/outputs/base'
9
+
10
+ require "logstash/plugin_mixins/ecs_compatibility_support/target_check"
11
+
12
+ describe LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck do
13
+
14
+ describe "check_target_set_in_ecs_mode" do
15
+
16
+ context 'with a plugin' do
17
+
18
+ subject(:plugin_class) do
19
+ Class.new(LogStash::Filters::Base) do
20
+ include LogStash::PluginMixins::ECSCompatibilitySupport
21
+ include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
22
+
23
+ config :target, :validate => :string
24
+
25
+ def register; 42 end
26
+
27
+ end
28
+ end
29
+
30
+ it 'skips check when ECS disabled' do
31
+ plugin = plugin_class.new('ecs_compatibility' => 'disabled')
32
+ allow( plugin.logger ).to receive(:info)
33
+ expect( plugin.register ).to eql 42
34
+ expect( plugin.logger ).to_not have_received(:info).with(a_string_including "`target` option")
35
+ end
36
+
37
+ it 'warns when target is not set in ECS mode' do
38
+ plugin = plugin_class.new('ecs_compatibility' => 'v1')
39
+ allow( plugin.logger ).to receive(:info)
40
+ expect( plugin.register ).to eql 42
41
+ expect( plugin.logger ).to have_received(:info).with(a_string_including "ECS compatibility is enabled but `target` option was not specified.")
42
+ end
43
+
44
+ it 'does not warn when target is set' do
45
+ plugin = plugin_class.new('ecs_compatibility' => 'v1', 'target' => 'foo')
46
+ allow( plugin.logger ).to receive(:info)
47
+ expect( plugin.register ).to eql 42
48
+ expect( plugin.logger ).to_not have_received(:info).with(a_string_including "`target` option")
49
+ end
50
+
51
+ end
52
+
53
+ it 'fails check when no target config' do
54
+ plugin_class = Class.new(LogStash::Filters::Base) do
55
+ include LogStash::PluginMixins::ECSCompatibilitySupport
56
+ include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
57
+
58
+ def register; end
59
+
60
+ end
61
+ plugin = plugin_class.new('ecs_compatibility' => 'v1')
62
+ expect { plugin.register }.to raise_error NameError, /\btarget\b/
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -142,3 +142,25 @@ describe LogStash::PluginMixins::ECSCompatibilitySupport do
142
142
  end
143
143
  end
144
144
 
145
+ describe 'LogStash::PluginMixins::ECSCompatibilitySupport()' do
146
+ context 'with no arguments' do
147
+ it 'returns LogStash::PluginMixins::ECSCompatibilitySupport' do
148
+ expect(LogStash::PluginMixins::ECSCompatibilitySupport()).to eq(LogStash::PluginMixins::ECSCompatibilitySupport)
149
+ end
150
+ end
151
+ context 'with symbol arguments' do
152
+ it 'returns a properly-configured LogStash::PluginMixins::ECSCompatibilitySupport::Selector' do
153
+ selector_module = LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1)
154
+ expect(selector_module).to be_a_kind_of(LogStash::PluginMixins::ECSCompatibilitySupport::Selector)
155
+ expect(selector_module.ecs_modes_supported).to contain_exactly(:disabled,:v1)
156
+ end
157
+ end
158
+ context 'with symbol arguments and alias mapping' do
159
+ it 'returns a properly-configured LogStash::PluginMixins::ECSCompatibilitySupport::Selector' do
160
+ selector_module = LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1,:v8 => :v1)
161
+ expect(selector_module).to be_a_kind_of(LogStash::PluginMixins::ECSCompatibilitySupport::Selector)
162
+ expect(selector_module.ecs_modes_supported).to contain_exactly(:disabled,:v1,:v8)
163
+ end
164
+ end
165
+ end
166
+
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-mixin-ecs_compatibility_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2021-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 5.0.0
18
+ version: 6.0.0
19
19
  name: logstash-core
20
20
  prerelease: false
21
21
  type: :runtime
@@ -23,7 +23,21 @@ dependencies:
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.0.0
26
+ version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: logstash-devutils
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  requirement: !ruby/object:Gem::Requirement
29
43
  requirements:
@@ -80,6 +94,12 @@ files:
80
94
  - LICENSE
81
95
  - README.md
82
96
  - lib/logstash/plugin_mixins/ecs_compatibility_support.rb
97
+ - lib/logstash/plugin_mixins/ecs_compatibility_support/selector.rb
98
+ - lib/logstash/plugin_mixins/ecs_compatibility_support/spec_helper.rb
99
+ - lib/logstash/plugin_mixins/ecs_compatibility_support/target_check.rb
100
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/selector_spec.rb
101
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/spec_helper_spec.rb
102
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/target_check_spec.rb
83
103
  - spec/logstash/plugin_mixins/ecs_compatibility_support_spec.rb
84
104
  homepage: https://github.com/logstash-plugins/logstash-mixin-ecs_compatibility_support
85
105
  licenses:
@@ -101,10 +121,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
121
  version: '0'
102
122
  requirements: []
103
123
  rubyforge_project:
104
- rubygems_version: 2.6.11
124
+ rubygems_version: 2.6.13
105
125
  signing_key:
106
126
  specification_version: 4
107
127
  summary: Support for the ECS-Compatibility mode introduced in Logstash 7.x, for plugins
108
128
  wishing to use this API on older Logstashes
109
129
  test_files:
130
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/selector_spec.rb
131
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/spec_helper_spec.rb
132
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/target_check_spec.rb
110
133
  - spec/logstash/plugin_mixins/ecs_compatibility_support_spec.rb