logstash-core 5.6.16-java → 6.0.0.alpha1-java

Sign up to get free protection for your applications and to get access to all the features.
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