diff options
Diffstat (limited to 'spec/unit/util')
24 files changed, 640 insertions, 232 deletions
diff --git a/spec/unit/util/colors_spec.rb b/spec/unit/util/colors_spec.rb index 7407b628b..b0f791f82 100755 --- a/spec/unit/util/colors_spec.rb +++ b/spec/unit/util/colors_spec.rb @@ -67,17 +67,23 @@ describe Puppet::Util::Colors do end end - describe "on Windows", :if => Puppet.features.microsoft_windows? do - it "expects a trailing embedded NULL character in the wide string" do - message = "hello" + context "on Windows in Ruby 1.x", :if => Puppet.features.microsoft_windows? && RUBY_VERSION =~ /^1./ do + it "should define WideConsole" do + expect(defined?(Puppet::Util::Colors::WideConsole)).to be_true + end - console = Puppet::Util::Colors::WideConsole.new - wstr, nchars = console.string_encode(message) + it "should define WideIO" do + expect(defined?(Puppet::Util::Colors::WideIO)).to be_true + end + end - expect(nchars).to eq(message.length) + context "on Windows in Ruby 2.x", :if => Puppet.features.microsoft_windows? && RUBY_VERSION =~ /^2./ do + it "should not define WideConsole" do + expect(defined?(Puppet::Util::Colors::WideConsole)).to be_false + end - expect(wstr.length).to eq(nchars + 1) - expect(wstr[-1].ord).to be_zero + it "should not define WideIO" do + expect(defined?(Puppet::Util::Colors::WideIO)).to be_false end end end diff --git a/spec/unit/util/command_line_spec.rb b/spec/unit/util/command_line_spec.rb index 6ba8077c2..9eb61b077 100755 --- a/spec/unit/util/command_line_spec.rb +++ b/spec/unit/util/command_line_spec.rb @@ -70,7 +70,7 @@ describe Puppet::Util::CommandLine do it "should print the version and exit if #{arg} is given" do expect do described_class.new("puppet", [arg]).execute - end.to have_printed(/^#{Puppet.version}$/) + end.to have_printed(/^#{Regexp.escape(Puppet.version)}$/) end end end @@ -93,35 +93,39 @@ describe Puppet::Util::CommandLine do end describe "and an external implementation cannot be found" do + before :each do + Puppet::Util::CommandLine::UnknownSubcommand.any_instance.stubs(:console_has_color?).returns false + end + it "should abort and show the usage message" do - commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) commandline.expects(:exec).never expect { commandline.execute - }.to have_printed(/Unknown Puppet subcommand 'whatever'/) + }.to have_printed(/Unknown Puppet subcommand 'whatever'/).and_exit_with(1) end it "should abort and show the help message" do - commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) commandline.expects(:exec).never expect { commandline.execute - }.to have_printed(/See 'puppet help' for help on available puppet subcommands/) + }.to have_printed(/See 'puppet help' for help on available puppet subcommands/).and_exit_with(1) end %w{--version -V}.each do |arg| it "should abort and display #{arg} information" do - commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', arg]) Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', arg]) commandline.expects(:exec).never expect { commandline.execute - }.to have_printed(/^#{Puppet.version}$/) + }.to have_printed(%r[^#{Regexp.escape(Puppet.version)}$]).and_exit_with(1) end end end diff --git a/spec/unit/util/execution_spec.rb b/spec/unit/util/execution_spec.rb index 7c6238f9f..6a4bee490 100755 --- a/spec/unit/util/execution_spec.rb +++ b/spec/unit/util/execution_spec.rb @@ -1,15 +1,9 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'puppet/file_system/uniquefile' describe Puppet::Util::Execution do include Puppet::Util::Execution - # utility method to help deal with some windows vs. unix differences - def process_status(exitstatus) - return exitstatus if Puppet.features.microsoft_windows? - - stub('child_status', :exitstatus => exitstatus) - end - # utility methods to help us test some private methods without being quite so verbose def call_exec_posix(command, arguments, stdin, stdout, stderr) Puppet::Util::Execution.send(:execute_posix, command, arguments, stdin, stdout, stderr) @@ -28,8 +22,8 @@ describe Puppet::Util::Execution do def stub_process_wait(exitstatus) if Puppet.features.microsoft_windows? Puppet::Util::Windows::Process.stubs(:wait_process).with(process_handle).returns(exitstatus) - Process.stubs(:CloseHandle).with(process_handle) - Process.stubs(:CloseHandle).with(thread_handle) + FFI::WIN32.stubs(:CloseHandle).with(process_handle) + FFI::WIN32.stubs(:CloseHandle).with(thread_handle) else Process.stubs(:waitpid2).with(pid).returns([pid, stub('child_status', :exitstatus => exitstatus)]) end @@ -52,7 +46,7 @@ describe Puppet::Util::Execution do $stderr.stubs(:reopen) @stdin = File.open(null_file, 'r') - @stdout = Tempfile.new('stdout') + @stdout = Puppet::FileSystem::Uniquefile.new('stdout') @stderr = File.open(null_file, 'w') # there is a danger here that ENV will be modified by exec_posix. Normally it would only affect the ENV @@ -132,7 +126,7 @@ describe Puppet::Util::Execution do stub_process_wait(0) @stdin = File.open(null_file, 'r') - @stdout = Tempfile.new('stdout') + @stdout = Puppet::FileSystem::Uniquefile.new('stdout') @stderr = File.open(null_file, 'w') end @@ -223,8 +217,8 @@ describe Puppet::Util::Execution do describe "when squelch is not set" do it "should set stdout to a temporary output file" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,_| stdout.path == outfile.path @@ -234,8 +228,8 @@ describe Puppet::Util::Execution do end it "should set stderr to the same file as stdout if combine is true" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == outfile.path @@ -245,8 +239,8 @@ describe Puppet::Util::Execution do end it "should set stderr to the null device if combine is false" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == null_file @@ -256,8 +250,8 @@ describe Puppet::Util::Execution do end it "should combine stdout and stderr if combine is true" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == outfile.path @@ -267,8 +261,8 @@ describe Puppet::Util::Execution do end it "should default combine to true when no options are specified" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == outfile.path @@ -278,8 +272,8 @@ describe Puppet::Util::Execution do end it "should default combine to false when options are specified, but combine is not" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == null_file @@ -289,8 +283,8 @@ describe Puppet::Util::Execution do end it "should default combine to false when an empty hash of options is specified" do - outfile = Tempfile.new('stdout') - Tempfile.stubs(:new).returns(outfile) + outfile = Puppet::FileSystem::Uniquefile.new('stdout') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(outfile) Puppet::Util::Execution.expects(executor).with do |_,_,_,stdout,stderr| stdout.path == outfile.path and stderr.path == null_file @@ -306,8 +300,8 @@ describe Puppet::Util::Execution do Puppet::Util::Execution.stubs(:execute_windows).returns(proc_info_stub) Puppet::Util::Windows::Process.expects(:wait_process).with(process_handle).raises('whatever') - Puppet::Util::Windows::Process.expects(:CloseHandle).with(thread_handle) - Puppet::Util::Windows::Process.expects(:CloseHandle).with(process_handle) + FFI::WIN32.expects(:CloseHandle).with(thread_handle) + FFI::WIN32.expects(:CloseHandle).with(process_handle) expect { Puppet::Util::Execution.execute('test command') }.to raise_error(RuntimeError) end @@ -507,25 +501,25 @@ describe Puppet::Util::Execution do end it "should read and return the output if squelch is false" do - stdout = Tempfile.new('test') - Tempfile.stubs(:new).returns(stdout) + stdout = Puppet::FileSystem::Uniquefile.new('test') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(stdout) stdout.write("My expected command output") Puppet::Util::Execution.execute('test command').should == "My expected command output" end it "should not read the output if squelch is true" do - stdout = Tempfile.new('test') - Tempfile.stubs(:new).returns(stdout) + stdout = Puppet::FileSystem::Uniquefile.new('test') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(stdout) stdout.write("My expected command output") Puppet::Util::Execution.execute('test command', :squelch => true).should == '' end it "should delete the file used for output if squelch is false" do - stdout = Tempfile.new('test') + stdout = Puppet::FileSystem::Uniquefile.new('test') path = stdout.path - Tempfile.stubs(:new).returns(stdout) + Puppet::FileSystem::Uniquefile.stubs(:new).returns(stdout) Puppet::Util::Execution.execute('test command') @@ -533,8 +527,8 @@ describe Puppet::Util::Execution do end it "should not raise an error if the file is open" do - stdout = Tempfile.new('test') - Tempfile.stubs(:new).returns(stdout) + stdout = Puppet::FileSystem::Uniquefile.new('test') + Puppet::FileSystem::Uniquefile.stubs(:new).returns(stdout) file = File.new(stdout.path, 'r') Puppet::Util.execute('test command') @@ -597,40 +591,39 @@ describe Puppet::Util::Execution do describe "#execpipe" do it "should execute a string as a string" do Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') - $CHILD_STATUS.expects(:==).with(0).returns(true) + Puppet::Util::Execution.expects(:exitstatus).returns(0) Puppet::Util::Execution.execpipe('echo hello').should == 'hello' end it "should print meaningful debug message for string argument" do Puppet::Util::Execution.expects(:debug).with("Executing 'echo hello'") Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') - $CHILD_STATUS.expects(:==).with(0).returns(true) + Puppet::Util::Execution.expects(:exitstatus).returns(0) Puppet::Util::Execution.execpipe('echo hello') end it "should print meaningful debug message for array argument" do Puppet::Util::Execution.expects(:debug).with("Executing 'echo hello'") Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') - $CHILD_STATUS.expects(:==).with(0).returns(true) + Puppet::Util::Execution.expects(:exitstatus).returns(0) Puppet::Util::Execution.execpipe(['echo','hello']) end it "should execute an array by pasting together with spaces" do Puppet::Util::Execution.expects(:open).with('| echo hello 2>&1').returns('hello') - $CHILD_STATUS.expects(:==).with(0).returns(true) + Puppet::Util::Execution.expects(:exitstatus).returns(0) Puppet::Util::Execution.execpipe(['echo', 'hello']).should == 'hello' end it "should fail if asked to fail, and the child does" do - Puppet::Util::Execution.stubs(:open).returns('error message') - $CHILD_STATUS.expects(:==).with(0).returns(false) + Puppet::Util::Execution.stubs(:open).with('| echo hello 2>&1').returns('error message') + Puppet::Util::Execution.expects(:exitstatus).returns(1) expect { Puppet::Util::Execution.execpipe('echo hello') }. to raise_error Puppet::ExecutionFailure, /error message/ end it "should not fail if asked not to fail, and the child does" do Puppet::Util::Execution.stubs(:open).returns('error message') - $CHILD_STATUS.stubs(:==).with(0).returns(false) Puppet::Util::Execution.execpipe('echo hello', false).should == 'error message' end end diff --git a/spec/unit/util/feature_spec.rb b/spec/unit/util/feature_spec.rb index aa8afbba6..e6d844533 100755 --- a/spec/unit/util/feature_spec.rb +++ b/spec/unit/util/feature_spec.rb @@ -91,4 +91,16 @@ describe Puppet::Util::Feature do @features.should_not be_myfeature @features.should be_myfeature end + + it "should cache load failures when configured to do so" do + Puppet[:always_cache_features] = true + + @features.add(:myfeature, :libs => %w{foo bar}) + @features.expects(:require).with("foo").raises(LoadError) + + @features.should_not be_myfeature + # second call would cause an expectation exception if 'require' was + # called a second time + @features.should_not be_myfeature + end end diff --git a/spec/unit/util/http_proxy_spec.rb b/spec/unit/util/http_proxy_spec.rb index bc6b4d2b7..59f39c511 100644 --- a/spec/unit/util/http_proxy_spec.rb +++ b/spec/unit/util/http_proxy_spec.rb @@ -4,7 +4,7 @@ require 'puppet/util/http_proxy' describe Puppet::Util::HttpProxy do - host, port = 'some.host', 1234 + host, port, user, password = 'some.host', 1234, 'user1', 'pAssw0rd' describe ".http_proxy_env" do it "should return nil if no environment variables" do @@ -80,4 +80,46 @@ describe Puppet::Util::HttpProxy do end + describe ".http_proxy_user" do + it "should return a proxy user if set in environment" do + Puppet::Util.withenv('HTTP_PROXY' => "http://#{user}:#{password}@#{host}:#{port}") do + subject.http_proxy_user.should == user + end + end + + it "should return a proxy user if set in config" do + Puppet.settings[:http_proxy_user] = user + subject.http_proxy_user.should == user + end + + it "should use environment variable before puppet settings" do + Puppet::Util.withenv('HTTP_PROXY' => "http://#{user}:#{password}@#{host}:#{port}") do + Puppet.settings[:http_proxy_user] = 'clownpants' + subject.http_proxy_user.should == user + end + end + + end + + describe ".http_proxy_password" do + it "should return a proxy password if set in environment" do + Puppet::Util.withenv('HTTP_PROXY' => "http://#{user}:#{password}@#{host}:#{port}") do + subject.http_proxy_password.should == password + end + end + + it "should return a proxy password if set in config" do + Puppet.settings[:http_proxy_user] = user + Puppet.settings[:http_proxy_password] = password + subject.http_proxy_password.should == password + end + + it "should use environment variable before puppet settings" do + Puppet::Util.withenv('HTTP_PROXY' => "http://#{user}:#{password}@#{host}:#{port}") do + Puppet.settings[:http_proxy_password] = 'clownpants' + subject.http_proxy_password.should == password + end + end + + end end diff --git a/spec/unit/util/log/destinations_spec.rb b/spec/unit/util/log/destinations_spec.rb index a91236dba..a81eac631 100755 --- a/spec/unit/util/log/destinations_spec.rb +++ b/spec/unit/util/log/destinations_spec.rb @@ -29,7 +29,7 @@ describe Puppet::Util::Log.desttypes[:file] do before do File.stubs(:open) # prevent actually creating the file - File.stubs(:chown) # prevent chown on non existing file from failing + File.stubs(:chown) # prevent chown on non existing file from failing @class = Puppet::Util::Log.desttypes[:file] end @@ -181,3 +181,47 @@ describe Puppet::Util::Log.desttypes[:console] do end end end + + +describe ":eventlog", :if => Puppet::Util::Platform.windows? do + before do + if Facter.value(:kernelmajversion).to_f < 6.0 + pending("requires win32-eventlog gem upgrade to 0.6.2 on Windows 2003") + end + end + + let(:klass) { Puppet::Util::Log.desttypes[:eventlog] } + + def expects_message_with_type(klass, level, eventlog_type, eventlog_id) + eventlog = stub('eventlog') + eventlog.expects(:report_event).with(has_entries(:source => "Puppet", :event_type => eventlog_type, :event_id => eventlog_id, :data => "a hitchhiker: don't panic")) + Win32::EventLog.stubs(:open).returns(eventlog) + + msg = Puppet::Util::Log.new(:level => level, :message => "don't panic", :source => "a hitchhiker") + dest = klass.new + dest.handle(msg) + end + + it "supports the eventlog feature" do + expect(Puppet.features.eventlog?).to be_true + end + + it "logs to the Application event log" do + eventlog = stub('eventlog') + Win32::EventLog.expects(:open).with('Application').returns(stub('eventlog')) + + klass.new + end + + it "logs :debug level as an information type event" do + expects_message_with_type(klass, :debug, klass::EVENTLOG_INFORMATION_TYPE, 0x1) + end + + it "logs :warning level as an warning type event" do + expects_message_with_type(klass, :warning, klass::EVENTLOG_WARNING_TYPE, 0x2) + end + + it "logs :err level as an error type event" do + expects_message_with_type(klass, :err, klass::EVENTLOG_ERROR_TYPE, 0x3) + end +end diff --git a/spec/unit/util/logging_spec.rb b/spec/unit/util/logging_spec.rb index 0858f7857..abdae9189 100755 --- a/spec/unit/util/logging_spec.rb +++ b/spec/unit/util/logging_spec.rb @@ -93,6 +93,12 @@ describe Puppet::Util::Logging do end describe "when sending a deprecation warning" do + it "does not log a message when deprecation warnings are disabled" do + Puppet.expects(:[]).with(:disable_warnings).returns %w[deprecations] + @logger.expects(:warning).never + @logger.deprecation_warning 'foo' + end + it "logs the message with warn" do @logger.expects(:warning).with do |msg| msg =~ /^foo\n/ @@ -133,6 +139,44 @@ describe Puppet::Util::Logging do end end + describe "when sending a puppet_deprecation_warning" do + it "requires file and line or key options" do + expect do + @logger.puppet_deprecation_warning("foo") + end.to raise_error(Puppet::DevError, /Need either :file and :line, or :key/) + expect do + @logger.puppet_deprecation_warning("foo", :file => 'bar') + end.to raise_error(Puppet::DevError, /Need either :file and :line, or :key/) + expect do + @logger.puppet_deprecation_warning("foo", :key => 'akey') + @logger.puppet_deprecation_warning("foo", :file => 'afile', :line => 1) + end.to_not raise_error + end + + it "warns with file and line" do + @logger.expects(:warning).with(regexp_matches(/deprecated foo.*afile:5/m)) + @logger.puppet_deprecation_warning("deprecated foo", :file => 'afile', :line => 5) + end + + it "warns keyed from file and line" do + @logger.expects(:warning).with(regexp_matches(/deprecated foo.*afile:5/m)).once + 5.times do + @logger.puppet_deprecation_warning("deprecated foo", :file => 'afile', :line => 5) + end + end + + it "warns with separate key only once regardless of file and line" do + @logger.expects(:warning).with(regexp_matches(/deprecated foo.*afile:5/m)).once + @logger.puppet_deprecation_warning("deprecated foo", :key => 'some_key', :file => 'afile', :line => 5) + @logger.puppet_deprecation_warning("deprecated foo", :key => 'some_key', :file => 'bfile', :line => 3) + end + + it "warns with key but no file and line" do + @logger.expects(:warning).with(regexp_matches(/deprecated foo.*unknown:unknown/m)) + @logger.puppet_deprecation_warning("deprecated foo", :key => 'some_key') + end + end + describe "when formatting exceptions" do it "should be able to format a chain of exceptions" do exc3 = Puppet::Error.new("original") diff --git a/spec/unit/util/pidlock_spec.rb b/spec/unit/util/pidlock_spec.rb index 2ebe7dec8..fcef7aa31 100644 --- a/spec/unit/util/pidlock_spec.rb +++ b/spec/unit/util/pidlock_spec.rb @@ -50,6 +50,26 @@ describe Puppet::Util::Pidlock do Puppet::FileSystem.exist?(@lockfile).should be_true end + it 'should create an empty lock file even when pid is missing' do + Process.stubs(:pid).returns('') + @lock.lock + Puppet::FileSystem.exist?(@lock.file_path).should be_true + Puppet::FileSystem.read(@lock.file_path).should be_empty + end + + it 'should replace an existing empty lockfile with a pid, given a subsequent lock call made against a valid pid' do + # empty pid results in empty lockfile + Process.stubs(:pid).returns('') + @lock.lock + Puppet::FileSystem.exist?(@lock.file_path).should be_true + + # next lock call with valid pid kills existing empty lockfile + Process.stubs(:pid).returns(1234) + @lock.lock + Puppet::FileSystem.exist?(@lock.file_path).should be_true + Puppet::FileSystem.read(@lock.file_path).should == '1234' + end + it "should expose the lock file_path" do @lock.file_path.should == @lockfile end @@ -83,6 +103,22 @@ describe Puppet::Util::Pidlock do @lock.lock @lock.should be_locked end + + it "should remove the lockfile when pid is missing" do + Process.stubs(:pid).returns('') + @lock.lock + @lock.locked?.should be_false + Puppet::FileSystem.exist?(@lock.file_path).should be_false + end + end + + describe '#lock_pid' do + it 'should return nil if the pid is empty' do + # fake pid to get empty lockfile + Process.stubs(:pid).returns('') + @lock.lock + @lock.lock_pid.should == nil + end end describe "with a stale lock" do @@ -105,7 +141,7 @@ describe Puppet::Util::Pidlock do describe "#lock" do it "should clear stale locks" do - @lock.locked? + @lock.locked?.should be_false Puppet::FileSystem.exist?(@lockfile).should be_false end diff --git a/spec/unit/util/profiler/aggregate_spec.rb b/spec/unit/util/profiler/aggregate_spec.rb new file mode 100644 index 000000000..8d38d4673 --- /dev/null +++ b/spec/unit/util/profiler/aggregate_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' +require 'puppet/util/profiler' +require 'puppet/util/profiler/around_profiler' +require 'puppet/util/profiler/aggregate' + +describe Puppet::Util::Profiler::Aggregate do + let(:logger) { AggregateSimpleLog.new } + let(:profiler) { Puppet::Util::Profiler::Aggregate.new(logger, nil) } + let(:profiler_mgr) do + p = Puppet::Util::Profiler::AroundProfiler.new + p.add_profiler(profiler) + p + end + + it "tracks the aggregate counts and time for the hierarchy of metrics" do + profiler_mgr.profile("Looking up hiera data in production environment", ["function", "hiera_lookup", "production"]) { sleep 0.01 } + profiler_mgr.profile("Looking up hiera data in test environment", ["function", "hiera_lookup", "test"]) {} + profiler_mgr.profile("looking up stuff for compilation", ["compiler", "lookup"]) { sleep 0.01 } + profiler_mgr.profile("COMPILING ALL OF THE THINGS!", ["compiler", "compiling"]) {} + + profiler.values["function"].count.should == 2 + profiler.values["function"].time.should be > 0 + profiler.values["function"]["hiera_lookup"].count.should == 2 + profiler.values["function"]["hiera_lookup"]["production"].count.should == 1 + profiler.values["function"]["hiera_lookup"]["test"].count.should == 1 + profiler.values["function"].time.should be >= profiler.values["function"]["hiera_lookup"]["test"].time + + profiler.values["compiler"].count.should == 2 + profiler.values["compiler"].time.should be > 0 + profiler.values["compiler"]["lookup"].count.should == 1 + profiler.values["compiler"]["compiling"].count.should == 1 + profiler.values["compiler"].time.should be >= profiler.values["compiler"]["lookup"].time + + profiler.shutdown + + logger.output.should =~ /function -> hiera_lookup: .*\(2 calls\)\nfunction -> hiera_lookup ->.*\(1 calls\)/ + logger.output.should =~ /compiler: .*\(2 calls\)\ncompiler ->.*\(1 calls\)/ + end + + it "tolerates calls to `profile` that don't include a metric id" do + profiler_mgr.profile("yo") {} + end + + it "supports both symbols and strings as components of a metric id" do + profiler_mgr.profile("yo", [:foo, "bar"]) {} + end + + class AggregateSimpleLog + attr_reader :output + + def initialize + @output = "" + end + + def call(msg) + @output << msg << "\n" + end + end +end diff --git a/spec/unit/util/profiler/around_profiler_spec.rb b/spec/unit/util/profiler/around_profiler_spec.rb new file mode 100644 index 000000000..0837395b5 --- /dev/null +++ b/spec/unit/util/profiler/around_profiler_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' +require 'puppet/util/profiler' + +describe Puppet::Util::Profiler::AroundProfiler do + let(:child) { TestAroundProfiler.new() } + let(:profiler) { Puppet::Util::Profiler::AroundProfiler.new } + + before :each do + profiler.add_profiler(child) + end + + it "returns the value of the profiled segment" do + retval = profiler.profile("Testing", ["testing"]) { "the return value" } + + retval.should == "the return value" + end + + it "propagates any errors raised in the profiled segment" do + expect do + profiler.profile("Testing", ["testing"]) { raise "a problem" } + end.to raise_error("a problem") + end + + it "makes the description and the context available to the `start` and `finish` methods" do + profiler.profile("Testing", ["testing"]) { } + + child.context.should == "Testing" + child.description.should == "Testing" + end + + it "calls finish even when an error is raised" do + begin + profiler.profile("Testing", ["testing"]) { raise "a problem" } + rescue + child.context.should == "Testing" + end + end + + it "supports multiple profilers" do + profiler2 = TestAroundProfiler.new + profiler.add_profiler(profiler2) + profiler.profile("Testing", ["testing"]) {} + + child.context.should == "Testing" + profiler2.context.should == "Testing" + end + + class TestAroundProfiler + attr_accessor :context, :description + + def start(description, metric_id) + description + end + + def finish(context, description, metric_id) + @context = context + @description = description + end + end +end + diff --git a/spec/unit/util/profiler/logging_spec.rb b/spec/unit/util/profiler/logging_spec.rb index 5316e5ae9..3f6a728dd 100644 --- a/spec/unit/util/profiler/logging_spec.rb +++ b/spec/unit/util/profiler/logging_spec.rb @@ -4,51 +4,40 @@ require 'puppet/util/profiler' describe Puppet::Util::Profiler::Logging do let(:logger) { SimpleLog.new } let(:identifier) { "Profiling ID" } - let(:profiler) { TestLoggingProfiler.new(logger, identifier) } - - it "returns the value of the profiled segment" do - retval = profiler.profile("Testing") { "the return value" } - - retval.should == "the return value" - end - - it "propogates any errors raised in the profiled segment" do - expect do - profiler.profile("Testing") { raise "a problem" } - end.to raise_error("a problem") + let(:logging_profiler) { TestLoggingProfiler.new(logger, identifier) } + let(:profiler) do + p = Puppet::Util::Profiler::AroundProfiler.new + p.add_profiler(logging_profiler) + p end it "logs the explanation of the profile results" do - profiler.profile("Testing") { } + profiler.profile("Testing", ["test"]) { } logger.messages.first.should =~ /the explanation/ end - it "logs results even when an error is raised" do - begin - profiler.profile("Testing") { raise "a problem" } - rescue - logger.messages.first.should =~ /the explanation/ - end - end - it "describes the profiled segment" do - profiler.profile("Tested measurement") { } + profiler.profile("Tested measurement", ["test"]) { } logger.messages.first.should =~ /PROFILE \[#{identifier}\] \d Tested measurement/ end it "indicates the order in which segments are profiled" do - profiler.profile("Measurement") { } - profiler.profile("Another measurement") { } + profiler.profile("Measurement", ["measurement"]) { } + profiler.profile("Another measurement", ["measurement"]) { } logger.messages[0].should =~ /1 Measurement/ logger.messages[1].should =~ /2 Another measurement/ end it "indicates the nesting of profiled segments" do - profiler.profile("Measurement") { profiler.profile("Nested measurement") { } } - profiler.profile("Another measurement") { profiler.profile("Another nested measurement") { } } + profiler.profile("Measurement", ["measurement1"]) do + profiler.profile("Nested measurement", ["measurement2"]) { } + end + profiler.profile("Another measurement", ["measurement1"]) do + profiler.profile("Another nested measurement", ["measurement2"]) { } + end logger.messages[0].should =~ /1.1 Nested measurement/ logger.messages[1].should =~ /1 Measurement/ @@ -57,12 +46,12 @@ describe Puppet::Util::Profiler::Logging do end class TestLoggingProfiler < Puppet::Util::Profiler::Logging - def start + def do_start(metric, description) "the start" end - def finish(context) - "the explanation of #{context}" + def do_finish(context, metric, description) + {:msg => "the explanation of #{context}"} end end diff --git a/spec/unit/util/profiler/none_spec.rb b/spec/unit/util/profiler/none_spec.rb deleted file mode 100644 index 0cabfef6f..000000000 --- a/spec/unit/util/profiler/none_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'spec_helper' -require 'puppet/util/profiler' - -describe Puppet::Util::Profiler::None do - let(:profiler) { Puppet::Util::Profiler::None.new } - - it "returns the value of the profiled block" do - retval = profiler.profile("Testing") { "the return value" } - - retval.should == "the return value" - end -end diff --git a/spec/unit/util/profiler/wall_clock_spec.rb b/spec/unit/util/profiler/wall_clock_spec.rb index 668f63221..1adcf0d61 100644 --- a/spec/unit/util/profiler/wall_clock_spec.rb +++ b/spec/unit/util/profiler/wall_clock_spec.rb @@ -6,7 +6,7 @@ describe Puppet::Util::Profiler::WallClock do it "logs the number of seconds it took to execute the segment" do profiler = Puppet::Util::Profiler::WallClock.new(nil, nil) - message = profiler.finish(profiler.start) + message = profiler.do_finish(profiler.start(["foo", "bar"], "Testing"), ["foo", "bar"], "Testing")[:msg] message.should =~ /took \d\.\d{4} seconds/ end diff --git a/spec/unit/util/profiler_spec.rb b/spec/unit/util/profiler_spec.rb new file mode 100644 index 000000000..c7fc48cb9 --- /dev/null +++ b/spec/unit/util/profiler_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' +require 'puppet/util/profiler' + +describe Puppet::Util::Profiler do + let(:profiler) { TestProfiler.new() } + + it "supports adding profilers" do + subject.add_profiler(profiler) + subject.current[0].should == profiler + end + + it "supports removing profilers" do + subject.add_profiler(profiler) + subject.remove_profiler(profiler) + subject.current.length.should == 0 + end + + it "supports clearing profiler list" do + subject.add_profiler(profiler) + subject.clear + subject.current.length.should == 0 + end + + it "supports profiling" do + subject.add_profiler(profiler) + subject.profile("hi", ["mymetric"]) {} + profiler.context[:metric_id].should == ["mymetric"] + profiler.context[:description].should == "hi" + profiler.description.should == "hi" + end + + it "supports profiling without a metric id" do + subject.add_profiler(profiler) + subject.profile("hi") {} + profiler.context[:metric_id].should == nil + profiler.context[:description].should == "hi" + profiler.description.should == "hi" + end + + class TestProfiler + attr_accessor :context, :metric, :description + + def start(description, metric_id) + {:metric_id => metric_id, + :description => description} + end + + def finish(context, description, metric_id) + @context = context + @metric_id = metric_id + @description = description + end + end +end + diff --git a/spec/unit/util/queue_spec.rb b/spec/unit/util/queue_spec.rb index d7ba57f85..48b98e8e3 100755 --- a/spec/unit/util/queue_spec.rb +++ b/spec/unit/util/queue_spec.rb @@ -1,7 +1,6 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/queue' -require 'spec/mocks' def make_test_client_class(n) c = Class.new do diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb index acc606b76..7ed2cffcc 100755 --- a/spec/unit/util/rdoc/parser_spec.rb +++ b/spec/unit/util/rdoc/parser_spec.rb @@ -21,6 +21,17 @@ describe "RDoc::Parser", :if => Puppet.features.rdoc1? do end describe "when scanning files" do + around(:each) do |example| + Puppet.override({ + :current_environment => Puppet::Node::Environment.create(:doc, [], '/somewhere/etc/manifests/site.pp') + }, + "A fake current environment that the application would have established by now" + ) do + + example.run + end + end + it "should parse puppet files with the puppet parser" do @parser.stubs(:scan_top_level) parser = stub 'parser' @@ -56,15 +67,12 @@ describe "RDoc::Parser", :if => Puppet.features.rdoc1? do it "should scan the top level even if the file has already parsed" do known_type = stub 'known_types' - env = Puppet::Node::Environment.create(Puppet[:environment].to_sym, []) + env = Puppet.lookup(:current_environment) env.stubs(:known_resource_types).returns(known_type) known_type.expects(:watching_file?).with("module/manifests/init.pp").returns(true) - Puppet.override(:environments => Puppet::Environments::Static.new(env)) do - - @parser.expects(:scan_top_level) + @parser.expects(:scan_top_level) - @parser.scan - end + @parser.scan end end diff --git a/spec/unit/util/tagging_spec.rb b/spec/unit/util/tagging_spec.rb index 248e915e9..53bb39d7a 100755 --- a/spec/unit/util/tagging_spec.rb +++ b/spec/unit/util/tagging_spec.rb @@ -41,7 +41,7 @@ describe Puppet::Util::Tagging do end it "should allow tags containing '.' characters" do - expect { tagger.tag("good.tag") }.to_not raise_error(Puppet::ParseError) + expect { tagger.tag("good.tag") }.to_not raise_error end it "should add qualified classes as tags" do @@ -127,5 +127,36 @@ describe Puppet::Util::Tagging do expect(tagger).to be_tagged("two") expect(tagger).to be_tagged("three") end + + it "protects against empty tags" do + expect { tagger.tags = "one,,two"}.to raise_error(/Invalid tag ''/) + end + + it "takes an array of tags" do + tagger.tags = ["one", "two"] + + expect(tagger).to be_tagged("one") + expect(tagger).to be_tagged("two") + end + + it "removes any existing tags when reassigning" do + tagger.tags = "one, two" + + tagger.tags = "three, four" + + expect(tagger).to_not be_tagged("one") + expect(tagger).to_not be_tagged("two") + expect(tagger).to be_tagged("three") + expect(tagger).to be_tagged("four") + end + + it "allows empty tags that are generated from :: separated tags" do + tagger.tags = "one::::two::three" + + expect(tagger).to be_tagged("one") + expect(tagger).to be_tagged("") + expect(tagger).to be_tagged("two") + expect(tagger).to be_tagged("three") + end end end diff --git a/spec/unit/util/windows/access_control_entry_spec.rb b/spec/unit/util/windows/access_control_entry_spec.rb index b139b0d42..8d3f51c8a 100644 --- a/spec/unit/util/windows/access_control_entry_spec.rb +++ b/spec/unit/util/windows/access_control_entry_spec.rb @@ -5,7 +5,7 @@ require 'puppet/util/windows' describe "Puppet::Util::Windows::AccessControlEntry", :if => Puppet.features.microsoft_windows? do let(:klass) { Puppet::Util::Windows::AccessControlEntry } let(:sid) { 'S-1-5-18' } - let(:mask) { Windows::File::FILE_ALL_ACCESS } + let(:mask) { Puppet::Util::Windows::File::FILE_ALL_ACCESS } it "creates an access allowed ace" do ace = klass.new(sid, mask) diff --git a/spec/unit/util/adsi_spec.rb b/spec/unit/util/windows/adsi_spec.rb index 491c4374b..f569d91e9 100755 --- a/spec/unit/util/adsi_spec.rb +++ b/spec/unit/util/windows/adsi_spec.rb @@ -2,97 +2,104 @@ require 'spec_helper' -require 'puppet/util/adsi' +require 'puppet/util/windows' -describe Puppet::Util::ADSI do +describe Puppet::Util::Windows::ADSI, :if => Puppet.features.microsoft_windows? do let(:connection) { stub 'connection' } before(:each) do - Puppet::Util::ADSI.instance_variable_set(:@computer_name, 'testcomputername') - Puppet::Util::ADSI.stubs(:connect).returns connection + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, 'testcomputername') + Puppet::Util::Windows::ADSI.stubs(:connect).returns connection end after(:each) do - Puppet::Util::ADSI.instance_variable_set(:@computer_name, nil) + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, nil) end it "should generate the correct URI for a resource" do - Puppet::Util::ADSI.uri('test', 'user').should == "WinNT://./test,user" + Puppet::Util::Windows::ADSI.uri('test', 'user').should == "WinNT://./test,user" end it "should be able to get the name of the computer" do - Puppet::Util::ADSI.computer_name.should == 'testcomputername' + Puppet::Util::Windows::ADSI.computer_name.should == 'testcomputername' end it "should be able to provide the correct WinNT base URI for the computer" do - Puppet::Util::ADSI.computer_uri.should == "WinNT://." + Puppet::Util::Windows::ADSI.computer_uri.should == "WinNT://." end it "should generate a fully qualified WinNT URI" do - Puppet::Util::ADSI.computer_uri('testcomputername').should == "WinNT://testcomputername" + Puppet::Util::Windows::ADSI.computer_uri('testcomputername').should == "WinNT://testcomputername" end - describe ".sid_for_account", :if => Puppet.features.microsoft_windows? do + describe ".sid_for_account" do it "should return nil if the account does not exist" do - Puppet::Util::Windows::Security.expects(:name_to_sid).with('foobar').returns nil + Puppet::Util::Windows::SID.expects(:name_to_sid).with('foobar').returns nil - Puppet::Util::ADSI.sid_for_account('foobar').should be_nil + Puppet::Util::Windows::ADSI.sid_for_account('foobar').should be_nil end it "should return a SID for a passed user or group name" do - Puppet::Util::Windows::Security.expects(:name_to_sid).with('testers').returns 'S-1-5-32-547' + Puppet::Util::Windows::SID.expects(:name_to_sid).with('testers').returns 'S-1-5-32-547' - Puppet::Util::ADSI.sid_for_account('testers').should == 'S-1-5-32-547' + Puppet::Util::Windows::ADSI.sid_for_account('testers').should == 'S-1-5-32-547' end it "should return a SID for a passed fully-qualified user or group name" do - Puppet::Util::Windows::Security.expects(:name_to_sid).with('MACHINE\testers').returns 'S-1-5-32-547' + Puppet::Util::Windows::SID.expects(:name_to_sid).with('MACHINE\testers').returns 'S-1-5-32-547' - Puppet::Util::ADSI.sid_for_account('MACHINE\testers').should == 'S-1-5-32-547' + Puppet::Util::Windows::ADSI.sid_for_account('MACHINE\testers').should == 'S-1-5-32-547' end end - describe ".sid_uri", :if => Puppet.features.microsoft_windows? do + describe ".computer_name" do + it "should return a non-empty ComputerName string" do + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, nil) + Puppet::Util::Windows::ADSI.computer_name.should_not be_empty + end + end + + describe ".sid_uri" do it "should raise an error when the input is not a SID object" do [Object.new, {}, 1, :symbol, '', nil].each do |input| expect { - Puppet::Util::ADSI.sid_uri(input) + Puppet::Util::Windows::ADSI.sid_uri(input) }.to raise_error(Puppet::Error, /Must use a valid SID object/) end end it "should return a SID uri for a well-known SID (SYSTEM)" do sid = Win32::Security::SID.new('SYSTEM') - Puppet::Util::ADSI.sid_uri(sid).should == 'WinNT://S-1-5-18' + Puppet::Util::Windows::ADSI.sid_uri(sid).should == 'WinNT://S-1-5-18' end end - describe Puppet::Util::ADSI::User do + describe Puppet::Util::Windows::ADSI::User do let(:username) { 'testuser' } let(:domain) { 'DOMAIN' } let(:domain_username) { "#{domain}\\#{username}"} it "should generate the correct URI" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI::User.uri(username).should == "WinNT://./#{username},user" + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::User.uri(username).should == "WinNT://./#{username},user" end it "should generate the correct URI for a user with a domain" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI::User.uri(username, domain).should == "WinNT://#{domain}/#{username},user" + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::User.uri(username, domain).should == "WinNT://#{domain}/#{username},user" end it "should be able to parse a username without a domain" do - Puppet::Util::ADSI::User.parse_name(username).should == [username, '.'] + Puppet::Util::Windows::ADSI::User.parse_name(username).should == [username, '.'] end it "should be able to parse a username with a domain" do - Puppet::Util::ADSI::User.parse_name(domain_username).should == [username, domain] + Puppet::Util::Windows::ADSI::User.parse_name(domain_username).should == [username, domain] end it "should raise an error with a username that contains a /" do expect { - Puppet::Util::ADSI::User.parse_name("#{domain}/#{username}") + Puppet::Util::Windows::ADSI::User.parse_name("#{domain}/#{username}") }.to raise_error(Puppet::Error, /Value must be in DOMAIN\\user style syntax/) end @@ -100,63 +107,61 @@ describe Puppet::Util::ADSI do adsi_user = stub('adsi') connection.expects(:Create).with('user', username).returns(adsi_user) - Puppet::Util::ADSI::Group.expects(:exists?).with(username).returns(false) + Puppet::Util::Windows::ADSI::Group.expects(:exists?).with(username).returns(false) - user = Puppet::Util::ADSI::User.create(username) + user = Puppet::Util::Windows::ADSI::User.create(username) - user.should be_a(Puppet::Util::ADSI::User) + user.should be_a(Puppet::Util::Windows::ADSI::User) user.native_user.should == adsi_user end it "should be able to check the existence of a user" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI.expects(:connect).with("WinNT://./#{username},user").returns connection - Puppet::Util::ADSI::User.exists?(username).should be_true + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{username},user").returns connection + Puppet::Util::Windows::ADSI::User.exists?(username).should be_true end it "should be able to check the existence of a domain user" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI.expects(:connect).with("WinNT://#{domain}/#{username},user").returns connection - Puppet::Util::ADSI::User.exists?(domain_username).should be_true + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://#{domain}/#{username},user").returns connection + Puppet::Util::Windows::ADSI::User.exists?(domain_username).should be_true end - it "should be able to confirm the existence of a user with a well-known SID", - :if => Puppet.features.microsoft_windows? do + it "should be able to confirm the existence of a user with a well-known SID" do system_user = Win32::Security::SID::LocalSystem # ensure that the underlying OS is queried here - Puppet::Util::ADSI.unstub(:connect) - Puppet::Util::ADSI::User.exists?(system_user).should be_true + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::User.exists?(system_user).should be_true end - it "should return nil with an unknown SID", - :if => Puppet.features.microsoft_windows? do + it "should return nil with an unknown SID" do bogus_sid = 'S-1-2-3-4' # ensure that the underlying OS is queried here - Puppet::Util::ADSI.unstub(:connect) - Puppet::Util::ADSI::User.exists?(bogus_sid).should be_false + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::User.exists?(bogus_sid).should be_false end it "should be able to delete a user" do connection.expects(:Delete).with('user', username) - Puppet::Util::ADSI::User.delete(username) + Puppet::Util::Windows::ADSI::User.delete(username) end it "should return an enumeration of IADsUser wrapped objects" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) name = 'Administrator' wmi_users = [stub('WMI', :name => name)] - Puppet::Util::ADSI.expects(:execquery).with('select name from win32_useraccount where localaccount = "TRUE"').returns(wmi_users) + Puppet::Util::Windows::ADSI.expects(:execquery).with('select name from win32_useraccount where localaccount = "TRUE"').returns(wmi_users) native_user = stub('IADsUser') homedir = "C:\\Users\\#{name}" native_user.expects(:Get).with('HomeDirectory').returns(homedir) - Puppet::Util::ADSI.expects(:connect).with("WinNT://./#{name},user").returns(native_user) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{name},user").returns(native_user) - users = Puppet::Util::ADSI::User.to_a + users = Puppet::Util::Windows::ADSI::User.to_a users.length.should == 1 users[0].name.should == name users[0]['HomeDirectory'].should == homedir @@ -165,7 +170,7 @@ describe Puppet::Util::ADSI do describe "an instance" do let(:adsi_user) { stub('user', :objectSID => []) } let(:sid) { stub(:account => username, :domain => 'testcomputername') } - let(:user) { Puppet::Util::ADSI::User.new(username, adsi_user) } + let(:user) { Puppet::Util::Windows::ADSI::User.new(username, adsi_user) } it "should provide its groups as a list of names" do names = ["group1", "group2"] @@ -178,8 +183,8 @@ describe Puppet::Util::ADSI do end it "should be able to test whether a given password is correct" do - Puppet::Util::ADSI::User.expects(:logon).with(username, 'pwdwrong').returns(false) - Puppet::Util::ADSI::User.expects(:logon).with(username, 'pwdright').returns(true) + Puppet::Util::Windows::ADSI::User.expects(:logon).with(username, 'pwdwrong').returns(false) + Puppet::Util::Windows::ADSI::User.expects(:logon).with(username, 'pwdright').returns(true) user.password_is?('pwdwrong').should be_false user.password_is?('pwdright').should be_true @@ -198,16 +203,16 @@ describe Puppet::Util::ADSI do user.password = 'pwd' end - it "should generate the correct URI", :if => Puppet.features.microsoft_windows? do - Puppet::Util::Windows::Security.stubs(:octet_string_to_sid_object).returns(sid) + it "should generate the correct URI" do + Puppet::Util::Windows::SID.stubs(:octet_string_to_sid_object).returns(sid) user.uri.should == "WinNT://testcomputername/#{username},user" end - describe "when given a set of groups to which to add the user", :if => Puppet.features.microsoft_windows? do + describe "when given a set of groups to which to add the user" do let(:groups_to_set) { 'group1,group2' } before(:each) do - Puppet::Util::Windows::Security.stubs(:octet_string_to_sid_object).returns(sid) + Puppet::Util::Windows::SID.stubs(:octet_string_to_sid_object).returns(sid) user.expects(:groups).returns ['group2', 'group3'] end @@ -219,9 +224,9 @@ describe Puppet::Util::ADSI do group3 = stub 'group1' group3.expects(:Remove).with("WinNT://testcomputername/#{username},user") - Puppet::Util::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user").twice - Puppet::Util::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 - Puppet::Util::ADSI.expects(:connect).with('WinNT://./group3,group').returns group3 + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user").twice + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group3,group').returns group3 user.set_groups(groups_to_set, false) end @@ -232,8 +237,8 @@ describe Puppet::Util::ADSI do group1 = stub 'group1' group1.expects(:Add).with("WinNT://testcomputername/#{username},user") - Puppet::Util::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user") - Puppet::Util::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user") + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 user.set_groups(groups_to_set, true) end @@ -242,50 +247,50 @@ describe Puppet::Util::ADSI do end end - describe Puppet::Util::ADSI::Group do + describe Puppet::Util::Windows::ADSI::Group do let(:groupname) { 'testgroup' } describe "an instance" do let(:adsi_group) { stub 'group' } - let(:group) { Puppet::Util::ADSI::Group.new(groupname, adsi_group) } + let(:group) { Puppet::Util::Windows::ADSI::Group.new(groupname, adsi_group) } let(:someone_sid){ stub(:account => 'someone', :domain => 'testcomputername')} - it "should be able to add a member (deprecated)", :if => Puppet.features.microsoft_windows? do - Puppet.expects(:deprecation_warning).with('Puppet::Util::ADSI::Group#add_members is deprecated; please use Puppet::Util::ADSI::Group#add_member_sids') + it "should be able to add a member (deprecated)" do + Puppet.expects(:deprecation_warning).with('Puppet::Util::Windows::ADSI::Group#add_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#add_member_sids') - Puppet::Util::Windows::Security.expects(:name_to_sid_object).with('someone').returns(someone_sid) - Puppet::Util::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('someone').returns(someone_sid) + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") adsi_group.expects(:Add).with("WinNT://testcomputername/someone,user") group.add_member('someone') end - it "should raise when adding a member that can't resolve to a SID (deprecated)", :if => Puppet.features.microsoft_windows? do + it "should raise when adding a member that can't resolve to a SID (deprecated)" do expect { group.add_member('foobar') }.to raise_error(Puppet::Error, /Could not resolve username: foobar/) end - it "should be able to remove a member (deprecated)", :if => Puppet.features.microsoft_windows? do - Puppet.expects(:deprecation_warning).with('Puppet::Util::ADSI::Group#remove_members is deprecated; please use Puppet::Util::ADSI::Group#remove_member_sids') + it "should be able to remove a member (deprecated)" do + Puppet.expects(:deprecation_warning).with('Puppet::Util::Windows::ADSI::Group#remove_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#remove_member_sids') - Puppet::Util::Windows::Security.expects(:name_to_sid_object).with('someone').returns(someone_sid) - Puppet::Util::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('someone').returns(someone_sid) + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") adsi_group.expects(:Remove).with("WinNT://testcomputername/someone,user") group.remove_member('someone') end - it "should raise when removing a member that can't resolve to a SID (deprecated)", :if => Puppet.features.microsoft_windows? do + it "should raise when removing a member that can't resolve to a SID (deprecated)" do expect { group.remove_member('foobar') }.to raise_error(Puppet::Error, /Could not resolve username: foobar/) end - describe "should be able to use SID objects", :if => Puppet.features.microsoft_windows? do - let(:system) { Puppet::Util::Windows::Security.name_to_sid_object('SYSTEM') } + describe "should be able to use SID objects" do + let(:system) { Puppet::Util::Windows::SID.name_to_sid_object('SYSTEM') } it "to add a member" do adsi_group.expects(:Add).with("WinNT://S-1-5-18") @@ -310,7 +315,7 @@ describe Puppet::Util::ADSI do group.members.should =~ names end - it "should be able to add a list of users to a group", :if => Puppet.features.microsoft_windows? do + it "should be able to add a list of users to a group" do names = ['DOMAIN\user1', 'user2'] sids = [ stub(:account => 'user1', :domain => 'DOMAIN'), @@ -319,14 +324,14 @@ describe Puppet::Util::ADSI do ] # use stubbed objectSid on member to return stubbed SID - Puppet::Util::Windows::Security.expects(:octet_string_to_sid_object).with([0]).returns(sids[0]) - Puppet::Util::Windows::Security.expects(:octet_string_to_sid_object).with([1]).returns(sids[1]) + Puppet::Util::Windows::SID.expects(:octet_string_to_sid_object).with([0]).returns(sids[0]) + Puppet::Util::Windows::SID.expects(:octet_string_to_sid_object).with([1]).returns(sids[1]) - Puppet::Util::Windows::Security.expects(:name_to_sid_object).with('user2').returns(sids[1]) - Puppet::Util::Windows::Security.expects(:name_to_sid_object).with('DOMAIN2\user3').returns(sids[2]) + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('user2').returns(sids[1]) + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('DOMAIN2\user3').returns(sids[2]) - Puppet::Util::ADSI.expects(:sid_uri).with(sids[0]).returns("WinNT://DOMAIN/user1,user") - Puppet::Util::ADSI.expects(:sid_uri).with(sids[2]).returns("WinNT://DOMAIN2/user3,user") + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sids[0]).returns("WinNT://DOMAIN/user1,user") + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sids[2]).returns("WinNT://DOMAIN2/user3,user") members = names.each_with_index.map{|n,i| stub(:Name => n, :objectSID => [i])} adsi_group.expects(:Members).returns members @@ -337,7 +342,7 @@ describe Puppet::Util::ADSI do group.set_members(['user2', 'DOMAIN2\user3']) end - it "should raise an error when a username does not resolve to a SID", :if => Puppet.features.microsoft_windows? do + it "should raise an error when a username does not resolve to a SID" do expect { adsi_group.expects(:Members).returns [] group.set_members(['foobar']) @@ -345,81 +350,79 @@ describe Puppet::Util::ADSI do end it "should generate the correct URI" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) group.uri.should == "WinNT://./#{groupname},group" end end it "should generate the correct URI" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI::Group.uri("people").should == "WinNT://./people,group" + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::Group.uri("people").should == "WinNT://./people,group" end it "should be able to create a group" do adsi_group = stub("adsi") connection.expects(:Create).with('group', groupname).returns(adsi_group) - Puppet::Util::ADSI::User.expects(:exists?).with(groupname).returns(false) + Puppet::Util::Windows::ADSI::User.expects(:exists?).with(groupname).returns(false) - group = Puppet::Util::ADSI::Group.create(groupname) + group = Puppet::Util::Windows::ADSI::Group.create(groupname) - group.should be_a(Puppet::Util::ADSI::Group) + group.should be_a(Puppet::Util::Windows::ADSI::Group) group.native_group.should == adsi_group end it "should be able to confirm the existence of a group" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) - Puppet::Util::ADSI.expects(:connect).with("WinNT://./#{groupname},group").returns connection + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{groupname},group").returns connection - Puppet::Util::ADSI::Group.exists?(groupname).should be_true + Puppet::Util::Windows::ADSI::Group.exists?(groupname).should be_true end - it "should be able to confirm the existence of a group with a well-known SID", - :if => Puppet.features.microsoft_windows? do + it "should be able to confirm the existence of a group with a well-known SID" do service_group = Win32::Security::SID::Service # ensure that the underlying OS is queried here - Puppet::Util::ADSI.unstub(:connect) - Puppet::Util::ADSI::Group.exists?(service_group).should be_true + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::Group.exists?(service_group).should be_true end - it "should return nil with an unknown SID", - :if => Puppet.features.microsoft_windows? do + it "should return nil with an unknown SID" do bogus_sid = 'S-1-2-3-4' # ensure that the underlying OS is queried here - Puppet::Util::ADSI.unstub(:connect) - Puppet::Util::ADSI::Group.exists?(bogus_sid).should be_false + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::Group.exists?(bogus_sid).should be_false end it "should be able to delete a group" do connection.expects(:Delete).with('group', groupname) - Puppet::Util::ADSI::Group.delete(groupname) + Puppet::Util::Windows::ADSI::Group.delete(groupname) end it "should return an enumeration of IADsGroup wrapped objects" do - Puppet::Util::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) name = 'Administrators' wmi_groups = [stub('WMI', :name => name)] - Puppet::Util::ADSI.expects(:execquery).with('select name from win32_group where localaccount = "TRUE"').returns(wmi_groups) + Puppet::Util::Windows::ADSI.expects(:execquery).with('select name from win32_group where localaccount = "TRUE"').returns(wmi_groups) native_group = stub('IADsGroup') native_group.expects(:Members).returns([stub(:Name => 'Administrator')]) - Puppet::Util::ADSI.expects(:connect).with("WinNT://./#{name},group").returns(native_group) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{name},group").returns(native_group) - groups = Puppet::Util::ADSI::Group.to_a + groups = Puppet::Util::Windows::ADSI::Group.to_a groups.length.should == 1 groups[0].name.should == name groups[0].members.should == ['Administrator'] end end - describe Puppet::Util::ADSI::UserProfile do + describe Puppet::Util::Windows::ADSI::UserProfile do it "should be able to delete a user profile" do connection.expects(:Delete).with("Win32_UserProfile.SID='S-A-B-C'") - Puppet::Util::ADSI::UserProfile.delete('S-A-B-C') + Puppet::Util::Windows::ADSI::UserProfile.delete('S-A-B-C') end it "should warn on 2003" do @@ -431,7 +434,7 @@ describe Puppet::Util::ADSI do Exception occurred.") Puppet.expects(:warning).with("Cannot delete user profile for 'S-A-B-C' prior to Vista SP1") - Puppet::Util::ADSI::UserProfile.delete('S-A-B-C') + Puppet::Util::Windows::ADSI::UserProfile.delete('S-A-B-C') end end end diff --git a/spec/unit/util/windows/api_types_spec.rb b/spec/unit/util/windows/api_types_spec.rb new file mode 100644 index 000000000..a1e1c76c9 --- /dev/null +++ b/spec/unit/util/windows/api_types_spec.rb @@ -0,0 +1,28 @@ +# encoding: UTF-8 +#!/usr/bin/env ruby + +require 'spec_helper' + +describe "FFI::MemoryPointer", :if => Puppet.features.microsoft_windows? do + context "read_wide_string" do + let (:string) { "foo_bar" } + + it "should properly roundtrip a given string" do + read_string = nil + FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr| + read_string = ptr.read_wide_string(string.length) + end + + read_string.should == string + end + + it "should return a given string in the default encoding" do + read_string = nil + FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr| + read_string = ptr.read_wide_string(string.length) + end + + read_string.encoding.should == Encoding.default_external + end + end +end diff --git a/spec/unit/util/windows/registry_spec.rb b/spec/unit/util/windows/registry_spec.rb index 636ba0c93..ed52539a5 100755 --- a/spec/unit/util/windows/registry_spec.rb +++ b/spec/unit/util/windows/registry_spec.rb @@ -1,7 +1,6 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/windows' -require 'puppet/util/windows/registry' describe Puppet::Util::Windows::Registry, :if => Puppet::Util::Platform.windows? do subject do @@ -43,12 +42,14 @@ describe Puppet::Util::Windows::Registry, :if => Puppet::Util::Platform.windows? yielded.should == subkey end - [described_class::KEY64, described_class::KEY32].each do |access| - it "should open the key for read access 0x#{access.to_s(16)}" do - mode = described_class::KEY_READ | access - hkey.expects(:open).with(path, mode) + if Puppet::Util::Platform.windows? + [described_class::KEY64, described_class::KEY32].each do |access| + it "should open the key for read access 0x#{access.to_s(16)}" do + mode = described_class::KEY_READ | access + hkey.expects(:open).with(path, mode) - subject.open(name, path, mode) {|reg| } + subject.open(name, path, mode) {|reg| } + end end end diff --git a/spec/unit/util/windows/sid_spec.rb b/spec/unit/util/windows/sid_spec.rb index 770512188..2748f13c6 100755 --- a/spec/unit/util/windows/sid_spec.rb +++ b/spec/unit/util/windows/sid_spec.rb @@ -4,12 +4,9 @@ require 'spec_helper' describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? do if Puppet.features.microsoft_windows? require 'puppet/util/windows' - class SIDTester - include Puppet::Util::Windows::SID - end end - let(:subject) { SIDTester.new } + let(:subject) { Puppet::Util::Windows::SID } let(:sid) { Win32::Security::SID::LocalSystem } let(:invalid_sid) { 'bogus' } let(:unknown_sid) { 'S-0-0-0' } @@ -50,7 +47,7 @@ describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? expect { invalid_octet = [1] subject.octet_string_to_sid_object(invalid_octet) - }.to raise_error(Win32::Security::SID::Error, /No mapping between account names and security IDs was done./) + }.to raise_error(SystemCallError, /No mapping between account names and security IDs was done./) end end @@ -159,7 +156,7 @@ describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? it "should raise if the conversion fails" do subject.expects(:string_to_sid_ptr).with(sid). - raises(Puppet::Util::Windows::Error.new("Failed to convert string SID: #{sid}", Windows::Error::ERROR_ACCESS_DENIED)) + raises(Puppet::Util::Windows::Error.new("Failed to convert string SID: #{sid}", Puppet::Util::Windows::Error::ERROR_ACCESS_DENIED)) expect { subject.string_to_sid_ptr(sid) {|ptr| } diff --git a/spec/unit/util/windows/string_spec.rb b/spec/unit/util/windows/string_spec.rb index 60f7e6449..5c6473e70 100644 --- a/spec/unit/util/windows/string_spec.rb +++ b/spec/unit/util/windows/string_spec.rb @@ -50,5 +50,9 @@ describe "Puppet::Util::Windows::String", :if => Puppet.features.microsoft_windo it "should convert an UTF-32BE string" do converts_to_wide_string("bob\u00E8".encode(Encoding::UTF_32BE)) end + + it "should return a nil when given a nil" do + wide_string(nil).should == nil + end end end diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index 56c5cb719..b239b4a84 100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -69,7 +69,11 @@ describe "Pure ruby yaml implementation" do end it "serializes a time in UTC" do - pending("not supported on Windows", :if => Puppet.features.microsoft_windows? && RUBY_VERSION[0,3] == '1.8') do + bad_rubies = + RUBY_VERSION[0,3] == '1.8' || + RUBY_VERSION[0,3] == '2.0' && RUBY_PLATFORM == 'i386-mingw32' + + pending("not supported on Windows", :if => Puppet.features.microsoft_windows? && bad_rubies) do the_time_in("Europe/London").should be_equivalent_to(the_time_in_yaml_offset_by("+00:00")) end end |