# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require_relative '../../framework/fixture' require_relative '../../framework/settings' require_relative '../../services/logstash_service' require_relative '../../framework/helpers' require_relative "pluginmanager_spec_helper" require "logstash/devutils/rspec/spec_helper" describe "CLI > logstash-plugin remove" do include_context "pluginmanager validation helpers" before(:each) do @fixture = Fixture.new(__FILE__) @logstash = @fixture.get_service("logstash") @logstash_plugin = @logstash.plugin_cli end if RbConfig::CONFIG["host_os"] == "linux" context "without internet connection (linux seccomp wrapper)" do let(:offline_wrapper_path) { File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "fixtures", "offline_wrapper")) } let(:offline_wrapper_cmd) { File.join(offline_wrapper_path, "offline") } before do Dir.chdir(offline_wrapper_path) do system("make clean") system("make") end end context "when no other plugins depends on this plugin" do let(:test_plugin) { "logstash-filter-qatest" } before :each do @logstash_plugin.install(File.join(File.dirname(__FILE__), "..", "..", "fixtures", "logstash-filter-qatest-0.1.1.gem")) end it "successfully remove the plugin" do execute = @logstash_plugin.run_raw("#{offline_wrapper_cmd} bin/logstash-plugin remove #{test_plugin}") expect(execute.exit_code).to eq(0) expect(execute.stderr_and_stdout).to match(/Successfully removed #{test_plugin}/) presence_check = @logstash_plugin.list(test_plugin) expect(presence_check.exit_code).to eq(1) expect(presence_check.stderr_and_stdout).to match(/ERROR: No plugins found/) expect("logstash-filter-qatest").to_not be_installed_gem end end context "when other plugins depends on this plugin" do it "refuses to remove the plugin and display the plugin that depends on it." do execute = @logstash_plugin.run_raw("#{offline_wrapper_cmd} bin/logstash-plugin remove logstash-codec-json") expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to match(/Failed to remove "logstash-codec-json"/) expect(execute.stderr_and_stdout).to match(/logstash-integration-kafka/) # one of the dependency expect(execute.stderr_and_stdout).to match(/logstash-output-udp/) # one of the dependency presence_check = @logstash_plugin.list("logstash-codec-json") expect(presence_check.exit_code).to eq(0) expect(presence_check.stderr_and_stdout).to match(/logstash-codec-json/) end end end end context "when no other plugins depends on this plugin" do let(:test_plugin) { "logstash-filter-qatest" } before :each do @logstash_plugin.install(File.join(File.dirname(__FILE__), "..", "..", "fixtures", "logstash-filter-qatest-0.1.1.gem")) end it "successfully remove the plugin" do execute = @logstash_plugin.remove(test_plugin) expect(execute.exit_code).to eq(0) expect(execute.stderr_and_stdout).to match(/Successfully removed #{test_plugin}/) presence_check = @logstash_plugin.list(test_plugin) expect(presence_check.exit_code).to eq(1) expect(presence_check.stderr_and_stdout).to match(/ERROR: No plugins found/) expect("logstash-filter-qatest").to_not be_installed_gem end end context "plugins with unshared dependencies" do let(:plugin_to_remove) { } it "successfully removes the plugin and its unshared dependencies" do execute = @logstash_plugin.remove("logstash-integration-aws") expect(execute.exit_code).to eq(0) expect(execute.stderr_and_stdout).to match(/Successfully removed logstash-integration-aws/) expect("logstash-integration-aws").to_not be_installed_gem # known unshared dependencies, including transitive dependencies aggregate_failures("known unshared dependencies") do expect("aws-sdk-core").to_not be_installed_gem expect("aws-sdk-s3").to_not be_installed_gem expect("aws-sdk-kms").to_not be_installed_gem expect("aws-sdk-cloudfront").to_not be_installed_gem expect("aws-sdk-cloudwatch").to_not be_installed_gem expect("aws-eventstream").to_not be_installed_gem expect("aws-partitions").to_not be_installed_gem end # known shared dependencies aggregate_failures("known shared dependencies") do expect("concurrent-ruby").to be_installed_gem expect("logstash-codec-json").to be_installed_gem end end end context "when other plugins depends on this plugin" do it "refuses to remove the plugin and display the plugin that depends on it." do execute = @logstash_plugin.remove("logstash-codec-json") expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to match(/Failed to remove "logstash-codec-json"/) expect(execute.stderr_and_stdout).to match(/logstash-integration-kafka/) # one of the dependency expect(execute.stderr_and_stdout).to match(/logstash-output-udp/) # one of the dependency presence_check = @logstash_plugin.list("logstash-codec-json") expect(presence_check.exit_code).to eq(0) expect(presence_check.stderr_and_stdout).to match(/logstash-codec-json/) expect("logstash-codec-json").to be_installed_gem end end context "multiple plugins" do let(:setup_plugin_list) do fail("spec must override `setup_plugin_list`") end before(:each) do if setup_plugin_list.any? search_dir = File.expand_path(File.join(__dir__, "..", "..", "fixtures", "plugins")) plugin_paths = [] aggregate_failures('setup: resolve plugin paths') do setup_plugin_list.each do |requested_plugin| found = Dir.glob(File.join(search_dir, "#{requested_plugin}-*.gem")) expect(found).to have_attributes(:size => 1), lambda { "expected exactly one `#{requested_plugin}` in `#{search_dir}`, got #{found.inspect}" } plugin_paths << found.first end end aggregate_failures('setup: installing plugins') do puts "installing plugins #{plugin_paths.inspect}" outcome = @logstash_plugin.install(*plugin_paths) expect(outcome.exit_code).to eq(0) expect(outcome.stderr_and_stdout).to match(/Installation successful/) end end end context "when a remaining plugin has a dependency on a removed plugin" do let(:setup_plugin_list) do %w( logstash-filter-zero_no_dependencies logstash-filter-one_no_dependencies logstash-filter-two_depends_on_one logstash-filter-three_no_dependencies logstash-filter-four_depends_on_one_and_three ) end it "errors helpfully without removing any of the plugins" do execute = @logstash_plugin.remove("logstash-filter-three_no_dependencies", "logstash-filter-zero_no_dependencies") expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to include('Failed to remove "logstash-filter-three_no_dependencies"') expect(execute.stderr_and_stdout).to include("* logstash-filter-four_depends_on_one_and_three") # one of the dependency expect(execute.stderr_and_stdout).to include("No plugins were removed.") aggregate_failures("list plugins") do presence_check = @logstash_plugin.list expect(presence_check.exit_code).to eq(0) expect(presence_check.stderr_and_stdout).to include('logstash-filter-three_no_dependencies') expect(presence_check.stderr_and_stdout).to include('logstash-filter-zero_no_dependencies') end end end context "when multiple remaining plugins have a dependency on a removed plugin" do let(:setup_plugin_list) do %w( logstash-filter-zero_no_dependencies logstash-filter-one_no_dependencies logstash-filter-two_depends_on_one logstash-filter-three_no_dependencies logstash-filter-four_depends_on_one_and_three ) end it "errors helpfully without removing any of the plugins" do execute = @logstash_plugin.remove("logstash-filter-one_no_dependencies", "logstash-filter-zero_no_dependencies") expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to include('Failed to remove "logstash-filter-one_no_dependencies"') expect(execute.stderr_and_stdout).to include("* logstash-filter-four_depends_on_one_and_three") # one of the dependency expect(execute.stderr_and_stdout).to include("* logstash-filter-two_depends_on_one") # one of the dependency expect(execute.stderr_and_stdout).to include("No plugins were removed.") aggregate_failures("list plugins") do presence_check = @logstash_plugin.list expect(presence_check.exit_code).to eq(0) expect(presence_check.stderr_and_stdout).to include('logstash-filter-one_no_dependencies') expect(presence_check.stderr_and_stdout).to include('logstash-filter-zero_no_dependencies') end end end context "when removing plugins and all plugins that depend on them" do let(:setup_plugin_list) do %w( logstash-filter-zero_no_dependencies logstash-filter-one_no_dependencies logstash-filter-two_depends_on_one logstash-filter-three_no_dependencies logstash-filter-four_depends_on_one_and_three ) end it "removes the plugins" do plugins_to_remove = %w( logstash-filter-one_no_dependencies logstash-filter-two_depends_on_one logstash-filter-three_no_dependencies logstash-filter-four_depends_on_one_and_three ).shuffle #random order execute = @logstash_plugin.remove(*plugins_to_remove) aggregate_failures("removal action") do expect(execute).to have_attributes(:exit_code => 0, :stderr_and_stdout => include("Success")) plugins_to_remove.each do |gem_name| expect(execute.stderr_and_stdout).to include("Successfully removed #{gem_name}") end end aggregate_failures("list plugins") do presence_check = @logstash_plugin.list expect(presence_check.exit_code).to eq(0) aggregate_failures("removed plugins") do plugins_to_remove.each do |expected_removed_plugin| expect(presence_check.stderr_and_stdout).to_not include(expected_removed_plugin) end end aggregate_failures("non-removed plugins") do (setup_plugin_list - plugins_to_remove).each do |expected_remaining_plugin| expect(presence_check.stderr_and_stdout).to include(expected_remaining_plugin) end end end end end end end