inspec/test/unit/plugin/v2/loader_test.rb
Ryan Davis ca4844210d Fixed Inspec::Plugin::V2::Registry#detect_system_plugins
+ Falls back to checking for inspec-core if inspec not found.
+ Fails gracefully if neither are found.

Signed-off-by: Ryan Davis <zenspider@chef.io>
2019-09-25 16:10:00 -07:00

329 lines
13 KiB
Ruby

# Unit tests for Inspec::PluginLoader and Registry
require "helper"
require "inspec/plugin/v2"
require "train" # Needed for Train plugin testing
class Inspec::Plugin::V2::Loader
public :detect_system_plugins
end
class PluginLoaderTests < Minitest::Test
@@orig_home = Dir.home
def reset_globals
ENV["HOME"] = @@orig_home
ENV["INSPEC_CONFIG_DIR"] = nil
Inspec::Plugin::V2::Registry.instance.__reset
end
def setup
reset_globals
@config_dir_path = File.expand_path "test/unit/mock/config_dirs"
@bundled_plugins = [
:'inspec-supermarket',
]
@core_plugins = %i{
inspec-artifact
inspec-compliance
inspec-habitat
inspec-init
}
@system_plugins = [
"train-habitat",
]
end
def teardown
reset_globals
# Clean up any activated gems
Gem.loaded_specs.delete("inspec-test-fixture")
Gem.loaded_specs.delete("ordinal_array")
end
#====================================================================#
# basic constructor usage and bundle detection #
#====================================================================#
def test_constructor_should_detect_bundled_plugins
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new
@bundled_plugins.each do |bundled_plugin_name|
assert reg.known_plugin?(bundled_plugin_name), "\n#{bundled_plugin_name} should be detected as a bundled plugin"
end
end
def test_constructor_should_detect_core_plugins
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new
@core_plugins.each do |core_plugin_name|
assert reg.known_plugin?(core_plugin_name), "\n#{core_plugin_name} should be detected as a core plugin"
end
end
def test_constructor_should_skip_bundles_when_option_is_set
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new(omit_bundles: true)
@bundled_plugins.each do |bundled_plugin_name|
refute reg.known_plugin?(bundled_plugin_name), "\n#{bundled_plugin_name} should not be detected when omit_bundles is set"
end
end
def test_constructor_should_skip_core_when_option_is_set
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new(omit_core_plugins: true)
@core_plugins.each do |core_plugin_name|
refute reg.known_plugin?(core_plugin_name), "\n#{core_plugin_name} should not be detected when omit_core_plugins is set"
end
end
def test_constructor_when_using_home_dir_detects_declared_plugins
ENV["HOME"] = File.join(@config_dir_path, "fakehome")
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new
assert reg.known_plugin?(:'inspec-test-home-marker'), "\ninspec-test-home-marker should be detected as a plugin"
end
#====================================================================#
# unusual plugin.json situations #
#====================================================================#
def test_constructor_when_the_plugin_config_is_absent_it_detects_bundled_plugins
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "empty")
reg = Inspec::Plugin::V2::Registry.instance
Inspec::Plugin::V2::Loader.new
@bundled_plugins.each do |bundled_plugin_name|
assert reg.known_plugin?(bundled_plugin_name), "\n#{bundled_plugin_name} should be detected as a bundled plugin"
end
end
#====================================================================#
# basic loading #
#====================================================================#
def test_load_no_plugins_should_load_no_plugins
reg = Inspec::Plugin::V2::Registry.instance
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true, omit_core_plugins: true, omit_user_plugins: true, omit_sys_plugins: true)
loader.load_all
assert_equal 0, reg.loaded_count, "\nRegistry load count"
end
def test_load_only_bundled_plugins_should_load_bundled_plugins
skip "This keeps failing, only affects legacy bundles, will fix later"
# Skip rationale: I beleive this test is failing due to a test artifact - we
# keep loading v1 CLI plugins and then purging the registry, which results (depending
# on test order) in the Ruby `require` refusing to re-load the v1 plugin (since it was
# previously loaded). But since we purge the Registry, the Registry doesn't know
# about it either. Neither of those things are intended to happen as
# the plugin system is finished (the v1 plugins will be ported to v2, and registry
# purging should never happen in real-world use)
reg = Inspec::Plugin::V2::Registry.instance
loader = Inspec::Plugin::V2::Loader.new
loader.load_all
@bundled_plugins.each do |bundled_plugin_name|
assert reg.loaded_plugin?(bundled_plugin_name), "\n#{bundled_plugin_name} should be loaded"
assert_equal [ :cli_command ], reg[bundled_plugin_name].plugin_types, "annotate plugin type of bundled plugins"
assert_equal 0, reg[bundled_plugin_name].api_generation, "annotate API generation of bundled plugins"
assert_kind_of(Class, reg[bundled_plugin_name].plugin_class)
end
assert_equal @bundled_plugins.count, reg.loaded_count, "\nRegistry load count"
end
def test_load_cli_plugin_by_path
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "meaning_by_path")
reg = Inspec::Plugin::V2::Registry.instance
plugin_name = :'inspec-meaning-of-life'
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
assert reg.known_plugin?(plugin_name), "\n#{plugin_name} should be a known plugin"
refute reg.loaded_plugin?(plugin_name), "\n#{plugin_name} should not be loaded yet"
loader.load_all
assert reg.loaded_plugin?(plugin_name), "\n#{plugin_name} should be loaded"
end
def test_list_managed_gems
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "test-fixture-2-float")
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
gemspecs = loader.list_managed_gems
gem = gemspecs.detect { |spec| spec.name == "ordinal_array" }
refute_nil gem, "loader.list_managed_gems should find ordinal_array"
assert_equal Gem::Version.new("0.2.0"), gem.version
end
def test_list_installed_plugin_gems
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "test-fixture-1-float")
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
gemspecs = loader.list_installed_plugin_gems
gem = gemspecs.detect { |spec| spec.name == "inspec-test-fixture" }
refute_nil gem, "loader.list_installed_plugin_gems should find inspec-test-fixture"
assert_equal Gem::Version.new("0.1.0"), gem.version
end
def test_load_mock_plugin_by_gem
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "test-fixture-2-float")
reg = Inspec::Plugin::V2::Registry.instance
plugin_name = :'inspec-test-fixture'
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
assert_operator reg, :known_plugin?, plugin_name
refute_operator reg, :loaded_plugin?, plugin_name
loader.load_all
assert_operator reg, :loaded_plugin?, plugin_name
end
#====================================================================#
# activation #
#====================================================================#
def test_activation
# Setup
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "meaning_by_path")
registry = Inspec::Plugin::V2::Registry.instance
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
loader.load_all
status = registry[:'inspec-meaning-of-life']
# Management methods for activation
assert_respond_to status, :activators, "A plugin status should respond to `activators`"
assert_respond_to registry, :find_activators, "Registry should respond to `find_activators`"
# Finding an Activator
assert_kind_of Array, status.activators, "status should have an array for activators"
assert_kind_of Array, registry.find_activators, "find_activators should return an array"
assert_equal "Inspec::Plugin::V2::Activator", registry.find_activators[0].class.name, "find_activators should return an array of Activators"
activator = registry.find_activators(plugin_type: :mock_plugin_type, name: :'meaning-of-life-the-universe-and-everything')[0]
refute_nil activator, "find_activators should find the test activator"
%i{plugin_name plugin_type activator_name activated? exception activation_proc implementation_class}.each do |method_name|
assert_respond_to activator, method_name
end
# Activation preconditions
refute activator.activated?, "Test activator should start out unactivated"
assert_nil activator.exception, "Test activator should have no exception prior to activation"
assert_nil activator.implementation_class, "Test activator should not know implementation class prior to activation"
refute InspecPlugins::MeaningOfLife.const_defined?(:MockPlugin), "impl_class should not be defined prior to activation"
activator.activate
# Activation postconditions
assert activator.activated?, "Test activator should be activated after activate"
assert_nil activator.exception, "Test activator should have no exception after activation"
# facts about the implementation class
impl_class = activator.implementation_class
refute_nil impl_class, "Activation should set the implementation class"
assert_kind_of Class, impl_class, "Should have a Class in the implementation class slot"
assert_includes impl_class.ancestors, Inspec::Plugin::V2::PluginBase, "impl_class should derive from PluginBase"
assert_includes impl_class.ancestors, Inspec::Plugin::V2::PluginType::Mock, "impl_class should derive from PluginType::Mock"
assert InspecPlugins::MeaningOfLife.const_defined?(:MockPlugin), "impl_class should now be defined"
assert_equal :'inspec-meaning-of-life', Inspec::Plugin::V2::PluginBase.find_name_by_implementation_class(impl_class), "find_name_by_implementation_class should work"
end
#====================================================================#
# Train Plugin Special Handling #
#====================================================================#
def test_when_a_train_plugin_is_installed_via_gem_and_required
ENV["INSPEC_CONFIG_DIR"] = File.join(@config_dir_path, "train-test-fixture")
reg = Inspec::Plugin::V2::Registry.instance
assert_silent { Inspec::Plugin::V2::Loader.new }
plugin_name = :'train-test-fixture'
assert(reg.known_plugin?(plugin_name), "The train plugin should be known after loader init")
status = reg[plugin_name]
assert_equal(:'train-1', status.api_generation, "It should have a special value for api gen (:'train-1')")
refute(reg.loaded_plugin?(plugin_name), "It should not be loaded until needed")
# 'Requiring' the gem name should succeed
require "train-test-fixture"
assert_includes(Train::Plugins.registry.keys, "test-fixture", "After requiring the gem, the Train Registry should know the plugin is loaded")
assert(reg.loaded_plugin?(plugin_name), "After requiring, InSpec Registry should know the the plugin is loaded")
end
REG_INST = Inspec::Plugin::V2::Registry.instance
def with_empty_registry
old_reg = REG_INST.registry.dup
REG_INST.registry.clear
yield
ensure
REG_INST.registry.replace old_reg
end
def with_logger
old_logger = Inspec::Log.logger
io = StringIO.new
Inspec::Log.logger = Logger.new(io)
yield
io.string
ensure
Inspec::Log.logger = old_logger
end
def using_bundler?
Gem::Specification.find_by_name("inspec")
rescue Gem::MissingSpecError
nil
end
def assert_detect_system_plugins(exp_keys, exp_err)
# rubocop:disable Style/HashSyntax
loader = Inspec::Plugin::V2::Loader.new(:omit_user_plugins => true,
:omit_bundles => true,
:omit_core_plugins => true,
:omit_sys_plugins => true)
assert_empty REG_INST.registry
yield loader
log_out = with_logger do
assert_silent do
loader.detect_system_plugins
end
end
assert_equal exp_keys, REG_INST.registry.keys.sort
assert_match exp_err, log_out
end
def test_detect_system_plugins
with_empty_registry do
exp = []
exp_err = "inspec gem not found, skipping detecting of system plugins\n"
assert_detect_system_plugins exp, exp_err do |loader|
def loader.find_inspec_gemspec(*)
nil
end
end
end
end
def test_detect_system_plugins_inspec
skip "not valid in this env" unless using_bundler?
with_empty_registry do
exp = %i{ train-aws train-habitat train-winrm }
exp_err = ""
assert_detect_system_plugins exp, exp_err do |loader|
def loader.find_inspec_gemspec(name, version)
super if name == "inspec"
end
end
end
end
end