#! /usr/bin/env ruby -S rspec require 'spec_helper' require 'tempfile' provider_class = Puppet::Type.type(:file_line).provider(:ruby) # These tests fail on windows when run as part of the rake task. Individually they pass describe provider_class, :unless => Puppet::Util::Platform.windows? do context "when adding" do let :tmpfile do tmp = Tempfile.new('tmp') path = tmp.path tmp.close! path end let :resource do Puppet::Type::File_line.new( {:name => 'foo', :path => tmpfile, :line => 'foo'} ) end let :provider do provider_class.new(resource) end it 'should detect if the line exists in the file' do File.open(tmpfile, 'w') do |fh| fh.write('foo') end expect(provider.exists?).to be_truthy end it 'should detect if the line does not exist in the file' do File.open(tmpfile, 'w') do |fh| fh.write('foo1') end expect(provider.exists?).to eql (false) end it 'should append to an existing file when creating' do provider.create expect(File.read(tmpfile).chomp).to eq('foo') end end context 'when using replace' do before :each do # TODO: these should be ported over to use the PuppetLabs spec_helper # file fixtures once the following pull request has been merged: # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files tmp = Tempfile.new('tmp') @tmpfile = tmp.path tmp.close! @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo = bar', :match => '^foo\s*=.*$', :replace => false, } ) @provider = provider_class.new(@resource) end it 'should not replace the matching line' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo=blah\nfoo2\nfoo3") end expect(@provider.exists?).to be_truthy @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo=blah\nfoo2\nfoo3") end it 'should append the line if no matches are found' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2") end expect(@provider.exists?).to eql (false) @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo2\nfoo = bar") end it 'should raise an error with invalid values' do expect { @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo = bar', :match => '^foo\s*=.*$', :replace => 'asgadga', } ) }.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./) end end context "when matching" do before :each do # TODO: these should be ported over to use the PuppetLabs spec_helper # file fixtures once the following pull request has been merged: # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files tmp = Tempfile.new('tmp') @tmpfile = tmp.path tmp.close! @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo = bar', :match => '^foo\s*=.*$', } ) @provider = provider_class.new(@resource) end describe 'using match' do it 'should raise an error if more than one line matches, and should not have modified the file' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz") end expect(@provider.exists?).to eql(false) expect { @provider.create }.to raise_error(Puppet::Error, /More than one line.*matches/) expect(File.read(@tmpfile)).to eql("foo1\nfoo=blah\nfoo2\nfoo=baz") end it 'should replace all lines that matches' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo = bar', :match => '^foo\s*=.*$', :multiple => true, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz") end expect(@provider.exists?).to eql(false) @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2\nfoo = bar") end it 'should replace all lines that match, even when some lines are correct' do @resource = Puppet::Type::File_line.new( { :name => 'neil', :path => @tmpfile, :line => "\thard\tcore\t0\n", :match => '^[ \t]hard[ \t]+core[ \t]+.*', :multiple => true, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("\thard\tcore\t90\n\thard\tcore\t0\n") end expect(@provider.exists?).to eql(false) @provider.create expect(File.read(@tmpfile).chomp).to eql("\thard\tcore\t0\n\thard\tcore\t0") end it 'should raise an error with invalid values' do expect { @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo = bar', :match => '^foo\s*=.*$', :multiple => 'asgadga', } ) }.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./) end it 'should replace a line that matches' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo=blah\nfoo2") end expect(@provider.exists?).to eql(false) @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2") end it 'should add a new line if no lines match' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2") end expect(@provider.exists?).to eql(false) @provider.create expect(File.read(@tmpfile)).to eql("foo1\nfoo2\nfoo = bar\n") end it 'should do nothing if the exact line already exists' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo = bar\nfoo2") end expect(@provider.exists?).to eql(true) @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2") end it 'should not add line after no matches found' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'inserted = line', :match => '^foo3$', :append_on_no_match => false, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo = blah\nfoo2\nfoo = baz") end expect(@provider.exists?).to be true expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = blah\nfoo2\nfoo = baz") end end describe 'using after' do let :resource do Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'inserted = line', :after => '^foo1', } ) end let :provider do provider_class.new(resource) end context 'match and after set' do shared_context 'resource_create' do let(:match) { '^foo2$' } let(:after) { '^foo1$' } let(:resource) { Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'inserted = line', :after => after, :match => match, } ) } end before :each do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2\nfoo = baz") end end describe 'inserts at match' do include_context 'resource_create' it { provider.create expect(File.read(@tmpfile).chomp).to eq("foo1\ninserted = line\nfoo = baz") } end describe 'inserts a new line after when no match' do include_context 'resource_create' do let(:match) { '^nevergoingtomatch$' } end it { provider.create expect(File.read(@tmpfile).chomp).to eq("foo1\ninserted = line\nfoo2\nfoo = baz") } end describe 'append to end of file if no match for both after and match' do include_context 'resource_create' do let(:match) { '^nevergoingtomatch$' } let(:after) { '^stillneverafter' } end it { provider.create expect(File.read(@tmpfile).chomp).to eq("foo1\nfoo2\nfoo = baz\ninserted = line") } end end context 'with one line matching the after expression' do before :each do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo = blah\nfoo2\nfoo = baz") end end it 'inserts the specified line after the line matching the "after" expression' do provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\ninserted = line\nfoo = blah\nfoo2\nfoo = baz") end end context 'with multiple lines matching the after expression' do before :each do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo = blah\nfoo2\nfoo1\nfoo = baz") end end it 'errors out stating "One or no line must match the pattern"' do expect { provider.create }.to raise_error(Puppet::Error, /One or no line must match the pattern/) end it 'adds the line after all lines matching the after expression' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'inserted = line', :after => '^foo1$', :multiple => true, } ) @provider = provider_class.new(@resource) expect(@provider.exists?).to eql (false) @provider.create expect(File.read(@tmpfile).chomp).to eql("foo1\ninserted = line\nfoo = blah\nfoo2\nfoo1\ninserted = line\nfoo = baz") end end context 'with no lines matching the after expression' do let :content do "foo3\nfoo = blah\nfoo2\nfoo = baz\n" end before :each do File.open(@tmpfile, 'w') do |fh| fh.write(content) end end it 'appends the specified line to the file' do provider.create expect(File.read(@tmpfile)).to eq(content << resource[:line] << "\n") end end end end context "when removing with a line" do before :each do # TODO: these should be ported over to use the PuppetLabs spec_helper # file fixtures once the following pull request has been merged: # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files tmp = Tempfile.new('tmp') @tmpfile = tmp.path tmp.close! @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo', :ensure => 'absent', } ) @provider = provider_class.new(@resource) end it 'should remove the line if it exists' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2") end it 'should remove the line without touching the last new line' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2\n") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\n") end it 'should remove any occurence of the line' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2\nfoo\nfoo") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\n") end it 'example in the docs' do @resource = Puppet::Type::File_line.new( { :name => 'bashrc_proxy', :ensure => 'absent', :path => @tmpfile, :line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128', } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2\nexport HTTP_PROXY=http://squid.puppetlabs.vm:3128\nfoo4\n") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\nfoo4\n") end end context "when removing with a match" do before :each do # TODO: these should be ported over to use the PuppetLabs spec_helper # file fixtures once the following pull request has been merged: # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files tmp = Tempfile.new('tmp') @tmpfile = tmp.path tmp.close! @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo2', :ensure => 'absent', :match => 'o$', :match_for_absence => true, } ) @provider = provider_class.new(@resource) end it 'should find a line to match' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end expect(@provider.exists?).to eql (true) end it 'should remove one line if it matches' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2") end it 'the line parameter is actually not used at all but is silently ignored if here' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'supercalifragilisticexpialidocious', :ensure => 'absent', :match => 'o$', :match_for_absence => true, } ) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2") end it 'and may not be here and does not need to be here' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :ensure => 'absent', :match => 'o$', :match_for_absence => true, } ) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2") end it 'should raise an error if more than one line matches' do File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2\nfoo\nfoo") end expect { @provider.destroy }.to raise_error(Puppet::Error, /More than one line/) end it 'should remove multiple lines if :multiple is true' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo2', :ensure => 'absent', :match => 'o$', :multiple => true, :match_for_absence => true, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2\nfoo\nfoo") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\n") end it 'should ignore the match if match_for_absence is not specified' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo2', :ensure => 'absent', :match => 'o$', } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo\n") end it 'should ignore the match if match_for_absence is false' do @resource = Puppet::Type::File_line.new( { :name => 'foo', :path => @tmpfile, :line => 'foo2', :ensure => 'absent', :match => 'o$', :match_for_absence => false, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo\nfoo2") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo\n") end it 'example in the docs' do @resource = Puppet::Type::File_line.new( { :name => 'bashrc_proxy', :ensure => 'absent', :path => @tmpfile, :line => 'export HTTP_PROXY=http://squid.puppetlabs.vm:3128', :match => '^export\ HTTP_PROXY\=', :match_for_absence => true, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2\nexport HTTP_PROXY=foo\nfoo4\n") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\nfoo4\n") end it 'example in the docs showing line is redundant' do @resource = Puppet::Type::File_line.new( { :name => 'bashrc_proxy', :ensure => 'absent', :path => @tmpfile, :match => '^export\ HTTP_PROXY\=', :match_for_absence => true, } ) @provider = provider_class.new(@resource) File.open(@tmpfile, 'w') do |fh| fh.write("foo1\nfoo2\nexport HTTP_PROXY=foo\nfoo4\n") end @provider.destroy expect(File.read(@tmpfile)).to eql("foo1\nfoo2\nfoo4\n") end end end