logstash-core 5.6.16-java → 6.0.0.alpha1-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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/gemspec_jars.rb +4 -7
  3. data/lib/logstash-core/logstash-core.jar +0 -0
  4. data/lib/logstash-core/version.rb +4 -8
  5. data/lib/logstash-core_jars.rb +12 -26
  6. data/lib/logstash/agent.rb +261 -246
  7. data/lib/logstash/api/commands/default_metadata.rb +1 -1
  8. data/lib/logstash/api/commands/hot_threads_reporter.rb +5 -11
  9. data/lib/logstash/api/commands/node.rb +3 -2
  10. data/lib/logstash/api/commands/stats.rb +3 -2
  11. data/lib/logstash/bootstrap_check/bad_java.rb +16 -0
  12. data/lib/logstash/bootstrap_check/bad_ruby.rb +12 -0
  13. data/lib/logstash/bootstrap_check/default_config.rb +17 -0
  14. data/lib/logstash/compiler.rb +38 -0
  15. data/lib/logstash/compiler/lscl.rb +566 -0
  16. data/lib/logstash/compiler/lscl/lscl_grammar.rb +3503 -0
  17. data/lib/logstash/compiler/treetop_monkeypatches.rb +92 -0
  18. data/lib/logstash/config/config_ast.rb +4 -82
  19. data/lib/logstash/config/mixin.rb +73 -41
  20. data/lib/logstash/config/pipeline_config.rb +48 -0
  21. data/lib/logstash/config/source/base.rb +16 -0
  22. data/lib/logstash/config/source/local.rb +215 -0
  23. data/lib/logstash/config/source_loader.rb +125 -0
  24. data/lib/logstash/converge_result.rb +103 -0
  25. data/lib/logstash/environment.rb +6 -19
  26. data/lib/logstash/errors.rb +2 -0
  27. data/lib/logstash/execution_context.rb +4 -7
  28. data/lib/logstash/filter_delegator.rb +6 -9
  29. data/lib/logstash/inputs/base.rb +0 -2
  30. data/lib/logstash/instrument/collector.rb +5 -7
  31. data/lib/logstash/instrument/metric_store.rb +12 -12
  32. data/lib/logstash/instrument/metric_type/mean.rb +0 -5
  33. data/lib/logstash/instrument/namespaced_metric.rb +0 -4
  34. data/lib/logstash/instrument/namespaced_null_metric.rb +0 -4
  35. data/lib/logstash/instrument/null_metric.rb +0 -10
  36. data/lib/logstash/instrument/periodic_poller/cgroup.rb +85 -168
  37. data/lib/logstash/instrument/periodic_poller/jvm.rb +5 -5
  38. data/lib/logstash/instrument/periodic_poller/pq.rb +3 -7
  39. data/lib/logstash/instrument/periodic_pollers.rb +1 -3
  40. data/lib/logstash/instrument/wrapped_write_client.rb +24 -33
  41. data/lib/logstash/logging/logger.rb +15 -47
  42. data/lib/logstash/namespace.rb +0 -1
  43. data/lib/logstash/output_delegator.rb +5 -7
  44. data/lib/logstash/outputs/base.rb +0 -2
  45. data/lib/logstash/pipeline.rb +159 -87
  46. data/lib/logstash/pipeline_action.rb +13 -0
  47. data/lib/logstash/pipeline_action/base.rb +29 -0
  48. data/lib/logstash/pipeline_action/create.rb +47 -0
  49. data/lib/logstash/pipeline_action/reload.rb +48 -0
  50. data/lib/logstash/pipeline_action/stop.rb +23 -0
  51. data/lib/logstash/plugin.rb +0 -1
  52. data/lib/logstash/plugins/hooks_registry.rb +6 -0
  53. data/lib/logstash/plugins/registry.rb +0 -1
  54. data/lib/logstash/program.rb +14 -0
  55. data/lib/logstash/queue_factory.rb +5 -1
  56. data/lib/logstash/runner.rb +58 -80
  57. data/lib/logstash/settings.rb +3 -27
  58. data/lib/logstash/state_resolver.rb +41 -0
  59. data/lib/logstash/util/java_version.rb +6 -0
  60. data/lib/logstash/util/safe_uri.rb +12 -148
  61. data/lib/logstash/util/thread_dump.rb +4 -7
  62. data/lib/logstash/util/wrapped_acked_queue.rb +36 -39
  63. data/lib/logstash/util/wrapped_synchronous_queue.rb +29 -39
  64. data/lib/logstash/version.rb +10 -8
  65. data/locales/en.yml +3 -54
  66. data/logstash-core.gemspec +8 -35
  67. data/spec/{logstash/api/modules → api/lib/api}/logging_spec.rb +10 -1
  68. data/spec/{logstash/api/modules → api/lib/api}/node_plugins_spec.rb +2 -1
  69. data/spec/{logstash/api/modules → api/lib/api}/node_spec.rb +3 -3
  70. data/spec/{logstash/api/modules → api/lib/api}/node_stats_spec.rb +3 -7
  71. data/spec/{logstash/api/modules → api/lib/api}/plugins_spec.rb +3 -4
  72. data/spec/{logstash/api/modules → api/lib/api}/root_spec.rb +2 -2
  73. data/spec/api/lib/api/support/resource_dsl_methods.rb +87 -0
  74. data/spec/{logstash/api/commands/stats_spec.rb → api/lib/commands/stats.rb} +2 -7
  75. data/spec/{logstash/api → api/lib}/errors_spec.rb +1 -1
  76. data/spec/{logstash/api → api/lib}/rack_app_spec.rb +0 -0
  77. data/spec/api/spec_helper.rb +106 -0
  78. data/spec/logstash/agent/converge_spec.rb +286 -0
  79. data/spec/logstash/agent/metrics_spec.rb +244 -0
  80. data/spec/logstash/agent_spec.rb +213 -225
  81. data/spec/logstash/compiler/compiler_spec.rb +584 -0
  82. data/spec/logstash/config/config_ast_spec.rb +8 -47
  83. data/spec/logstash/config/mixin_spec.rb +2 -42
  84. data/spec/logstash/config/pipeline_config_spec.rb +75 -0
  85. data/spec/logstash/config/source/local_spec.rb +395 -0
  86. data/spec/logstash/config/source_loader_spec.rb +122 -0
  87. data/spec/logstash/converge_result_spec.rb +179 -0
  88. data/spec/logstash/event_spec.rb +0 -66
  89. data/spec/logstash/execution_context_spec.rb +8 -12
  90. data/spec/logstash/filter_delegator_spec.rb +12 -24
  91. data/spec/logstash/inputs/base_spec.rb +7 -5
  92. data/spec/logstash/instrument/periodic_poller/cgroup_spec.rb +92 -225
  93. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +1 -1
  94. data/spec/logstash/instrument/periodic_poller/os_spec.rb +32 -29
  95. data/spec/logstash/instrument/wrapped_write_client_spec.rb +33 -33
  96. data/spec/logstash/legacy_ruby_event_spec.rb +13 -4
  97. data/spec/logstash/output_delegator_spec.rb +11 -20
  98. data/spec/logstash/outputs/base_spec.rb +7 -5
  99. data/spec/logstash/pipeline_action/create_spec.rb +83 -0
  100. data/spec/logstash/pipeline_action/reload_spec.rb +83 -0
  101. data/spec/logstash/pipeline_action/stop_spec.rb +37 -0
  102. data/spec/logstash/pipeline_pq_file_spec.rb +1 -1
  103. data/spec/logstash/pipeline_spec.rb +81 -137
  104. data/spec/logstash/plugin_spec.rb +2 -1
  105. data/spec/logstash/plugins/hooks_registry_spec.rb +6 -0
  106. data/spec/logstash/queue_factory_spec.rb +13 -1
  107. data/spec/logstash/runner_spec.rb +29 -140
  108. data/spec/logstash/settings/writable_directory_spec.rb +10 -13
  109. data/spec/logstash/settings_spec.rb +0 -91
  110. data/spec/logstash/state_resolver_spec.rb +156 -0
  111. data/spec/logstash/timestamp_spec.rb +2 -6
  112. data/spec/logstash/util/java_version_spec.rb +22 -0
  113. data/spec/logstash/util/safe_uri_spec.rb +0 -56
  114. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +22 -0
  115. data/spec/support/helpers.rb +9 -11
  116. data/spec/support/matchers.rb +96 -6
  117. data/spec/support/mocks_classes.rb +80 -0
  118. data/spec/support/shared_contexts.rb +2 -27
  119. metadata +100 -149
  120. data/lib/logstash/config/loader.rb +0 -107
  121. data/lib/logstash/config/modules_common.rb +0 -103
  122. data/lib/logstash/config/source/modules.rb +0 -55
  123. data/lib/logstash/config/string_escape.rb +0 -27
  124. data/lib/logstash/dependency_report.rb +0 -131
  125. data/lib/logstash/dependency_report_runner.rb +0 -17
  126. data/lib/logstash/elasticsearch_client.rb +0 -142
  127. data/lib/logstash/instrument/global_metrics.rb +0 -13
  128. data/lib/logstash/instrument/periodic_poller/dlq.rb +0 -24
  129. data/lib/logstash/modules/cli_parser.rb +0 -74
  130. data/lib/logstash/modules/elasticsearch_config.rb +0 -22
  131. data/lib/logstash/modules/elasticsearch_importer.rb +0 -37
  132. data/lib/logstash/modules/elasticsearch_resource.rb +0 -10
  133. data/lib/logstash/modules/file_reader.rb +0 -36
  134. data/lib/logstash/modules/kibana_base.rb +0 -24
  135. data/lib/logstash/modules/kibana_client.rb +0 -124
  136. data/lib/logstash/modules/kibana_config.rb +0 -105
  137. data/lib/logstash/modules/kibana_dashboards.rb +0 -36
  138. data/lib/logstash/modules/kibana_importer.rb +0 -17
  139. data/lib/logstash/modules/kibana_resource.rb +0 -10
  140. data/lib/logstash/modules/kibana_settings.rb +0 -40
  141. data/lib/logstash/modules/logstash_config.rb +0 -120
  142. data/lib/logstash/modules/resource_base.rb +0 -38
  143. data/lib/logstash/modules/scaffold.rb +0 -52
  144. data/lib/logstash/modules/settings_merger.rb +0 -23
  145. data/lib/logstash/modules/util.rb +0 -17
  146. data/lib/logstash/util/dead_letter_queue_manager.rb +0 -61
  147. data/lib/logstash/util/environment_variables.rb +0 -43
  148. data/spec/logstash/config/loader_spec.rb +0 -38
  149. data/spec/logstash/config/string_escape_spec.rb +0 -24
  150. data/spec/logstash/instrument/periodic_poller/dlq_spec.rb +0 -17
  151. data/spec/logstash/modules/logstash_config_spec.rb +0 -56
  152. data/spec/logstash/modules/scaffold_spec.rb +0 -234
  153. data/spec/logstash/pipeline_dlq_commit_spec.rb +0 -109
  154. data/spec/logstash/settings/splittable_string_array_spec.rb +0 -51
  155. data/spec/logstash/util/wrapped_acked_queue_spec.rb +0 -49
  156. data/versions-gem-copy.yml +0 -12
