diff --git a/.fixtures.yml b/.fixtures.yml index 7e09776b..845ad562 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,3 +1,4 @@ fixtures: symlinks: registry: "#{source_dir}" + mixed_default_settings: "#{source_dir}/spec/fixtures/mixed_default_settings" diff --git a/lib/puppet_x/puppetlabs/registry.rb b/lib/puppet_x/puppetlabs/registry.rb index e13ef24e..962ed56b 100644 --- a/lib/puppet_x/puppetlabs/registry.rb +++ b/lib/puppet_x/puppetlabs/registry.rb @@ -135,7 +135,7 @@ def canonical # preserve the trailing backslash for the provider, otherwise it won't # think this is a default value. if default? - filter_path[:canonical] << "\\" + filter_path[:canonical] + "\\" else filter_path[:canonical] end @@ -156,6 +156,16 @@ def valuename def default? !!filter_path[:is_default] end + + def filter_path + result = super + + # It's possible to pass in a path of 'hklm' which can still be parsed, but is not valid registry key. Only the default value 'hklm\' + # and named values 'hklm\something' are allowed + raise ArgumentError, "Invalid registry key: #{path}" if result[:trailing_path].empty? && result[:valuename].empty? && !result[:is_default] + + result + end end end end diff --git a/spec/classes/mixed_default_settings_spec.rb b/spec/classes/mixed_default_settings_spec.rb new file mode 100644 index 00000000..23adcafd --- /dev/null +++ b/spec/classes/mixed_default_settings_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +# The manifest used for testing, is located in spec/fixtures/mixed_default_settings/manifests/init.pp + +# This test is to ensure that the way of setting default values (trailing slash) compiles correctly +# when there is a similar looking path in the manifest. It mixes default and non-default value_names in the same manifest +# +# This manifest attempts to manage two registry values +# +# + HKLM +# + Software +# - foo <-- This is a value called 'foo' in the 'HKLM\Sofware' key. +# | This is the 'hklm\Software\foo' resource +# | +# + foo +# + (default value) <-- This is the default value for a key called 'HKLM\Software\foo'. +# This is the 'hklm\Software\foo\\' resource +# + +describe 'mixed_default_settings' do + it { is_expected.to compile } + + it { is_expected.to contain_registry_value('hklm\Software\foo\\') } + it { is_expected.to contain_registry_value('hklm\Software\foo') } +end diff --git a/spec/fixtures/mixed_default_settings/manifests/init.pp b/spec/fixtures/mixed_default_settings/manifests/init.pp new file mode 100644 index 00000000..57ac7f4c --- /dev/null +++ b/spec/fixtures/mixed_default_settings/manifests/init.pp @@ -0,0 +1,13 @@ +class mixed_default_settings { + registry_value { 'hklm\Software\foo\\': + ensure => present, + type => string, + data => 'default', + } + + registry_value { 'hklm\Software\foo': + ensure => present, + type => string, + data => 'nondefault', + } +} diff --git a/spec/unit/puppet/provider/registry_value_spec.rb b/spec/unit/puppet/provider/registry_value_spec.rb index 3b6f612f..fdd5255f 100644 --- a/spec/unit/puppet/provider/registry_value_spec.rb +++ b/spec/unit/puppet/provider/registry_value_spec.rb @@ -51,7 +51,12 @@ describe "#exists?" do it "should return true for a well known hive" do - reg_value = type.new(:path => 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareType', :provider => described_class.name) + reg_value = type.new(:title => 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareType', :provider => described_class.name) + reg_value.provider.exists?.should be true + end + + it "should return true for a well known hive with mixed case name" do + reg_value = type.new(:title => 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareType'.upcase, :provider => described_class.name) reg_value.provider.exists?.should be true end @@ -82,6 +87,7 @@ end describe "#destroy" do + let (:default_path) { path = "hklm\\#{puppet_key}\\#{subkey_name}\\" } let (:path) { path = "hklm\\#{puppet_key}\\#{subkey_name}\\#{SecureRandom.uuid}" } def create_and_destroy(path, reg_type, data) reg_value = type.new(:path => path, @@ -102,6 +108,10 @@ def create_and_destroy(path, reg_type, data) reg_value.provider.exists?.should be false end + it "can destroy a randomly created default REG_SZ value" do + create_and_destroy(default_path, :string, SecureRandom.uuid) + end + it "can destroy a randomly created REG_SZ value" do create_and_destroy(path, :string, SecureRandom.uuid) end diff --git a/spec/unit/puppet/type/registry_key_spec.rb b/spec/unit/puppet/type/registry_key_spec.rb index dd90ca90..13b8bf09 100644 --- a/spec/unit/puppet/type/registry_key_spec.rb +++ b/spec/unit/puppet/type/registry_key_spec.rb @@ -39,7 +39,7 @@ key[:path] = path end end - + %w[hku hku\.DEFAULT hku\.DEFAULT\software hku\.DEFAULT\software\vendor].each do |path| it "should accept #{path}" do key[:path] = path @@ -110,6 +110,18 @@ res[:path].must == "#{key[:path]}\\val3" end + it "should purge existing values that are not being managed and case insensitive)" do + pending("eval_generate is currently not case insensitive, but should be") + key.provider.expects(:values).returns(['VAL1', 'VaL\3', 'Val99']) + resources = key.eval_generate + resources.count.must == 1 + res = resources.first + + res[:ensure].must == :absent + res[:path].must == key[:path] + res[:value_name].must == 'Val99' + end + it "should return an empty array if all existing values are being managed" do key.provider.expects(:values).returns(['val1', 'val2']) key.eval_generate.must be_empty @@ -117,7 +129,7 @@ end end - describe "#autorequire" do + describe "resource aliases" do let :the_catalog do Puppet::Resource::Catalog.new end diff --git a/spec/unit/puppet/type/registry_value_spec.rb b/spec/unit/puppet/type/registry_value_spec.rb index 03deb1c7..3500976d 100644 --- a/spec/unit/puppet/type/registry_value_spec.rb +++ b/spec/unit/puppet/type/registry_value_spec.rb @@ -17,7 +17,7 @@ describe "path parameter" do it "should have a path parameter" do - Puppet::Type.type(:registry_key).attrtype(:path).should == :param + Puppet::Type.type(:registry_value).attrtype(:path).should == :param end %w[hklm\propname hklm\software\propname].each do |path| @@ -33,7 +33,9 @@ end it "should strip trailling slashes from unnamed values" do - described_class.new(:path => 'hklm\\software\\\\', :catalog => catalog) + value = described_class.new(:path => 'hklm\\software\\\\', :catalog => catalog) + + expect(value[:path]).to eq('hklm\\software\\') end %w[HKEY_DYN_DATA\\ HKEY_PERFORMANCE_DATA\name].each do |path| @@ -44,8 +46,7 @@ %w[hklm hkcr unknown\\name unknown\\subkey\\name].each do |path| it "should reject #{path} as invalid" do - pending 'wrong message' - expect { described_class.new(:path => path, :catalog => catalog) }.should raise_error(Puppet::Error, /Invalid registry key/) + expect { described_class.new(:path => path, :catalog => catalog) }.to raise_error(Puppet::Error, /Invalid registry key/) end end @@ -60,12 +61,55 @@ it 'should validate the length of the value data' it 'should be case-preserving' it 'should be case-insensitive' - it 'should autorequire ancestor keys' it 'should support 32-bit values' do value = described_class.new(:path => '32:hklm\software\foo', :catalog => catalog) end end + describe '#autorequire' do + let(:subject) { described_class.new(:title => subject_title, :catalog => catalog) } + [ + { + :context => 'with a non-default value_name', + :reg_value_title => 'hklm\software\foo\bar', + :expected_reg_key_title => 'hklm\Software\foo', + }, + { + :context => 'with a mixed case path and value_name', + :reg_value_title => 'hkLm\soFtwarE\fOo\Bar', + :expected_reg_key_title => 'hklm\Software\foo', + }, + { + :context => 'with a default value_name', + :reg_value_title => 'hklm\software\foo\bar\\', + :expected_reg_key_title => 'hklm\Software\foo\bar', + }, + { + :context => 'with a value whose parent key is not managed but does have an ancestor key in the catalog', + :reg_value_title => 'hklm\software\foo\bar\baz\alice', + :expected_reg_key_title => 'hklm\Software\foo\bar', + } + ].each do |testcase| + context testcase[:context] do + let(:subject) { described_class.new(:title => testcase[:reg_value_title], :catalog => catalog) } + + it 'should not autorequire ancestor keys if none exist' do + expect(subject.autorequire).to eq([]) + end + + it 'should only autorequire the nearest ancestor registry_key resource' do + catalog.add_resource(Puppet::Type.type(:registry_key).new(:path => 'hklm\Software', :catalog => catalog)) + catalog.add_resource(Puppet::Type.type(:registry_key).new(:path => 'hklm\Software\foo', :catalog => catalog)) + catalog.add_resource(Puppet::Type.type(:registry_key).new(:path => 'hklm\Software\foo\bar', :catalog => catalog)) + + autorequire_array = subject.autorequire + expect(autorequire_array.count).to eq(1) + expect(autorequire_array[0].to_s).to eq("Registry_key[#{testcase[:expected_reg_key_title]}] => Registry_value[#{testcase[:reg_value_title]}]") + end + end + end + end + describe "type property" do let (:value) { described_class.new(:path => 'hklm\software\foo', :catalog => catalog) }