diff --git a/spec/acceptance/ini_subsetting_spec.rb b/spec/acceptance/ini_subsetting_spec.rb index ac426fc..374f60d 100644 --- a/spec/acceptance/ini_subsetting_spec.rb +++ b/spec/acceptance/ini_subsetting_spec.rb @@ -1,291 +1,290 @@ # frozen_string_literal: true require 'spec_helper_acceptance' describe 'ini_subsetting resource' do basedir = setup_test_directory after :all do run_shell("rm #{basedir}/*.ini", expect_failures: true) end shared_examples 'has_content' do |path, pp, content| before :all do run_shell("rm #{path}", expect_failures: true) end it 'applies the manifest twice' do idempotent_apply(pp) end describe file(path) do it { is_expected.to be_file } describe '#content' do subject { super().content } it { is_expected.to match content } end end end shared_examples 'has_error' do |path, pp, error| before :all do run_shell("rm #{path}", expect_failures: true) end it 'applies the manifest and gets a failure message' do expect(apply_manifest(pp, expect_failures: true).stderr).to match(error) end describe file(path) do it { is_expected.not_to be_file } end end describe 'ensure, section, setting, subsetting, & value parameters => present with subsections' do pp = <<-EOS ini_subsetting { 'ensure => present for alpha': ensure => present, path => "#{basedir}/ini_subsetting.ini", section => 'one', setting => 'key', subsetting => 'alpha', value => 'bet', } ini_subsetting { 'ensure => present for beta': ensure => present, path => "#{basedir}/ini_subsetting.ini", section => 'one', setting => 'key', subsetting => 'beta', value => 'trons', require => Ini_subsetting['ensure => present for alpha'], } EOS describe file("#{basedir}/ini_subsetting.ini") do it_behaves_like 'has_content', "#{basedir}/ini_subsetting.ini", pp, %r{\[one\]\Rkey = alphabet betatrons} end end describe 'ensure => absent' do pp = <<-EOS ini_subsetting { 'ensure => absent for subsetting': ensure => absent, path => "#{basedir}/ini_subsetting.ini", section => 'one', setting => 'key', subsetting => 'alpha', } EOS it 'applies the manifest twice' do idempotent_apply(pp) end describe file("#{basedir}/ini_subsetting.ini") do it { is_expected.to be_file } describe '#content' do subject { super().content } it { is_expected.to match %r{\[one\]} } it { is_expected.to match %r{key = betatrons} } it { is_expected.not_to match %r{alphabet} } end end end describe 'delete_if_empty => true' do pp = <<-EOS ini_subsetting { 'ensure => absent for alpha': ensure => absent, path => "#{basedir}/ini_subsetting.ini", section => 'one', setting => 'key', subsetting => 'alpha', delete_if_empty => true, } ini_subsetting { 'ensure => absent for beta': ensure => absent, path => "#{basedir}/ini_subsetting.ini", section => 'one', setting => 'key', subsetting => 'beta', delete_if_empty => true, } EOS it 'applies the manifest twice' do run_shell("echo -e [one]\\\\nkey = alphabet betatrons > #{basedir}/ini_subsetting.ini", expect_failures: true) idempotent_apply(pp) end describe file("#{basedir}/ini_subsetting.ini") do it { is_expected.to be_file } describe '#content' do subject { super().content } it { is_expected.not_to match %r{\[one\]} } it { is_expected.not_to match %r{key =} } it { is_expected.not_to match %r{alphabet} } it { is_expected.not_to match %r{betatrons} } end end end describe 'quote_char' do { ['-Xmx'] => %r{args=""}, ['-Xmx', '256m'] => %r{args=-Xmx256m}, ['-Xmx', '512m'] => %r{args="-Xmx512m"}, ['-Xms', '256m'] => %r{args="-Xmx256m -Xms256m"}, }.each do |parameter, content| context %(with '#{parameter.first}' #{(parameter.length > 1) ? '=> \'' << parameter[1] << '\'' : 'absent'} makes '#{content}') do path = File.join(basedir, 'ini_subsetting.ini') before :all do ipp = <<-MANIFEST file { '#{path}': content => "[java]\nargs=-Xmx256m", force => true, } MANIFEST apply_manifest(ipp) end after :all do run_shell("cat #{path}", expect_failures: true) run_shell("rm #{path}", expect_failures: true) end pp = <<-EOS ini_subsetting { '#{parameter.first}': ensure => #{(parameter.length > 1) ? 'present' : 'absent'}, path => '#{path}', section => 'java', setting => 'args', quote_char => '"', subsetting => '#{parameter.first}', value => '#{(parameter.length > 1) ? parameter[1] : ''}' } EOS it 'applies the manifest twice' do idempotent_apply(pp) end describe file("#{basedir}/ini_subsetting.ini") do it { is_expected.to be_file } describe '#content' do subject { super().content } it { is_expected.to match content } end end end end end describe 'show_diff parameter and logging:' do setup_puppet_config_file [{ value: 'initial_value', matcher: 'created', show_diff: true }, { value: 'public_value', matcher: %r{initial_value.*public_value}, show_diff: true }, { value: 'secret_value', matcher: %r{redacted sensitive information.*redacted sensitive information}, show_diff: false }, { value: 'md5_value', matcher: %r{\{md5\}881671aa2bbc680bc530c4353125052b.*\{md5\}ed0903a7fa5de7886ca1a7a9ad06cf51}, show_diff: :md5 }].each do |i| - pp = <<-EOS ini_subsetting { 'test_show_diff': ensure => present, section => 'test', setting => 'something', subsetting => 'xxx', value => '#{i[:value]}', path => "#{basedir}/test_show_diff.ini", show_diff => #{i[:show_diff]} } EOS context "show_diff => #{i[:show_diff]}" do res = apply_manifest(pp, expect_changes: true) it 'applies manifest and expects changed value to be logged in proper form' do expect(res.stdout).to match(i[:matcher]) end it 'applies manifest and expects changed value to be logged in proper form #optional test' do expect(res.stdout).not_to match(i[:value]) unless i[:show_diff] == true end end end end describe 'insert types:' do [ { insert_type: :start, content: %r{d a b c}, }, { insert_type: :end, content: %r{a b c d}, }, { insert_type: :before, insert_value: 'c', content: %r{a b d c}, }, { insert_type: :after, insert_value: 'a', content: %r{a d b c}, }, { insert_type: :index, insert_value: 2, content: %r{a b d c}, }, ].each do |params| context "with '#{params[:insert_type]}' makes '#{params[:content]}'" do pp = <<-EOS ini_subsetting { "a": ensure => present, section => 'one', setting => 'two', subsetting => 'a', path => "#{basedir}/insert_types.ini", } -> ini_subsetting { "b": ensure => present, section => 'one', setting => 'two', subsetting => 'b', path => "#{basedir}/insert_types.ini", } -> ini_subsetting { "c": ensure => present, section => 'one', setting => 'two', subsetting => 'c', path => "#{basedir}/insert_types.ini", } -> ini_subsetting { "insert makes #{params[:content]}": ensure => present, section => 'one', setting => 'two', subsetting => 'd', path => "#{basedir}/insert_types.ini", insert_type => '#{params[:insert_type]}', insert_value => '#{params[:insert_value]}', } EOS it_behaves_like 'has_content', "#{basedir}/insert_types.ini", pp, params[:content] end end end end diff --git a/spec/unit/puppet/util/ini_file_spec.rb b/spec/unit/puppet/util/ini_file_spec.rb index efd5122..abf4a25 100644 --- a/spec/unit/puppet/util/ini_file_spec.rb +++ b/spec/unit/puppet/util/ini_file_spec.rb @@ -1,318 +1,317 @@ # frozen_string_literal: true require 'spec_helper' require 'stringio' require 'puppet/util/ini_file' describe Puppet::Util::IniFile do subject(:ini_sub) { described_class.new('/my/ini/file/path') } before :each do allow(File).to receive(:file?).with('/my/ini/file/path') { true } allow(described_class).to receive(:readlines).once.with('/my/ini/file/path') do sample_content end end context 'when parsing a file' do let(:sample_content) do template = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue baz = [section2] foo= foovalue2 baz=bazvalue ; commented = out setting #another comment ; yet another comment zot = multi word value xyzzy['thing1']['thing2']=xyzzyvalue l=git log EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 3. expect(ini_sub.section_names.length).to eq(3) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1', 'section2']) end it 'exposes settings for sections #section1' do expect(ini_sub.get_settings('section1')).to eq('bar' => 'barvalue', 'baz' => '', 'foo' => 'foovalue') end it 'exposes settings for sections #section2' do expect(ini_sub.get_settings('section2')).to eq('baz' => 'bazvalue', 'foo' => 'foovalue2', 'l' => 'git log', "xyzzy['thing1']['thing2']" => 'xyzzyvalue', 'zot' => 'multi word value') end end context 'when parsing a file whose first line is a section' do let(:sample_content) do template = <<-EOS [section1] ; This is a comment foo=foovalue EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 2. expect(ini_sub.section_names.length).to eq(2) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1']) end it 'exposes settings for sections' do expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end end context "when parsing a file with a 'global' section" do let(:sample_content) do template = <<-EOS foo = bar [section1] ; This is a comment foo=foovalue EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 2. expect(ini_sub.section_names.length).to eq(2) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1']) end it 'exposes settings for sections #bar' do expect(ini_sub.get_value('', 'foo')).to eq('bar') end it 'exposes settings for sections #foovalue' do expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end end context 'when updating a file with existing empty values' do let(:sample_content) do template = <<-EOS [section1] foo= #bar= #xyzzy['thing1']['thing2']='xyzzyvalue' EOS template.split("\n") end - # rubocop:disable RSpec/ExpectInHook before :each do expect(ini_sub.get_value('section1', 'far')).to eq(nil) expect(ini_sub.get_value('section1', 'bar')).to eq(nil) expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq(nil) end # rubocop:enable RSpec/ExpectInHook it 'properlies update uncommented values' do ini_sub.set_value('section1', 'foo', ' = ', 'foovalue') expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end it 'properlies update uncommented values without separator' do ini_sub.set_value('section1', 'foo', 'foovalue') expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end it 'properlies update commented value' do ini_sub.set_value('section1', 'bar', ' = ', 'barvalue') expect(ini_sub.get_value('section1', 'bar')).to eq('barvalue') end it 'properlies update commented values' do ini_sub.set_value('section1', "xyzzy['thing1']['thing2']", ' = ', 'xyzzyvalue') expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq('xyzzyvalue') end it 'properlies update commented value without separator' do ini_sub.set_value('section1', 'bar', 'barvalue') expect(ini_sub.get_value('section1', 'bar')).to eq('barvalue') end it 'properlies update commented values without separator' do ini_sub.set_value('section1', "xyzzy['thing1']['thing2']", 'xyzzyvalue') expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq('xyzzyvalue') end it 'properlies add new empty values' do ini_sub.set_value('section1', 'baz', ' = ', 'bazvalue') expect(ini_sub.get_value('section1', 'baz')).to eq('bazvalue') end it 'adds new empty values without separator' do ini_sub.set_value('section1', 'baz', 'bazvalue') expect(ini_sub.get_value('section1', 'baz')).to eq('bazvalue') end end context 'the file has quotation marks in its section names' do let(:sample_content) do template = <<-EOS [branch "main"] remote = origin merge = refs/heads/main [alias] to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/main [branch "production"] remote = origin merge = refs/heads/production EOS template.split("\n") end it 'parses the sections' do expect(ini_sub.section_names).to match_array ['', 'branch "main"', 'alias', 'branch "production"'] end end context 'Samba INI file with dollars in section names' do let(:sample_content) do template = <<-EOS [global] workgroup = FELLOWSHIP ; ... idmap config * : backend = tdb [printers] comment = All Printers ; ... browseable = No [print$] comment = Printer Drivers path = /var/lib/samba/printers [Shares] path = /home/shares read only = No guest ok = Yes EOS template.split("\n") end it 'parses the correct section_names' do expect(ini_sub.section_names).to match_array ['', 'global', 'printers', 'print$', 'Shares'] end end context 'section names with forward slashes in them' do let(:sample_content) do template = <<-EOS [monitor:///var/log/*.log] disabled = test_value EOS template.split("\n") end it 'parses the correct section_names' do expect(ini_sub.section_names).to match_array [ '', 'monitor:///var/log/*.log', ] end end context 'KDE Configuration with braces in setting names' do let(:sample_content) do template = <<-EOS [khotkeys] _k_friendly_name=khotkeys {5465e8c7-d608-4493-a48f-b99d99fdb508}=Print,none,PrintScreen {d03619b6-9b3c-48cc-9d9c-a2aadb485550}=Search,none,Search EOS template.split("\n") end it 'exposes settings for sections #print' do expect(ini_sub.get_value('khotkeys', '{5465e8c7-d608-4493-a48f-b99d99fdb508}')).to eq('Print,none,PrintScreen') end it 'exposes settings for sections #search' do expect(ini_sub.get_value('khotkeys', '{d03619b6-9b3c-48cc-9d9c-a2aadb485550}')).to eq('Search,none,Search') end end context 'Configuration with colons in setting names' do let(:sample_content) do template = <<-EOS [Drive names] A:=5.25" Floppy B:=3.5" Floppy C:=Winchester EOS template.split("\n") end it 'exposes settings for sections #A' do expect(ini_sub.get_value('Drive names', 'A:')).to eq '5.25" Floppy' end it 'exposes settings for sections #B' do expect(ini_sub.get_value('Drive names', 'B:')).to eq '3.5" Floppy' end it 'exposes settings for sections #C' do expect(ini_sub.get_value('Drive names', 'C:')).to eq 'Winchester' end end context 'Configuration with spaces in setting names' do let(:sample_content) do template = <<-EOS [global] # log files split per-machine: log file = /var/log/samba/log.%m kerberos method = system keytab passdb backend = tdbsam security = ads EOS template.split("\n") end it 'exposes settings for sections #log' do expect(ini_sub.get_value('global', 'log file')).to eq '/var/log/samba/log.%m' end it 'exposes settings for sections #kerberos' do expect(ini_sub.get_value('global', 'kerberos method')).to eq 'system keytab' end it 'exposes settings for sections #passdb' do expect(ini_sub.get_value('global', 'passdb backend')).to eq 'tdbsam' end it 'exposes settings for sections #security' do expect(ini_sub.get_value('global', 'security')).to eq 'ads' end end end diff --git a/spec/unit/puppet/util/setting_value_spec.rb b/spec/unit/puppet/util/setting_value_spec.rb index b830123..ce3847e 100644 --- a/spec/unit/puppet/util/setting_value_spec.rb +++ b/spec/unit/puppet/util/setting_value_spec.rb @@ -1,122 +1,122 @@ # frozen_string_literal: true require 'spec_helper' require 'puppet/util/setting_value' describe Puppet::Util::SettingValue do describe 'space subsetting separator' do - INIT_VALUE_SPACE = '"-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof"'.freeze + INIT_VALUE_SPACE = '"-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof"' let(:setting_value) { described_class.new(INIT_VALUE_SPACE, ' ') } it 'gets the original value' do expect(setting_value.get_value).to eq(INIT_VALUE_SPACE) end it 'gets the correct value' do expect(setting_value.get_subsetting_value('-Xmx')).to eq('192m') end it 'adds a new value #correct' do setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_subsetting_value('-Xms')).to eq('256m') end it 'adds a new value #original' do setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_value).to eq(INIT_VALUE_SPACE[0, INIT_VALUE_SPACE.length - 1] + ' -Xms256m"') end it 'changes existing value' do setting_value.add_subsetting('-Xmx', '512m') expect(setting_value.get_subsetting_value('-Xmx')).to eq('512m') end it 'removes existing value' do setting_value.remove_subsetting('-Xmx') expect(setting_value.get_subsetting_value('-Xmx')).to eq(nil) end end describe 'comma subsetting separator' do - INIT_VALUE_COMMA = '"-Xmx192m,-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof"'.freeze + INIT_VALUE_COMMA = '"-Xmx192m,-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof"' let(:setting_value) { described_class.new(INIT_VALUE_COMMA, ',') } it 'gets the original value' do expect(setting_value.get_value).to eq(INIT_VALUE_COMMA) end it 'gets the correct value' do expect(setting_value.get_subsetting_value('-Xmx')).to eq('192m') end it 'adds a new value #actual' do setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_subsetting_value('-Xms')).to eq('256m') end it 'adds a new value #original' do setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_value).to eq(INIT_VALUE_COMMA[0, INIT_VALUE_COMMA.length - 1] + ',-Xms256m"') end it 'changes existing value' do setting_value.add_subsetting('-Xmx', '512m') expect(setting_value.get_subsetting_value('-Xmx')).to eq('512m') end it 'removes existing value' do setting_value.remove_subsetting('-Xmx') expect(setting_value.get_subsetting_value('-Xmx')).to eq(nil) end end describe 'quote_char parameter' do - QUOTE_CHAR = '"'.freeze - INIT_VALUE_UNQUOTED = '-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof'.freeze + QUOTE_CHAR = '"' + INIT_VALUE_UNQUOTED = '-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof' it 'gets quoted empty string if original value was empty' do setting_value = described_class.new(nil, ' ', QUOTE_CHAR) expect(setting_value.get_value).to eq(QUOTE_CHAR * 2) end it 'quotes the setting when adding a value #actual' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_subsetting_value('-Xms')).to eq('256m') end it 'quotes the setting when adding a value #original' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.add_subsetting('-Xms', '256m') expect(setting_value.get_value).to eq(QUOTE_CHAR + INIT_VALUE_UNQUOTED + ' -Xms256m' + QUOTE_CHAR) end it 'quotes the setting when changing an existing value #value' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.add_subsetting('-Xmx', '512m') expect(setting_value.get_subsetting_value('-Xmx')).to eq('512m') end it 'quotes the setting when changing an existing value #quotes' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.add_subsetting('-Xmx', '512m') expect(setting_value.get_value).to match(%r{^#{Regexp.quote(QUOTE_CHAR)}.*#{Regexp.quote(QUOTE_CHAR)}$}) end it 'quotes the setting when removing an existing value #value' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.remove_subsetting('-Xmx') expect(setting_value.get_subsetting_value('-Xmx')).to eq(nil) end end it 'quotes the setting when removing an existing value #quotes' do setting_value = described_class.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) setting_value.remove_subsetting('-Xmx') expect(setting_value.get_value).to match(%r{^#{Regexp.quote(QUOTE_CHAR)}.*#{Regexp.quote(QUOTE_CHAR)}$}) end end