@@ -0,0 +1,87 @@
1
+ # Ruby doesn't have common class for boolean,
2
+ # And to simplify the ResourceDSLMethods check it make sense to have it.
3
+ module Boolean; end
4
+ class TrueClass
5
+ include Boolean
6
+ end
7
+ class FalseClass
8
+ include Boolean
9
+ end
10
+
11
+ module ResourceDSLMethods
12
+ # Convert a nested hash to a mapping of key paths to expected classes
13
+ def hash_to_mapping(h, path=[], mapping={})
14
+ h.each do |k,v|
15
+ if v.is_a?(Hash)
16
+ hash_to_mapping(v, path + [k], mapping)
17
+ else
18
+ full_path = path + [k]
19
+ mapping[full_path] = v
20
+ end
21
+ end
22
+ mapping
23
+ end
24
+
25
+ def test_api(expected, path)
26
+ context "GET #{path}" do
27
+ let(:payload) { LogStash::Json.load(last_response.body) }
28
+
29
+ before(:all) do
30
+ get path
31
+ end
32
+
33
+ it "should respond OK" do
34
+ expect(last_response).to be_ok
35
+ end
36
+
37
+
38
+ describe "the default metadata" do
39
+ it "should include the host" do
40
+ expect(payload["host"]).to eql(Socket.gethostname)
41
+ end
42
+
43
+ it "should include the version" do
44
+ expect(payload["version"]).to eql(LOGSTASH_CORE_VERSION)
45
+ end
46
+
47
+ it "should include the http address" do
48
+ expect(payload["http_address"]).to eql("#{Socket.gethostname}:#{::LogStash::WebServer::DEFAULT_PORTS.first}")
49
+ end
50
+
51
+ it "should include the node name" do
52
+ expect(payload["name"]).to eql(@runner.agent.name)
53
+ end
54
+
55
+ it "should include the node id" do
56
+ expect(payload["id"]).to eql(@runner.agent.id)
57
+ end
58
+ end
59
+
60
+ hash_to_mapping(expected).each do |resource_path,klass|
61
+ dotted = resource_path.join(".")
62
+
63
+ it "should set '#{dotted}' at '#{path}' to be a '#{klass}'" do
64
+ expect(last_response).to be_ok # fail early if need be
65
+ resource_path_value = resource_path.reduce(payload) do |acc,v|
66
+ expect(acc.has_key?(v)).to eql(true), "Expected to find value '#{v}' in structure '#{acc}', but could not. Payload was '#{payload}'"
67
+ acc[v]
68
+ end
69
+ expect(resource_path_value).to be_a(klass), "could not find '#{dotted}' in #{payload}"
70
+ end
71
+ end
72
+ end
73
+
74
+ yield if block_given? # Add custom expectations
75
+ end
76
+
77
+ def test_api_and_resources(expected, xopts={})
78
+ xopts[:exclude_from_root] ||= []
79
+ root_expectation = expected.clone
80
+ xopts[:exclude_from_root].each {|k| root_expectation.delete(k)}
81
+ test_api(root_expectation, "/")
82
+
83
+ expected.keys.each do |key|
84
+ test_api({key => expected[key]}, "/#{key}")
85
+ end
86
+ end
87
+ end
@@ -1,15 +1,10 @@
1
1
  # encoding: utf-8
