diff options
author | Adam Jacob <adam@hjksolutions.com> | 2009-04-24 17:47:24 -0700 |
---|---|---|
committer | Adam Jacob <adam@hjksolutions.com> | 2009-04-24 17:47:24 -0700 |
commit | 0e67f1b224400858edfe3fff0345d04ba9aef71f (patch) | |
tree | 2a81cfdaa5679b15977d2c098feccd91052248dd /chef | |
parent | 2abe9484b4ae546807e48ee5f030bae209eede3b (diff) | |
parent | bd2fad29a8045fc64354d68830a0e1f0f6494ca3 (diff) | |
download | chef-0e67f1b224400858edfe3fff0345d04ba9aef71f.tar.gz |
Merge branch 'master' into cabeca/chef-186
Diffstat (limited to 'chef')
26 files changed, 779 insertions, 363 deletions
diff --git a/chef/bin/chef-client b/chef/bin/chef-client index df06e068fd..1c1b38bd19 100755 --- a/chef/bin/chef-client +++ b/chef/bin/chef-client @@ -79,6 +79,8 @@ end Chef::Config.from_file(config[:config_file]) Chef::Config.configure { |c| c.merge!(config) } +Chef::Daemon.change_privilege + if Chef::Config[:daemonize] unless Chef::Config[:log_location].is_a? IO Chef::Log.init(Chef::Config[:log_location]) diff --git a/chef/bin/chef-solo b/chef/bin/chef-solo index 5543faf9c3..ecc2c57f8a 100755 --- a/chef/bin/chef-solo +++ b/chef/bin/chef-solo @@ -34,7 +34,7 @@ config = { Chef::Config[:solo] = true opts = OptionParser.new do |opts| - opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)" + opts.banner = "Usage: #{$0} (options)" opts.on("-c CONFIG", "--config CONFIG", "The Chef Config file to use") do |c| config[:config_file] = c end diff --git a/chef/contrib/el/chef-client.config b/chef/contrib/el/chef-client.config new file mode 100644 index 0000000000..5be5f35114 --- /dev/null +++ b/chef/contrib/el/chef-client.config @@ -0,0 +1,16 @@ +# +# Chef Client Config File +# + +log_level :info +ssl_verify_mode :verify_none +registration_url "http://127.0.0.1:4000" +openid_url "http://127.0.0.1:4001" +template_url "http://127.0.0.1:4000" +remotefile_url "http://127.0.0.1:4000" +search_url "http://127.0.0.1:4000" + +pid_file "/var/run/chef/chef-client.pid" + +#interval 1800 +#splay 0 diff --git a/chef/contrib/el/chef-client.init b/chef/contrib/el/chef-client.init new file mode 100644 index 0000000000..332e9606d9 --- /dev/null +++ b/chef/contrib/el/chef-client.init @@ -0,0 +1,74 @@ +#!/bin/bash +# Startup script for chef-client +# +# chkconfig: - 98 02 +# description: Client component of the Chef systems integration framework. +# processname: chef-client +# +# config: /etc/sysconfig/chef-client +# pidfile: /var/run/chef/chef-client.pid + +# Source function library +. /etc/init.d/functions + +[ -f /etc/sysconfig/chef-client ] && . /etc/sysconfig/chef-client + +prog="chef-client" +pidfile=${PIDFILE-/var/run/chef/chef-client.pid} +lockfile=${LOCKFILE-/var/lock/subsys/$prog} +config=${CONFIG-/etc/chef/client.rb} +logfile=${LOGFILE-/var/log/chef/chef-client.log} +OPTIONS= + +start() { + echo -n "Starting $prog:" + daemon chef-client -d -c "$config" -L "$logfile" "$OPTIONS" ">/dev/null" + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch ${lockfile} + return $RETVAL +} + +stop() { + echo -n "Stopping $prog: " + if [ -f $pidfile ]; then + killproc chef-client + RETVAL=$? + if [ $RETVAL -ne 0 ]; then + failure; + fi; + else + RETVAL=1 + failure; + fi + rm -f $lockfile + echo + return $RETVAL +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + condrestart) + if [ -f $lockfile ]; then + stop + start + fi + ;; + status) + status chef-client + ;; + *) + echo "Usage: $0 {start|stop|restart|condrestart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/chef/lib/chef/config.rb b/chef/lib/chef/config.rb index f864274b40..f9fda13cf0 100644 --- a/chef/lib/chef/config.rb +++ b/chef/lib/chef/config.rb @@ -41,8 +41,6 @@ class Chef :interval => nil, :splay => nil, :solo => false, - :user => nil, - :group => nil, :json_attribs => nil, :cookbook_path => [ "/var/chef/site-cookbooks", "/var/chef/cookbooks" ], :validation_token => nil, diff --git a/chef/lib/chef/daemon.rb b/chef/lib/chef/daemon.rb index 7ab66ab710..2b6e6db3ea 100644 --- a/chef/lib/chef/daemon.rb +++ b/chef/lib/chef/daemon.rb @@ -40,12 +40,12 @@ class Chef exit if fork Process.setsid exit if fork - change_privilege Chef::Log.info("Forked, in #{Process.pid}. Priveleges: #{Process.euid} #{Process.egid}") File.umask 0000 $stdin.reopen("/dev/null") $stdout.reopen("/dev/null", "a") $stdout.reopen($stdout) + save_pid_file at_exit { remove_pid_file } rescue NotImplementedError => e Chef.fatal!("There is no fork: #{e.message}") @@ -167,4 +167,4 @@ class Chef end end end -end
\ No newline at end of file +end diff --git a/chef/lib/chef/mixin/command.rb b/chef/lib/chef/mixin/command.rb index d787059548..f0c76b09e9 100644 --- a/chef/lib/chef/mixin/command.rb +++ b/chef/lib/chef/mixin/command.rb @@ -113,35 +113,11 @@ class Chef end exec_processing_block = lambda do |pid, stdin, stdout, stderr| - stdout.sync = true - stderr.sync = true - Chef::Log.debug("---- Begin output of #{args[:command]} ----") - - stdout_finished = false - stderr_finished = false - - while !stdout_finished || !stderr_finished - ready = IO.select([stdout, stderr], nil, nil, 1.0) - if ready && ready.first.include?(stdout) - line = stdout.gets - if line - command_output << "STDOUT: #{line.strip}\n" - Chef::Log.debug("STDOUT: #{line.strip}") - else - stdout_finished = true - end - end - if ready && ready.first.include?(stderr) - line = stderr.gets - if line - command_output << "STDERR: #{line.strip}\n" - Chef::Log.debug("STDERR: #{line.strip}") - else - stderr_finished = true - end - end - end + Chef::Log.debug("STDOUT: #{stdout.string.chomp!}") + Chef::Log.debug("STDERR: #{stderr.string.chomp!}") + command_output << "STDOUT: #{stdout.string.chomp!}" + command_output << "STDERR: #{stderr.string.chomp!}" Chef::Log.debug("---- End output of #{args[:command]} ----") end @@ -154,10 +130,6 @@ class Chef status = nil - # I don't understand what this :waitlast argument is doing, but setting it to true is causing the block in popen4 - # not to wait until the command is finished to execute, kind of the opposite of what I would guess from the name - args[:waitlast] ||= true - Dir.chdir(args[:cwd]) do if args[:timeout] begin @@ -200,8 +172,13 @@ class Chef # # Thanks Ara! def popen4(cmd, args={}, &b) - + # Waitlast - this is magic. + # + # Do we wait for the child process to die before we yield + # to the block, or after? That is the magic of waitlast. + # + # By default, we are waiting before we yield the block. args[:waitlast] ||= false args[:user] ||= nil @@ -298,11 +275,58 @@ class Chef # wants to do must be done - it's dead. If it isn't, # it's because something totally skanky is happening, # and we don't care. + o = StringIO.new + e = StringIO.new + pi[0].close - pi[1].fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) - pi[2].fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) - results = Process.waitpid2(cid).last - b[cid, *pi] + + stdout = pi[1] + stderr = pi[2] + + stdout.sync = true + stderr.sync = true + + stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) + stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) + + + stdout_finished = false + stderr_finished = false + + results = nil + + while !stdout_finished || !stderr_finished + begin + ready = IO.select([stdout, stderr], nil, nil, 1.0) + rescue Errno::EAGAIN + results = Process.waitpid2(cid, Process::WNOHANG) + if results + stdout_finished = true + stderr_finished = true + end + end + + if ready && ready.first.include?(stdout) + line = results ? stdout.gets(nil) : stdout.gets + if line + o.write(line) + else + stdout_finished = true + end + end + if ready && ready.first.include?(stderr) + line = results ? stderr.gets(nil) : stderr.gets + if line + e.write(line) + else + stderr_finished = true + end + end + end + results = Process.waitpid2(cid).last unless results + o.rewind + e.rewind + b[cid, pi[0], o, e] results end ensure diff --git a/chef/lib/chef/provider/package/yum-dump-json.py b/chef/lib/chef/provider/package/yum-dump-json.py new file mode 100644 index 0000000000..115265e5aa --- /dev/null +++ b/chef/lib/chef/provider/package/yum-dump-json.py @@ -0,0 +1,67 @@ +# +# Author:: Matthew Kent (<mkent@magoazul.com>) +# Copyright:: Copyright (c) 2009 Matthew Kent +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# yum-dump-json.py +# Inspired by yumhelper.py by David Lutterkort +# +# Produce a list of installed and available packages using yum and dump the +# result as json to stdout. +# +# This invokes yum just as the command line would which makes it subject to +# all the caching related configuration paramaters in yum.conf. +# +# Can be run as non root, but that won't update the cache. + +import os +import sys +import yum +import json + +y = yum.YumBase() +# Only want json in output +y.doConfigSetup(debuglevel=0, errorlevel=0) + +# yum assumes it can update the cache directory. Disable this for non root +# users. +y.conf.cache = os.geteuid() != 0 + +y.doTsSetup() +y.doRpmDBSetup() + +db = y.doPackageLists('all') + +y.closeRpmDB() + +combined = {} + +for pkg in db.installed: + combined[pkg.name] = {} + combined[pkg.name]["installed"] = { "epoch": pkg.epoch, + "version": pkg.version, + "release": pkg.release, + "arch": pkg.arch } +for pkg in db.available: + if not combined.has_key(pkg.name): + combined[pkg.name] = {} + combined[pkg.name]["available"] = { "epoch": pkg.epoch, + "version": pkg.version, + "release": pkg.release, + "arch": pkg.arch } +print json.write( combined ) + +sys.exit(0) diff --git a/chef/lib/chef/provider/package/yum.rb b/chef/lib/chef/provider/package/yum.rb index 7e4a6e96ba..5eab817f0e 100644 --- a/chef/lib/chef/provider/package/yum.rb +++ b/chef/lib/chef/provider/package/yum.rb @@ -19,63 +19,114 @@ require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' +require 'singleton' class Chef class Provider class Package class Yum < Chef::Provider::Package + class YumCache + include Chef::Mixin::Command + include Singleton + + def initialize + @created_at = Time.now + load_data + end + + def stale? + interval = Chef::Config[:interval].to_f + + # run once mode + if interval == 0 + return false + elsif (Time.now - @created_at) > interval + return true + end + + false + end + + def refresh + if @data.empty? + reload + elsif stale? + reload + end + end + + def load_data + parsed = String.new + helper = ::File.join(::File.dirname(__FILE__), 'yum-dump-json.py') + status = popen4("python #{helper}", :waitlast => true) do |pid, stdin, stdout, stderr| + stdout.each do |line| + parsed << line + end + end + + unless status.exitstatus == 0 + raise Chef::Exceptions::Package, "yum failed - #{status.inspect}!" + end + + @data = JSON.parse(parsed) + end + alias :reload :load_data + + def version(package_name, type) + if (x = @data[package_name]) + if (y = x[type]) + return "#{y["version"]}-#{y["release"]}" + end + end + + nil + end + + def installed_version(package_name) + version(package_name, "installed") + end + + def candidate_version(package_name) + version(package_name, "available") + end + + def flush + @data.clear + end + end + + def initialize(node, new_resource) + @yum = YumCache.instance + super(node, new_resource) + end + def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) Chef::Log.debug("Checking yum info for #{@new_resource.package_name}") - status = popen4("yum info -q -y #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| - package_type = nil - installed_version = nil - candidate_version = nil - stdout.each do |line| - case line - when /^Installed Packages$/ - package_type = :installed - when /^Available Packages$/ - package_type = :available - when /^Version\s*: (.+)$/ - if package_type == :installed - installed_version = $1 - elsif package_type == :available - candidate_version = $1 - end - when /^Release: (.+)$/ - if package_type == :installed - installed_version += "-#{$1}" - Chef::Log.debug("Installed release is #{installed_version}") - elsif package_type == :available - candidate_version += "-#{$1}" - Chef::Log.debug("Candidate version is #{candidate_version}") - end - end - end - - @current_resource.version(installed_version) - if candidate_version - @candidate_version = candidate_version - else - @candidate_version = installed_version - end - end + + @yum.refresh - unless status.exitstatus == 0 - raise Chef::Exceptions::Package, "yum failed - #{status.inspect}!" + installed_version = @yum.installed_version(@new_resource.package_name) + @candidate_version = @yum.candidate_version(@new_resource.package_name) + + @current_resource.version(installed_version) + if candidate_version + @candidate_version = candidate_version + else + @candidate_version = installed_version end @current_resource end - + def install_package(name, version) run_command( :command => "yum -q -y install #{name}-#{version}" ) + @yum.flush end def upgrade_package(name, version) @@ -84,6 +135,7 @@ class Chef run_command( :command => "yum -q -y update #{name}-#{version}" ) + @yum.flush else install_package(name, version) end @@ -93,6 +145,7 @@ class Chef run_command( :command => "yum -q -y remove #{name}-#{version}" ) + @yum.flush end def purge_package(name, version) diff --git a/chef/lib/chef/provider/remote_file.rb b/chef/lib/chef/provider/remote_file.rb index df2afd4976..3c55b873e3 100644 --- a/chef/lib/chef/provider/remote_file.rb +++ b/chef/lib/chef/provider/remote_file.rb @@ -43,48 +43,50 @@ class Chef end def do_remote_file(source, path) - # The current files checksum - current_checksum = self.checksum(path) if ::File.exists?(path) + if(@new_resource.checksum && @current_resource.checksum && @current_resource.checksum =~ /^#{@new_resource.checksum}/) + Chef::Log.debug("File #{@new_resource} checksum matches, not updating") + else + begin + # The remote filehandle + raw_file = get_from_uri(source) || + get_from_server(source, @current_resource.checksum) || + get_from_local_cookbook(source) + rescue Net::HTTPRetriableError => e + if e.response.kind_of?(Net::HTTPNotModified) + Chef::Log.debug("File #{path} is unchanged") + return false + else + raise e + end + end - begin - # The remote filehandle - raw_file = get_from_uri(source) || - get_from_server(source, current_checksum) || - get_from_local_cookbook(source) - rescue Net::HTTPRetriableError => e - if e.response.kind_of?(Net::HTTPNotModified) - Chef::Log.debug("File #{path} is unchanged") - return false + # If the file exists + if ::File.exists?(@new_resource.path) + # And it matches the checksum of the raw file + @new_resource.checksum(self.checksum(raw_file.path)) + if @new_resource.checksum != @current_resource.checksum + # Updating target file, let's perform a backup! + Chef::Log.debug("#{@new_resource} changed from #{@current_resource.checksum} to #{@new_resource.checksum}") + Chef::Log.info("Updating #{@new_resource} at #{@new_resource.path}") + backup(@new_resource.path) + end else - raise e + # We're creating a new file + Chef::Log.info("Creating #{@new_resource} at #{@new_resource.path}") end - end - # If the file exists - if ::File.exists?(@new_resource.path) - # And it matches the checksum of the raw file - @new_resource.checksum(self.checksum(raw_file.path)) - if @new_resource.checksum != @current_resource.checksum - # Updating target file, let's perform a backup! - Chef::Log.debug("#{@new_resource} changed from #{@current_resource.checksum} to #{@new_resource.checksum}") - Chef::Log.info("Updating #{@new_resource} at #{@new_resource.path}") - backup(@new_resource.path) - end - else - # We're creating a new file - Chef::Log.info("Creating #{@new_resource} at #{@new_resource.path}") - end + FileUtils.cp(raw_file.path, @new_resource.path) + @new_resource.updated = true - FileUtils.cp(raw_file.path, @new_resource.path) - @new_resource.updated = true - + # We're done with the file, so make sure to close it if it was open. + raw_file.close + true + end + set_owner if @new_resource.owner set_group if @new_resource.group set_mode if @new_resource.mode - # We're done with the file, so make sure to close it if it was open. - raw_file.close - true end def get_from_uri(source) diff --git a/chef/lib/chef/resource/remote_file.rb b/chef/lib/chef/resource/remote_file.rb index a1f276aff3..136a704c63 100644 --- a/chef/lib/chef/resource/remote_file.rb +++ b/chef/lib/chef/resource/remote_file.rb @@ -46,6 +46,15 @@ class Chef ) end + def checksum(args=nil) + set_or_return( + :checksum, + args, + :kind_of => String + ) + end + + end end end diff --git a/chef/lib/chef/util/file_edit.rb b/chef/lib/chef/util/file_edit.rb new file mode 100644 index 0000000000..c09e427741 --- /dev/null +++ b/chef/lib/chef/util/file_edit.rb @@ -0,0 +1,125 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2009 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'ftools' +require 'fileutils' +require 'tempfile' + +class Chef + class Util + class FileEdit + + private + + attr_accessor :original_pathname, :contents, :file_edited + + public + + def initialize(filepath) + @original_pathname = filepath + @file_edited = false + + raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname + raise ArgumentError, "File is blank" unless (@contents = File.new(@original_pathname).readlines).length > 0 + end + + #search the file line by line and match each line with the given regex + #if matched, replace the whole line with newline. + def search_file_replace_line(regex, newline) + search_match(regex, newline, 'r', 1) + end + + #search the file line by line and match each line with the given regex + #if matched, replace the match (all occurances) with the replace parameter + def search_file_replace(regex, replace) + search_match(regex, replace, 'r', 2) + end + + #search the file line by line and match each line with the given regex + #if matched, delete the line + def search_file_delete_line(regex) + search_match(regex, " ", 'd', 1) + end + + #search the file line by line and match each line with the given regex + #if matched, delete the match (all occurances) from the line + def search_file_delete(regex) + search_match(regex, " ", 'd', 2) + end + + #search the file line by line and match each line with the given regex + #if matched, insert newline after each matching line + def insert_line_after_match(regex, newline) + search_match(regex, newline, 'i', 0) + end + + #Make a copy of old_file and write new file out (only if file changed) + def write_file + + # file_edited is false when there was no match in the whole file and thus no contents have changed. + if file_edited + backup_pathname = original_pathname + ".old" + File.copy(original_pathname, backup_pathname) + Tempfile.open("w") do |newfile| + contents.each do |line| + newfile.puts(line) + end + newfile.flush + FileUtils.mv(newfile.path, original_pathname) + end + end + self.file_edited = false + + end + + private + + #helper method to do the match, replace, delete, and insert operations + #command is the switch of delete, replace, and insert ('d', 'r', 'i') + #method is to control operation on whole line or only the match (1 for line, 2 for match) + def search_match(regex, replace, command, method) + + #convert regex to a Regexp object (if not already is one) and store it in exp. + exp = Regexp.new(regex) + + #loop through contents and do the appropriate operation depending on 'command' and 'method' + new_contents = [] + + contents.each do |line| + if line.match(exp) + self.file_edited = true + case + when command == 'r' + new_contents << ((method == 1) ? replace : line.gsub!(exp, replace)) + when command == 'd' + if method == 2 + new_contents << line.gsub!(exp, "") + end + when command == 'i' + new_contents << line + new_contents << replace + end + else + new_contents << line + end + end + + self.contents = new_contents + end + end + end +end diff --git a/chef/spec/data/fileedit/blank b/chef/spec/data/fileedit/blank new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/chef/spec/data/fileedit/blank diff --git a/chef/spec/data/fileedit/hosts b/chef/spec/data/fileedit/hosts new file mode 100644 index 0000000000..6fbdc0f59d --- /dev/null +++ b/chef/spec/data/fileedit/hosts @@ -0,0 +1,4 @@ +127.0.0.1 localhost +255.255.255.255 broadcasthost +::1 localhost +fe80::1%lo0 localhost diff --git a/chef/spec/lib/chef/provider/easy.rb b/chef/spec/lib/chef/provider/easy.rb index 966fbc8dc5..054b45256c 100644 --- a/chef/spec/lib/chef/provider/easy.rb +++ b/chef/spec/lib/chef/provider/easy.rb @@ -1,22 +1,20 @@ # # Author:: Adam Jacob (<adam@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: GNU General Public License version 2 or later -# -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# class Chef class Provider @@ -34,4 +32,4 @@ class Chef end end end -end
\ No newline at end of file +end diff --git a/chef/spec/lib/chef/provider/snakeoil.rb b/chef/spec/lib/chef/provider/snakeoil.rb index 7985218f04..5db174bdf7 100644 --- a/chef/spec/lib/chef/provider/snakeoil.rb +++ b/chef/spec/lib/chef/provider/snakeoil.rb @@ -1,22 +1,20 @@ # # Author:: Adam Jacob (<adam@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: GNU General Public License version 2 or later -# -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# class Chef class Provider @@ -34,4 +32,4 @@ class Chef end end end -end
\ No newline at end of file +end diff --git a/chef/spec/lib/chef/resource/cat.rb b/chef/spec/lib/chef/resource/cat.rb index 0602158312..71e1df1f75 100644 --- a/chef/spec/lib/chef/resource/cat.rb +++ b/chef/spec/lib/chef/resource/cat.rb @@ -1,21 +1,20 @@ +# # Author:: Adam Jacob (<adam@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: GNU General Public License version 2 or later +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# class Chef class Resource @@ -39,4 +38,4 @@ class Chef end end end -end
\ No newline at end of file +end diff --git a/chef/spec/lib/chef/resource/zen_master.rb b/chef/spec/lib/chef/resource/zen_master.rb index 5cbb82f5b9..6a40d545c3 100644 --- a/chef/spec/lib/chef/resource/zen_master.rb +++ b/chef/spec/lib/chef/resource/zen_master.rb @@ -1,21 +1,20 @@ +# # Author:: Adam Jacob (<adam@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: GNU General Public License version 2 or later +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# class Chef class Resource @@ -41,4 +40,4 @@ class Chef end end end -end
\ No newline at end of file +end diff --git a/chef/spec/spec_helper.rb b/chef/spec/spec_helper.rb index 35bc9d57ac..0dd5b202cb 100644 --- a/chef/spec/spec_helper.rb +++ b/chef/spec/spec_helper.rb @@ -1,21 +1,20 @@ +# # Author:: Adam Jacob (<adam@opscode.com>) # Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: GNU General Public License version 2 or later +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) diff --git a/chef/spec/unit/couchdb_spec.rb b/chef/spec/unit/couchdb_spec.rb index c822671225..62ba85e33d 100644 --- a/chef/spec/unit/couchdb_spec.rb +++ b/chef/spec/unit/couchdb_spec.rb @@ -31,7 +31,7 @@ describe Chef::CouchDB, "new" do Chef::REST.should_receive(:new).with("http://monkey") Chef::CouchDB.new end - + it "should create a new Chef::REST object from a provided url" do Chef::REST.should_receive(:new).with("http://monkeypants") Chef::CouchDB.new("http://monkeypants") @@ -292,4 +292,4 @@ describe Chef::CouchDB, "view_uri" do @couchdb.view_uri("nodes", "all") end end -end
\ No newline at end of file +end diff --git a/chef/spec/unit/mixin/command_spec.rb b/chef/spec/unit/mixin/command_spec.rb deleted file mode 100644 index d35712bab5..0000000000 --- a/chef/spec/unit/mixin/command_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# -# Author:: Matthew Landauer (<matthew@openaustralia.org>) -# Copyright:: Copyright (c) 2008 Matthew Landauer -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -describe Chef::Mixin::Command do - before :each do - Chef::Log.init - end - - # Reset the logger for other tests - after :each do - Chef::Log.init - end - - it "should log the command's standard output at debug log level" do - command = "ruby -e 'puts 5'" - Chef::Log.should_receive(:debug).with("Executing #{command}").ordered - Chef::Log.should_receive(:debug).with("---- Begin output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("STDOUT: 5").ordered - Chef::Log.should_receive(:debug).with("---- End output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("Ran #{command} returned 0").ordered - Chef::Mixin::Command.run_command(:command => command) - end - - it "should log the command's standard error at debug log level" do - command = "ruby -e 'STDERR.puts 5'" - Chef::Log.should_receive(:debug).with("Executing #{command}").ordered - Chef::Log.should_receive(:debug).with("---- Begin output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("STDERR: 5").ordered - Chef::Log.should_receive(:debug).with("---- End output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("Ran #{command} returned 0").ordered - Chef::Mixin::Command.run_command(:command => command) - end - - it "should log the command's standard out and error at the same time" do - command = "ruby -e 'STDERR.puts 1; puts 2; STDERR.puts 3; puts 4'" - Chef::Log.should_receive(:debug).with("Executing #{command}").ordered - Chef::Log.should_receive(:debug).with("---- Begin output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("STDERR: 1").ordered - Chef::Log.should_receive(:debug).with("STDOUT: 2").ordered - Chef::Log.should_receive(:debug).with("STDERR: 3").ordered - Chef::Log.should_receive(:debug).with("STDOUT: 4").ordered - Chef::Log.should_receive(:debug).with("---- End output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("Ran #{command} returned 0").ordered - Chef::Mixin::Command.run_command(:command => command) - end - - it "should throw an exception if the command returns a bad exit value" do - command = "ruby -e 'puts 1; exit 1'" - Chef::Log.level :debug - # Stub out Chef::Log.debug to avoid messages going to console - Chef::Log.stub!(:debug) - lambda {Chef::Mixin::Command.run_command(:command => command)}.should raise_error(Chef::Exceptions::Exec, "#{command} returned 1, expected 0") - end - - it "should include the command output in the exception if the log level is not at debug" do - command = "ruby -e 'puts 1; exit 1'" - Chef::Log.level :info - lambda {Chef::Mixin::Command.run_command(:command => command)}.should raise_error(Chef::Exceptions::Exec, "#{command} returned 1, expected 0\n---- Begin output of #{command} ----\nSTDOUT: 1\n---- End output of #{command} ----\n") - end - - it "should log the output as the command is executing" do - command = "ruby -e 'STDOUT.sync = true; puts 1; sleep 2; puts 2'" - Chef::Log.should_receive(:debug).with("Executing #{command}").ordered - Chef::Log.should_receive(:debug).with("---- Begin output of #{command} ----").ordered - Chef::Log.should_receive(:debug).with("STDOUT: 1").ordered - lambda {Chef::Mixin::Command.run_command(:command => command, :timeout => 1)}.should raise_error(Timeout::Error) - end -end diff --git a/chef/spec/unit/mixin/template_spec.rb b/chef/spec/unit/mixin/template_spec.rb index 86e0b59232..05fee6820a 100644 --- a/chef/spec/unit/mixin/template_spec.rb +++ b/chef/spec/unit/mixin/template_spec.rb @@ -31,7 +31,8 @@ describe Chef::Mixin::Template, "render_template" do end it "should return a file" do - @template.render_template("abcdef", {}).should be_kind_of(File) + f = @template.render_template("abcdef", {}) + @template.render_template("abcdef", {}).should be_kind_of(Tempfile) end describe "when an exception is raised in the template" do diff --git a/chef/spec/unit/provider/package/yum_spec.rb b/chef/spec/unit/provider/package/yum_spec.rb index 6a554c812f..2e8ddb9971 100644 --- a/chef/spec/unit/provider/package/yum_spec.rb +++ b/chef/spec/unit/provider/package/yum_spec.rb @@ -36,55 +36,16 @@ describe Chef::Provider::Package::Yum, "load_current_resource" do :updated => nil ) @status = mock("Status", :exitstatus => 0) + @yum_cache = mock( + 'Chef::Provider::Yum::YumCache', + :refresh => true, + :flush => true, + :installed_version => "1.2.4-11.18.el5", + :candidate_version => "1.2.4-11.18.el5_2.3" + ) + Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@node, @new_resource) Chef::Resource::Package.stub!(:new).and_return(@current_resource) - @provider.stub!(:popen4).and_return(@status) - @stdin = mock("STDIN", :null_object => true) - @stdout = mock("STDOUT", :null_object => true) - @stdout.stub!(:each).and_yield("Installed Packages"). - and_yield("Name : cups"). - and_yield("Arch : i386"). - and_yield("Epoch : 1"). - and_yield("Version: 1.2.4"). - and_yield("Release: 11.18.el5"). - and_yield("Size : 7.8 M"). - and_yield("Repo : installed"). - and_yield("Summary: Common Unix Printing System"). - and_yield("Description:"). - and_yield("The Common UNIX Printing System provides a portable printing layer for"). - and_yield("UNIX® operating systems. It has been developed by Easy Software Products"). - and_yield("to promote a standard printing solution for all UNIX vendors and users."). - and_yield("CUPS provides the System V and Berkeley command-line interfaces."). - and_yield(""). - and_yield("Available Packages"). - and_yield("Name : cups"). - and_yield("Arch : i386"). - and_yield("Epoch : 1"). - and_yield("Version: 1.2.4"). - and_yield("Release: 11.18.el5_2.3"). - and_yield("Size : 2.7 M"). - and_yield("Repo : updates"). - and_yield("Summary: Common Unix Printing System"). - and_yield("Description:"). - and_yield("The Common UNIX Printing System provides a portable printing layer for"). - and_yield("UNIX® operating systems. It has been developed by Easy Software Products"). - and_yield("to promote a standard printing solution for all UNIX vendors and users."). - and_yield("CUPS provides the System V and Berkeley command-line interfaces.") - @stdout_available = mock("STDOUT AVAILABLE", :null_object => true) - @stdout_available.stub!(:each).and_yield("Available Packages"). - and_yield("Name : cups"). - and_yield("Arch : i386"). - and_yield("Epoch : 1"). - and_yield("Version: 1.2.4"). - and_yield("Release: 11.18.el5_2.3"). - and_yield("Size : 2.7 M"). - and_yield("Repo : updates"). - and_yield("Summary: Common Unix Printing System"). - and_yield("Description:"). - and_yield("The Common UNIX Printing System provides a portable printing layer for"). - and_yield("UNIX® operating systems. It has been developed by Easy Software Products"). - and_yield("to promote a standard printing solution for all UNIX vendors and users."). - and_yield("CUPS provides the System V and Berkeley command-line interfaces.") @stderr = mock("STDERR", :null_object => true) @pid = mock("PID", :null_object => true) end @@ -99,45 +60,22 @@ describe Chef::Provider::Package::Yum, "load_current_resource" do @provider.load_current_resource end - it "should run yum info with the package name" do - @provider.should_receive(:popen4).with("yum info -q -y #{@new_resource.package_name}").and_return(@status) - @provider.load_current_resource - end - - it "should read stdout on yum info" do - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @stdout.should_receive(:each).and_return(true) - @provider.load_current_resource - end - it "should set the installed version to nil on the current resource if no installed package" do - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout_available, @stderr).and_return(@status) + @yum_cache.stub!(:installed_version).and_return(nil) @current_resource.should_receive(:version).with(nil).and_return(true) @provider.load_current_resource end - it "should set the installed version if yum info has one" do - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + it "should set the installed version if yum has one" do @current_resource.should_receive(:version).with("1.2.4-11.18.el5").and_return(true) @provider.load_current_resource end it "should set the candidate version if yum info has one" do - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.candidate_version.should eql("1.2.4-11.18.el5_2.3") end - it "should raise an exception if yum info fails" do - @status.should_receive(:exitstatus).and_return(1) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should not raise an exception if yum info succeeds" do - @status.should_receive(:exitstatus).and_return(0) - lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Package) - end - it "should return the current resouce" do @provider.load_current_resource.should eql(@current_resource) end @@ -154,6 +92,14 @@ describe Chef::Provider::Package::Yum, "install_package" do :package_name => "emacs", :updated => nil ) + @yum_cache = mock( + 'Chef::Provider::Yum::YumCache', + :refresh => true, + :flush => true, + :installed_version => "1.2.4-11.18.el5", + :candidate_version => "1.2.4-11.18.el5_2.3" + ) + Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@node, @new_resource) end @@ -169,13 +115,21 @@ describe Chef::Provider::Package::Yum, "upgrade_package" do before(:each) do @node = mock("Chef::Node", :null_object => true) - @new_resource = mock("Chef::Resource::Package", + @new_resource = mock("Chef::Resource::Package", :null_object => true, :name => "emacs", :version => nil, :package_name => "emacs", :updated => nil ) + @yum_cache = mock( + 'Chef::Provider::Yum::YumCache', + :refresh => true, + :flush => true, + :installed_version => "1.2.4-11.18.el5", + :candidate_version => "1.2.4-11.18.el5_2.3" + ) + Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @current_resource = mock("Chef::Resource::Package", :null_object => true, :name => "emacs", @@ -214,6 +168,14 @@ describe Chef::Provider::Package::Yum, "remove_package" do :package_name => "emacs", :updated => nil ) + @yum_cache = mock( + 'Chef::Provider::Yum::YumCache', + :refresh => true, + :flush => true, + :installed_version => "1.2.4-11.18.el5", + :candidate_version => "1.2.4-11.18.el5_2.3" + ) + Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@node, @new_resource) end @@ -235,6 +197,14 @@ describe Chef::Provider::Package::Yum, "purge_package" do :package_name => "emacs", :updated => nil ) + @yum_cache = mock( + 'Chef::Provider::Yum::YumCache', + :refresh => true, + :flush => true, + :installed_version => "1.2.4-11.18.el5", + :candidate_version => "1.2.4-11.18.el5_2.3" + ) + Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@node, @new_resource) end diff --git a/chef/spec/unit/provider/remote_file_spec.rb b/chef/spec/unit/provider/remote_file_spec.rb index 430a2e5916..e2a5fbb94d 100644 --- a/chef/spec/unit/provider/remote_file_spec.rb +++ b/chef/spec/unit/provider/remote_file_spec.rb @@ -65,10 +65,46 @@ describe Chef::Provider::RemoteFile, "do_remote_file" do end describe "when given a URI source" do - it "should download the file from the remote URL" do - @resource.source("http://opscode.com/seattle.txt") - @rest.should_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) - do_remote_file + describe "and given a checksum" do + it "should not download the file if the checksum matches" do + @resource.checksum("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") + @resource.source("http://opscode.com/seattle.txt") + @rest.should_not_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) + do_remote_file + end + + it "should not download the file if the checksum is a partial match from the beginning" do + @resource.checksum("0fd012fd") + @resource.source("http://opscode.com/seattle.txt") + @rest.should_not_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) + do_remote_file + end + + + it "should download the file if the checksum does not match" do + @resource.checksum("this hash doesn't match") + @resource.source("http://opscode.com/seattle.txt") + @rest.should_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) + do_remote_file + end + + it "should download the file if the checksum matches, but not from the beginning" do + @resource.checksum("fd012fd") + @resource.source("http://opscode.com/seattle.txt") + @rest.should_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) + do_remote_file + end + + + end + + describe "and not given a checksum" do + it "should download the file from the remote URL" do + @resource.checksum(nil) + @resource.source("http://opscode.com/seattle.txt") + @rest.should_receive(:get_rest).with("http://opscode.com/seattle.txt", true).and_return(@tempfile) + do_remote_file + end end end @@ -102,17 +138,6 @@ describe Chef::Provider::RemoteFile, "do_remote_file" do end end - it "should set the checksum if the file exists" do - @provider.should_receive(:checksum).with(@resource.path) - do_remote_file - end - - it "should not set the checksum if the file doesn't exist" do - File.stub!(:exists?).with(@resource.path).and_return(false) - @provider.should_not_receive(:checksum).with(@resource.path) - do_remote_file - end - it "should not transfer the file if it has not been changed" do r = Net::HTTPNotModified.new("one", "two", "three") e = Net::HTTPRetriableError.new("304", r) diff --git a/chef/spec/unit/resource/remote_file_spec.rb b/chef/spec/unit/resource/remote_file_spec.rb index 24ed30f4e0..cc31b543ef 100644 --- a/chef/spec/unit/resource/remote_file_spec.rb +++ b/chef/spec/unit/resource/remote_file_spec.rb @@ -49,5 +49,16 @@ describe Chef::Resource::RemoteFile do @resource.cookbook.should == nil end end + + describe "checksum" do + it "should accept a string for the checksum object" do + @resource.checksum "asdf" + @resource.checksum.should eql("asdf") + end + + it "should default to nil" do + @resource.checksum.should == nil + end + end -end
\ No newline at end of file +end diff --git a/chef/spec/unit/util/file_edit_spec.rb b/chef/spec/unit/util/file_edit_spec.rb new file mode 100644 index 0000000000..24d6503fc2 --- /dev/null +++ b/chef/spec/unit/util/file_edit_spec.rb @@ -0,0 +1,127 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +require File.join(File.dirname(__FILE__), '..', '..', "spec_helper") + +describe Chef::Util::FileEdit, "initialiize" do + it "should create a new Chef::Util::FileEdit object" do + Chef::Util::FileEdit.new("./spec/data/fileedit/hosts").should be_kind_of(Chef::Util::FileEdit) + end + + it "should throw an exception if the input file does not exist" do + lambda{Chef::Util::FileEdit.new("nonexistfile")}.should raise_error + end + + it "should throw an exception if the input file is blank" do + lambda{Chef::Util::FileEdit.new("./spec/data/fileedit/blank")}.should raise_error + end + +end + +describe Chef::Util::FileEdit, "search_file_replace" do + + it "should accept regex passed in as a string (not Regexp object) and replace the match if there is one" do + helper_method("./spec/data/fileedit/hosts", "localhost", true) + end + + + it "should accept regex passed in as a Regexp object and replace the match if there is one" do + helper_method("./spec/data/fileedit/hosts", /localhost/, true) + end + + + it "should do nothing if there isn't a match" do + helper_method("./spec/data/fileedit/hosts", /pattern/, false) + end + + + def helper_method(filename, regex, value) + fedit = Chef::Util::FileEdit.new(filename) + fedit.search_file_replace(regex, "replacement") + fedit.write_file + (File.exist? filename+".old").should be(value) + if value == true + newfile = File.new(filename).readlines + newfile[0].should match(/replacement/) + File.delete("./spec/data/fileedit/hosts") + File.rename("./spec/data/fileedit/hosts.old", "./spec/data/fileedit/hosts") + end + end + +end + +describe Chef::Util::FileEdit, "search_file_replace_line" do + + it "should search for match and replace the whole line" do + fedit = Chef::Util::FileEdit.new("./spec/data/fileedit/hosts") + fedit.search_file_replace_line(/localhost/, "replacement line") + fedit.write_file + newfile = File.new("./spec/data/fileedit/hosts").readlines + newfile[0].should match(/replacement/) + newfile[0].should_not match(/127/) + File.delete("./spec/data/fileedit/hosts") + File.rename("./spec/data/fileedit/hosts.old", "./spec/data/fileedit/hosts") + end + +end + +describe Chef::Util::FileEdit, "search_file_delete" do + it "should search for match and delete the match" do + fedit = Chef::Util::FileEdit.new("./spec/data/fileedit/hosts") + fedit.search_file_delete(/localhost/) + fedit.write_file + newfile = File.new("./spec/data/fileedit/hosts").readlines + newfile[0].should_not match(/localhost/) + newfile[0].should match(/127/) + File.delete("./spec/data/fileedit/hosts") + File.rename("./spec/data/fileedit/hosts.old", "./spec/data/fileedit/hosts") + end +end + +describe Chef::Util::FileEdit, "search_file_delete_line" do + it "should search for match and delete the matching line" do + fedit = Chef::Util::FileEdit.new("./spec/data/fileedit/hosts") + fedit.search_file_delete_line(/localhost/) + fedit.write_file + newfile = File.new("./spec/data/fileedit/hosts").readlines + newfile[0].should_not match(/localhost/) + newfile[0].should match(/broadcasthost/) + File.delete("./spec/data/fileedit/hosts") + File.rename("./spec/data/fileedit/hosts.old", "./spec/data/fileedit/hosts") + end +end + +describe Chef::Util::FileEdit, "insert_line_after_match" do + it "should search for match and insert the given line after the matching line" do + fedit = Chef::Util::FileEdit.new("./spec/data/fileedit/hosts") + fedit.insert_line_after_match(/localhost/, "new line inserted") + fedit.write_file + newfile = File.new("./spec/data/fileedit/hosts").readlines + newfile[1].should match(/new/) + File.delete("./spec/data/fileedit/hosts") + File.rename("./spec/data/fileedit/hosts.old", "./spec/data/fileedit/hosts") + end + +end + + + + + + |