diff options
-rw-r--r-- | .rubocop.yml | 8 | ||||
-rw-r--r-- | .travis.yml | 11 | ||||
-rw-r--r-- | Gemfile | 12 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | Rakefile | 15 | ||||
-rw-r--r-- | appveyor.yml | 4 | ||||
-rw-r--r-- | lib/mixlib/shellout.rb | 56 | ||||
-rw-r--r-- | lib/mixlib/shellout/unix.rb | 14 | ||||
-rw-r--r-- | lib/mixlib/shellout/windows.rb | 60 | ||||
-rw-r--r-- | lib/mixlib/shellout/windows/core_ext.rb | 128 | ||||
-rw-r--r-- | mixlib-shellout-windows.gemspec | 2 | ||||
-rw-r--r-- | mixlib-shellout.gemspec | 15 | ||||
-rw-r--r-- | spec/mixlib/shellout/windows_spec.rb | 144 | ||||
-rw-r--r-- | spec/mixlib/shellout_spec.rb | 606 | ||||
-rw-r--r-- | spec/spec_helper.rb | 11 |
15 files changed, 554 insertions, 538 deletions
diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..4343509 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,8 @@ +Lint/UnderscorePrefixedVariableName: + Exclude: + - 'spec/mixlib/shellout/windows_spec.rb' + +# Configuration parameters: ContextCreatingMethods. +Lint/UselessAccessModifier: + Exclude: + - 'lib/mixlib/shellout/windows/core_ext.rb' diff --git a/.travis.yml b/.travis.yml index ea98a8b..c5340d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,13 @@ language: ruby cache: bundler - sudo: false - rvm: - - 2.1.9 - 2.2.5 - 2.3.1 - -before_install: - - gem update bundler - branches: only: - master +before_install: + - gem update bundler -script: bundle exec rspec --color --format progress +script: bundle exec rake @@ -1,15 +1,15 @@ -source 'https://rubygems.org' +source "https://rubygems.org" gemspec :name => "mixlib-shellout" group(:test) do gem "rspec_junit_formatter" - gem 'rake' + gem "rake" end group(:development) do - gem 'pry' - gem 'pry-byebug' - gem 'pry-stack_explorer' - gem 'rb-readline' + gem "pry" + gem "pry-byebug" + gem "pry-stack_explorer" + gem "rb-readline" end @@ -65,9 +65,13 @@ Invoke "whoami.exe" to demonstrate running a command as another user: Mixlib::ShellOut does a standard fork/exec on Unix, and uses the Win32 API on Windows. There is not currently support for JRuby. ## See Also -- `Process.spawn` in Ruby 1.9 +- `Process.spawn` in Ruby 1.9+ - [https://github.com/rtomayko/posix-spawn](https://github.com/rtomayko/posix-spawn) +## Contributing + +For information on contributing to this project see <https://github.com/chef/chef/blob/master/CONTRIBUTING.md> + ## License - Copyright:: Copyright (c) 2011-2016 Chef Software, Inc. - License:: Apache License, Version 2.0 @@ -1,11 +1,16 @@ -require 'bundler' -require 'rspec/core/rake_task' +require "bundler" +require "rspec/core/rake_task" -Bundler::GemHelper.install_tasks +Bundler::GemHelper.install_tasks name: "mixlib-shellout" + +require "chefstyle" +require "rubocop/rake_task" +desc "Run Ruby style checks" +RuboCop::RakeTask.new(:style) desc "Run all specs in spec directory" RSpec::Core::RakeTask.new(:spec) do |t| - t.pattern = FileList['spec/**/*_spec.rb'] + t.pattern = FileList["spec/**/*_spec.rb"] end -task default: :spec +task default: [:style, :spec] diff --git a/appveyor.yml b/appveyor.yml index 0ea6535..e49c59e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,9 @@ platform: environment: matrix: - - ruby_version: "21" + - ruby_version: "22" + - ruby_version: "23" + - ruby_version: "23-x64" clone_folder: c:\projects\mixlib-shellout clone_depth: 1 diff --git a/lib/mixlib/shellout.rb b/lib/mixlib/shellout.rb index 2fdbcfd..d15b645 100644 --- a/lib/mixlib/shellout.rb +++ b/lib/mixlib/shellout.rb @@ -16,10 +16,10 @@ # limitations under the License. # -require 'etc' -require 'tmpdir' -require 'fcntl' -require 'mixlib/shellout/exceptions' +require "etc" +require "tmpdir" +require "fcntl" +require "mixlib/shellout/exceptions" module Mixlib @@ -29,10 +29,10 @@ module Mixlib DEFAULT_READ_TIMEOUT = 600 if RUBY_PLATFORM =~ /mswin|mingw32|windows/ - require 'mixlib/shellout/windows' + require "mixlib/shellout/windows" include ShellOut::Windows else - require 'mixlib/shellout/unix' + require "mixlib/shellout/unix" include ShellOut::Unix end @@ -162,7 +162,7 @@ module Mixlib # cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp') # cmd.run_command # etc. def initialize(*command_args) - @stdout, @stderr, @process_status = '', '', '' + @stdout, @stderr, @process_status = "", "", "" @live_stdout = @live_stderr = nil @input = nil @log_level = :debug @@ -284,15 +284,15 @@ module Mixlib # is highly encouraged. # === Raises # ShellCommandFailed always - def invalid!(msg=nil) + def invalid!(msg = nil) msg ||= "Command produced unexpected results" raise ShellCommandFailed, msg + "\n" + format_for_exception end def inspect "<#{self.class.name}##{object_id}: command: '#@command' process_status: #{@status.inspect} " + - "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " + - "environment: #{@environment.inspect} timeout: #{timeout} user: #@user group: #@group working_dir: #@cwd >" + "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " + + "environment: #{@environment.inspect} timeout: #{timeout} user: #@user group: #@group working_dir: #@cwd >" end private @@ -300,44 +300,44 @@ module Mixlib def parse_options(opts) opts.each do |option, setting| case option.to_s - when 'cwd' + when "cwd" self.cwd = setting - when 'domain' + when "domain" self.domain = setting - when 'password' + when "password" self.password = setting - when 'user' + when "user" self.user = setting self.with_logon = setting - when 'group' + when "group" self.group = setting - when 'umask' + when "umask" self.umask = setting - when 'timeout' + when "timeout" self.timeout = setting - when 'returns' + when "returns" self.valid_exit_codes = Array(setting) - when 'live_stream' + when "live_stream" self.live_stdout = self.live_stderr = setting - when 'live_stdout' + when "live_stdout" self.live_stdout = setting - when 'live_stderr' + when "live_stderr" self.live_stderr = setting - when 'input' + when "input" self.input = setting - when 'logger' + when "logger" self.logger = setting - when 'log_level' + when "log_level" self.log_level = setting - when 'log_tag' + when "log_tag" self.log_tag = setting - when 'environment', 'env' + when "environment", "env" if setting - self.environment = Hash[setting.map{|(k,v)| [k.to_s,v]}] + self.environment = Hash[setting.map { |(k, v)| [k.to_s, v] }] else self.environment = {} end - when 'login' + when "login" self.login = setting else raise InvalidCommandOption, "option '#{option.inspect}' is not a valid option for #{self.class.name}" diff --git a/lib/mixlib/shellout/unix.rb b/lib/mixlib/shellout/unix.rb index 734a597..238273c 100644 --- a/lib/mixlib/shellout/unix.rb +++ b/lib/mixlib/shellout/unix.rb @@ -39,7 +39,7 @@ module Mixlib def all_seconderies ret = [] Etc.endgrent - while ( g = Etc.getgrent ) do + while ( g = Etc.getgrent ) ret << g end Etc.endgrent @@ -52,7 +52,7 @@ module Mixlib def sgids return nil unless using_login? user_name = Etc.getpwuid(uid).name - all_seconderies.select{|g| g.mem.include?(user_name)}.map{|g|g.gid} + all_seconderies.select { |g| g.mem.include?(user_name) }.map { |g| g.gid } end # The environment variables that are deduced from simulating logon @@ -63,7 +63,7 @@ module Mixlib # According to `man su`, the set fields are: # $HOME, $SHELL, $USER, $LOGNAME, $PATH, and $IFS # Values are copied from "shadow" package in Ubuntu 14.10 - {'HOME'=>entry.dir, 'SHELL'=>entry.shell, 'USER'=>entry.name, 'LOGNAME'=>entry.name, 'PATH'=>'/sbin:/bin:/usr/sbin:/usr/bin', 'IFS'=>"\t\n"} + { "HOME" => entry.dir, "SHELL" => entry.shell, "USER" => entry.name, "LOGNAME" => entry.name, "PATH" => "/sbin:/bin:/usr/sbin:/usr/bin", "IFS" => "\t\n" } end # Merges the two environments for the process @@ -170,7 +170,7 @@ module Mixlib def set_environment # user-set variables should override the login ones - process_environment.each do |env_var,value| + process_environment.each do |env_var, value| ENV[env_var] = value end end @@ -335,14 +335,14 @@ module Mixlib set_cwd begin - command.kind_of?(Array) ? exec(*command, :close_others=>true) : exec(command, :close_others=>true) + command.kind_of?(Array) ? exec(*command, :close_others => true) : exec(command, :close_others => true) - raise 'forty-two' # Should never get here + raise "forty-two" # Should never get here rescue Exception => e Marshal.dump(e, process_status_pipe.last) process_status_pipe.last.flush end - process_status_pipe.last.close unless (process_status_pipe.last.closed?) + process_status_pipe.last.close unless process_status_pipe.last.closed? exit! end end diff --git a/lib/mixlib/shellout/windows.rb b/lib/mixlib/shellout/windows.rb index 5b13dad..0c66c2e 100644 --- a/lib/mixlib/shellout/windows.rb +++ b/lib/mixlib/shellout/windows.rb @@ -18,8 +18,8 @@ # limitations under the License. # -require 'win32/process' -require 'mixlib/shellout/windows/core_ext' +require "win32/process" +require "mixlib/shellout/windows/core_ext" module Mixlib class ShellOut @@ -63,10 +63,10 @@ module Mixlib :startup_info => { :stdout => stdout_write, :stderr => stderr_write, - :stdin => stdin_read + :stdin => stdin_read, }, - :environment => inherit_environment.map { |k,v| "#{k}=#{v}" }, - :close_handles => false + :environment => inherit_environment.map { |k, v| "#{k}=#{v}" }, + :close_handles => false, } create_process_args[:cwd] = cwd if cwd # default to local account database if domain is not specified @@ -90,24 +90,24 @@ module Mixlib # Wait for the process to finish, consuming output as we go # start_wait = Time.now - while true + loop do wait_status = WaitForSingleObject(process.process_handle, 0) case wait_status when WAIT_OBJECT_0 # Get process exit code - exit_code = [0].pack('l') + exit_code = [0].pack("l") unless GetExitCodeProcess(process.process_handle, exit_code) raise get_last_error end @status = ThingThatLooksSortOfLikeAProcessStatus.new - @status.exitstatus = exit_code.unpack('l').first + @status.exitstatus = exit_code.unpack("l").first return self when WAIT_TIMEOUT # Kill the process if (Time.now - start_wait) > timeout begin - require 'wmi-lite/wmi' + require "wmi-lite/wmi" wmi = WmiLite::Wmi.new Utils.kill_process_tree(process.process_id, wmi, logger) Process.kill(:KILL, process.process_id) @@ -118,13 +118,13 @@ module Mixlib raise Mixlib::ShellOut::CommandTimeout, [ "command timed out:", format_for_exception, - Utils.format_process(process, app_name, command_line, timeout) + Utils.format_process(process, app_name, command_line, timeout), ].join("\n") end consume_output(open_streams, stdout_read, stderr_read) else - raise "Unknown response from WaitForSingleObject(#{process.process_handle}, #{timeout*1000}): #{wait_status}" + raise "Unknown response from WaitForSingleObject(#{process.process_handle}, #{timeout * 1000}): #{wait_status}" end end @@ -212,7 +212,7 @@ module Mixlib # https://github.com/opscode/mixlib-shellout/pull/2#issuecomment-4837859 # http://ss64.com/nt/syntax-esc.html def _run_under_cmd(command) - [ ENV['COMSPEC'], "cmd /c \"#{command}\"" ] + [ ENV["COMSPEC"], "cmd /c \"#{command}\"" ] end def _run_directly(command, exe) @@ -220,7 +220,7 @@ module Mixlib end def unquoted_executable_path(command) - command[0,command.index(/\s/) || command.length] + command[0, command.index(/\s/) || command.length] end def candidate_executable_for_command(command) @@ -235,11 +235,11 @@ module Mixlib def inherit_environment result = {} - ENV.each_pair do |k,v| + ENV.each_pair do |k, v| result[k] = v end - environment.each_pair do |k,v| + environment.each_pair do |k, v| if v == nil result.delete(k) else @@ -266,15 +266,15 @@ module Mixlib command.dup.each_char do |c| case c when "'", '"' - if (!quote) + if !quote quote = c elsif quote == c quote = nil end next - when '>', '<', '|', '&', "\n" + when ">", "<", "|", "&", "\n" return true unless quote - when '%' + when "%" return true if env env = env_first_char = true next @@ -282,7 +282,7 @@ module Mixlib next unless env if env_first_char env_first_char = false - env = false and next if c !~ /[A-Za-z_]/ + (env = false) && next if c !~ /[A-Za-z_]/ end env = false if c !~ /[A-Za-z1-9_]/ end @@ -291,13 +291,13 @@ module Mixlib end def self.pathext - @pathext ||= ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') + [''] : [''] + @pathext ||= ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") + [""] : [""] end # which() mimicks the Unix which command # FIXME: it is not working def self.which(cmd) - ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + ENV["PATH"].split(File::PATH_SEPARATOR).each do |path| exe = find_executable("#{path}/#{cmd}") return exe if exe end @@ -323,13 +323,13 @@ module Mixlib def self.system_required_processes [ - 'System Idle Process', - 'System', - 'spoolsv.exe', - 'lsass.exe', - 'csrss.exe', - 'smss.exe', - 'svchost.exe' + "System Idle Process", + "System", + "spoolsv.exe", + "lsass.exe", + "csrss.exe", + "smss.exe", + "svchost.exe", ] end @@ -358,13 +358,13 @@ module Mixlib child_pid = instance.wmi_ole_object.processid logger.debug([ "killing child process #{child_pid}::", - "#{instance.wmi_ole_object.Name} of parent #{pid}" + "#{instance.wmi_ole_object.Name} of parent #{pid}", ].join) if logger Process.kill(:KILL, instance.wmi_ole_object.processid) rescue Errno::EIO, SystemCallError logger.debug([ "Failed to kill child process #{child_pid}::", - "#{instance.wmi_ole_object.Name} of parent #{pid}" + "#{instance.wmi_ole_object.Name} of parent #{pid}", ].join) if logger end diff --git a/lib/mixlib/shellout/windows/core_ext.rb b/lib/mixlib/shellout/windows/core_ext.rb index 2fe2bf2..17faff2 100644 --- a/lib/mixlib/shellout/windows/core_ext.rb +++ b/lib/mixlib/shellout/windows/core_ext.rb @@ -17,7 +17,7 @@ # limitations under the License. # -require 'win32/process' +require "win32/process" # Add new constants for Logon module Process::Constants @@ -65,78 +65,78 @@ module Process class << self def create(args) unless args.kind_of?(Hash) - raise TypeError, 'hash keyword arguments expected' + raise TypeError, "hash keyword arguments expected" end - valid_keys = %w[ + valid_keys = %w{ app_name command_line inherit creation_flags cwd environment startup_info thread_inherit process_inherit close_handles with_logon domain password - ] + } - valid_si_keys = %w[ + valid_si_keys = %w{ startf_flags desktop title x y x_size y_size x_count_chars y_count_chars fill_attribute sw_flags stdin stdout stderr - ] + } # Set default values hash = { - 'app_name' => nil, - 'creation_flags' => 0, - 'close_handles' => true + "app_name" => nil, + "creation_flags" => 0, + "close_handles" => true, } # Validate the keys, and convert symbols and case to lowercase strings. - args.each{ |key, val| + args.each do |key, val| key = key.to_s.downcase unless valid_keys.include?(key) raise ArgumentError, "invalid key '#{key}'" end hash[key] = val - } + end si_hash = {} # If the startup_info key is present, validate its subkeys - if hash['startup_info'] - hash['startup_info'].each{ |key, val| + if hash["startup_info"] + hash["startup_info"].each do |key, val| key = key.to_s.downcase unless valid_si_keys.include?(key) raise ArgumentError, "invalid startup_info key '#{key}'" end si_hash[key] = val - } + end end # The +command_line+ key is mandatory unless the +app_name+ key # is specified. - unless hash['command_line'] - if hash['app_name'] - hash['command_line'] = hash['app_name'] - hash['app_name'] = nil + unless hash["command_line"] + if hash["app_name"] + hash["command_line"] = hash["app_name"] + hash["app_name"] = nil else - raise ArgumentError, 'command_line or app_name must be specified' + raise ArgumentError, "command_line or app_name must be specified" end end env = nil # The env string should be passed as a string of ';' separated paths. - if hash['environment'] - env = hash['environment'] + if hash["environment"] + env = hash["environment"] unless env.respond_to?(:join) - env = hash['environment'].split(File::PATH_SEPARATOR) + env = hash["environment"].split(File::PATH_SEPARATOR) end - env = env.map{ |e| e + 0.chr }.join('') + 0.chr - env.to_wide_string! if hash['with_logon'] + env = env.map { |e| e + 0.chr }.join("") + 0.chr + env.to_wide_string! if hash["with_logon"] end # Process SECURITY_ATTRIBUTE structure process_security = nil - if hash['process_inherit'] + if hash["process_inherit"] process_security = SECURITY_ATTRIBUTES.new process_security[:nLength] = 12 process_security[:bInheritHandle] = 1 @@ -145,7 +145,7 @@ module Process # Thread SECURITY_ATTRIBUTE structure thread_security = nil - if hash['thread_inherit'] + if hash["thread_inherit"] thread_security = SECURITY_ATTRIBUTES.new thread_security[:nLength] = 12 thread_security[:bInheritHandle] = 1 @@ -156,7 +156,7 @@ module Process # will not work on JRuby because of the way it handles internal file # descriptors. # - ['stdin', 'stdout', 'stderr'].each{ |io| + %w{stdin stdout stderr}.each do |io| if si_hash[io] if si_hash[io].respond_to?(:fileno) handle = get_osfhandle(si_hash[io].fileno) @@ -187,66 +187,66 @@ module Process raise SystemCallError.new("SetHandleInformation", FFI.errno) unless bool si_hash[io] = handle - si_hash['startf_flags'] ||= 0 - si_hash['startf_flags'] |= STARTF_USESTDHANDLES - hash['inherit'] = true + si_hash["startf_flags"] ||= 0 + si_hash["startf_flags"] |= STARTF_USESTDHANDLES + hash["inherit"] = true end - } + end procinfo = PROCESS_INFORMATION.new startinfo = STARTUPINFO.new unless si_hash.empty? startinfo[:cb] = startinfo.size - startinfo[:lpDesktop] = si_hash['desktop'] if si_hash['desktop'] - startinfo[:lpTitle] = si_hash['title'] if si_hash['title'] - startinfo[:dwX] = si_hash['x'] if si_hash['x'] - startinfo[:dwY] = si_hash['y'] if si_hash['y'] - startinfo[:dwXSize] = si_hash['x_size'] if si_hash['x_size'] - startinfo[:dwYSize] = si_hash['y_size'] if si_hash['y_size'] - startinfo[:dwXCountChars] = si_hash['x_count_chars'] if si_hash['x_count_chars'] - startinfo[:dwYCountChars] = si_hash['y_count_chars'] if si_hash['y_count_chars'] - startinfo[:dwFillAttribute] = si_hash['fill_attribute'] if si_hash['fill_attribute'] - startinfo[:dwFlags] = si_hash['startf_flags'] if si_hash['startf_flags'] - startinfo[:wShowWindow] = si_hash['sw_flags'] if si_hash['sw_flags'] + startinfo[:lpDesktop] = si_hash["desktop"] if si_hash["desktop"] + startinfo[:lpTitle] = si_hash["title"] if si_hash["title"] + startinfo[:dwX] = si_hash["x"] if si_hash["x"] + startinfo[:dwY] = si_hash["y"] if si_hash["y"] + startinfo[:dwXSize] = si_hash["x_size"] if si_hash["x_size"] + startinfo[:dwYSize] = si_hash["y_size"] if si_hash["y_size"] + startinfo[:dwXCountChars] = si_hash["x_count_chars"] if si_hash["x_count_chars"] + startinfo[:dwYCountChars] = si_hash["y_count_chars"] if si_hash["y_count_chars"] + startinfo[:dwFillAttribute] = si_hash["fill_attribute"] if si_hash["fill_attribute"] + startinfo[:dwFlags] = si_hash["startf_flags"] if si_hash["startf_flags"] + startinfo[:wShowWindow] = si_hash["sw_flags"] if si_hash["sw_flags"] startinfo[:cbReserved2] = 0 - startinfo[:hStdInput] = si_hash['stdin'] if si_hash['stdin'] - startinfo[:hStdOutput] = si_hash['stdout'] if si_hash['stdout'] - startinfo[:hStdError] = si_hash['stderr'] if si_hash['stderr'] + startinfo[:hStdInput] = si_hash["stdin"] if si_hash["stdin"] + startinfo[:hStdOutput] = si_hash["stdout"] if si_hash["stdout"] + startinfo[:hStdError] = si_hash["stderr"] if si_hash["stderr"] end app = nil cmd = nil # Convert strings to wide character strings if present - if hash['app_name'] - app = hash['app_name'].to_wide_string + if hash["app_name"] + app = hash["app_name"].to_wide_string end - if hash['command_line'] - cmd = hash['command_line'].to_wide_string + if hash["command_line"] + cmd = hash["command_line"].to_wide_string end - if hash['cwd'] - cwd = hash['cwd'].to_wide_string + if hash["cwd"] + cwd = hash["cwd"].to_wide_string end - inherit = hash['inherit'] ? 1 : 0 + inherit = hash["inherit"] ? 1 : 0 - if hash['with_logon'] - logon = hash['with_logon'].to_wide_string + if hash["with_logon"] + logon = hash["with_logon"].to_wide_string - if hash['password'] - passwd = hash['password'].to_wide_string + if hash["password"] + passwd = hash["password"].to_wide_string else - raise ArgumentError, 'password must be specified if with_logon is used' + raise ArgumentError, "password must be specified if with_logon is used" end - if hash['domain'] - domain = hash['domain'].to_wide_string + if hash["domain"] + domain = hash["domain"].to_wide_string end - hash['creation_flags'] |= CREATE_UNICODE_ENVIRONMENT + hash["creation_flags"] |= CREATE_UNICODE_ENVIRONMENT winsta_name = FFI::MemoryPointer.new(:char, 256) return_size = FFI::MemoryPointer.new(:ulong) @@ -297,7 +297,7 @@ module Process process_security, # Process attributes thread_security, # Thread attributes inherit, # Inherit handles - hash['creation_flags'], # Creation Flags + hash["creation_flags"], # Creation Flags env, # Environment cwd, # Working directory startinfo, # Startup Info @@ -318,7 +318,7 @@ module Process LOGON_WITH_PROFILE, # Logon flags app, # App name cmd, # Command line - hash['creation_flags'], # Creation flags + hash["creation_flags"], # Creation flags env, # Environment cwd, # Working directory startinfo, # Startup Info @@ -336,7 +336,7 @@ module Process process_security, # Process attributes thread_security, # Thread attributes inherit, # Inherit handles? - hash['creation_flags'], # Creation flags + hash["creation_flags"], # Creation flags env, # Environment cwd, # Working directory startinfo, # Startup Info @@ -350,7 +350,7 @@ module Process # Automatically close the process and thread handles in the # PROCESS_INFORMATION struct unless explicitly told not to. - if hash['close_handles'] + if hash["close_handles"] CloseHandle(procinfo[:hProcess]) CloseHandle(procinfo[:hThread]) # Clear these fields so callers don't attempt to close the handle diff --git a/mixlib-shellout-windows.gemspec b/mixlib-shellout-windows.gemspec index f051dc6..bd3c21d 100644 --- a/mixlib-shellout-windows.gemspec +++ b/mixlib-shellout-windows.gemspec @@ -1,6 +1,6 @@ gemspec = eval(File.read(File.expand_path("../mixlib-shellout.gemspec", __FILE__))) -gemspec.platform = Gem::Platform.new(["universal", "mingw32"]) +gemspec.platform = Gem::Platform.new(%w{universal mingw32}) gemspec.add_dependency "win32-process", "~> 0.8.2" gemspec.add_dependency "wmi-lite", "~> 1.0" diff --git a/mixlib-shellout.gemspec b/mixlib-shellout.gemspec index 4aa568f..bbbe0df 100644 --- a/mixlib-shellout.gemspec +++ b/mixlib-shellout.gemspec @@ -1,8 +1,8 @@ -$:.unshift(File.dirname(__FILE__) + '/lib') -require 'mixlib/shellout/version' +$:.unshift(File.dirname(__FILE__) + "/lib") +require "mixlib/shellout/version" Gem::Specification.new do |s| - s.name = 'mixlib-shellout' + s.name = "mixlib-shellout" s.version = Mixlib::ShellOut::VERSION s.platform = Gem::Platform::RUBY s.extra_rdoc_files = ["README.md", "LICENSE" ] @@ -12,13 +12,14 @@ Gem::Specification.new do |s| s.email = "info@chef.io" s.homepage = "https://www.chef.io/" - s.required_ruby_version = ">= 2.1" + s.required_ruby_version = ">= 2.2" s.add_development_dependency "rspec", "~> 3.0" + s.add_development_dependency "chefstyle" s.bindir = "bin" s.executables = [] - s.require_path = 'lib' - s.files = %w(Gemfile Rakefile LICENSE README.md) + Dir.glob("*.gemspec") + - Dir.glob("lib/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + s.require_path = "lib" + s.files = %w{Gemfile Rakefile LICENSE README.md} + Dir.glob("*.gemspec") + + Dir.glob("lib/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } end diff --git a/spec/mixlib/shellout/windows_spec.rb b/spec/mixlib/shellout/windows_spec.rb index 8b40fde..fe511eb 100644 --- a/spec/mixlib/shellout/windows_spec.rb +++ b/spec/mixlib/shellout/windows_spec.rb @@ -1,9 +1,9 @@ -require 'spec_helper' +require "spec_helper" -describe 'Mixlib::ShellOut::Windows', :windows_only do +describe "Mixlib::ShellOut::Windows", :windows_only do - describe 'Utils' do - describe '.should_run_under_cmd?' do + describe "Utils" do + describe ".should_run_under_cmd?" do subject { Mixlib::ShellOut::Windows::Utils.should_run_under_cmd?(command) } def self.with_command(_command, &example) @@ -13,7 +13,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do end end - context 'when unquoted' do + context "when unquoted" do with_command(%q{ruby -e 'prints "foobar"'}) { is_expected.not_to be_truthy } # https://github.com/opscode/mixlib-shellout/pull/2#issuecomment-4825574 @@ -38,7 +38,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do with_command(%q{run.exe %A B% %PATH1%}) { is_expected.to be_truthy } with_command(%q{run.exe %A B% %_PATH1%}) { is_expected.to be_truthy } - context 'when outside quotes' do + context "when outside quotes" do with_command(%q{ruby -e "exit 1" | ruby -e "exit 0"}) { is_expected.to be_truthy } with_command(%q{ruby -e "exit 1" > out.txt}) { is_expected.to be_truthy } with_command(%q{ruby -e "exit 1" > out.txt 2>&1}) { is_expected.to be_truthy } @@ -47,7 +47,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do with_command(%q{ruby -e "exit 1" && ruby -e "exit 0"}) { is_expected.to be_truthy } with_command(%q{@echo "TRUE"}) { is_expected.to be_truthy } - context 'with unclosed quote' do + context "with unclosed quote" do with_command(%q{ruby -e "exit 1" | ruby -e "exit 0}) { is_expected.to be_truthy } with_command(%q{ruby -e "exit 1" > "out.txt}) { is_expected.to be_truthy } with_command(%q{ruby -e "exit 1" > "out.txt 2>&1}) { is_expected.to be_truthy } @@ -70,7 +70,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do end end - context 'when quoted' do + context "when quoted" do with_command(%q{run.exe "ruby -e 'exit 1' || ruby -e 'exit 0'"}) { is_expected.to be_falsey } with_command(%q{run.exe "ruby -e 'exit 1' > out.txt"}) { is_expected.to be_falsey } with_command(%q{run.exe "ruby -e 'exit 1' > out.txt 2>&1"}) { is_expected.to be_falsey } @@ -88,7 +88,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do with_command(%q{run.exe "%A B% %PATH1%"}) { is_expected.to be_truthy } with_command(%q{run.exe "%A B% %_PATH1%"}) { is_expected.to be_truthy } - context 'with unclosed quote' do + context "with unclosed quote" do with_command(%q{run.exe "ruby -e 'exit 1' || ruby -e 'exit 0'}) { is_expected.to be_falsey } with_command(%q{run.exe "ruby -e 'exit 1' > out.txt}) { is_expected.to be_falsey } with_command(%q{run.exe "ruby -e 'exit 1' > out.txt 2>&1}) { is_expected.to be_falsey } @@ -109,7 +109,7 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do end end - describe '.kill_process_tree' do + describe ".kill_process_tree" do let(:utils) { Mixlib::ShellOut::Windows::Utils } let(:wmi) { Object.new } let(:wmi_ole_object) { Object.new } @@ -122,25 +122,25 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do allow(logger).to receive(:debug) end - context 'with a protected system process in the process tree' do + context "with a protected system process in the process tree" do before do - allow(wmi_ole_object).to receive(:name).and_return('csrss.exe') + allow(wmi_ole_object).to receive(:name).and_return("csrss.exe") allow(wmi_ole_object).to receive(:processid).and_return(100) end - it 'does not attempt to kill csrss.exe' do + it "does not attempt to kill csrss.exe" do expect(utils).to_not receive(:kill_process) utils.kill_process_tree(200, wmi, logger) end end - context 'with a non-system-critical process in the process tree' do + context "with a non-system-critical process in the process tree" do before do - allow(wmi_ole_object).to receive(:name).and_return('blah.exe') + allow(wmi_ole_object).to receive(:name).and_return("blah.exe") allow(wmi_ole_object).to receive(:processid).and_return(300) end - it 'does attempt to kill blah.exe' do + it "does attempt to kill blah.exe" do expect(utils).to receive(:kill_process).with(wmi_process, logger) expect(utils).to receive(:kill_process_tree).with(200, wmi, logger).and_call_original expect(utils).to receive(:kill_process_tree).with(300, wmi, logger) @@ -152,9 +152,9 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do # Caveat: Private API methods are subject to change without notice. # Monkeypatch at your own risk. - context 'for private API methods' do + context "for private API methods" do - describe '::IS_BATCH_FILE' do + describe "::IS_BATCH_FILE" do subject { candidate =~ Mixlib::ShellOut::Windows::IS_BATCH_FILE } def self.with_candidate(_context, _options = {}, &example) @@ -164,130 +164,130 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do end end - with_candidate('valid .bat file', :candidate => 'autoexec.bat') { is_expected.to be_truthy } - with_candidate('valid .cmd file', :candidate => 'autoexec.cmd') { is_expected.to be_truthy } - with_candidate('valid quoted .bat file', :candidate => '"C:\Program Files\autoexec.bat"') { is_expected.to be_truthy } - with_candidate('valid quoted .cmd file', :candidate => '"C:\Program Files\autoexec.cmd"') { is_expected.to be_truthy } + with_candidate("valid .bat file", :candidate => "autoexec.bat") { is_expected.to be_truthy } + with_candidate("valid .cmd file", :candidate => "autoexec.cmd") { is_expected.to be_truthy } + with_candidate("valid quoted .bat file", :candidate => '"C:\Program Files\autoexec.bat"') { is_expected.to be_truthy } + with_candidate("valid quoted .cmd file", :candidate => '"C:\Program Files\autoexec.cmd"') { is_expected.to be_truthy } - with_candidate('invalid .bat file', :candidate => 'autoexecbat') { is_expected.not_to be_truthy } - with_candidate('invalid .cmd file', :candidate => 'autoexeccmd') { is_expected.not_to be_truthy } - with_candidate('bat in filename', :candidate => 'abattoir.exe') { is_expected.not_to be_truthy } - with_candidate('cmd in filename', :candidate => 'parse_cmd.exe') { is_expected.not_to be_truthy } + with_candidate("invalid .bat file", :candidate => "autoexecbat") { is_expected.not_to be_truthy } + with_candidate("invalid .cmd file", :candidate => "autoexeccmd") { is_expected.not_to be_truthy } + with_candidate("bat in filename", :candidate => "abattoir.exe") { is_expected.not_to be_truthy } + with_candidate("cmd in filename", :candidate => "parse_cmd.exe") { is_expected.not_to be_truthy } - with_candidate('invalid quoted .bat file', :candidate => '"C:\Program Files\autoexecbat"') { is_expected.not_to be_truthy } - with_candidate('invalid quoted .cmd file', :candidate => '"C:\Program Files\autoexeccmd"') { is_expected.not_to be_truthy } - with_candidate('quoted bat in filename', :candidate => '"C:\Program Files\abattoir.exe"') { is_expected.not_to be_truthy } - with_candidate('quoted cmd in filename', :candidate => '"C:\Program Files\parse_cmd.exe"') { is_expected.not_to be_truthy } + with_candidate("invalid quoted .bat file", :candidate => '"C:\Program Files\autoexecbat"') { is_expected.not_to be_truthy } + with_candidate("invalid quoted .cmd file", :candidate => '"C:\Program Files\autoexeccmd"') { is_expected.not_to be_truthy } + with_candidate("quoted bat in filename", :candidate => '"C:\Program Files\abattoir.exe"') { is_expected.not_to be_truthy } + with_candidate("quoted cmd in filename", :candidate => '"C:\Program Files\parse_cmd.exe"') { is_expected.not_to be_truthy } end - describe '#command_to_run' do + describe "#command_to_run" do subject { stubbed_shell_out.send(:command_to_run, cmd) } - let(:stubbed_shell_out) { fail NotImplemented, 'Must declare let(:stubbed_shell_out)' } + let(:stubbed_shell_out) { raise NotImplemented, "Must declare let(:stubbed_shell_out)" } let(:shell_out) { Mixlib::ShellOut.new(cmd) } let(:utils) { Mixlib::ShellOut::Windows::Utils } let(:with_valid_exe_at_location) { lambda { |s| allow(utils).to receive(:find_executable).and_return(executable_path) } } let(:with_invalid_exe_at_location) { lambda { |s| allow(utils).to receive(:find_executable).and_return(nil) } } - context 'with empty command' do + context "with empty command" do let(:stubbed_shell_out) { shell_out } - let(:cmd) { ' ' } + let(:cmd) { " " } - it 'should return with a nil executable' do + it "should return with a nil executable" do is_expected.to eql([nil, cmd]) end end - context 'with extensionless executable' do + context "with extensionless executable" do let(:stubbed_shell_out) { shell_out } let(:executable_path) { 'C:\Windows\system32/ping.EXE' } - let(:cmd) { 'ping' } + let(:cmd) { "ping" } before do - allow(ENV).to receive(:[]).with('PATH').and_return('C:\Windows\system32') - allow(ENV).to receive(:[]).with('PATHEXT').and_return('.EXE') - allow(ENV).to receive(:[]).with('COMSPEC').and_return('C:\Windows\system32\cmd.exe') + allow(ENV).to receive(:[]).with("PATH").and_return('C:\Windows\system32') + allow(ENV).to receive(:[]).with("PATHEXT").and_return(".EXE") + allow(ENV).to receive(:[]).with("COMSPEC").and_return('C:\Windows\system32\cmd.exe') allow(File).to receive(:executable?).and_return(false) allow(File).to receive(:executable?).with(executable_path).and_return(true) allow(File).to receive(:directory?).and_return(false) end - it 'should return with full path with extension' do + it "should return with full path with extension" do is_expected.to eql([executable_path, cmd]) end - context 'there is a directory named after command' do + context "there is a directory named after command" do before do # File.executable? returns true for directories allow(File).to receive(:executable?).with(cmd).and_return(true) allow(File).to receive(:directory?).with(cmd).and_return(true) end - it 'should return with full path with extension' do + it "should return with full path with extension" do is_expected.to eql([executable_path, cmd]) end end end - context 'with batch files' do + context "with batch files" do let(:stubbed_shell_out) { shell_out.tap(&with_valid_exe_at_location) } let(:cmd_invocation) { "cmd /c \"#{cmd}\"" } let(:cmd_exe) { "C:\\Windows\\system32\\cmd.exe" } let(:cmd) { "#{executable_path}" } - before { ENV['ComSpec'] = 'C:\Windows\system32\cmd.exe' } + before { ENV["ComSpec"] = 'C:\Windows\system32\cmd.exe' } - context 'with .bat file' do + context "with .bat file" do let(:executable_path) { '"C:\Program Files\Application\Start.bat"' } # Examples taken from: https://github.com/opscode/mixlib-shellout/pull/2#issuecomment-4825574 - context 'with executable path enclosed in double quotes' do + context "with executable path enclosed in double quotes" do - it 'should use specified batch file' do + it "should use specified batch file" do is_expected.to eql([cmd_exe, cmd_invocation]) end - context 'with arguments' do + context "with arguments" do let(:cmd) { "#{executable_path} arguments" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([cmd_exe, cmd_invocation]) end end - context 'with quoted arguments' do + context "with quoted arguments" do let(:cmd) { "#{executable_path} /i \"C:\Program Files (x86)\NUnit 2.6\bin\framework\nunit.framework.dll\"" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([cmd_exe, cmd_invocation]) end end end end - context 'with .cmd file' do + context "with .cmd file" do let(:executable_path) { '"C:\Program Files\Application\Start.cmd"' } # Examples taken from: https://github.com/opscode/mixlib-shellout/pull/2#issuecomment-4825574 - context 'with executable path enclosed in double quotes' do + context "with executable path enclosed in double quotes" do - it 'should use specified batch file' do + it "should use specified batch file" do is_expected.to eql([cmd_exe, cmd_invocation]) end - context 'with arguments' do + context "with arguments" do let(:cmd) { "#{executable_path} arguments" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([cmd_exe, cmd_invocation]) end end - context 'with quoted arguments' do + context "with quoted arguments" do let(:cmd) { "#{executable_path} /i \"C:\Program Files (x86)\NUnit 2.6\bin\framework\nunit.framework.dll\"" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([cmd_exe, cmd_invocation]) end end @@ -296,55 +296,55 @@ describe 'Mixlib::ShellOut::Windows', :windows_only do end end - context 'with valid executable at location' do + context "with valid executable at location" do let(:stubbed_shell_out) { shell_out.tap(&with_valid_exe_at_location) } - context 'with executable path' do + context "with executable path" do let(:cmd) { "#{executable_path}" } let(:executable_path) { 'C:\RUBY192\bin\ruby.exe' } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end - context 'with arguments' do + context "with arguments" do let(:cmd) { "#{executable_path} arguments" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end end - context 'with quoted arguments' do + context "with quoted arguments" do let(:cmd) { "#{executable_path} -e \"print 'fee fie foe fum'\"" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end end end # Examples taken from: https://github.com/opscode/mixlib-shellout/pull/2#issuecomment-4825574 - context 'with executable path enclosed in double quotes' do + context "with executable path enclosed in double quotes" do let(:cmd) { "#{executable_path}" } let(:executable_path) { '"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe"' } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end - context 'with arguments' do + context "with arguments" do let(:cmd) { "#{executable_path} arguments" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end end - context 'with quoted arguments' do + context "with quoted arguments" do let(:cmd) { "#{executable_path} /i \"C:\Program Files (x86)\NUnit 2.6\bin\framework\nunit.framework.dll\"" } - it 'should use specified executable' do + it "should use specified executable" do is_expected.to eql([executable_path, cmd]) end end diff --git a/spec/mixlib/shellout_spec.rb b/spec/mixlib/shellout_spec.rb index 38915f3..b5df5dd 100644 --- a/spec/mixlib/shellout_spec.rb +++ b/spec/mixlib/shellout_spec.rb @@ -1,6 +1,6 @@ -require 'spec_helper' -require 'logger' -require 'timeout' +require "spec_helper" +require "logger" +require "timeout" describe Mixlib::ShellOut do let(:shell_cmd) { options ? shell_cmd_with_options : shell_cmd_without_options } @@ -14,76 +14,76 @@ describe Mixlib::ShellOut do let(:shell_cmd_without_options) { Mixlib::ShellOut.new(cmd) } let(:shell_cmd_with_options) { Mixlib::ShellOut.new(cmd, options) } let(:cmd) { ruby_eval.call(ruby_code) } - let(:ruby_code) { raise 'define let(:ruby_code)' } + let(:ruby_code) { raise "define let(:ruby_code)" } let(:options) { nil } let(:ruby_eval) { lambda { |code| "ruby -e '#{code}'" } } - context 'when instantiating' do + context "when instantiating" do subject { shell_cmd } - let(:cmd) { 'apt-get install chef' } + let(:cmd) { "apt-get install chef" } it "should set the command" do expect(subject.command).to eql(cmd) end - context 'with default settings' do - describe '#cwd' do + context "with default settings" do + describe "#cwd" do subject { super().cwd } it { is_expected.to be_nil } end - describe '#user' do + describe "#user" do subject { super().user } it { is_expected.to be_nil } end - describe '#with_logon' do + describe "#with_logon" do subject { super().with_logon } it { is_expected.to be_nil } end - describe '#login' do + describe "#login" do subject { super().login } it { is_expected.to be_nil } end - describe '#domain' do + describe "#domain" do subject { super().domain } it { is_expected.to be_nil } end - describe '#password' do + describe "#password" do subject { super().password } it { is_expected.to be_nil } end - describe '#group' do + describe "#group" do subject { super().group } it { is_expected.to be_nil } end - describe '#umask' do + describe "#umask" do subject { super().umask } it { is_expected.to be_nil } end - describe '#timeout' do + describe "#timeout" do subject { super().timeout } it { is_expected.to eql(600) } end - describe '#valid_exit_codes' do + describe "#valid_exit_codes" do subject { super().valid_exit_codes } it { is_expected.to eql([0]) } end - describe '#live_stream' do + describe "#live_stream" do subject { super().live_stream } it { is_expected.to be_nil } end - describe '#input' do + describe "#input" do subject { super().input } it { is_expected.to be_nil } end @@ -93,23 +93,23 @@ describe Mixlib::ShellOut do end end - context 'when setting accessors' do + context "when setting accessors" do subject { shell_cmd.send(accessor) } let(:shell_cmd) { blank_shell_cmd.tap(&with_overrides) } - let(:blank_shell_cmd) { Mixlib::ShellOut.new('apt-get install chef') } + let(:blank_shell_cmd) { Mixlib::ShellOut.new("apt-get install chef") } let(:with_overrides) { lambda { |shell_cmd| shell_cmd.send("#{accessor}=", value) } } - context 'when setting user' do + context "when setting user" do let(:accessor) { :user } - let(:value) { 'root' } + let(:value) { "root" } it "should set the user" do is_expected.to eql(value) end # TODO add :unix_only - context 'with an integer value for user' do + context "with an integer value for user" do let(:value) { 0 } it "should use the user-supplied uid" do expect(shell_cmd.uid).to eql(value) @@ -117,7 +117,7 @@ describe Mixlib::ShellOut do end # TODO add :unix_only - context 'with string value for user' do + context "with string value for user" do let(:value) { username } let(:username) { user_info.name } @@ -130,16 +130,16 @@ describe Mixlib::ShellOut do end end - context 'when setting with_logon' do + context "when setting with_logon" do let(:accessor) { :with_logon } - let(:value) { 'root' } + let(:value) { "root" } it "should set the with_logon" do is_expected.to eql(value) end end - context 'when setting login' do + context "when setting login" do let(:accessor) { :login } let(:value) { true } @@ -148,41 +148,41 @@ describe Mixlib::ShellOut do end end - context 'when setting domain' do + context "when setting domain" do let(:accessor) { :domain } - let(:value) { 'localhost' } + let(:value) { "localhost" } it "should set the domain" do is_expected.to eql(value) end end - context 'when setting password' do + context "when setting password" do let(:accessor) { :password } - let(:value) { 'vagrant' } + let(:value) { "vagrant" } it "should set the password" do is_expected.to eql(value) end end - context 'when setting group' do + context "when setting group" do let(:accessor) { :group } - let(:value) { 'wheel' } + let(:value) { "wheel" } it "should set the group" do is_expected.to eql(value) end # TODO add :unix_only - context 'with integer value for group' do + context "with integer value for group" do let(:value) { 0 } it "should use the user-supplied gid" do expect(shell_cmd.gid).to eql(value) end end - context 'with string value for group' do + context "with string value for group" do let(:value) { groupname } let(:groupname) { group_info.name } let(:expected_gid) { group_info.gid } @@ -194,44 +194,44 @@ describe Mixlib::ShellOut do end end - context 'when setting the umask' do + context "when setting the umask" do let(:accessor) { :umask } - context 'with octal integer' do - let(:value) { 007555} + context "with octal integer" do + let(:value) { 007555 } - it 'should set the umask' do + it "should set the umask" do is_expected.to eql(value) end end - context 'with decimal integer' do + context "with decimal integer" do let(:value) { 2925 } - it 'should sets the umask' do + it "should sets the umask" do is_expected.to eql(005555) end end - context 'with string' do - let(:value) { '7777' } + context "with string" do + let(:value) { "7777" } - it 'should sets the umask' do + it "should sets the umask" do is_expected.to eql(007777) end end end - context 'when setting read timeout' do + context "when setting read timeout" do let(:accessor) { :timeout } let(:value) { 10 } - it 'should set the read timeout' do + it "should set the read timeout" do is_expected.to eql(value) end end - context 'when setting valid exit codes' do + context "when setting valid exit codes" do let(:accessor) { :valid_exit_codes } let(:value) { [0, 23, 42] } @@ -240,7 +240,7 @@ describe Mixlib::ShellOut do end end - context 'when setting a live stream' do + context "when setting a live stream" do let(:accessor) { :live_stream } let(:value) { stream } let(:stream) { StringIO.new } @@ -262,7 +262,7 @@ describe Mixlib::ShellOut do end end - context 'when setting the live stdout and live stderr streams separately' do + context "when setting the live stdout and live stderr streams separately" do let(:accessor) { :live_stream } let(:stream) { StringIO.new } let(:value) { stream } @@ -287,7 +287,7 @@ describe Mixlib::ShellOut do end end - context 'when setting a live stream and then overriding the live stderr' do + context "when setting a live stream and then overriding the live stderr" do let(:accessor) { :live_stream } let(:value) { stream } let(:stream) { StringIO.new } @@ -310,7 +310,7 @@ describe Mixlib::ShellOut do end end - context 'when setting an input' do + context "when setting an input" do let(:accessor) { :input } let(:value) { "Random content #{rand(1000000)}" } @@ -320,107 +320,108 @@ describe Mixlib::ShellOut do end end - context 'testing login', :unix_only do - subject {shell_cmd} - let (:uid) {1005} - let (:gid) {1002} - let (:shell) {'/bin/money'} - let (:dir) {'/home/castle'} - let (:path) {'/sbin:/bin:/usr/sbin:/usr/bin'} + context "testing login", :unix_only do + subject { shell_cmd } + let (:uid) { 1005 } + let (:gid) { 1002 } + let (:shell) { "/bin/money" } + let (:dir) { "/home/castle" } + let (:path) { "/sbin:/bin:/usr/sbin:/usr/bin" } before :each do - shell_cmd.login=true - catbert_user=double("Etc::Passwd", :name=>'catbert', :passwd=>'x', :uid=>1005, :gid=>1002, :gecos=>"Catbert,,,", :dir=>'/home/castle', :shell=>'/bin/money') - group_double=[ - double("Etc::Group", :name=>'catbert', :passwd=>'x', :gid=>1002, :mem=>[]), - double("Etc::Group", :name=>'sudo', :passwd=>'x', :gid=>52, :mem=>['catbert']), - double("Etc::Group", :name=>'rats', :passwd=>'x', :gid=>43, :mem=>['ratbert']), - double("Etc::Group", :name=>'dilbertpets', :passwd=>'x', :gid=>700, :mem=>['catbert', 'ratbert']), + shell_cmd.login = true + catbert_user = double("Etc::Passwd", :name => "catbert", :passwd => "x", :uid => 1005, :gid => 1002, :gecos => "Catbert,,,", :dir => "/home/castle", :shell => "/bin/money") + group_double = [ + double("Etc::Group", :name => "catbert", :passwd => "x", :gid => 1002, :mem => []), + double("Etc::Group", :name => "sudo", :passwd => "x", :gid => 52, :mem => ["catbert"]), + double("Etc::Group", :name => "rats", :passwd => "x", :gid => 43, :mem => ["ratbert"]), + double("Etc::Group", :name => "dilbertpets", :passwd => "x", :gid => 700, :mem => %w{catbert ratbert}), ] - allow(Etc).to receive(:getpwuid).with(1005) {catbert_user} - allow(Etc).to receive(:getpwnam).with('catbert') {catbert_user} - allow(shell_cmd).to receive(:all_seconderies) {group_double} + allow(Etc).to receive(:getpwuid).with(1005) { catbert_user } + allow(Etc).to receive(:getpwnam).with("catbert") { catbert_user } + allow(shell_cmd).to receive(:all_seconderies) { group_double } end # Setting the user by name should change the uid - context 'when setting user by name' do - before(:each){ shell_cmd.user='catbert' } - describe '#uid' do - subject { super().uid } - it { is_expected.to eq(uid) } - end + context "when setting user by name" do + before(:each) { shell_cmd.user = "catbert" } + describe "#uid" do + subject { super().uid } + it { is_expected.to eq(uid) } + end end - context 'when setting user by id' do - before(:each){shell_cmd.user=uid} + context "when setting user by id" do + before(:each) { shell_cmd.user = uid } # Setting the user by uid should change the uid #it 'should set the uid' do - describe '#uid' do + describe "#uid" do subject { super().uid } it { is_expected.to eq(uid) } end #end # Setting the user without a different gid should change the gid to 1002 - describe '#gid' do + describe "#gid" do subject { super().gid } it { is_expected.to eq(gid) } end # Setting the user and the group (to 43) should change the gid to 43 - context 'when setting the group manually' do - before(:each){shell_cmd.group=43} + context "when setting the group manually" do + before(:each) { shell_cmd.group = 43 } - describe '#gid' do + describe "#gid" do subject { super().gid } - it {is_expected.to eq(43)} + it { is_expected.to eq(43) } end end # Setting the user should set the env variables - describe '#process_environment' do - subject { super().process_environment } - it { is_expected.to eq ({'HOME'=>dir, 'SHELL'=>shell, 'USER'=>'catbert', 'LOGNAME'=>'catbert', 'PATH'=>path, 'IFS'=>"\t\n"}) } - end + describe "#process_environment" do + subject { super().process_environment } + it { is_expected.to eq ({ "HOME" => dir, "SHELL" => shell, "USER" => "catbert", "LOGNAME" => "catbert", "PATH" => path, "IFS" => "\t\n" }) } + end # Setting the user with overriding env variables should override - context 'when adding environment variables' do - before(:each){shell_cmd.environment={'PATH'=>'/lord:/of/the/dance', 'CUSTOM'=>'costume'}} - it 'should preserve custom variables' do - expect(shell_cmd.process_environment['PATH']).to eq('/lord:/of/the/dance') - end - # Setting the user with additional env variables should have both - it 'should allow new variables' do - expect(shell_cmd.process_environment['CUSTOM']).to eq('costume') - end - end + context "when adding environment variables" do + before(:each) { shell_cmd.environment = { "PATH" => "/lord:/of/the/dance", "CUSTOM" => "costume" } } + it "should preserve custom variables" do + expect(shell_cmd.process_environment["PATH"]).to eq("/lord:/of/the/dance") + end + # Setting the user with additional env variables should have both + it "should allow new variables" do + expect(shell_cmd.process_environment["CUSTOM"]).to eq("costume") + end + end # Setting the user should set secondary groups - describe '#sgids' do - subject { super().sgids } - it { is_expected.to match_array([52,700]) } - end + describe "#sgids" do + subject { super().sgids } + it { is_expected.to match_array([52, 700]) } + end end # Setting login with user should throw errors - context 'when not setting a user id' do - it 'should fail showing an error' do - expect { Mixlib::ShellOut.new('hostname', {login:true}) }.to raise_error(Mixlib::ShellOut::InvalidCommandOption) + context "when not setting a user id" do + it "should fail showing an error" do + expect { Mixlib::ShellOut.new("hostname", { login: true }) }.to raise_error(Mixlib::ShellOut::InvalidCommandOption) end end end context "with options hash" do - let(:cmd) { 'brew install couchdb' } - let(:options) { { :cwd => cwd, :user => user, :login => true, :domain => domain, :password => password, :group => group, - :umask => umask, :timeout => timeout, :environment => environment, :returns => valid_exit_codes, - :live_stream => stream, :input => input } } - - let(:cwd) { '/tmp' } - let(:user) { 'toor' } + let(:cmd) { "brew install couchdb" } + let(:options) do + { :cwd => cwd, :user => user, :login => true, :domain => domain, :password => password, :group => group, + :umask => umask, :timeout => timeout, :environment => environment, :returns => valid_exit_codes, + :live_stream => stream, :input => input } end + + let(:cwd) { "/tmp" } + let(:user) { "toor" } let(:with_logon) { user } let(:login) { true } - let(:domain) { 'localhost' } - let(:password) { 'vagrant' } - let(:group) { 'wheel' } - let(:umask) { '2222' } + let(:domain) { "localhost" } + let(:password) { "vagrant" } + let(:group) { "wheel" } + let(:umask) { "2222" } let(:timeout) { 5 } - let(:environment) { { 'RUBY_OPTS' => '-w' } } + let(:environment) { { "RUBY_OPTS" => "-w" } } let(:valid_exit_codes) { [ 0, 1, 42 ] } let(:stream) { StringIO.new } let(:input) { 1.upto(10).map { "Data #{rand(100000)}" }.join("\n") } @@ -462,27 +463,27 @@ describe Mixlib::ShellOut do end it "should add environment settings to the default" do - expect(shell_cmd.environment).to eql({'RUBY_OPTS' => '-w'}) + expect(shell_cmd.environment).to eql({ "RUBY_OPTS" => "-w" }) end - context 'when setting custom environments' do - context 'when setting the :env option' do + context "when setting custom environments" do + context "when setting the :env option" do let(:options) { { :env => environment } } it "should also set the enviroment" do - expect(shell_cmd.environment).to eql({'RUBY_OPTS' => '-w'}) + expect(shell_cmd.environment).to eql({ "RUBY_OPTS" => "-w" }) end end - context 'when setting environments with symbols' do - let(:options) { { :environment => { SYMBOL: 'cymbal' } } } + context "when setting environments with symbols" do + let(:options) { { :environment => { SYMBOL: "cymbal" } } } it "should also set the enviroment" do - expect(shell_cmd.environment).to eql({'SYMBOL' => 'cymbal'}) + expect(shell_cmd.environment).to eql({ "SYMBOL" => "cymbal" }) end end - context 'when :environment is set to nil' do + context "when :environment is set to nil" do let(:options) { { :environment => nil } } it "should not set any environment" do @@ -490,7 +491,7 @@ describe Mixlib::ShellOut do end end - context 'when :env is set to nil' do + context "when :env is set to nil" do let(:options) { { :env => nil } } it "should not set any environment" do @@ -511,7 +512,7 @@ describe Mixlib::ShellOut do expect(shell_cmd.input).to eql(input) end - context 'with an invalid option' do + context "with an invalid option" do let(:options) { { :frab => :job } } let(:invalid_option_exception) { Mixlib::ShellOut::InvalidCommandOption } let(:exception_message) { "option ':frab' is not a valid option for Mixlib::ShellOut" } @@ -523,9 +524,9 @@ describe Mixlib::ShellOut do end context "with array of command and args" do - let(:cmd) { [ 'ruby', '-e', %q{'puts "hello"'} ] } + let(:cmd) { [ "ruby", "-e", %q{'puts "hello"'} ] } - context 'without options' do + context "without options" do let(:options) { nil } it "should set the command to the array of command and args" do @@ -533,46 +534,46 @@ describe Mixlib::ShellOut do end end - context 'with options' do - let(:options) { {:cwd => '/tmp', :user => 'nobody', :password => "something"} } + context "with options" do + let(:options) { { :cwd => "/tmp", :user => "nobody", :password => "something" } } it "should set the command to the array of command and args" do expect(shell_cmd.command).to eql(cmd) end it "should evaluate the options" do - expect(shell_cmd.cwd).to eql('/tmp') - expect(shell_cmd.user).to eql('nobody') - expect(shell_cmd.password).to eql('something') + expect(shell_cmd.cwd).to eql("/tmp") + expect(shell_cmd.user).to eql("nobody") + expect(shell_cmd.password).to eql("something") end end end end - context 'when executing the command' do + context "when executing the command" do let(:dir) { Dir.mktmpdir } let(:dump_file) { "#{dir}/out.txt" } let(:dump_file_content) { stdout; IO.read(dump_file) } - context 'with a current working directory' do + context "with a current working directory" do subject { File.expand_path(chomped_stdout) } let(:fully_qualified_cwd) { File.expand_path(cwd) } let(:options) { { :cwd => cwd } } - context 'when running under Unix', :unix_only do + context "when running under Unix", :unix_only do # Use /bin for tests only if it is not a symlink. Some # distributions (e.g. Fedora) symlink it to /usr/bin - let(:cwd) { File.symlink?('/bin') ? '/tmp' : '/bin' } - let(:cmd) { 'pwd' } + let(:cwd) { File.symlink?("/bin") ? "/tmp" : "/bin" } + let(:cmd) { "pwd" } it "should chdir to the working directory" do is_expected.to eql(fully_qualified_cwd) end end - context 'when running under Windows', :windows_only do + context "when running under Windows", :windows_only do let(:cwd) { Dir.tmpdir } - let(:cmd) { 'echo %cd%' } + let(:cmd) { "echo %cd%" } it "should chdir to the working directory" do is_expected.to eql(fully_qualified_cwd) @@ -580,53 +581,53 @@ describe Mixlib::ShellOut do end end - context 'when handling locale' do + context "when handling locale" do before do - @original_lc_all = ENV['LC_ALL'] - ENV['LC_ALL'] = "en_US.UTF-8" + @original_lc_all = ENV["LC_ALL"] + ENV["LC_ALL"] = "en_US.UTF-8" end after do - ENV['LC_ALL'] = @original_lc_all + ENV["LC_ALL"] = @original_lc_all end subject { stripped_stdout } let(:cmd) { ECHO_LC_ALL } - let(:options) { { :environment => { 'LC_ALL' => locale } } } + let(:options) { { :environment => { "LC_ALL" => locale } } } - context 'without specifying environment' do + context "without specifying environment" do let(:options) { nil } it "should no longer use the C locale by default" do is_expected.to eql("en_US.UTF-8") end end - context 'with locale' do - let(:locale) { 'es' } + context "with locale" do + let(:locale) { "es" } it "should use the requested locale" do is_expected.to eql(locale) end end - context 'with LC_ALL set to nil' do + context "with LC_ALL set to nil" do let(:locale) { nil } - context 'when running under Unix', :unix_only do + context "when running under Unix", :unix_only do it "should unset the process's locale" do is_expected.to eql("") end end - context 'when running under Windows', :windows_only do + context "when running under Windows", :windows_only do it "should unset process's locale" do - is_expected.to eql('%LC_ALL%') + is_expected.to eql("%LC_ALL%") end end end end context "when running under Windows", :windows_only do - let(:cmd) { '%windir%/system32/whoami.exe' } + let(:cmd) { "%windir%/system32/whoami.exe" } let(:running_user) { shell_cmd.run_command.stdout.strip.downcase } context "when no user is set" do @@ -647,8 +648,8 @@ describe Mixlib::ShellOut do expect(system("net user #{user} /delete")).to eq(true) end - let(:user) { 'testuser' } - let(:password) { 'testpass1!' } + let(:user) { "testuser" } + let(:password) { "testpass1!" } let(:options) { { :user => user, :password => password } } it "should run as specified user" do @@ -702,8 +703,8 @@ describe Mixlib::ShellOut do context "with an input" do subject { stdout } - let(:input) { 'hello' } - let(:ruby_code) { 'STDIN.sync = true; STDOUT.sync = true; puts gets' } + let(:input) { "hello" } + let(:ruby_code) { "STDIN.sync = true; STDOUT.sync = true; puts gets" } let(:options) { { :input => input } } it "should copy the input to the child's stdin" do @@ -716,41 +717,41 @@ describe Mixlib::ShellOut do let(:file_name) { "#{dir}/Setup Script.cmd" } let(:script_name) { "\"#{script.path}\"" } - let(:open_file) { File.open(file_name, 'w') } + let(:open_file) { File.open(file_name, "w") } let(:write_file) { lambda { |f| f.write(script_content) } } let(:make_executable) { lambda { |f| File.chmod(0755, f.path) } } - context 'with spaces in the path' do + context "with spaces in the path" do subject { chomped_stdout } let(:cmd) { script_name } - context 'when running under Unix', :unix_only do - let(:script_content) { 'echo blah' } + context "when running under Unix", :unix_only do + let(:script_content) { "echo blah" } - it 'should execute' do - is_expected.to eql('blah') + it "should execute" do + is_expected.to eql("blah") end end - context 'when running under Windows', :windows_only do + context "when running under Windows", :windows_only do let(:cmd) { "#{script_name} #{argument}" } - let(:script_content) { '@echo %1' } + let(:script_content) { "@echo %1" } let(:argument) { rand(10000).to_s } - it 'should execute' do + it "should execute" do is_expected.to eql(argument) end - context 'with multiple quotes in the command and args' do - context 'when using a batch file' do + context "with multiple quotes in the command and args" do + context "when using a batch file" do let(:argument) { "\"Random #{rand(10000)}\"" } - it 'should execute' do + it "should execute" do is_expected.to eql(argument) end end - context 'when not using a batch file' do + context "when not using a batch file" do let(:cmd) { "#{executable_file_name} #{script_name}" } let(:executable_file_name) { "\"#{dir}/Ruby Parser.exe\"".tap(&make_executable!) } @@ -758,10 +759,10 @@ describe Mixlib::ShellOut do let(:script_content) { "print \"#{expected_output}\"" } let(:expected_output) { "Random #{rand(10000)}" } - let(:full_path_to_ruby) { ENV['PATH'].split(';').map(&try_ruby).reject(&:nil?).first } + let(:full_path_to_ruby) { ENV["PATH"].split(";").map(&try_ruby).reject(&:nil?).first } let(:try_ruby) { lambda { |path| "#{path}\\ruby.exe" if File.executable? "#{path}\\ruby.exe" } } - it 'should execute' do + it "should execute" do is_expected.to eql(expected_output) end end @@ -769,72 +770,72 @@ describe Mixlib::ShellOut do end end - context 'with lots of long arguments' do + context "with lots of long arguments" do subject { chomped_stdout } # This number was chosen because it seems to be an actual maximum # in Windows--somewhere around 6-7K of command line - let(:echotext) { 10000.upto(11340).map(&:to_s).join(' ') } + let(:echotext) { 10000.upto(11340).map(&:to_s).join(" ") } let(:cmd) { "echo #{echotext}" } - it 'should execute' do + it "should execute" do is_expected.to eql(echotext) end end - context 'with special characters' do + context "with special characters" do subject { stdout } - let(:special_characters) { '<>&|&&||;' } + let(:special_characters) { "<>&|&&||;" } let(:ruby_code) { "print \"#{special_characters}\"" } - it 'should execute' do + it "should execute" do is_expected.to eql(special_characters) end end - context 'with backslashes' do + context "with backslashes" do subject { stdout } let(:backslashes) { %q{\\"\\\\} } let(:cmd) { ruby_eval.call("print \"#{backslashes}\"") } - it 'should execute' do + it "should execute" do is_expected.to eql("\"\\") end end - context 'with pipes' do + context "with pipes" do let(:input_script) { "STDOUT.sync = true; STDERR.sync = true; print true; STDERR.print false" } let(:output_script) { "print STDIN.read.length" } let(:cmd) { ruby_eval.call(input_script) + " | " + ruby_eval.call(output_script) } - it 'should execute' do - expect(stdout).to eql('4') + it "should execute" do + expect(stdout).to eql("4") end - it 'should handle stderr' do - expect(stderr).to eql('false') + it "should handle stderr" do + expect(stderr).to eql("false") end end - context 'with stdout and stderr file pipes' do + context "with stdout and stderr file pipes" do let(:code) { "STDOUT.sync = true; STDERR.sync = true; print true; STDERR.print false" } let(:cmd) { ruby_eval.call(code) + " > #{dump_file}" } - it 'should execute' do - expect(stdout).to eql('') + it "should execute" do + expect(stdout).to eql("") end - it 'should handle stderr' do - expect(stderr).to eql('false') + it "should handle stderr" do + expect(stderr).to eql("false") end - it 'should write to file pipe' do - expect(dump_file_content).to eql('true') + it "should write to file pipe" do + expect(dump_file_content).to eql("true") end end - context 'with stdin file pipe' do + context "with stdin file pipe" do let(:code) { "STDIN.sync = true; STDOUT.sync = true; STDERR.sync = true; print gets; STDERR.print false" } let(:cmd) { ruby_eval.call(code) + " < #{dump_file_path}" } let(:file_content) { "Random content #{rand(100000)}" } @@ -843,48 +844,48 @@ describe Mixlib::ShellOut do let(:dump_file) { open_file.tap(&write_file).tap(&:close) } let(:file_name) { "#{dir}/input" } - let(:open_file) { File.open(file_name, 'w') } + let(:open_file) { File.open(file_name, "w") } let(:write_file) { lambda { |f| f.write(file_content) } } - it 'should execute' do + it "should execute" do expect(stdout).to eql(file_content) end - it 'should handle stderr' do - expect(stderr).to eql('false') + it "should handle stderr" do + expect(stderr).to eql("false") end end - context 'with stdout and stderr file pipes' do + context "with stdout and stderr file pipes" do let(:code) { "STDOUT.sync = true; STDERR.sync = true; print true; STDERR.print false" } let(:cmd) { ruby_eval.call(code) + " > #{dump_file} 2>&1" } - it 'should execute' do - expect(stdout).to eql('') + it "should execute" do + expect(stdout).to eql("") end - it 'should write to file pipe' do - expect(dump_file_content).to eql('truefalse') + it "should write to file pipe" do + expect(dump_file_content).to eql("truefalse") end end - context 'with &&' do + context "with &&" do subject { stdout } - let(:cmd) { ruby_eval.call('print "foo"') + ' && ' + ruby_eval.call('print "bar"') } + let(:cmd) { ruby_eval.call('print "foo"') + " && " + ruby_eval.call('print "bar"') } - it 'should execute' do - is_expected.to eql('foobar') + it "should execute" do + is_expected.to eql("foobar") end end - context 'with ||' do - let(:cmd) { ruby_eval.call('print "foo"; exit 1') + ' || ' + ruby_eval.call('print "bar"') } + context "with ||" do + let(:cmd) { ruby_eval.call('print "foo"; exit 1') + " || " + ruby_eval.call('print "bar"') } - it 'should execute' do - expect(stdout).to eql('foobar') + it "should execute" do + expect(stdout).to eql("foobar") end - it 'should exit with code 0' do + it "should exit with code 0" do expect(exit_status).to eql(0) end end @@ -893,7 +894,7 @@ describe Mixlib::ShellOut do context "when handling process exit codes" do let(:cmd) { ruby_eval.call("exit #{exit_code}") } - context 'with normal exit status' do + context "with normal exit status" do let(:exit_code) { 0 } it "should not raise error" do @@ -905,7 +906,7 @@ describe Mixlib::ShellOut do end end - context 'with nonzero exit status' do + context "with nonzero exit status" do let(:exit_code) { 2 } let(:exception_message_format) { Regexp.escape(executed_cmd.format_for_exception) } @@ -926,11 +927,11 @@ describe Mixlib::ShellOut do end end - context 'with valid exit codes' do + context "with valid exit codes" do let(:cmd) { ruby_eval.call("exit #{exit_code}" ) } let(:options) { { :returns => valid_exit_codes } } - context 'when exiting with valid code' do + context "when exiting with valid code" do let(:valid_exit_codes) { 42 } let(:exit_code) { 42 } @@ -943,7 +944,7 @@ describe Mixlib::ShellOut do end end - context 'when exiting with invalid code' do + context "when exiting with invalid code" do let(:valid_exit_codes) { [ 0, 1, 42 ] } let(:exit_code) { 2 } @@ -955,7 +956,7 @@ describe Mixlib::ShellOut do expect(exit_status).to eql(exit_code) end - context 'with input data' do + context "with input data" do let(:options) { { :returns => valid_exit_codes, :input => input } } let(:input) { "Random data #{rand(1000000)}" } @@ -969,7 +970,7 @@ describe Mixlib::ShellOut do end end - context 'when exiting with invalid code 0' do + context "when exiting with invalid code 0" do let(:valid_exit_codes) { 42 } let(:exit_code) { 0 } @@ -992,7 +993,7 @@ describe Mixlib::ShellOut do end describe "#error?" do - context 'when exiting with invalid code' do + context "when exiting with invalid code" do let(:exit_code) { 2 } it "should return true" do @@ -1000,7 +1001,7 @@ describe Mixlib::ShellOut do end end - context 'when exiting with valid code' do + context "when exiting with valid code" do let(:exit_code) { 0 } it "should return false" do @@ -1011,8 +1012,8 @@ describe Mixlib::ShellOut do end context "when handling the subprocess" do - context 'with STDOUT and STDERR' do - let(:ruby_code) { 'STDERR.puts :hello; STDOUT.puts :world' } + context "with STDOUT and STDERR" do + let(:ruby_code) { "STDERR.puts :hello; STDOUT.puts :world" } # We could separate this into two examples, but we want to make # sure that stderr and stdout gets collected without stepping @@ -1023,7 +1024,7 @@ describe Mixlib::ShellOut do end end - context 'with forking subprocess that does not close stdout and stderr' do + context "with forking subprocess that does not close stdout and stderr" do let(:ruby_code) { "exit if fork; 10.times { sleep 1 }" } it "should not hang" do @@ -1066,9 +1067,9 @@ describe Mixlib::ShellOut do end end - context 'with open files for parent process' do + context "with open files for parent process" do before do - @test_file = Tempfile.new('fd_test') + @test_file = Tempfile.new("fd_test") @test_file.write("hello") @test_file.flush end @@ -1095,7 +1096,7 @@ describe Mixlib::ShellOut do end context "when the child process dies immediately" do - let(:cmd) { [ 'exit' ] } + let(:cmd) { [ "exit" ] } it "handles ESRCH from getpgid of a zombie", :unix_only do allow(Process).to receive(:setsid) { exit!(4) } @@ -1113,22 +1114,22 @@ describe Mixlib::ShellOut do end - context 'with subprocess that takes longer than timeout' do + context "with subprocess that takes longer than timeout" do let(:options) { { :timeout => 1 } } - context 'on windows', :windows_only do + context "on windows", :windows_only do let(:cmd) do 'cmd /c powershell -c "sleep 10"' end it "should raise CommandTimeout" do - Timeout::timeout(5) do + Timeout.timeout(5) do expect { executed_cmd }.to raise_error(Mixlib::ShellOut::CommandTimeout) end end - context 'and child processes should be killed' do - it 'kills the child processes' do + context "and child processes should be killed" do + it "kills the child processes" do expect(Mixlib::ShellOut::Windows::Utils).to receive(:kill_process) do |instance| expect(instance.wmi_ole_object.Name).to match(/powershell/) Process.kill(:KILL, instance.wmi_ole_object.processid) @@ -1138,9 +1139,9 @@ describe Mixlib::ShellOut do end end - context 'on unix', :unix_only do + context "on unix", :unix_only do def ruby_wo_shell(code) - parts = %w[ruby] + parts = %w{ruby} parts << "-e" parts << code end @@ -1177,7 +1178,7 @@ describe Mixlib::ShellOut do it "should KILL the wayward child" do # note: let blocks don't correctly memoize if an exception is raised, # so can't use executed_cmd - expect { shell_cmd.run_command}.to raise_error(Mixlib::ShellOut::CommandTimeout) + expect { shell_cmd.run_command }.to raise_error(Mixlib::ShellOut::CommandTimeout) expect(shell_cmd.stdout).to include("nanana cant hear you") expect(shell_cmd.status.termsig).to eq(9) end @@ -1185,12 +1186,12 @@ describe Mixlib::ShellOut do context "and a logger is configured" do let(:log_output) { StringIO.new } let(:logger) { Logger.new(log_output) } - let(:options) { {:timeout => 1, :logger => logger} } + let(:options) { { :timeout => 1, :logger => logger } } it "should log messages about killing the child process" do # note: let blocks don't correctly memoize if an exception is raised, # so can't use executed_cmd - expect { shell_cmd.run_command}.to raise_error(Mixlib::ShellOut::CommandTimeout) + expect { shell_cmd.run_command }.to raise_error(Mixlib::ShellOut::CommandTimeout) expect(shell_cmd.stdout).to include("nanana cant hear you") expect(shell_cmd.status.termsig).to eq(9) @@ -1217,7 +1218,7 @@ describe Mixlib::ShellOut do it "should TERM the wayward child and grandchild" do # note: let blocks don't correctly memoize if an exception is raised, # so can't use executed_cmd - expect { shell_cmd.run_command}.to raise_error(Mixlib::ShellOut::CommandTimeout) + expect { shell_cmd.run_command }.to raise_error(Mixlib::ShellOut::CommandTimeout) expect(shell_cmd.stdout).to include("got term in child") expect(shell_cmd.stdout).to include("got term in grandchild") end @@ -1240,7 +1241,7 @@ describe Mixlib::ShellOut do it "should TERM the wayward child and grandchild, then KILL whoever is left" do # note: let blocks don't correctly memoize if an exception is raised, # so can't use executed_cmd - expect { shell_cmd.run_command}.to raise_error(Mixlib::ShellOut::CommandTimeout) + expect { shell_cmd.run_command }.to raise_error(Mixlib::ShellOut::CommandTimeout) begin @@ -1257,7 +1258,7 @@ describe Mixlib::ShellOut do kill_return_val = Process.kill(:INT, child_pgid) # should raise ESRCH # AIX - kill returns code > 0 for error, where as other platforms return -1. Ruby code signal.c treats < 0 as error and raises exception and hence fails on AIX. So we check the return code for assertions since ruby wont raise an error here. - if(kill_return_val == 0) + if kill_return_val == 0 # Debug the failure: puts "child pgid=#{child_pgid.inspect}" Process.wait @@ -1276,7 +1277,7 @@ describe Mixlib::ShellOut do end end - context 'with subprocess that exceeds buffersize' do + context "with subprocess that exceeds buffersize" do let(:ruby_code) { 'print("X" * 16 * 1024); print("." * 1024)' } it "should still reads all of the output" do @@ -1284,39 +1285,39 @@ describe Mixlib::ShellOut do end end - context 'with subprocess that returns nothing' do - let(:ruby_code) { 'exit 0' } + context "with subprocess that returns nothing" do + let(:ruby_code) { "exit 0" } - it 'should return an empty string for stdout' do - expect(stdout).to eql('') + it "should return an empty string for stdout" do + expect(stdout).to eql("") end - it 'should return an empty string for stderr' do - expect(stderr).to eql('') + it "should return an empty string for stderr" do + expect(stderr).to eql("") end end - context 'with subprocess that closes stdin and continues writing to stdout' do + context "with subprocess that closes stdin and continues writing to stdout" do let(:ruby_code) { "STDIN.close; sleep 0.5; STDOUT.puts :win" } let(:options) { { :input => "Random data #{rand(100000)}" } } - it 'should not hang or lose output' do + it "should not hang or lose output" do expect(stdout).to eql("win#{LINE_ENDING}") end end - context 'with subprocess that closes stdout and continues writing to stderr' do + context "with subprocess that closes stdout and continues writing to stderr" do let(:ruby_code) { "STDOUT.close; sleep 0.5; STDERR.puts :win" } - it 'should not hang or lose output' do + it "should not hang or lose output" do expect(stderr).to eql("win#{LINE_ENDING}") end end - context 'with subprocess that closes stderr and continues writing to stdout' do + context "with subprocess that closes stderr and continues writing to stdout" do let(:ruby_code) { "STDERR.close; sleep 0.5; STDOUT.puts :win" } - it 'should not hang or lose output' do + it "should not hang or lose output" do expect(stdout).to eql("win#{LINE_ENDING}") end end @@ -1333,54 +1334,54 @@ describe Mixlib::ShellOut do # Otherwise, we will attempt to read from the closed STDOUT pipe over and # over again and generate lots of garbage, which will not be collected # since we have to turn GC off to avoid segv. - context 'with subprocess that closes STDOUT before closing STDERR' do - let(:ruby_code) { %q{STDOUT.puts "F" * 4096; STDOUT.close; sleep 0.1; STDERR.puts "foo"; STDERR.close; sleep 0.1; exit} } + context "with subprocess that closes STDOUT before closing STDERR" do + let(:ruby_code) { %q{STDOUT.puts "F" * 4096; STDOUT.close; sleep 0.1; STDERR.puts "foo"; STDERR.close; sleep 0.1; exit} } let(:unclosed_pipes) { executed_cmd.send(:open_pipes) } - it 'should not hang' do + it "should not hang" do expect(stdout).not_to be_empty end - it 'should close all pipes', :unix_only do + it "should close all pipes", :unix_only do expect(unclosed_pipes).to be_empty end end - context 'with subprocess reading lots of data from stdin' do + context "with subprocess reading lots of data from stdin" do subject { stdout.to_i } - let(:ruby_code) { 'STDOUT.print gets.size' } + let(:ruby_code) { "STDOUT.print gets.size" } let(:options) { { :input => input } } - let(:input) { 'f' * 20_000 } + let(:input) { "f" * 20_000 } let(:input_size) { input.size } - it 'should not hang' do + it "should not hang" do is_expected.to eql(input_size) end end - context 'with subprocess writing lots of data to both stdout and stderr' do + context "with subprocess writing lots of data to both stdout and stderr" do let(:expected_output_with) { lambda { |chr| (chr * 20_000) + "#{LINE_ENDING}" + (chr * 20_000) + "#{LINE_ENDING}" } } - context 'when writing to STDOUT first' do + context "when writing to STDOUT first" do let(:ruby_code) { %q{puts "f" * 20_000; STDERR.puts "u" * 20_000; puts "f" * 20_000; STDERR.puts "u" * 20_000} } it "should not deadlock" do - expect(stdout).to eql(expected_output_with.call('f')) - expect(stderr).to eql(expected_output_with.call('u')) + expect(stdout).to eql(expected_output_with.call("f")) + expect(stderr).to eql(expected_output_with.call("u")) end end - context 'when writing to STDERR first' do + context "when writing to STDERR first" do let(:ruby_code) { %q{STDERR.puts "u" * 20_000; puts "f" * 20_000; STDERR.puts "u" * 20_000; puts "f" * 20_000} } it "should not deadlock" do - expect(stdout).to eql(expected_output_with.call('f')) - expect(stderr).to eql(expected_output_with.call('u')) + expect(stdout).to eql(expected_output_with.call("f")) + expect(stderr).to eql(expected_output_with.call("u")) end end end - context 'with subprocess piping lots of data through stdin, stdout, and stderr' do + context "with subprocess piping lots of data through stdin, stdout, and stderr" do let(:multiplier) { 20 } let(:expected_output_with) { lambda { |chr| (chr * multiplier) + (chr * multiplier) } } @@ -1389,78 +1390,78 @@ describe Mixlib::ShellOut do let(:options) { { :input => input } } - context 'when writing to STDOUT first' do - let(:input) { [ 'f' * multiplier, 'u' * multiplier, 'f' * multiplier, 'u' * multiplier ].join(LINE_ENDING) } + context "when writing to STDOUT first" do + let(:input) { [ "f" * multiplier, "u" * multiplier, "f" * multiplier, "u" * multiplier ].join(LINE_ENDING) } it "should not deadlock" do - expect(stdout).to eql(expected_output_with.call('f')) - expect(stderr).to eql(expected_output_with.call('u')) + expect(stdout).to eql(expected_output_with.call("f")) + expect(stderr).to eql(expected_output_with.call("u")) end end - context 'when writing to STDERR first' do - let(:input) { [ 'u' * multiplier, 'f' * multiplier, 'u' * multiplier, 'f' * multiplier ].join(LINE_ENDING) } + context "when writing to STDERR first" do + let(:input) { [ "u" * multiplier, "f" * multiplier, "u" * multiplier, "f" * multiplier ].join(LINE_ENDING) } it "should not deadlock" do - expect(stdout).to eql(expected_output_with.call('f')) - expect(stderr).to eql(expected_output_with.call('u')) + expect(stdout).to eql(expected_output_with.call("f")) + expect(stderr).to eql(expected_output_with.call("u")) end end end - context 'when subprocess closes prematurely', :unix_only do - context 'with input data' do - let(:ruby_code) { 'bad_ruby { [ } ]' } + context "when subprocess closes prematurely", :unix_only do + context "with input data" do + let(:ruby_code) { "bad_ruby { [ } ]" } let(:options) { { :input => input } } - let(:input) { [ 'f' * 20_000, 'u' * 20_000, 'f' * 20_000, 'u' * 20_000 ].join(LINE_ENDING) } + let(:input) { [ "f" * 20_000, "u" * 20_000, "f" * 20_000, "u" * 20_000 ].join(LINE_ENDING) } # Should the exception be handled? - it 'should raise error' do + it "should raise error" do expect { executed_cmd }.to raise_error(Errno::EPIPE) end end end - context 'when subprocess writes, pauses, then continues writing' do + context "when subprocess writes, pauses, then continues writing" do subject { stdout } let(:ruby_code) { %q{puts "before"; sleep 0.5; puts "after"} } - it 'should not hang or lose output' do + it "should not hang or lose output" do is_expected.to eql("before#{LINE_ENDING}after#{LINE_ENDING}") end end - context 'when subprocess pauses before writing' do + context "when subprocess pauses before writing" do subject { stdout } let(:ruby_code) { 'sleep 0.5; puts "missed_the_bus"' } - it 'should not hang or lose output' do + it "should not hang or lose output" do is_expected.to eql("missed_the_bus#{LINE_ENDING}") end end - context 'when subprocess pauses before reading from stdin' do + context "when subprocess pauses before reading from stdin" do subject { stdout.to_i } - let(:ruby_code) { 'sleep 0.5; print gets.size ' } - let(:input) { 'c' * 1024 } + let(:ruby_code) { "sleep 0.5; print gets.size " } + let(:input) { "c" * 1024 } let(:input_size) { input.size } let(:options) { { :input => input } } - it 'should not hang or lose output' do + it "should not hang or lose output" do is_expected.to eql(input_size) end end - context 'when execution fails' do + context "when execution fails" do let(:cmd) { "fuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu" } - context 'when running under Unix', :unix_only do + context "when running under Unix", :unix_only do it "should recover the error message" do expect { executed_cmd }.to raise_error(Errno::ENOENT) end - context 'with input' do - let(:options) { {:input => input } } + context "with input" do + let(:options) { { :input => input } } let(:input) { "Random input #{rand(1000000)}" } it "should recover the error message" do @@ -1469,16 +1470,16 @@ describe Mixlib::ShellOut do end end - skip 'when running under Windows', :windows_only + skip "when running under Windows", :windows_only end - context 'without input data' do - context 'with subprocess that expects stdin' do + context "without input data" do + context "with subprocess that expects stdin" do let(:ruby_code) { %q{print STDIN.eof?.to_s} } # If we don't have anything to send to the subprocess, we need to close # stdin so that the subprocess won't wait for input. - it 'should close stdin' do + it "should close stdin" do expect(stdout).to eql("true") end end @@ -1488,13 +1489,14 @@ describe Mixlib::ShellOut do describe "#format_for_exception" do let(:ruby_code) { %q{STDERR.puts "msg_in_stderr"; puts "msg_in_stdout"} } let(:exception_output) { executed_cmd.format_for_exception.split("\n") } - let(:expected_output) { [ + let(:expected_output) do + [ "---- Begin output of #{cmd} ----", %q{STDOUT: msg_in_stdout}, %q{STDERR: msg_in_stderr}, "---- End output of #{cmd} ----", - "Ran #{cmd} returned 0" - ] } + "Ran #{cmd} returned 0", + ] end it "should format exception messages" do exception_output.each_with_index do |output_line, i| @@ -1505,7 +1507,7 @@ describe Mixlib::ShellOut do end context "when running under *nix", :requires_root, :unix_only do - let(:cmd) { 'whoami' } + let(:cmd) { "whoami" } let(:running_user) { shell_cmd.run_command.stdout.chomp } context "when no user is set" do @@ -1515,7 +1517,7 @@ describe Mixlib::ShellOut do end context "when user is specified" do - let(:user) { 'nobody' } + let(:user) { "nobody" } let(:options) { { :user => user } } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b84b302..e1d530d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,15 +1,14 @@ $:.unshift File.expand_path("../../lib", __FILE__) $:.unshift File.expand_path("../..", __FILE__) -require 'mixlib/shellout' - -require 'tmpdir' -require 'tempfile' -require 'timeout' +require "mixlib/shellout" +require "tmpdir" +require "tempfile" +require "timeout" # Load everything from spec/support # Do not change the gsub. -Dir["spec/support/**/*.rb"].map { |f| f.gsub(%r{.rb$}, '') }.each { |f| require f } +Dir["spec/support/**/*.rb"].map { |f| f.gsub(%r{.rb$}, "") }.each { |f| require f } RSpec.configure do |config| config.mock_with :rspec |