2
- require "spec_helper"
2
+ require_relative "../../spec_helper"
3
3
 
4
4
  describe LogStash::Api::Commands::Stats do
5
- include_context "api setup"
6
5
 
7
6
  let(:report_method) { :run }
8
- subject(:report) do
9
- factory = ::LogStash::Api::CommandFactory.new(LogStash::Api::Service.new(@agent))
10
-
11
- factory.build(:stats).send(report_method)
12
- end
7
+ subject(:report) { report_class.new.send(report_method) }
13
8
 
14
9
  let(:report_class) { described_class }
15
10
 
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require "spec_helper"
2
+ require_relative "../spec_helper"
3
3
  require "logstash/api/errors"
4
4
 
5
5
  describe LogStash::Api::ApiError do
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+ API_ROOT = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib", "logstash", "api"))
3
+
4
+ require "stud/task"
5
+ require "logstash/devutils/rspec/spec_helper"
6
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
7
+ require "lib/api/support/resource_dsl_methods"
8
+ require_relative "../support/mocks_classes"
9
+ require_relative "../support/helpers"
10
+ require 'rspec/expectations'
11
+ require "logstash/settings"
12
+ require 'rack/test'
13
+ require 'rspec'
14
+ require "json"
15
+
16
+ def read_fixture(name)
17
+ path = File.join(File.dirname(__FILE__), "fixtures", name)
18
+ File.read(path)
19
+ end
20
+
21
+ module LogStash
22
+ class DummyAgent < Agent
23
+ def start_webserver
24
+ http_address = "#{Socket.gethostname}:#{::LogStash::WebServer::DEFAULT_PORTS.first}"
25
+ @webserver = Struct.new(:address).new(http_address)
26
+ self.metric.gauge([], :http_address, http_address)
27
+ end
28
+
29
+ def stop_webserver; end
30
+ end
31
+ end
32
+
33
+ ##
34
+ # Class used to wrap and manage the execution of an agent for test,
35
+ # this helps a lot in order to have a more integrated test for the
36
+ # web api, could be also used for other use cases if generalized enough
37
+ ##
38
+ class LogStashRunner
39
+
40
+ attr_reader :config_str, :agent, :pipeline_settings
41
+
42
+ def initialize
43
+
44
+ require "securerandom"
45
+ id = SecureRandom.uuid
46
+
47
+ @config_str = "input { generator {id => 'api-generator-pipeline-#{id}' count => 100 } } output { dummyoutput {} }"
48
+
49
+ args = {
50
+ "config.reload.automatic" => false,
51
+ "metric.collect" => true,
52
+ "log.level" => "debug",
53
+ "node.name" => "test_agent",
54
+ "http.port" => rand(9600..9700),
55
+ "http.environment" => "test",
56
+ "config.string" => @config_str,
57
+ "pipeline.batch.size" => 1,
58
+ "pipeline.workers" => 1
59
+ }
60
+
61
+ @settings = ::LogStash::SETTINGS.clone.merge(args)
62
+ source_loader = LogStash::Config::SourceLoader.new
63
+ source_loader.configure_sources(LogStash::Config::Source::Local.new(@settings))
64
+ @agent = LogStash::DummyAgent.new(@settings, source_loader)
65
+ end
66
+
67
+ def start
68
+ # We start a pipeline that will generate a finite number of events
69
+ # before starting the expectations
70
+ @agent_task = Stud::Task.new { agent.execute }
71
+ @agent_task.wait
72
+ end
73
+
74
+ def stop
75
+ agent.shutdown
76
+ end
77
+ end
78
+
79
+ RSpec::Matchers.define :be_available? do
80
+ match do |plugin|
81
+ begin
82
+ Gem::Specification.find_by_name(plugin["name"])
83
+ true
84
+ rescue
85
+ false
86
+ end
87
+ end
88
+ end
89
+
90
+ shared_context "api setup" do
91
+ before :all do
92
+ clear_data_dir
93
+ @runner = LogStashRunner.new
94
+ @runner.start
95
+ end
96
+
97
+ after :all do
98
+ @runner.stop
99
+ end
100
+
101
+ include Rack::Test::Methods
102
+
103
+ def app()
104
+ described_class.new(nil, @runner.agent)
105
+ end
106
+ end
@@ -0,0 +1,286 @@
1
+ # encoding: utf-8
2
+ require "logstash/agent"
3
+ require_relative "../../support/helpers"
4
+ require_relative "../../support/matchers"
5
+ require_relative "../../support/mocks_classes"
6
+ require "spec_helper"
7
+
8
+ describe LogStash::Agent do
9
+ # by default no tests uses the auto reload logic
10
+ let(:agent_settings) { mock_settings("config.reload.automatic" => false, "queue.type" => "persisted") }
11
+
12
+ subject { described_class.new(agent_settings, source_loader) }
13
+
14
+ before do
15
+ clear_data_dir
16
+
17
+ # until we decouple the webserver from the agent
18
+ allow(subject).to receive(:start_webserver).and_return(false)
19
+ allow(subject).to receive(:stop_webserver).and_return(false)
20
+ end
21
+
22
+ # Make sure that we close any running pipeline to release any pending locks
23
+ # on the queues
24
+ after do
25
+ converge_result = subject.shutdown
26
+ expect(converge_result).to be_a_successful_converge
27
+ end
28
+
29
+
30
+ describe "passing the agent to the pipeline" do
31
+ let(:source_loader) { TestSourceLoader.new(pipeline_config) }
32
+ let(:pipeline_config) { mock_pipeline_config(:main, "input { generator { count => 10 } } output { null {} }") }
33
+
34
+ before { subject.execute }
35
+
36
+ it "execute the pipeline and stop execution" do
37
+ expect(subject.get_pipeline(:main).execution_context.agent).to eq(subject)
38
+ end
39
+ end
40
+
41
+ context "Agent execute options" do
42
+ let(:source_loader) do
43
+ TestSourceLoader.new(finite_pipeline_config)
44
+ end
45
+
46
+ context "when the pipeline execution is finite" do
47
+ let(:finite_pipeline_config) { mock_pipeline_config(:main, "input { generator { count => 1000 } } output { null {} }") }
48
+
49
+ it "execute the pipeline and stop execution" do
50
+ expect(subject.execute).to eq(0)
51
+ end
52
+ end
53
+
54
+ context "when the config is short lived (generator { count => 1 })" do
55
+ let(:finite_pipeline_config) { mock_pipeline_config(:main, "input { generator { count => 1 } } output { null {} }") }
56
+
57
+ it "execute the pipeline and stop execution" do
58
+ expect(subject.execute).to eq(0)
59
+ end
60
+ end
61
+
62
+ context "system pipeline" do
63
+ let(:finite_pipeline_config) { mock_pipeline_config(:main, "input { generator { count => 1000 } } output { null {} }") }
64
+ let(:system_pipeline_config) { mock_pipeline_config(:system_pipeline, "input { generator { } } output { null {} }", { "pipeline.system" => true }) }
65
+
66
+ let(:source_loader) do
67
+ TestSourceLoader.new(finite_pipeline_config, system_pipeline_config)
68
+ end
69
+
70
+ context "when we have a finite pipeline and a system pipeline running" do
71
+ it "execute the pipeline and stop execution" do
72
+ expect(subject.execute).to eq(0)
73
+ end
74
+ end
75
+
76
+ describe "#running_user_defined_pipelines" do
77
+ it "returns the user defined pipelines" do
78
+ agent_task = start_agent(subject)
79
+ expect(subject.running_user_defined_pipelines.keys).to include(:main)
80
+ expect(subject.running_user_defined_pipelines.keys).not_to include(:system_pipeline)
81
+ subject.shutdown
82
+ end
83
+ end
84
+
85
+ describe "#running_user_defined_pipelines?" do
86
+ it "returns true" do
87
+ agent_task = start_agent(subject)
88
+ expect(subject.running_user_defined_pipelines?).to be_truthy
89
+ subject.shutdown
90
+ end
91
+ end
92
+ end
93
+
94
+ context "when `config.reload.automatic`" do
95
+ let(:pipeline_config) { mock_pipeline_config(:main, "input { generator {} } output { null {} }") }
96
+
97
+ let(:source_loader) do
98
+ TestSourceLoader.new(pipeline_config)
99
+ end
100
+
101
+ context "is set to`FALSE`" do
102
+ context "and successfully load the config" do
103
+ let(:agent_settings) { mock_settings("config.reload.automatic" => false) }
104
+
105
+ it "converge only once" do
106
+ agent_task = start_agent(subject)
107
+
108
+ expect(source_loader.fetch_count).to eq(1)
109
+ expect(subject).to have_running_pipeline?(pipeline_config)
110
+
111
+ subject.shutdown
112
+ agent_task.stop!
113
+ end
114
+ end
115
+
116
+ context "and it fails to load the config" do
117
+ let(:source_loader) do
118
+ TestSourceLoader.new(TestSourceLoader::FailedFetch.new("can't load the file"))
119
+ end
120
+
121
+ it "doesn't execute any pipeline" do
122
+ expect { subject.execute }.not_to raise_error # errors is logged
123
+
124
+ expect(source_loader.fetch_count).to eq(1)
125
+ expect(subject.pipelines_count).to eq(0)
126
+
127
+ subject.shutdown
128
+ end
129
+ end
130
+ end
131
+
132
+ context "is set to `TRUE`" do
133
+ let(:interval) { 0.01 }
134
+ let(:agent_settings) do
135
+ mock_settings(
136
+ "config.reload.automatic" => true,
137
+ "config.reload.interval" => interval
138
+ )
139
+ end
140
+
141
+ context "and successfully load the config" do
142
+ it "converges periodically the pipelines from the configs source" do
143
+ agent_task = start_agent(subject)
144
+
145
+ sleep(2) # let the interval reload a few times
146
+ expect(subject).to have_running_pipeline?(pipeline_config)
147
+
148
+ # we rely on a periodic thread to call fetch count, we have seen unreliable run on
149
+ # travis, so lets add a few retries
150
+ try do
151
+ expect(source_loader.fetch_count).to be > 1
152
+ end
153
+
154
+ subject.shutdown
155
+ agent_task.stop!
156
+ end
157
+ end
158
+
159
+ context "and it fails to load the config" do
160
+ let(:source_loader) do
161
+ TestSourceLoader.new(TestSourceLoader::FailedFetch.new("can't load the file"))
162
+ end
163
+
164
+ it "it will keep trying to converge" do
165
+ agent_task = start_agent(subject)
166
+
167
+ sleep(interval * 20) # let the interval reload a few times
168
+ expect(subject.pipelines_count).to eq(0)
169
+ expect(source_loader.fetch_count).to be > 1
170
+
171
+ subject.shutdown
172
+ agent_task.stop!
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ context "when shutting down the agent" do
180
+ let(:pipeline_config) { mock_pipeline_config(:main, "input { generator {} } output { null {} }") }
181
+ let(:new_pipeline_config) { mock_pipeline_config(:new, "input { generator { id => 'new' } } output { null {} }") }
182
+
183
+ let(:source_loader) do
184
+ TestSourceLoader.new([pipeline_config, new_pipeline_config])
185
+ end
186
+
187
+ it "stops the running pipelines" do
188
+ expect(subject.converge_state_and_update).to be_a_successful_converge
189
+ expect { subject.shutdown }.to change { subject.running_pipelines.size }.from(2).to(0)
190
+ end
191
+ end
192
+
193
+ context "Configuration converge scenario" do
194
+ let(:pipeline_config) { mock_pipeline_config(:main, "input { generator {} } output { null {} }", { "pipeline.reloadable" => true }) }
195
+ let(:new_pipeline_config) { mock_pipeline_config(:new, "input { generator {} } output { null {} }", { "pipeline.reloadable" => true }) }
196
+
197
+ before do
198
+ # Set the Agent to an initial state of pipelines
199
+ expect(subject.converge_state_and_update).to be_a_successful_converge
200
+ end
201
+
202
+ context "no pipelines is running" do
203
+ let(:source_loader) do
204
+ TestSequenceSourceLoader.new([], pipeline_config)
205
+ end
206
+
207
+ it "creates and starts the new pipeline" do
208
+ expect {
209
+ expect(subject.converge_state_and_update).to be_a_successful_converge
210
+ }.to change { subject.running_pipelines.count }.from(0).to(1)
211
+ expect(subject).to have_running_pipeline?(pipeline_config)
212
+ end
213
+ end
214
+
215
+ context "when a pipeline is running" do
216
+ context "when the source returns the current pipeline and a new one" do
217
+ let(:source_loader) do
218
+ TestSequenceSourceLoader.new(
219
+ pipeline_config,
220
+ [pipeline_config, new_pipeline_config]
221
+ )
222
+ end
223
+
224
+ it "start a new pipeline and keep the original" do
225
+ expect {
226
+ expect(subject.converge_state_and_update).to be_a_successful_converge
227
+ }.to change { subject.running_pipelines.count }.from(1).to(2)
228
+ expect(subject).to have_running_pipeline?(pipeline_config)
229
+ expect(subject).to have_running_pipeline?(new_pipeline_config)
230
+ end
231
+ end
232
+
233
+ context "when the source returns a new pipeline but not the old one" do
234
+ let(:source_loader) do
235
+ TestSequenceSourceLoader.new(
236
+ pipeline_config,
237
+ new_pipeline_config
238
+ )
239
+ end
240
+
241
+ it "stops the missing pipeline and start the new one" do
242
+ expect {
243
+ expect(subject.converge_state_and_update).to be_a_successful_converge
244
+ }.not_to change { subject.running_pipelines.count }
245
+ expect(subject).not_to have_pipeline?(pipeline_config)
246
+ expect(subject).to have_running_pipeline?(new_pipeline_config)
247
+ end
248
+ end
249
+ end
250
+
251
+ context "when the source return a modified pipeline" do
252
+ let(:modified_pipeline_config) { mock_pipeline_config(:main, "input { generator { id => 'new-and-modified' } } output { null {} }", { "pipeline.reloadable" => true }) }
253
+
254
+ let(:source_loader) do
255
+ TestSequenceSourceLoader.new(
256
+ [pipeline_config],
257
+ [modified_pipeline_config]
258
+ )
259
+ end
260
+
261
+ it "reloads the modified pipeline" do
262
+ expect {
263
+ expect(subject.converge_state_and_update).to be_a_successful_converge
264
+ }.not_to change { subject.running_pipelines.count }
265
+ expect(subject).to have_running_pipeline?(modified_pipeline_config)
266
+ expect(subject).not_to have_pipeline?(pipeline_config)
267
+ end
268
+ end
269
+
270
+ context "when the source return no pipelines" do
271
+ let(:source_loader) do
272
+ TestSequenceSourceLoader.new(
273
+ [pipeline_config, new_pipeline_config],
274
+ []
275
+ )
276
+ end
277
+
278
+ it "stops all the pipelines" do
279
+ expect {
280
+ expect(subject.converge_state_and_update).to be_a_successful_converge
281
+ }.to change { subject.running_pipelines.count }.from(2).to(0)
282
+ expect(subject).not_to have_pipeline?(pipeline_config)
283
+ end
284
+ end
285
+ end
286
+ end