From 390e6bffbfd17db534815ebde32d0e8cab76fcb6 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 27 Jun 2019 14:14:12 +0100 Subject: [PATCH 1/2] (SERVER-2470) list_all_transports implementation for puppetserver This change implements a `list_all_transports(env)` method that loads all available transports from a specified environment. To test out, run `rake spec_prep` and use the following setup in pry: ``` require 'puppet' require 'puppet/resource_api/transport' require 'puppet/settings' Puppet.initialize_settings Puppet[:modulepath] = 'spec/fixtures/modules' Puppet::ResourceApi::Transport.list_all_transports('production') ``` --- lib/puppet/resource_api/transport.rb | 24 ++++++++++++++++ .../resource_api/transport_spec.rb | 28 +++++++++++++++++++ spec/spec_helper.rb | 4 +++ 3 files changed, 56 insertions(+) create mode 100644 spec/integration/resource_api/transport_spec.rb diff --git a/lib/puppet/resource_api/transport.rb b/lib/puppet/resource_api/transport.rb index adb9df63..7365ee57 100644 --- a/lib/puppet/resource_api/transport.rb +++ b/lib/puppet/resource_api/transport.rb @@ -20,11 +20,35 @@ def register(schema) module_function :register # rubocop:disable Style/AccessModifierDeclarations # retrieve a Hash of transport schemas, keyed by their name. + # Only already loaded transports are returned. def list Marshal.load(Marshal.dump(transports)) end module_function :list # rubocop:disable Style/AccessModifierDeclarations + # retrieve a Hash of transport schemas, keyed by their name. + # This uses the Puppet autoloader, provide a environment name as `force_environment` + # to choose where to load from. + # @api private + def list_all_transports(force_environment) + env = Puppet.lookup(:environments).get!(force_environment) + Puppet.override({ current_environment: env }, 'current env for list_all_transports') do + load_all_schemas + Marshal.load(Marshal.dump(transports)) + end + end + module_function :list_all_transports # rubocop:disable Style/AccessModifierDeclarations + + # Loads all schemas using the Puppet Autoloader. + def self.load_all_schemas + require 'puppet' + require 'puppet/settings' + require 'puppet/util/autoload' + @autoloader ||= Puppet::Util::Autoload.new(self, 'puppet/transport/schema') + @autoloader.loadall(Puppet.lookup(:current_environment)) + end + private_class_method :load_all_schemas + def connect(name, connection_info) validate(name, connection_info) require "puppet/transport/#{name}" diff --git a/spec/integration/resource_api/transport_spec.rb b/spec/integration/resource_api/transport_spec.rb new file mode 100644 index 00000000..b19f9067 --- /dev/null +++ b/spec/integration/resource_api/transport_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +RSpec.describe 'Resource API Transport integration tests:' do + after(:each) do + # reset registered transports between tests to reduce cross-test poisoning + Puppet::ResourceApi::Transport.instance_variable_set(:@transports, nil) + autoloader = Puppet::ResourceApi::Transport.instance_variable_get(:@autoloader) + autoloader.class.loaded.clear + end + + describe '#list_all_transports' do + subject(:transports) { Puppet::ResourceApi::Transport.list_all_transports('rp_env') } + + it 'can be called twice' do + expect { + Puppet::ResourceApi::Transport.list_all_transports('rp_env') + Puppet::ResourceApi::Transport.list_all_transports('rp_env') + }.not_to raise_error + end + + it 'loads all transports' do + expect(transports).to have_key 'test_device' + expect(transports).to have_key 'test_device_sensitive' + expect(transports['test_device']).to be_a Puppet::ResourceApi::TransportSchemaDef + expect(transports['test_device'].definition).to include(name: 'test_device') + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 90a14eef..dc91cb32 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,5 @@ require 'bundler/setup' +require 'rspec-puppet' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure @@ -14,6 +15,9 @@ # override legacy default from puppetlabs_spec_helper config.mock_with :rspec + # enable rspec-puppet support everywhere + config.include RSpec::Puppet::Support + # reset the warning suppression count config.before(:each) do Puppet::ResourceApi.warning_count = 0 From ad55367888a24519e86d93a1c78bd31e332fb6d4 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 27 Jun 2019 15:03:41 +0100 Subject: [PATCH 2/2] (maint) avoid clashing test with actual fixture, pt2 This might have been uncovered by the autoloader reset and random order testing. To make sure it does not recur, this change moves the autoloader reset to the top and runs it after each example. --- spec/integration/resource_api/transport_spec.rb | 7 ------- spec/puppet/resource_api/transport_spec.rb | 5 ----- spec/puppet/resource_api_spec.rb | 2 +- spec/spec_helper.rb | 11 +++++++++++ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/spec/integration/resource_api/transport_spec.rb b/spec/integration/resource_api/transport_spec.rb index b19f9067..fadfda3d 100644 --- a/spec/integration/resource_api/transport_spec.rb +++ b/spec/integration/resource_api/transport_spec.rb @@ -1,13 +1,6 @@ require 'spec_helper' RSpec.describe 'Resource API Transport integration tests:' do - after(:each) do - # reset registered transports between tests to reduce cross-test poisoning - Puppet::ResourceApi::Transport.instance_variable_set(:@transports, nil) - autoloader = Puppet::ResourceApi::Transport.instance_variable_get(:@autoloader) - autoloader.class.loaded.clear - end - describe '#list_all_transports' do subject(:transports) { Puppet::ResourceApi::Transport.list_all_transports('rp_env') } diff --git a/spec/puppet/resource_api/transport_spec.rb b/spec/puppet/resource_api/transport_spec.rb index 9da781ba..13267ab7 100644 --- a/spec/puppet/resource_api/transport_spec.rb +++ b/spec/puppet/resource_api/transport_spec.rb @@ -29,11 +29,6 @@ def change_environment(name = nil) Puppet.debug = true end - after(:each) do - # reset registered transports between tests to reduce cross-test poisoning - described_class.instance_variable_set(:@transports, nil) - end - describe '#register(schema)' do context 'when registering a schema with missing keys' do it { expect { described_class.register([]) }.to raise_error(Puppet::DevError, %r{requires a hash as schema}) } diff --git a/spec/puppet/resource_api_spec.rb b/spec/puppet/resource_api_spec.rb index c32eb4f6..0c91edd8 100644 --- a/spec/puppet/resource_api_spec.rb +++ b/spec/puppet/resource_api_spec.rb @@ -1847,7 +1847,7 @@ def set(_context, changes) end context 'when loading a type with unknown features' do let(:definition) do { - name: 'test_noop_support', + name: 'test_noop_support_2', desc: 'a test resource', features: ['no such feature'], attributes: {}, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index dc91cb32..763050cb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,3 +30,14 @@ # exclude the `version.rb` which already gets loaded by bundler via the gemspec, and doesn't need coverage testing anyways. SimpleCov.add_filter 'lib/puppet/resource_api/version.rb' if ENV['SIMPLECOV'] == 'yes' + +# configure this hook after Resource API is loaded to get access to Puppet::ResourceApi::Transport +RSpec.configure do |config| + config.after(:each) do + # reset registered transports between tests to reduce cross-test poisoning + Puppet::ResourceApi::Transport.instance_variable_set(:@transports, nil) + if (autoloader = Puppet::ResourceApi::Transport.instance_variable_get(:@autoloader)) + autoloader.class.loaded.clear + end + end +end