mirror of
https://github.com/elastic/logstash.git
synced 2025-04-24 14:47:19 -04:00
fixes for Windows platform tests/specs
use rm_rf to delete dir and shutdown pipeline after run avoid the use of rescue nil, bad practice do not mock close as it prevents closing the file an prevents removing it on Windows cleanup temporary files and relax file name check for Windows fix paths handling for Windows flag the read file string as UTF-8 which is what we expect fix Windows issues ignore load_average on windows windows safe URI cleanup and fix file handling for windows wait for pipeline shutdown to complete revert to original puts cleanups use environment for windows platform check fix hash path wait for pipeline thread to complete after shutdown
This commit is contained in:
parent
925284fc9c
commit
1230168113
12 changed files with 83 additions and 36 deletions
|
@ -68,7 +68,7 @@ module LogStash module PluginManager module Utils
|
|||
downloaded_file.path
|
||||
end
|
||||
rescue => e
|
||||
downloaded_file.close rescue nil
|
||||
downloaded_file.close unless downloaded_file.closed?
|
||||
FileUtils.rm_rf(download_to)
|
||||
raise e
|
||||
end
|
||||
|
|
|
@ -71,7 +71,8 @@ module LogStash module Config module Source
|
|||
end
|
||||
|
||||
config_string = ::File.read(file)
|
||||
|
||||
config_string.force_encoding("UTF-8")
|
||||
|
||||
if config_string.valid_encoding?
|
||||
part = org.logstash.common.SourceWithMetadata.new("file", file, 0, 0, config_string)
|
||||
config_parts << part
|
||||
|
|
|
@ -33,7 +33,7 @@ describe LogStash::Agent do
|
|||
# This MUST run first, before `subject` is invoked to ensure clean state
|
||||
clear_data_dir
|
||||
|
||||
File.open(config_file, "w") { |f| f.puts config_file_txt }
|
||||
File.open(config_file, "w") { |f| f.puts(config_file_txt) }
|
||||
|
||||
agent_args.each do |key, value|
|
||||
agent_settings.set(key, value)
|
||||
|
@ -50,8 +50,9 @@ describe LogStash::Agent do
|
|||
after :each do
|
||||
subject.shutdown
|
||||
LogStash::SETTINGS.reset
|
||||
File.unlink(config_file)
|
||||
File.unlink(subject.id_path)
|
||||
|
||||
FileUtils.rm(config_file)
|
||||
FileUtils.rm_rf(subject.id_path)
|
||||
end
|
||||
|
||||
it "fallback to hostname when no name is provided" do
|
||||
|
@ -314,8 +315,10 @@ describe LogStash::Agent do
|
|||
context "metrics after config reloading" do
|
||||
|
||||
let(:initial_generator_threshold) { 1000 }
|
||||
let(:temporary_file) { Stud::Temporary.file.path }
|
||||
let(:config_file_txt) { "input { generator { count => #{initial_generator_threshold*2} } } output { file { path => '#{temporary_file}'} }" }
|
||||
let(:original_config_output) { Stud::Temporary.pathname }
|
||||
let(:new_config_output) { Stud::Temporary.pathname }
|
||||
|
||||
let(:config_file_txt) { "input { generator { count => #{initial_generator_threshold*2} } } output { file { path => '#{original_config_output}'} }" }
|
||||
|
||||
let(:agent_args) do
|
||||
{
|
||||
|
@ -326,14 +329,25 @@ describe LogStash::Agent do
|
|||
|
||||
subject { described_class.new(agent_settings, default_source_loader) }
|
||||
|
||||
let(:agent_thread) do
|
||||
# subject has to be called for the first time outside the thread because it could create a race condition
|
||||
# with subsequent subject calls
|
||||
s = subject
|
||||
Thread.new { s.execute }
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@abort_on_exception = Thread.abort_on_exception
|
||||
Thread.abort_on_exception = true
|
||||
|
||||
@t = Thread.new { subject.execute }
|
||||
agent_thread
|
||||
|
||||
# wait for some events to reach the dummy_output
|
||||
sleep(0.01) until IO.readlines(temporary_file).size > initial_generator_threshold
|
||||
Timeout.timeout(timeout) do
|
||||
# wait for file existence otherwise it will raise exception on Windows
|
||||
sleep(0.1) until ::File.exist?(original_config_output)
|
||||
sleep(0.1) until IO.readlines(original_config_output).size > initial_generator_threshold
|
||||
end
|
||||
|
||||
# write new config
|
||||
File.open(config_file, "w") { |f| f.write(new_config) }
|
||||
|
@ -341,10 +355,14 @@ describe LogStash::Agent do
|
|||
|
||||
after :each do
|
||||
begin
|
||||
Stud.stop!(agent_thread) rescue nil # it may be dead already
|
||||
agent_thread.join
|
||||
subject.shutdown
|
||||
Stud.stop!(@t) rescue nil # it may be dead already
|
||||
@t.join
|
||||
File.unlink(temporary_file)
|
||||
|
||||
FileUtils.rm(original_config_output)
|
||||
FileUtils.rm(new_config_output) if File.exist?(new_config_output)
|
||||
rescue
|
||||
#don't care about errors here.
|
||||
ensure
|
||||
Thread.abort_on_exception = @abort_on_exception
|
||||
end
|
||||
|
@ -352,19 +370,20 @@ describe LogStash::Agent do
|
|||
|
||||
context "when reloading a good config" do
|
||||
let(:new_config_generator_counter) { 500 }
|
||||
let(:new_file) { Stud::Temporary.file.path }
|
||||
let(:new_config) { "input { generator { count => #{new_config_generator_counter} } } output { file { path => '#{new_file}'} }" }
|
||||
let(:new_config) { "input { generator { count => #{new_config_generator_counter} } } output { file { path => '#{new_config_output}'} }" }
|
||||
|
||||
before :each do
|
||||
subject.converge_state_and_update
|
||||
sleep(0.01) while ::File.read(new_file).chomp.empty?
|
||||
Timeout.timeout(timeout) do
|
||||
# wait for file existence otherwise it will raise exception on Windows
|
||||
sleep(0.1) until ::File.exist?(new_config_output)
|
||||
sleep(0.1) while ::File.read(new_config_output).chomp.empty?
|
||||
end
|
||||
# ensure the converge_state_and_update method has updated metrics by
|
||||
# invoking the mutex
|
||||
subject.running_pipelines?
|
||||
end
|
||||
|
||||
after(:each) { File.unlink(new_file) }
|
||||
|
||||
it "resets the pipeline metric collector" do
|
||||
snapshot = subject.metric.collector.snapshot_metric
|
||||
value = snapshot.metric_store.get_with_path("/stats/pipelines")[:stats][:pipelines][:main][:events][:in].value
|
||||
|
|
|
@ -69,7 +69,7 @@ describe LogStash::Api::Modules::NodeStats do
|
|||
"cpu"=>{
|
||||
"total_in_millis"=>Numeric,
|
||||
"percent"=>Numeric,
|
||||
"load_average" => { "1m" => Numeric }
|
||||
# load_average is not supported on Windows, set it below
|
||||
}
|
||||
},
|
||||
"pipelines" => {
|
||||
|
@ -89,5 +89,9 @@ describe LogStash::Api::Modules::NodeStats do
|
|||
}
|
||||
}
|
||||
|
||||
unless LogStash::Environment.windows?
|
||||
root_structure["process"]["cpu"]["load_average"] = { "1m" => Numeric }
|
||||
end
|
||||
|
||||
test_api_and_resources(root_structure)
|
||||
end
|
||||
|
|
|
@ -79,7 +79,7 @@ describe LogStash::Config::Source::Local::ConfigPathLoader do
|
|||
|
||||
parts.each do |part|
|
||||
basename = ::File.basename(part.id)
|
||||
file_path = ::File.join(directory, basename)
|
||||
file_path = ::File.expand_path(::File.join(directory, basename))
|
||||
content = files[basename]
|
||||
expect(part).to be_a_source_with_metadata("file", file_path, content)
|
||||
end
|
||||
|
@ -99,7 +99,8 @@ describe LogStash::Config::Source::Local::ConfigPathLoader do
|
|||
end
|
||||
|
||||
it "raises an exception" do
|
||||
expect { subject.read(file_path) }.to raise_error LogStash::ConfigLoadingError, /#{file_path}/
|
||||
# check against base name because on Windows long paths are shrinked in the exception message
|
||||
expect { subject.read(file_path) }.to raise_error LogStash::ConfigLoadingError, /.+#{::File.basename(file_path)}/
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -19,7 +19,10 @@ describe LogStash::PipelineAction::Create do
|
|||
subject { described_class.new(pipeline_config, metric) }
|
||||
|
||||
after do
|
||||
pipelines.each { |_, pipeline| pipeline.shutdown }
|
||||
pipelines.each do |_, pipeline|
|
||||
pipeline.shutdown
|
||||
pipeline.thread.join
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the pipeline_id" do
|
||||
|
|
|
@ -22,7 +22,10 @@ describe LogStash::PipelineAction::Reload do
|
|||
end
|
||||
|
||||
after do
|
||||
pipelines.each { |_, pipeline| pipeline.shutdown }
|
||||
pipelines.each do |_, pipeline|
|
||||
pipeline.shutdown
|
||||
pipeline.thread.join
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the pipeline_id" do
|
||||
|
|
|
@ -67,7 +67,7 @@ describe LogStash::Pipeline do
|
|||
end
|
||||
|
||||
after(:each) do
|
||||
FileUtils.remove_entry pipeline_settings["path.dead_letter_queue"]
|
||||
FileUtils.rm_rf(pipeline_settings["path.dead_letter_queue"])
|
||||
end
|
||||
|
||||
context "dlq is enabled" do
|
||||
|
@ -85,6 +85,7 @@ describe LogStash::Pipeline do
|
|||
entry = dlq_reader.pollEntry(40)
|
||||
expect(entry).to_not be_nil
|
||||
expect(entry.reason).to eq("my reason")
|
||||
subject.shutdown
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -101,6 +102,7 @@ describe LogStash::Pipeline do
|
|||
subject.run
|
||||
dlq_path = java.nio.file.Paths.get(pipeline_settings_obj.get("path.dead_letter_queue"), pipeline_id)
|
||||
expect(java.nio.file.Files.exists(dlq_path)).to eq(false)
|
||||
subject.shutdown
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,17 +3,17 @@ require "spec_helper"
|
|||
require "logstash/settings"
|
||||
require "tmpdir"
|
||||
require "socket" # for UNIXSocket
|
||||
require "fileutils"
|
||||
|
||||
describe LogStash::Setting::WritableDirectory do
|
||||
let(:mode_rx) { 0555 }
|
||||
# linux is 108, Macos is 104, so use a safe value
|
||||
# Stud::Temporary.pathname, will exceed that size without adding anything
|
||||
let(:parent) { File.join(Dir.tmpdir, Time.now.to_f.to_s) }
|
||||
let(:path) { File.join(parent, "fancy") }
|
||||
|
||||
before { Dir.mkdir(parent) }
|
||||
after { Dir.exist?(path) && Dir.unlink(path) rescue nil }
|
||||
after { Dir.unlink(parent) }
|
||||
after { Dir.exist?(path) && FileUtils.rm_rf(path)}
|
||||
after { FileUtils.rm_rf(parent) }
|
||||
|
||||
shared_examples "failure" do
|
||||
before { subject.set(path) }
|
||||
|
@ -44,8 +44,9 @@ describe LogStash::Setting::WritableDirectory do
|
|||
end
|
||||
|
||||
context "and the directory cannot be created" do
|
||||
before { File.chmod(mode_rx, parent) }
|
||||
it "should fail" do
|
||||
# using chmod does not work on Windows better mock and_raise("message")
|
||||
expect(FileUtils).to receive(:mkdir_p).and_raise("foobar")
|
||||
expect { subject.value }.to raise_error
|
||||
end
|
||||
end
|
||||
|
@ -66,7 +67,8 @@ describe LogStash::Setting::WritableDirectory do
|
|||
end
|
||||
|
||||
context "but is not writable" do
|
||||
before { File.chmod(0, path) }
|
||||
# chmod does not work on Windows, mock writable? instead
|
||||
before { expect(File).to receive(:writable?).and_return(false) }
|
||||
it_behaves_like "failure"
|
||||
end
|
||||
end
|
||||
|
@ -84,12 +86,13 @@ describe LogStash::Setting::WritableDirectory do
|
|||
before { socket } # realize `socket` value
|
||||
after { socket.close }
|
||||
it_behaves_like "failure"
|
||||
end
|
||||
end unless LogStash::Environment.windows?
|
||||
|
||||
|
||||
context "but is a symlink" do
|
||||
before { File::symlink("whatever", path) }
|
||||
before { FileUtils.symlink("whatever", path) }
|
||||
it_behaves_like "failure"
|
||||
end
|
||||
end unless LogStash::Environment.windows?
|
||||
end
|
||||
|
||||
context "when the directory is missing" do
|
||||
|
@ -114,8 +117,8 @@ describe LogStash::Setting::WritableDirectory do
|
|||
|
||||
context "and cannot be created" do
|
||||
before do
|
||||
# Remove write permission on the parent
|
||||
File.chmod(mode_rx, parent)
|
||||
# chmod does not work on Windows, mock writable? instead
|
||||
expect(File).to receive(:writable?).and_return(false)
|
||||
end
|
||||
|
||||
it_behaves_like "failure"
|
||||
|
|
|
@ -32,10 +32,12 @@ describe LogStash::PluginManager::PackFetchStrategy::Uri do
|
|||
let(:temporary_file) do
|
||||
f = Stud::Temporary.file
|
||||
f.write("hola")
|
||||
f.close
|
||||
f.path
|
||||
end
|
||||
|
||||
let(:plugin_path) { "file://#{temporary_file}" }
|
||||
# Windows safe way to produce a file: URI.
|
||||
let(:plugin_path) { URI.join("file:///" + File.absolute_path(temporary_file)).to_s }
|
||||
|
||||
it "returns a `LocalInstaller`" do
|
||||
expect(subject.get_installer_for(plugin_path)).to be_kind_of(LogStash::PluginManager::PackInstaller::Local)
|
||||
|
|
|
@ -79,6 +79,10 @@ describe LogStash::PluginManager::PrepareOfflinePack do
|
|||
expect(LogStash::PluginManager::OfflinePluginPackager).not_to receive(:package).with(anything)
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(tmp_zip_file)
|
||||
end
|
||||
|
||||
it "fails to do any action" do
|
||||
expect { subject.run(cmd_args) }.to raise_error Clamp::ExecutionError, /you must specify a filename/
|
||||
end
|
||||
|
@ -101,13 +105,18 @@ describe LogStash::PluginManager::PrepareOfflinePack do
|
|||
FileUtils.touch(tmp_zip_file)
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_f(tmp_zip_file)
|
||||
end
|
||||
|
||||
context "without `--overwrite`" do
|
||||
before do
|
||||
expect(LogStash::PluginManager::OfflinePluginPackager).not_to receive(:package).with(anything)
|
||||
end
|
||||
|
||||
it "should fails" do
|
||||
expect { subject.run(cmd_args) }.to raise_error Clamp::ExecutionError, /output file destination #{tmp_zip_file} already exist/
|
||||
# ignore the first path part of tmp_zip_file because on Windows the long path is shrinked in the exception message
|
||||
expect { subject.run(cmd_args) }.to raise_error Clamp::ExecutionError, /output file destination .+#{::File.basename(tmp_zip_file)} already exist/
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ describe LogStash::PluginManager::Utils::Downloader do
|
|||
let(:temporary_path) { Stud::Temporary.pathname }
|
||||
|
||||
before do
|
||||
expect_any_instance_of(::File).to receive(:close).at_least(:twice).and_raise("Didn't work")
|
||||
expect(Net::HTTP::Get).to receive(:new).once.and_raise("Didn't work")
|
||||
expect(Stud::Temporary).to receive(:pathname).and_return(temporary_path)
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue