From: <jh...@us...> - 2009-02-06 17:20:53
|
Revision: 62 http://etch.svn.sourceforge.net/etch/?rev=62&view=rev Author: jheiss Date: 2009-02-06 17:20:51 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add the allow_nonexistent_dest element. Added that feature to etch a while ago but forgot to update the DTD. Modified Paths: -------------- trunk/etchserver-demo/config.dtd trunk/etchserver-samples/config.dtd Modified: trunk/etchserver-demo/config.dtd =================================================================== --- trunk/etchserver-demo/config.dtd 2009-02-06 17:19:54 UTC (rev 61) +++ trunk/etchserver-demo/config.dtd 2009-02-06 17:20:51 UTC (rev 62) @@ -28,7 +28,8 @@ <!ELEMENT template (#PCDATA)> <!ELEMENT script (#PCDATA)> -<!ELEMENT link (owner?, group?, perms?, overwrite_directory?, (dest|script)*)> +<!ELEMENT link (owner?, group?, perms?, allow_nonexistent_dest?, overwrite_directory?, (dest|script)*)> +<!ELEMENT allow_nonexistent_dest EMPTY> <!ELEMENT dest (#PCDATA)> <!ELEMENT directory (owner?, group?, perms?, (create|script)*)> Modified: trunk/etchserver-samples/config.dtd =================================================================== --- trunk/etchserver-samples/config.dtd 2009-02-06 17:19:54 UTC (rev 61) +++ trunk/etchserver-samples/config.dtd 2009-02-06 17:20:51 UTC (rev 62) @@ -28,7 +28,8 @@ <!ELEMENT template (#PCDATA)> <!ELEMENT script (#PCDATA)> -<!ELEMENT link (owner?, group?, perms?, overwrite_directory?, (dest|script)*)> +<!ELEMENT link (owner?, group?, perms?, allow_nonexistent_dest?, overwrite_directory?, (dest|script)*)> +<!ELEMENT allow_nonexistent_dest EMPTY> <!ELEMENT dest (#PCDATA)> <!ELEMENT directory (owner?, group?, perms?, (create|script)*)> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-04-02 00:20:23
|
Revision: 76 http://etch.svn.sourceforge.net/etch/?rev=76&view=rev Author: jheiss Date: 2009-04-02 00:20:11 +0000 (Thu, 02 Apr 2009) Log Message: ----------- Fix handling of operator comparisons in attribute filtering. Improve test for same. Rescue any exceptions in configfilter! where it is called by generate file so that we can insert the name of the config.xml file that we were handling when the exception occurred. This should help the user with debugging. Same logic as the exception catch/re-raise that occurs when running user scripts. Modified Paths: -------------- trunk/server/lib/etchserver.rb trunk/test/attributes.rb Modified: trunk/server/lib/etchserver.rb =================================================================== --- trunk/server/lib/etchserver.rb 2009-02-06 19:47:29 UTC (rev 75) +++ trunk/server/lib/etchserver.rb 2009-04-02 00:20:11 UTC (rev 76) @@ -344,7 +344,11 @@ config_xml = LibXML::XML::Document.file(config_xml_file) # Filter the config.xml file by looking for attributes - configfilter!(config_xml.root) + begin + configfilter!(config_xml.root) + rescue Exception => e + raise e.exception("Error filtering config.xml for #{file}:\n" + e.message) + end # Validate the filtered file against config.dtd if !config_xml.validate(@config_dtd) @@ -939,7 +943,7 @@ operator = $1 valueversion = Version.new($2) compversion = Version.new(comp) - if valueversion.send(operator.to_sym, compversion) + if compversion.send(operator.to_sym, valueversion) result = true end # Regular expressions Modified: trunk/test/attributes.rb =================================================================== --- trunk/test/attributes.rb 2009-02-06 19:47:29 UTC (rev 75) +++ trunk/test/attributes.rb 2009-04-02 00:20:11 UTC (rev 76) @@ -481,7 +481,17 @@ # Version fact operator comparison # testname = 'version fact operator comparison' - + + # Try to make up a subset of operatingsystemrelease so that we really + # test the operator functionality and not just equality. I.e. if osrel + # is 2.5.1 we'd like to extract 2.5 + osrelsubset = osrel + osrelparts = osrel.split('.') + if osrelparts.length > 1 + osrelparts.pop + osrelsubset = osrelparts.join('.') + end + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| file.puts <<-EOF @@ -489,7 +499,7 @@ <file> <warning_file/> <source> - <plain operatingsystemrelease=">=#{osrel}">source</plain> + <plain operatingsystemrelease=">=#{osrelsubset}">source</plain> </source> </file> </config> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-10-12 23:49:17
|
Revision: 116 http://etch.svn.sourceforge.net/etch/?rev=116&view=rev Author: jheiss Date: 2009-10-12 23:49:06 +0000 (Mon, 12 Oct 2009) Log Message: ----------- Add support for guarded commands http://sourceforge.net/apps/trac/etch/wiki/ConfigurationCommands Add local mode so that the etch client can work against a local config repository rather than a server. Rename etch.rb to etchclient.rb to reflect its purpose. Break out the code from etchserver.rb which is not server-specific to a separate file named etch.rb. Abstract the XML calls in that file so that either REXML or LibXML can be used. This will support future modifications to the client to allow the client to run in standalone mode against a local configuration repository. Abstract the XML response generation in Etch::Server so that the server does not depend on LibXML. All code should now fall back to REXML if LibXML is not available. Add in support for an xmllib environment variable that can be used to force the code to a particular XML library. Fix bug in configfilter! which was triggering a bug in LibXML Fix issues with timing around saving originals, for non-directories etch was saving the original the first time it was asked for the original contents or metadata from the server. Fix bug with ordering of creating backups and creating directory structure. Modified Paths: -------------- trunk/server/lib/etchserver.rb trunk/test/README trunk/test/TODO trunk/test/etchtest.rb trunk/test/outputcapture.rb Added Paths: ----------- trunk/client/etchclient.rb trunk/etchserver-demo/commands.dtd trunk/etchserver-samples/commands.dtd trunk/server/lib/etch.rb trunk/test/commands.rb trunk/test/testrepo/commands.dtd Removed Paths: ------------- trunk/client/etch.rb Deleted: trunk/client/etch.rb =================================================================== --- trunk/client/etch.rb 2009-10-12 23:44:00 UTC (rev 115) +++ trunk/client/etch.rb 2009-10-12 23:49:06 UTC (rev 116) @@ -1,2085 +0,0 @@ -############################################################################## -# Etch configuration file management tool library -############################################################################## - -begin - # Try loading facter w/o gems first so that we don't introduce a - # dependency on gems if it is not needed. - require 'facter' # Facter -rescue LoadError - require 'rubygems' - require 'facter' -end -require 'find' -require 'digest/sha1' # hexdigest -require 'openssl' # OpenSSL -require 'base64' # decode64, encode64 -require 'uri' -require 'net/http' -require 'net/https' -require 'rexml/document' -require 'fileutils' # copy, mkpath, rmtree -require 'fcntl' # Fcntl::O_* -require 'etc' # getpwnam, getgrnam -require 'tempfile' # Tempfile -require 'cgi' -require 'timeout' - -module Etch -end - -class Etch::Client - VERSION = '1.14' - - CONFIRM_PROCEED = 1 - CONFIRM_SKIP = 2 - CONFIRM_QUIT = 3 - PRIVATE_KEY_PATHS = ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh_host_rsa_key"] - - # We need these in relation to the output capturing - ORIG_STDOUT = STDOUT.dup - ORIG_STDERR = STDERR.dup - - attr_reader :exec_once_per_run - - def initialize(options) - @server = options[:server] ? options[:server] : 'https://etch' - @tag = options[:tag] - @varbase = options[:varbase] ? options[:varbase] : '/var/etch' - @debug = options[:debug] - @dryrun = options[:dryrun] - @interactive = options[:interactive] - @filenameonly = options[:filenameonly] - @fullfile = options[:fullfile] - @key = options[:key] ? options[:key] : get_private_key_path - @disableforce = options[:disableforce] - @lockforce = options[:lockforce] - - # Ensure we have a sane path, particularly since we are often run from - # cron. - # FIXME: Read from config file - ENV['PATH'] = '/bin:/usr/bin:/sbin:/usr/sbin:/opt/csw/bin:/opt/csw/sbin' - - # Make sure the server URL ends in a / so that we can append paths - # to it using URI.join - if @server !~ %r{/$} - @server << '/' - end - - @filesuri = URI.join(@server, 'files') - @resultsuri = URI.join(@server, 'results') - - @origbase = File.join(@varbase, 'orig') - @historybase = File.join(@varbase, 'history') - @lockbase = File.join(@varbase, 'locks') - @requestbase = File.join(@varbase, 'requests') - - @blankrequest = {} - @facts = Facter.to_hash - # If the user specified a non-standard key then override the sshrsakey - # fact so that authentication works - if @key - @facts['sshrsakey'] = IO.read(@key+'.pub').chomp.split[1] - end - @facts.each_pair { |key, value| @blankrequest["facts[#{key}]"] = value.to_s } - @blankrequest['fqdn'] = @facts['fqdn'] - if @facts['operatingsystemrelease'] - # Some versions of Facter have a bug that leaves extraneous - # whitespace on this fact. Work around that with strip. I.e. on - # CentOS you'll get '5 ' or '5.2 '. - @facts['operatingsystemrelease'].strip! - end - if @debug - @blankrequest['debug'] = '1' - end - if @tag - @blankrequest['tag'] = @tag - end - - @locked_files = {} - @first_update = {} - @already_processed = {} - @exec_already_processed = {} - @exec_once_per_run = {} - @results = [] - # See start/stop_output_capture for these - @output_pipes = [] - - @lchown_supported = nil - @lchmod_supported = nil - end - - def process_until_done(files_to_generate) - # Our overall status. Will be reported to the server and used as the - # return value for this method. Command-line clients should use it as - # their exit value. Zero indicates no errors. - status = 0 - message = '' - - http = Net::HTTP.new(@filesuri.host, @filesuri.port) - if @filesuri.scheme == "https" - # Eliminate the OpenSSL "using default DH parameters" warning - if File.exist?('/etc/etch/dhparams') - dh = OpenSSL::PKey::DH.new(IO.read('/etc/etch/dhparams')) - Net::HTTP.ssl_context_accessor(:tmp_dh_callback) - http.tmp_dh_callback = proc { dh } - end - http.use_ssl = true - if File.exist?('/etc/etch/ca.pem') - http.ca_file = '/etc/etch/ca.pem' - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - elsif File.directory?('/etc/etch/ca') - http.ca_path = '/etc/etch/ca' - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - end - end - http.start - - # catch/throw for expected/non-error events that end processing - # begin/raise for error events that end processing - catch :stop_processing do - begin - enabled, message = check_for_disable_etch_file - if !enabled - # 200 is the arbitrarily picked exit value indicating - # that etch is disabled - status = 200 - throw :stop_processing - end - remove_stale_lock_files - - # Assemble the initial request - request = get_blank_request - - if !files_to_generate.nil? && !files_to_generate.empty? - files_to_generate.each do |file| - request["files[#{CGI.escape(file)}][sha1sum]"] = get_orig_sum(file) - local_requests = get_local_requests(file) - if local_requests - request["files[#{CGI.escape(file)}][local_requests]"] = local_requests - end - end - else - request['files[GENERATEALL]'] = '1' - end - - # - # Loop back and forth with the server sending requests for files and - # responding to the server's requests for original contents or sums - # it needs - # - - Signal.trap('EXIT') do - STDOUT.reopen(ORIG_STDOUT) - STDERR.reopen(ORIG_STDERR) - unlock_all_files - end - - 10.times do - # - # Send request to server - # - - puts "Sending request to server #{@filesuri}: #{request.inspect}" if (@debug) - post = Net::HTTP::Post.new(@filesuri.path) - post.set_form_data(request) - sign_post!(post, @key) - response = http.request(post) - response_xml = nil - case response - when Net::HTTPSuccess - puts "Response from server:\n'#{response.body}'" if (@debug) - if !response.body.nil? && !response.body.empty? - response_xml = REXML::Document.new(response.body) - else - puts " Response is empty" if (@debug) - break - end - else - $stderr.puts response.body - # error! raises an exception - response.error! - end - - # - # Process the response from the server - # - - # Prep a clean request hash - request = get_blank_request - - # With generateall we expect to make at least two round trips to the server. - # 1) Send GENERATEALL request, get back a list of need_sums - # 2) Send sums, possibly get back some need_origs - # 3) Send origs, get back generated files - need_to_loop = false - reset_already_processed - # Process configs first, as they may contain setup entries that are - # needed to create the original files. - response_xml.root.elements.each('/files/configs/config') do |config| - file = config.attributes['filename'] - puts "Processing config for #{file}" if (@debug) - continue_processing = process(response_xml, file) - if !continue_processing - throw :stop_processing - end - end - response_xml.root.elements.each('/files/need_sums/need_sum') do |need_sum| - puts "Processing request for sum of #{need_sum.text}" if (@debug) - request["files[#{CGI.escape(need_sum.text)}][sha1sum]"] = get_orig_sum(need_sum.text) - local_requests = get_local_requests(need_sum.text) - if local_requests - request["files[#{CGI.escape(need_sum.text)}][local_requests]"] = local_requests - end - need_to_loop = true - end - response_xml.root.elements.each('/files/need_origs/need_orig') do |need_orig| - puts "Processing request for contents of #{need_orig.text}" if (@debug) - request["files[#{CGI.escape(need_orig.text)}][contents]"] = Base64.encode64(get_orig_contents(need_orig.text)) - request["files[#{CGI.escape(need_orig.text)}][sha1sum]"] = get_orig_sum(need_orig.text) - local_requests = get_local_requests(need_orig.text) - if local_requests - request["files[#{CGI.escape(need_orig.text)}][local_requests]"] = local_requests - end - need_to_loop = true - end - - if !need_to_loop - break - end - end - - puts "Processing 'exec once per run' commands" if (!exec_once_per_run.empty?) - exec_once_per_run.keys.each do |exec| - process_exec('post', exec) - end - rescue Exception => e - status = 1 - $stderr.puts e.message - $stderr.puts e.backtrace.join("\n") if @debug - end # begin/rescue - end # catch - - # Send results to server - if !@dryrun - rails_results = [] - # A few of the fields here are numbers or booleans and need a - # to_s to make them compatible with CGI.escape, which expects a - # string. - rails_results << "fqdn=#{CGI.escape(@facts['fqdn'])}" - rails_results << "status=#{CGI.escape(status.to_s)}" - rails_results << "message=#{CGI.escape(message)}" - @results.each do |result| - # Strangely enough this works. Even though the key is not unique to - # each result the Rails parameter parsing code keeps track of keys it - # has seen, and if it sees a duplicate it starts a new hash. - rails_results << "results[][file]=#{CGI.escape(result['file'])}" - rails_results << "results[][success]=#{CGI.escape(result['success'].to_s)}" - rails_results << "results[][message]=#{CGI.escape(result['message'])}" - end - puts "Sending results to server #{@resultsuri}" if (@debug) - resultspost = Net::HTTP::Post.new(@resultsuri.path) - # We have to bypass Net::HTTP's set_form_data method in this case - # because it expects a hash and we can't provide the results in the - # format we want in a hash because we'd have duplicate keys (see above). - results_as_string = rails_results.join('&') - resultspost.body = results_as_string - resultspost.content_type = 'application/x-www-form-urlencoded' - sign_post!(resultspost, @key) - response = http.request(resultspost) - case response - when Net::HTTPSuccess - puts "Response from server:\n'#{response.body}'" if (@debug) - else - $stderr.puts "Error submitting results:" - $stderr.puts response.body - end - end - - status - end - - def check_for_disable_etch_file - disable_etch = File.join(@varbase, 'disable_etch') - message = '' - if File.exist?(disable_etch) - if !@disableforce - message = "Etch disabled:\n" - message << IO.read(disable_etch) - puts message - return false, message - else - puts "Ignoring disable_etch file" - end - end - return true, message - end - - def get_blank_request - @blankrequest.dup - end - - # Raises an exception if any fatal error is encountered - # Returns a boolean, true unless the user indicated in interactive mode - # that further processing should be halted - def process(response_xml, file) - continue_processing = true - save_results = true - exception = nil - - # Skip files we've already processed in response to <depend> - # statements. - if @already_processed.has_key?(file) - puts "Skipping already processed #{file}" if (@debug) - return continue_processing - end - - # Prep the results capturing for this file - result = {} - result['file'] = file - result['success'] = true - result['message'] = '' - - # catch/throw for expected/non-error events that end processing - # begin/raise for error events that end processing - # Within this block you should throw :process_done if you've reached - # a natural stopping point and nothing further needs to be done. You - # should raise an exception if you encounter an error condition. - # Do not 'return' or 'abort'. - catch :process_done do - begin - start_output_capture - - puts "Processing #{file}" if (@debug) - - # The %locked_files hash provides a convenient way to - # detect circular dependancies. It doesn't give us an ordered - # list of dependencies, which might be handy to help the user - # debug the problem, but I don't think it's worth maintaining a - # seperate array just for that purpose. - if @locked_files.has_key?(file) - raise "Circular dependancy detected. " + - "Dependancy list (unsorted) contains:\n " + - @locked_files.keys.join(', ') - end - - # This needs to be after the circular dependency check - lock_file(file) - - # We have to make a new document so that XPath paths are referenced - # relative to the configuration for this specific file. - config = REXML::Document.new(response_xml.root.elements["/files/configs/config[@filename='#{file}']"].to_s) - - # Process any other files that this file depends on - config.elements.each('/config/depend') do |depend| - puts "Generating dependency #{depend.text}" if (@debug) - process(response_xml, depend.text) - end - - # See what type of action the user has requested - - # Check to see if the user has requested that we revert back to the - # original file. - if config.elements['/config/revert'] - origpathbase = File.join(@origbase, file) - - # Restore the original file if it is around - if File.exist?("#{origpathbase}.ORIG") - origpath = "#{origpathbase}.ORIG" - origdir = File.dirname(origpath) - origbase = File.basename(origpath) - filedir = File.dirname(file) - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - - puts "Restoring #{origpath} to #{file}" - recursive_copy_and_rename(origdir, origbase, file) if (!@dryrun) - - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - elsif File.exist?("#{origpathbase}.TAR") - origpath = "#{origpathbase}.TAR" - filedir = File.dirname(file) - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - - puts "Restoring #{file} from #{origpath}" - system("cd #{filedir} && tar xf #{origpath}") if (!@dryrun) - - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - elsif File.exist?("#{origpathbase}.NOORIG") - origpath = "#{origpathbase}.NOORIG" - puts "Original #{file} didn't exist, restoring that state" - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - end - - throw :process_done - end - - # Perform any setup commands that the user has requested. - # These are occasionally needed to install software that is - # required to generate the file (think m4 for sendmail.cf) or to - # install a package containing a sample config file which we - # then edit with a script, and thus doing the install in <pre> - # is too late. - if config.elements['/config/setup'] - process_setup(file, config) - end - - if config.elements['/config/file'] # Regular file - newcontents = nil - if config.elements['/config/file/contents'] - newcontents = Base64.decode64(config.elements['/config/file/contents'].text) - end - - permstring = config.elements['/config/file/perms'].text - perms = permstring.oct - owner = config.elements['/config/file/owner'].text - group = config.elements['/config/file/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - set_file_contents = false - if newcontents - set_file_contents = compare_file_contents(file, newcontents) - end - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a plain file then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_file_contents && (!File.file?(file) || File.symlink?(file)) - set_permissions = true - set_ownership = true - else - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - - # Proceed if: - # - The new contents are different from the current file - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_file_contents && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - else - # Tell the user what we're going to do - if set_file_contents - # If the new contents are different from the current file - # show that to the user in the format they've requested. - # If the requested permissions are not world-readable then - # use the filenameonly format so that we don't disclose - # non-public data, unless we're in interactive mode - if @filenameonly || (permstring.to_i(8) & 0004 == 0 && !@interactive) - puts "Will write out new #{file}" - elsif @fullfile - # Grab the first 8k of the contents - first8k = newcontents.slice(0, 8192) - # Then check it for null characters. If it has any it's - # likely a binary file. - hasnulls = true if (first8k =~ /\0/) - - if !hasnulls - puts "Generated contents for #{file}:" - puts "=============================================" - puts newcontents - puts "=============================================" - else - puts "Will write out new #{file}, but " + - "generated contents are not plain text so " + - "they will not be displayed" - end - else - # Default is to show a diff of the current file and the - # newly generated file. - puts "Will make the following changes to #{file}, diff -c:" - tempfile = Tempfile.new(File.basename(file)) - tempfile.write(newcontents) - tempfile.close - puts "=============================================" - if File.file?(file) && !File.symlink?(file) - system("diff -c #{file} #{tempfile.path}") - else - # Either the file doesn't currently exist, - # or is something other than a normal file - # that we'll be replacing with a file. In - # either case diffing against /dev/null will - # produce the most logical output. - system("diff -c /dev/null #{tempfile.path}") - end - puts "=============================================" - tempfile.delete - end - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/file/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Make sure the directory tree for this file exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # If the new contents are different from the current file, - # replace the file. - if set_file_contents - if !@dryrun - # Write out the new contents into a temporary file - filebase = File.basename(file) - filedir = File.dirname(file) - newfile = Tempfile.new(filebase, filedir) - - # Set the proper permissions on the file before putting - # data into it. - newfile.chmod(perms) - begin - newfile.chown(uid, gid) - rescue Errno::EPERM - raise if Process.euid == 0 - end - - puts "Writing new contents of #{file} to #{newfile.path}" if (@debug) - newfile.write(newcontents) - newfile.close - - # If the current file is not a plain file, remove it. - # Plain files are left alone so that the replacement is - # atomic. - if File.symlink?(file) || (File.exist?(file) && ! File.file?(file)) - puts "Current #{file} is not a plain file, removing it" if (@debug) - remove_file(file) - end - - # Move the new file into place - File.rename(newfile.path, file) - - # Check the permissions and ownership now to ensure they - # end up set properly - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - end - - # Ensure the permissions are set properly - if set_permissions - File.chmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - File.chown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/link'] # Symbolic link - - dest = config.elements['/config/link/dest'].text - - set_link_destination = compare_link_destination(file, dest) - absdest = File.expand_path(dest, File.dirname(file)) - - permstring = config.elements['/config/link/perms'].text - perms = permstring.oct - owner = config.elements['/config/link/owner'].text - group = config.elements['/config/link/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - # lchown and lchmod are not supported on many platforms. The server - # always includes ownership and permissions settings with any link - # (pulling them from defaults.xml if the user didn't specify them in - # the config.xml file.) As such link management would always fail - # on systems which don't support lchown/lchmod, which seems like bad - # behavior. So instead we check to see if they are implemented, and - # if not just ignore ownership/permissions settings. I suppose the - # ideal would be for the server to tell the client whether the - # ownership/permissions were specifically requested (in config.xml) - # rather than just defaults, and then for the client to always try to - # manage ownership/permissions if the settings are not defaults (and - # fail in the event that they aren't implemented.) - if @lchown_supported.nil? - lchowntestlink = Tempfile.new('etchlchowntest').path - lchowntestfile = Tempfile.new('etchlchowntest').path - File.delete(lchowntestlink) - File.symlink(lchowntestfile, lchowntestlink) - begin - File.lchown(0, 0, lchowntestfile) - @lchown_supported = true - rescue NotImplementedError - @lchown_supported = false - rescue Errno::EPERM - raise if Process.euid == 0 - end - File.delete(lchowntestlink) - end - if @lchmod_supported.nil? - lchmodtestlink = Tempfile.new('etchlchmodtest').path - lchmodtestfile = Tempfile.new('etchlchmodtest').path - File.delete(lchmodtestlink) - File.symlink(lchmodtestfile, lchmodtestlink) - begin - File.lchmod(0644, lchmodtestfile) - @lchmod_supported = true - rescue NotImplementedError - @lchmod_supported = false - end - File.delete(lchmodtestlink) - end - - set_permissions = false - if @lchmod_supported - # If the file is currently something other than a link then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_link_destination && !File.symlink?(file) - set_permissions = true - else - set_permissions = compare_permissions(file, perms) - end - end - set_ownership = false - if @lchown_supported - if set_link_destination && !File.symlink?(file) - set_ownership = true - else - set_ownership = compare_ownership(file, uid, gid) - end - end - - # Proceed if: - # - The new link destination differs from the current one - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_link_destination && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - # Check that the link destination exists, and refuse to create - # the link unless it does exist or the user told us to go ahead - # anyway. - # - # Note that the destination may be a relative path, and the - # target directory may not exist yet, so we have to convert the - # destination to an absolute path and test that for existence. - # expand_path should handle paths that are already absolute - # properly. - elsif ! File.exist?(absdest) && ! File.symlink?(absdest) && - ! config.elements['/config/link/allow_nonexistent_dest'] - puts "Destination #{dest} for link #{file} does not exist," + - " consider the allow_nonexistent_dest flag if appropriate." - throw :process_done - else - # Tell the user what we're going to do - if set_link_destination - puts "Linking #{file} -> #{dest}" - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/link/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Make sure the directory tree for this link exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # Create the link - if set_link_destination - remove_file(file) if (!@dryrun) - File.symlink(dest, file) if (!@dryrun) - - # Check the permissions and ownership now to ensure they - # end up set properly - if @lchmod_supported - set_permissions = compare_permissions(file, perms) - end - if @lchown_supported - set_ownership = compare_ownership(file, uid, gid) - end - end - - # Ensure the permissions are set properly - if set_permissions - # Note: lchmod - File.lchmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - # Note: lchown - File.lchown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/directory'] # Directory - - # A little safety check - create = config.elements['/config/directory/create'] - raise "No create element found in directory section" if !create - - permstring = config.elements['/config/directory/perms'].text - perms = permstring.oct - owner = config.elements['/config/directory/owner'].text - group = config.elements['/config/directory/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - set_directory = !File.directory?(file) || File.symlink?(file) - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a directory then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_directory - set_permissions = true - set_ownership = true - else - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - - # Proceed if: - # - The current file is not a directory - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_directory && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - else - # Tell the user what we're going to do - if set_directory - puts "Making directory #{file}" - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, false) - # Update the history log - save_history(file) - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Make sure the directory tree for this directory exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # Create the directory - if set_directory - remove_file(file) if (!@dryrun) - Dir.mkdir(file) if (!@dryrun) - - # Check the permissions and ownership now to ensure they - # end up set properly - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - - # Ensure the permissions are set properly - if set_permissions - File.chmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - File.chown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/delete'] # Delete whatever is there - - # A little safety check - proceed = config.elements['/config/delete/proceed'] - raise "No proceed element found in delete section" if !proceed - - # Proceed only if the file currently exists - if !File.exist?(file) && !File.symlink?(file) - throw :process_done - else - # Tell the user what we're going to do - puts "Removing #{file}" - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/delete/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Remove the file - remove_file(file) if (!@dryrun) - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - rescue Exception - result['success'] = false - exception = $! - end # End begin block - end # End :process_done catch block - - unlock_file(file) - - output = stop_output_capture - if exception - output << exception.message - output << exception.backtrace.join("\n") if @debug - end - result['message'] << output - if save_results - @results << result - end - - if exception - raise exception - end - - @already_processed[file] = true - - continue_processing - end - - # Returns true if the new contents are different from the current file, - # or if the file does not currently exist. - def compare_file_contents(file, newcontents) - r = false - - # If the file currently exists and is a regular file, check to see - # if the new contents are different. - if File.file?(file) && !File.symlink?(file) - contents = IO.read(file) - if newcontents != contents - r = true - end - else - # The file doesn't currently exist or isn't a regular file - r = true - end - - r - end - - # Returns true if the new link destination is different from the current - # link, or if the link does not currently exist. - def compare_link_destination(file, newdest) - r = false - - # If the file currently exists and is a link, check to see if the - # new destination is different. - if File.symlink?(file) - currentdest = File.readlink(file) - if currentdest != newdest - r = true - end - else - # The file doesn't currently exist or isn't a link - r = true - end - - r - end - - def get_orig_sum(file) - Digest::SHA1.hexdigest(get_orig_contents(file)) - end - def get_orig_contents(file) - origpath = save_orig(file) - orig_contents = nil - # We only send back the actual original file contents if the original is - # a regular file, otherwise we send back an empty string. - if origpath =~ /\.ORIG$/ && File.file?(origpath) && !File.symlink?(origpath) - orig_contents = IO.read(origpath) - else - orig_contents = '' - end - orig_contents - end - # Save an original copy of the file if that hasn't been done already. - # Return the path to that original copy. - def save_orig(file, save_directory_contents=nil) - origpathbase = File.join(@origbase, file) - origpath = nil - - if File.exist?("#{origpathbase}.ORIG") || File.symlink?("#{origpathbase}.ORIG") - origpath = "#{origpathbase}.ORIG" - elsif File.exist?("#{origpathbase}.NOORIG") - origpath = "#{origpathbase}.NOORIG" - elsif File.exist?("#{origpathbase}.TAR") - origpath = "#{origpathbase}.TAR" - elsif File.exist?("#{origpathbase}.DIRTMP") && save_directory_contents.nil? - origpath = "#{origpathbase}.DIRTMP" - else - # The original file has not yet been saved - first_update = true - - # Make sure the directory tree for this file exists in the - # directory we save originals in. - origdir = File.dirname(origpathbase) - if !File.directory?(origdir) - puts "Making directory tree #{origdir}" - FileUtils.mkpath(origdir) if (!@dryrun) - end - - if File.directory?(file) && !File.symlink?(file) - # The original "file" is a directory - if save_directory_contents - # Tar up the original directory - origpath = "#{origpathbase}.TAR" - filedir = File.dirname(file) - filebase = File.basename(file) - puts "Saving contents of original directory #{file}" - system("cd #{filedir} && tar cf #{origpath} #{filebase}") if (!@dryrun) - # There may be contents in that directory that the - # user doesn't want exposed. Without a way to know, - # the safest thing is to set restrictive permissions - # on the tar file. - File.chmod(0400, origpath) if (!@dryrun) - elsif save_directory_contents.nil? - # We have a timing issue, in that we generally save original - # files before we have the configuration for that file. For - # directories that's a problem, because we save directories - # differently depending on whether we're configuring them to - # remain a directory, or replacing the directory with something - # else (file or symlink). So if we don't have a definitive - # directive on how to save the directory - # (i.e. save_directory_contents is nil) then just save a - # placeholder until we do get a definitive directive. - origpath = "#{origpathbase}.DIRTMP" - puts "Creating temporary original placeholder for directory #{file}" - File.open(origpath, 'w') { |file| } if (!@dryrun) - first_update = nil - else - # Just create a directory in the originals repository with - # ownership and permissions to match the original directory. - origpath = "#{origpathbase}.ORIG" - st = File::Stat.new(file) - puts "Saving ownership/permissions of original directory" - Dir.mkdir(origpath, st.mode) if (!@dryrun) - begin - File.chown(st.uid, st.gid, origpath) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - elsif File.exist?(file) || File.symlink?(file) - # The original file exists, and is not a directory - origpath = "#{origpathbase}.ORIG" - puts "Saving original file: #{file} -> #{origpath}" - filedir = File.dirname(file) - filebase = File.basename(file) - recursive_copy_and_rename(filedir, filebase, origpath) if (!@dryrun) - else - origpath = "#{origpathbase}.NOORIG" - # If the original doesn't exist, we need to flag that so - # that we don't try to save our generated file as an - # original on future runs - puts "Original file doesn't exist: #{file}" - File.open(origpath, 'w') { |file| } if (!@dryrun) - end - - if !@first_update.has_key?(file) && !first_update.nil? - @first_update[file] = first_update - end - end - - # Remove the DIRTMP placeholder if it exists and no longer applies - if origpath !~ /\.DIRTMP$/ && File.exists?("#{origpathbase}.DIRTMP") - File.delete("#{origpathbase}.DIRTMP") - end - - origpath - end - - # This subroutine maintains a revision history for the file in @historybase - def save_history(file) - histpath = File.join(@historybase, "#{file}.HISTORY") - - # Make sure the directory tree for this file exists in the - # directory we save history in. - histdir = File.dirname(histpath) - if !File.directory?(histdir) - puts "Making directory tree #{histdir}" - FileUtils.mkpath(histdir) if (!@dryrun) - end - # Make sure the corresponding RCS directory exists as well. - histrcsdir = File.join(histdir, 'RCS') - if !File.directory?(histrcsdir) - puts "Making directory tree #{histrcsdir}" - FileUtils.mkpath(histrcsdir) if (!@dryrun) - end - - # If the history log doesn't exist and we didn't just create the - # original backup, that indicates that the original backup was made - # previously but the history log was not started at the same time. - # There are a variety of reasons why this might be the case (the - # original was saved by a previous version of etch that didn't have - # the history log feature, or the original was saved manually by - # someone) but whatever the reason is we want to use the original - # backup to start the history log before updating the history log - # with the current file. - if !File.exist?(histpath) && !@first_update[file] - origpath = save_orig(file) - if File.file?(origpath) && !File.symlink?(origpath) - puts "Starting history log with saved original file: " + - "#{origpath} -> #{histpath}" - FileUtils.copy(origpath, histpath) if (!@dryrun) - else - puts "Starting history log with 'ls -ld' output for " + - "saved original file: #{origpath} -> #{histpath}" - system("ls -ld #{origpath} > #{histpath} 2>&1") if (!@dryrun) - end - # Check the newly created history file into RCS - histbase = File.basename(histpath) - puts "Checking initial history log into RCS: #{histpath}" - if !@dryrun - # The -m flag shouldn't be needed, but it won't hurt - # anything and if something is out of sync and an RCS file - # already exists it will prevent ci from going interactive. - system( - "cd #{histdir} && " + - "ci -q -t-'Original of an etch modified file' " + - "-m'Update of an etch modified file' #{histbase} && " + - "co -q -r -kb #{histbase}") - end - set_history_permissions(file) - end - - # Copy current file - - # If the file already exists in RCS we need to check out a locked - # copy before updating it - histbase = File.basename(histpath) - rcsstatus = false - if !@dryrun - rcsstatus = system("cd #{histdir} && rlog -R #{histbase} > /dev/null 2>&1") - end - if rcsstatus - # set_history_permissions may set the checked-out file - # writeable, which normally causes co to abort. Thus the -f - # flag. - system("cd #{histdir} && co -q -l -f #{histbase}") if !@dryrun - end - - if File.file?(file) && !File.symlink?(file) - puts "Updating history log: #{file} -> #{histpath}" - FileUtils.copy(file, histpath) if (!@dryrun) - else - puts "Updating history log with 'ls -ld' output: " + - "#{histpath}" - system("ls -ld #{file} > #{histpath} 2>&1") if (!@dryrun) - end - - # Check the history file into RCS - puts "Checking history log update into RCS: #{histpath}" - if !@dryrun - # We only need one of the -t or -m flags depending on whether - # the history log already exists or not, rather than try to - # keep track of which one we need just specify both and let RCS - # pick the one it needs. - system( - "cd #{histdir} && " + - "ci -q -t-'Original of an etch modified file' " + - "-m'Update of an etch modified file' #{histbase} && " + - "co -q -r -kb #{histbase}") - end - - set_history_permissions(file) - end - - # Ensures that the history log file has appropriate permissions to avoid - # leaking information. - def set_history_permissions(file) - origpath = File.join(@origbase, "#{file}.ORIG") - histpath = File.join(@historybase, "#{file}.HISTORY") - - # We set the permissions to the more restrictive of the original - # file permissions and the current file permissions. - origperms = 0777 - if File.e... [truncated message content] |
From: <jh...@us...> - 2009-11-03 02:04:31
|
Revision: 135 http://etch.svn.sourceforge.net/etch/?rev=135&view=rev Author: jheiss Date: 2009-11-03 02:04:24 +0000 (Tue, 03 Nov 2009) Log Message: ----------- Loosen up the DTD a bit so that folks can filter with the same freedom as with configs. Modified Paths: -------------- trunk/etchserver-demo/commands.dtd trunk/etchserver-samples/commands.dtd trunk/test/testrepo/commands.dtd Modified: trunk/etchserver-demo/commands.dtd =================================================================== --- trunk/etchserver-demo/commands.dtd 2009-10-29 21:09:09 UTC (rev 134) +++ trunk/etchserver-demo/commands.dtd 2009-11-03 02:04:24 UTC (rev 135) @@ -3,8 +3,8 @@ <!ELEMENT depend (#PCDATA)> <!ELEMENT step (guard, command)> -<!ELEMENT guard (exec+)> -<!ELEMENT command (exec+)> +<!ELEMENT guard (exec*)> +<!ELEMENT command (exec*)> <!ELEMENT exec (#PCDATA)> Modified: trunk/etchserver-samples/commands.dtd =================================================================== --- trunk/etchserver-samples/commands.dtd 2009-10-29 21:09:09 UTC (rev 134) +++ trunk/etchserver-samples/commands.dtd 2009-11-03 02:04:24 UTC (rev 135) @@ -3,8 +3,8 @@ <!ELEMENT depend (#PCDATA)> <!ELEMENT step (guard, command)> -<!ELEMENT guard (exec+)> -<!ELEMENT command (exec+)> +<!ELEMENT guard (exec*)> +<!ELEMENT command (exec*)> <!ELEMENT exec (#PCDATA)> Modified: trunk/test/testrepo/commands.dtd =================================================================== --- trunk/test/testrepo/commands.dtd 2009-10-29 21:09:09 UTC (rev 134) +++ trunk/test/testrepo/commands.dtd 2009-11-03 02:04:24 UTC (rev 135) @@ -4,8 +4,8 @@ <!ELEMENT dependfile (#PCDATA)> <!ELEMENT step (guard, command)> -<!ELEMENT guard (exec+)> -<!ELEMENT command (exec+)> +<!ELEMENT guard (exec*)> +<!ELEMENT command (exec*)> <!ELEMENT exec (#PCDATA)> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-11-06 00:47:46
|
Revision: 137 http://etch.svn.sourceforge.net/etch/?rev=137&view=rev Author: jheiss Date: 2009-11-06 00:47:38 +0000 (Fri, 06 Nov 2009) Log Message: ----------- Fix bug where specific dependency structures requested in specific ways on the command line might never complete due to the client and server never getting on the same page such that a complete dependency tree can be calculated. Add test cases for same. See code comments for details. Modified Paths: -------------- trunk/server/lib/etch.rb trunk/test/options.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2009-11-06 00:43:46 UTC (rev 136) +++ trunk/server/lib/etch.rb 2009-11-06 00:47:38 UTC (rev 137) @@ -305,12 +305,43 @@ r = generate_commands(Etch.xmltext(dependcommand), request) proceed = proceed && r end + if !proceed @dlogger.debug "One or more dependencies of #{file} need data from client" + end + + # Make sure we have the original contents for this file + original_file = nil + if request[:files] && request[:files][file] && request[:files][file][:orig] + original_file = request[:files][file][:orig] + else + @dlogger.debug "Need original contents of #{file} from client" + proceed = false + end + + if !proceed + # If any file dependency failed to generate (due to a need for orig + # contents from the client) then we need to tell the client to request + # all of the files in the dependency tree again. + # + # For example, we have afile which depends on bfile and cfile. The + # user requests afile and bfile on the command line. The client sends + # sums for afile and bfile. The server sees the need for cfile's sum, so + # it sends back contents for bfile and a sum request for cfile and afile + # (since afile depends on bfile). The client sends sums for afile and + # cfile. The server sends back contents for cfile, and a sum request for + # bfile and afile. This repeats forever as the server isn't smart enough + # to ask for everything it needs and the client isn't smart enough to send + # everything. + depends.each { |depend| @need_orig[depend] = true } + # Tell the client to request this file again @need_orig[file] = true + # Strip this file's config down to the bare necessities filter_xml_completely!(config_xml, ['depend', 'setup']) + + # And hit the eject button generation_status = false throw :generate_done end @@ -341,24 +372,6 @@ end end end - - # Make sure we have the original contents for this file - original_file = nil - if request[:files] && request[:files][file] && request[:files][file][:orig] - original_file = request[:files][file][:orig] - else - @dlogger.debug "Need original contents of #{file} from client" - @need_orig[file] = true - # If there are setup commands defined for this file we need to - # pass those back along with our request for the original file, - # as the setup commands may be needed to create the original - # file on the node. - filter_xml_completely!(config_xml, ['depend', 'setup']) - # Nothing more can be done until we have the original file from - # the client - generation_status = false - throw :generate_done - end # Pull out any local requests local_requests = nil @@ -852,6 +865,7 @@ # If we encounter either failure or success we set it to false or :success. catch :generate_done do # Generate any other commands that this command depends on + dependfiles = [] proceed = true Etch.xmleach(commands_xml, '/commands/depend') do |depend| @dlogger.debug "Generating command dependency #{Etch.xmltext(depend)}" @@ -861,10 +875,17 @@ # Also generate any files that this command depends on Etch.xmleach(commands_xml, '/commands/dependfile') do |dependfile| @dlogger.debug "Generating file dependency #{Etch.xmltext(dependfile)}" + dependfiles << Etch.xmltext(dependfile) r = generate_file(Etch.xmltext(dependfile), request) proceed = proceed && r end if !proceed + @dlogger.debug "One or more dependencies of #{command} need data from client" + # If any file dependency failed to generate (due to a need for orig + # contents from the client) then we need to tell the client to request + # all of the files in the dependency tree again. See the big comment + # in generate_file for further explanation. + dependfiles.each { |dependfile| @need_orig[dependfile] = true } # Try again next time @retrycommands[command] = true generation_status = false Modified: trunk/test/options.rb =================================================================== --- trunk/test/options.rb 2009-11-06 00:43:46 UTC (rev 136) +++ trunk/test/options.rb 2009-11-06 00:47:38 UTC (rev 137) @@ -247,6 +247,183 @@ assert_equal(origcontents, get_file_contents(cmdtargetfile3), testname + ' cmd 3') end + def test_file_requests_with_depends + # + # Test that the user can request specific files and commands on the + # command line with a dependency structure such that, in the right + # circumstances, a poor implementation never completes because it + # alternately sends/requests the orig sum for the two dependencies, never + # sending both at the same time. + # + # For example, we have afile which depends on bfile and cfile. The user + # requests afile and bfile on the command line. The client sends sums for + # afile and bfile. The server sees the need for cfile's sum, so it sends + # back contents for bfile and a sum request for cfile and afile (since + # afile depends on bfile). The client sends sums for afile and cfile. + # The server sends back contents for cfile, and a sum request for bfile + # and afile. This repeats forever as the server isn't smart enough to ask + # for everything it needs and the client isn't smart enough to send + # everything. + # + # Yup, had this bug at one point. + # + testname = 'command line file requests with depends' + + targetfile2 = Tempfile.new('etchtest').path + targetfile3 = Tempfile.new('etchtest').path + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <depend>#{targetfile2}</depend> + <depend>#{targetfile3}</depend> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + FileUtils.mkdir_p("#{@repodir}/source/#{targetfile2}") + File.open("#{@repodir}/source/#{targetfile2}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + FileUtils.mkdir_p("#{@repodir}/source/#{targetfile3}") + File.open("#{@repodir}/source/#{targetfile3}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + [@targetfile, targetfile2, targetfile3].each do |target| + File.open("#{@repodir}/source/#{target}/source", 'w') do |file| + file.write(sourcecontents) + end + end + + # Run etch + #puts "Running '#{testname}' test" + run_etch(@port, @testbase, false, "#{@targetfile} #{targetfile2}") + + # Verify that all were created + assert_equal(sourcecontents, get_file_contents(@targetfile), testname + ' filesonly file 1') + assert_equal(sourcecontents, get_file_contents(targetfile2), testname + ' filesonly file 2') + assert_equal(sourcecontents, get_file_contents(targetfile3), testname + ' filesonly file 3') + end + + def test_mixed_requests_with_depends + # + # Similar to previous test, but mixing file and command requests + # + testname = 'mixed command line requests with depends' + + targetfile2 = Tempfile.new('etchtest').path + targetfile3 = Tempfile.new('etchtest').path + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <depend>#{targetfile2}</depend> + <depend>#{targetfile3}</depend> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + FileUtils.mkdir_p("#{@repodir}/source/#{targetfile2}") + File.open("#{@repodir}/source/#{targetfile2}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + FileUtils.mkdir_p("#{@repodir}/source/#{targetfile3}") + File.open("#{@repodir}/source/#{targetfile3}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + [@targetfile, targetfile2, targetfile3].each do |target| + File.open("#{@repodir}/source/#{target}/source", 'w') do |file| + file.write(sourcecontents) + end + end + + cmdtargetfile1 = Tempfile.new('etchtest').path + FileUtils.mkdir_p("#{@repodir}/commands/etchtest1") + File.open("#{@repodir}/commands/etchtest1/commands.xml", 'w') do |file| + file.puts <<-EOF + <commands> + <dependfile>#{targetfile2}</dependfile> + <dependfile>#{targetfile3}</dependfile> + <step> + <guard> + <exec>grep '#{testname}' #{cmdtargetfile1}</exec> + </guard> + <command> + <exec>printf '#{testname}' >> #{cmdtargetfile1}</exec> + </command> + </step> + </commands> + EOF + end + + # Put some text into the original files. + origcontents = "This is the original text\n" + [@targetfile, targetfile2, targetfile3, cmdtargetfile1].each do |target| + File.open(target, 'w') do |file| + file.write(origcontents) + end + end + + # Run etch + #puts "Running '#{testname}' test" + run_etch(@port, @testbase, false, "etchtest1 #{targetfile2}") + + # Verify that all were created + assert_equal(origcontents + testname, get_file_contents(cmdtargetfile1), testname + ' cmdandfile cmd 1') + assert_equal(sourcecontents, get_file_contents(targetfile2), testname + ' cmdandfile file 2') + assert_equal(sourcecontents, get_file_contents(targetfile3), testname + ' cmdandfile file 3') + end + def teardown stop_server(@pid) remove_repository(@repodir) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-11-11 00:59:18
|
Revision: 146 http://etch.svn.sourceforge.net/etch/?rev=146&view=rev Author: jheiss Date: 2009-11-11 00:59:11 +0000 (Wed, 11 Nov 2009) Log Message: ----------- Explicitly invoke user actions via "sh -c" so that syntax like "FOO=bar myprogram" works When generating commands remove any steps where the guard and command have been filtered out. Raise an exception if either the guard or command were filtered out but not both. Improve error message in all cases to try to help the user track down the offending entry. Modify check_for_inconsistency to allow for 0 elements. When preping a blank local request in the client set up the :commands hash if it will be needed. Modified Paths: -------------- trunk/client/etchclient.rb trunk/server/lib/etch.rb Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2009-11-11 00:53:48 UTC (rev 145) +++ trunk/client/etchclient.rb 2009-11-11 00:59:11 UTC (rev 146) @@ -308,6 +308,9 @@ if !responsedata[:need_origs].empty? request[:files] = {} end + if !responsedata[:retrycommands].empty? + request[:commands] = {} + end else request = get_blank_request end @@ -2038,7 +2041,9 @@ end end - r = system(exec) + # Explicitly invoke using /bin/sh so that syntax like + # "FOO=bar myprogram" works. + r = system('/bin/sh', '-c', exec) if exectype == 'post' || exectype == 'command' if etch_priority != 0 Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2009-11-11 00:53:48 UTC (rev 145) +++ trunk/server/lib/etch.rb 2009-11-11 00:59:11 UTC (rev 146) @@ -366,7 +366,9 @@ @dlogger.debug "Processing server setup commands" Etch.xmleach(config_xml, '/config/server_setup/exec') do |cmd| @dlogger.debug " Executing #{Etch.xmltext(cmd)}" - success = system(Etch.xmltext(cmd)) + # Explicitly invoke using /bin/sh so that syntax like + # "FOO=bar myprogram" works. + success = system('/bin/sh', '-c', Etch.xmltext(cmd)) if !success raise "Server setup command #{Etch.xmltext(cmd)} for file #{file} exited with non-zero value" end @@ -897,16 +899,33 @@ Dir::chdir "#{@commandsbase}/#{command}" # Check that the resulting document is consistent after filtering + remove = [] Etch.xmleach(commands_xml, '/commands/step') do |step| guard_exec_elements = Etch.xmlarray(step, 'guard/exec') if check_for_inconsistency(guard_exec_elements) - raise "Inconsistent guard 'exec' entries for #{command}" + raise "Inconsistent guard 'exec' entries for #{command}: " + + guard_exec_elements.collect {|elem| Etch.xmltext(elem)}.join(',') end command_exec_elements = Etch.xmlarray(step, 'command/exec') if check_for_inconsistency(command_exec_elements) - raise "Inconsistent command 'exec' entries for #{command}" + raise "Inconsistent command 'exec' entries for #{command}: " + + command_exec_elements.collect {|elem| Etch.xmltext(elem)}.join(',') end + # If filtering has removed both the guard and command elements + # we can remove this step. + if guard_exec_elements.empty? && command_exec_elements.empty? + remove << step + # If filtering has removed the guard but not the command or vice + # versa that's an error. + elsif guard_exec_elements.empty? + raise "Filtering removed guard, but left command: " + + Etch.xmltext(command_exec_elements.first) + elsif command_exec_elements.empty? + raise "Filtering removed command, but left guard: " + + Etch.xmltext(guard_exec_elements.first) + end end + remove.each { |elem| Etch.xmlremove(commands_xml, elem) } # I'm not sure if we'd benefit from further checking the XML for # validity. For now we declare success if we got this far. @@ -1050,7 +1069,7 @@ # contain the same value. Returns true if there is inconsistency. def check_for_inconsistency(elements) elements_as_text = elements.collect { |elem| Etch.xmltext(elem) } - if elements_as_text.uniq.length != 1 + if elements_as_text.uniq.length > 1 return true else return false This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-11-18 06:24:07
|
Revision: 175 http://etch.svn.sourceforge.net/etch/?rev=175&view=rev Author: jheiss Date: 2009-11-18 06:24:01 +0000 (Wed, 18 Nov 2009) Log Message: ----------- Add license file Modified Paths: -------------- trunk/README Added Paths: ----------- trunk/LICENSE Added: trunk/LICENSE =================================================================== --- trunk/LICENSE (rev 0) +++ trunk/LICENSE 2009-11-18 06:24:01 UTC (rev 175) @@ -0,0 +1,24 @@ +The MIT License + +etch 1.x Copyright (c) <2003> <Jason Heiss> + +etch 3.x is a derivative work of etch 1.x +Copyright (c) <2008,2009> <YELLOWPAGES.COM LLC> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. Modified: trunk/README =================================================================== --- trunk/README 2009-11-17 00:35:34 UTC (rev 174) +++ trunk/README 2009-11-18 06:24:01 UTC (rev 175) @@ -20,7 +20,7 @@ License ------------------------------------------------------------------------------ -License: MIT (http://www.opensource.org/licenses/mit-license.php) +License: MIT (see LICENSE file) ------------------------------------------------------------------------------ Credits This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-12-03 23:01:22
|
Revision: 178 http://etch.svn.sourceforge.net/etch/?rev=178&view=rev Author: jheiss Date: 2009-12-03 23:01:12 +0000 (Thu, 03 Dec 2009) Log Message: ----------- Replace alltests.rb with a rake task so that we're a little more standard. Requires updating file paths in a lot of the test code so that tests can be run from a different directory. Rather than starting a new instance of the etch server for every test start one only if needed and reuse it. Cuts the time to run the entire test suite in half. Modified Paths: -------------- trunk/test/README trunk/test/actions.rb trunk/test/attributes.rb trunk/test/auth.rb trunk/test/commands.rb trunk/test/delete.rb trunk/test/depend.rb trunk/test/etchtest.rb trunk/test/file.rb trunk/test/history.rb trunk/test/link.rb trunk/test/local_requests.rb trunk/test/nodegroups.rb trunk/test/options.rb trunk/test/outputcapture.rb trunk/test/scripts.rb trunk/test/transitions.rb Added Paths: ----------- trunk/Rakefile Removed Paths: ------------- trunk/test/alltests.rb Added: trunk/Rakefile =================================================================== --- trunk/Rakefile (rev 0) +++ trunk/Rakefile 2009-12-03 23:01:12 UTC (rev 178) @@ -0,0 +1,14 @@ +require 'rake/testtask' + +# rake test +Rake::TestTask.new do |t| + # If the user hasn't already set the xmllib environment variable then set it + # to use LibXML so that the tests involving DTD validation are run. + if !ENV['xmllib'] + ENV['xmllib'] = 'libxml' + end + + t.verbose = true + #t.pattern = 'test/*.rb' + t.test_files = Dir.glob('test/*.rb').reject {|test| test =~ /etchtest.rb/} +end Modified: trunk/test/README =================================================================== --- trunk/test/README 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/README 2009-12-03 23:01:12 UTC (rev 178) @@ -1,7 +1,8 @@ -To execute all tests run alltests.rb +To execute all tests run "rake test". +To execute the tests in a specific file run "rake test TEST=test/file.rb". +To execute a specific test method run + "rake test TEST=test/file.rb TESTOPTS='--name=test_files'" -You can also run the individual .rb test files to test specific areas. - To force a particular XML library set xmllib=libxml or xmllib=rexml in your environment before running the tests. Modified: trunk/test/actions.rb =================================================================== --- trunk/test/actions.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/actions.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of various actions: pre, post, setup, test, etc. # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchActionTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -79,7 +76,7 @@ # Run etch #puts "Running initial action test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the actions were executed # The setup actions will get run several times as we loop @@ -103,7 +100,7 @@ # Run etch again and make sure that the exec_once command wasn't run # again - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal("exec_once\n", get_file_contents("#{@repodir}/exec_once"), 'exec_once_2nd_check') end @@ -145,7 +142,7 @@ # Run etch #puts "Running initial action test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), 'failed setup') @@ -188,7 +185,7 @@ # Run etch #puts "Running failed pre test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), 'failed pre') @@ -237,7 +234,7 @@ # Run etch #puts "Running failed test test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the original was restored, and that post was run twice assert_equal(origcontents, get_file_contents(@targetfile), 'failed test target') @@ -273,7 +270,7 @@ # Run etch #puts "Running failed test_before_post test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that post was not run assert(!File.exist?("#{@repodir}/post"), 'failed test_before_post post') @@ -289,7 +286,7 @@ # Run etch #puts "Running failed test symlink test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the original symlink was restored assert_equal(@destfile, File.readlink(@targetfile), 'failed test symlink') @@ -306,7 +303,7 @@ # Run etch #puts "Running failed test directory test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the original directory was restored assert(File.directory?(@targetfile), 'failed test directory') @@ -328,7 +325,7 @@ # Run etch #puts "Running failed test no original file test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the lack of an original file was restored assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), 'failed test no original file') @@ -376,7 +373,7 @@ # Run etch #puts "Running nested target with test test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(nestedtargetfile), 'nested target with test') @@ -417,7 +414,7 @@ # Run etch #puts "Running XML escape test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the action was executed assert_equal("post\n", get_file_contents("#{@repodir}/post_with_escape"), 'post with escape') @@ -460,14 +457,13 @@ # Run etch #puts "Running environment variable test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the action was executed assert_equal("testvalue\n", get_file_contents("#{@repodir}/post_with_env_output"), 'post with environment variable') end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Deleted: trunk/test/alltests.rb =================================================================== --- trunk/test/alltests.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/alltests.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -1,20 +0,0 @@ -#!/usr/bin/ruby -w - -# Some of the tests involve DTD validation. For that we need LibXML. -ENV['xmllib'] = 'libxml' - -# -# Run all of the etch test cases -# - -require 'test/unit' -Dir.chdir(File.dirname(__FILE__)) -Dir.foreach('.') do |entry| - next unless entry =~ /\.rb$/ - # Skip this file - next if entry == 'alltests.rb' - # And the shared file - next if entry == 'etchtest.rb' - - require entry -end Modified: trunk/test/attributes.rb =================================================================== --- trunk/test/attributes.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/attributes.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of attribute filtering in config.xml files # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') require 'rubygems' # Might be needed to find facter require 'facter' @@ -21,7 +18,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -63,7 +60,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -94,7 +91,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -139,7 +136,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -178,7 +175,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -209,7 +206,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -255,7 +252,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -294,7 +291,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -325,7 +322,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -364,7 +361,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -403,7 +400,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -434,7 +431,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -473,7 +470,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -514,7 +511,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -553,7 +550,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -589,7 +586,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -620,7 +617,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -628,7 +625,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/auth.rb =================================================================== --- trunk/test/auth.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/auth.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of client authentication # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') require 'net/http' require 'rexml/document' require 'facter' @@ -22,7 +19,10 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + # These tests set an etchserver.conf. The server only reads that file + # once and caches the settings, so we need to start up new server + # instances for these tests rather than reusing the global test server. + @server = start_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -30,7 +30,7 @@ # Make sure the server will initially think this is a new client hostname = Facter['fqdn'].value - Net::HTTP.start('localhost', @port) do |http| + Net::HTTP.start('localhost', @server[:port]) do |http| # Find our client id response = http.get("/clients.xml?name=#{hostname}") if !response.kind_of?(Net::HTTPSuccess) @@ -84,7 +84,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -115,7 +115,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -154,7 +154,7 @@ # Run etch with the wrong key to force a bad signature #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true, '--key=keys/testkey2') + run_etch(@server, @testbase, true, "--key=#{File.join(File.dirname(__FILE__), 'keys', 'testkey2')}") # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -200,7 +200,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -212,9 +212,9 @@ puts "# Starting a second copy of the server and adding this client to the database" sleep 3 repodir2 = initialize_repository - port2, pid2 = start_server(repodir2) - run_etch(port2, @testbase) - stop_server(pid2) + server2 = start_server(repodir2) + run_etch(server2, @testbase) + stop_server(server2) remove_repository(repodir2) # @@ -243,14 +243,14 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) end def teardown - stop_server(@pid) + stop_server(@server) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/commands.rb =================================================================== --- trunk/test/commands.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/commands.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of configuration commands # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchCommandTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -50,7 +47,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(testname, get_file_contents(@targetfile), testname) @@ -82,7 +79,7 @@ # The assertion here is handled by run_etch as we're passing it an # argument indicating that we expect failure. #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) end def test_commands_guard_succeeds @@ -111,7 +108,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was not touched assert_equal(testname, get_file_contents(@targetfile), testname) @@ -149,7 +146,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that both steps ran and in the proper order assert_equal("firststep\nsecondstep\n", get_file_contents(@targetfile), testname) @@ -194,7 +191,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that both commands ran, ordering doesn't matter assert_equal(['firstcmd', 'secondcmd'], get_file_contents(@targetfile).split("\n").sort, testname) @@ -240,7 +237,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that both commands ran and in the proper order assert_equal("firstcmd\nsecondcmd\n", get_file_contents(@targetfile), testname) @@ -294,7 +291,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the command-generated file and the regular file were created # properly @@ -339,7 +336,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that only the desired step executed assert_equal("notingroup\n", get_file_contents(@targetfile), testname) @@ -366,11 +363,10 @@ # The assertion here is handled by run_etch as we're passing it an # argument indicating that we expect failure. #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/delete.rb =================================================================== --- trunk/test/delete.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/delete.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of deleting files # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchDeleteTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -50,7 +47,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -76,7 +73,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -104,7 +101,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the directory was not deleted assert(File.directory?(@targetfile), testname) @@ -133,7 +130,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the directory was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -156,7 +153,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that we still don't have a file. That's rather unlikely, # this is really more a test that etch doesn't throw an error if @@ -190,7 +187,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert(!File.exist?(@targetfile), 'duplicate script instructions') @@ -223,7 +220,7 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file wasn't removed assert(File.exist?(@targetfile), 'contradictory script instructions') @@ -231,7 +228,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/depend.rb =================================================================== --- trunk/test/depend.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/depend.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of dependencies # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchDependTests < Test::Unit::TestCase include EtchTests @@ -21,7 +18,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -79,7 +76,7 @@ # Run etch #puts "Running initial dependency test" - run_etch(@port, @testbase, false) + run_etch(@server, @testbase, false) # Verify that the files were created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'dependency file 1') @@ -141,7 +138,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, false, @targetfile) + run_etch(@server, @testbase, false, @targetfile) # Verify that the files were created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'single request dependency file 1') @@ -205,7 +202,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true, @targetfile) + run_etch(@server, @testbase, true, @targetfile) # Verify that the files weren't modified assert_equal(origcontents, get_file_contents(@targetfile), 'circular dependency file 1') @@ -259,7 +256,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the regular file and the command-generated file were created # properly @@ -270,7 +267,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/etchtest.rb =================================================================== --- trunk/test/etchtest.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/etchtest.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -2,12 +2,15 @@ # Module of code shared by all of the etch test cases # +require 'test/unit' require 'tempfile' require 'fileutils' -ENV['RUBYLIB'] = '../server/lib' - module EtchTests + # Roughly ../server and ../client + SERVERDIR = "#{File.dirname(File.dirname(__FILE__))}/server" + CLIENTDIR = "#{File.dirname(File.dirname(__FILE__))}/client" + # Haven't found a Ruby method for creating temporary directories, # so create a temporary file and replace it with a directory. def tempdir @@ -17,18 +20,18 @@ Dir.mkdir(tmpdir) tmpdir end - - def initialize_repository(nodegroups = []) + + def initialize_repository(nodegroups=[]) # Generate a temp directory to put our test repository into - repodir = tempdir - + repo = tempdir + # Put the basic files into that directory needed for a basic etch tree - FileUtils.cp_r(Dir.glob('testrepo/*'), repodir) - + FileUtils.cp_r(Dir.glob("#{File.dirname(__FILE__)}/testrepo/*"), repo) + hostname = `facter fqdn`.chomp nodegroups_string = '' nodegroups.each { |ng| nodegroups_string << "<group>#{ng}</group>\n" } - File.open(File.join(repodir, 'nodes.xml'), 'w') do |file| + File.open(File.join(repo, 'nodes.xml'), 'w') do |file| file.puts <<-EOF <nodes> <node name="#{hostname}"> @@ -38,65 +41,87 @@ EOF end - puts "Created repository #{repodir}" + puts "Created repository #{repo}" - repodir + repo end - - def remove_repository(repodir) - FileUtils.rm_rf(repodir) + + def remove_repository(repo) + FileUtils.rm_rf(repo) end - + + @@server = nil + def get_server(newrepo=nil) + if !@@server + @@server = start_server + end + if newrepo + swap_repository(@@server, newrepo) + end + @@server + end + + def swap_repository(server, newrepo) + # Point server[:repo] symlink to newrepo + FileUtils.rm_f(server[:repo]) + File.symlink(newrepo, server[:repo]) + end + UNICORN = false - def start_server(repodir) - ENV['etchserverbase'] = repodir + def start_server(repo='no_repo_yet') + # We want the running server's notion of the server base to be a symlink + # that we can easily change later in swap_repository. + serverbase = Tempfile.new('etchtest').path + File.delete(serverbase) + File.symlink(repo, serverbase) + ENV['etchserverbase'] = serverbase # Pick a random port in the 3001-6000 range (range somewhat randomly chosen) port = 3001 + rand(3000) if pid = fork puts "Giving the server some time to start up" sleep(5) else - Dir.chdir('../server') if UNICORN - exec("unicorn_rails -p #{port}") + exec("cd #{SERVERDIR} && unicorn_rails -p #{port}") else - exec("./script/server -p #{port}") + exec("cd #{SERVERDIR} && ./script/server -p #{port}") end end - [port, pid] + {:port => port, :pid => pid, :repo => serverbase} end - - def stop_server(pid) - Process.kill('TERM', pid) - Process.waitpid(pid) + + def stop_server(server) + Process.kill('TERM', server[:pid]) + Process.waitpid(server[:pid]) end - - def run_etch(port, testbase, errors_expected=false, extra_args='') - #extra_args = extra_args + " --debug" + + def run_etch(server, testbase, errors_expected=false, extra_args='') + extra_args = extra_args + " --debug" if errors_expected # Warn the user that errors are expected. Otherwise it can be # disconcerting if you're watching the tests run and see errors. - sleep 3 + #sleep 3 puts "#" puts "# Errors expected here" puts "#" #sleep 3 end - result = system("ruby ../client/etch --generate-all --server=http://localhost:#{port} --test-base=#{testbase} --key=keys/testkey #{extra_args}") + result = system("ruby #{CLIENTDIR}/etch --generate-all --server=http://localhost:#{server[:port]} --test-base=#{testbase} --key=#{File.dirname(__FILE__)}/keys/testkey #{extra_args}") if errors_expected assert(!result) else assert(result) end end - + + # Wrap File.read and return nil if an exception occurs def get_file_contents(file) # Don't follow symlinks if File.file?(file) && !File.symlink?(file) # Trap exceptions (like non-existent file) so that tests can # properly report back whether the file contents match or not. begin - IO.read(file) + File.read(file) rescue nil end Modified: trunk/test/file.rb =================================================================== --- trunk/test/file.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/file.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of creating and updating regular files # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchFileTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -52,7 +49,7 @@ # Run etch #puts "Running initial file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -89,7 +86,7 @@ # Run etch #puts "Running initial file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -130,7 +127,7 @@ # Run etch #puts "Running different warning file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -167,7 +164,7 @@ # Run etch #puts "Running no warning file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'no warning file') @@ -197,7 +194,7 @@ # Run etch #puts "Running different line comment test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -236,7 +233,7 @@ # Run etch #puts "Running comment open/close test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = "/*\n" @@ -276,7 +273,7 @@ # Run etch #puts "Running warning on second line test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = sourcecontents_firstline @@ -314,7 +311,7 @@ # Run etch #puts "Running no space around warning test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -347,7 +344,7 @@ # Run etch #puts "Running file ownership and permissions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file ownership got set correctly # Most systems don't support give-away chown, so this test won't work @@ -383,7 +380,7 @@ # Run etch #puts "Running file ownership w/ bogus owner/group names" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the ownership defaulted to UID/GID 0 # Most systems don't support give-away chown, so this test won't work @@ -419,7 +416,7 @@ # Run etch #puts "Running always_manage_metadata test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file permissions got set correctly perms = File.stat(@targetfile).mode & 07777 @@ -459,7 +456,7 @@ # Run etch #puts "Running duplicate plain instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate plain instructions') @@ -498,7 +495,7 @@ # Run etch #puts "Running contradictory plain instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory plain instructions') @@ -534,7 +531,7 @@ # Run etch #puts "Running duplicate template instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate template instructions') @@ -573,7 +570,7 @@ # Run etch #puts "Running contradictory template instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory template instructions') @@ -609,7 +606,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate script instructions') @@ -648,7 +645,7 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory script instructions') @@ -687,14 +684,13 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(specialtargetfile), testname) end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/history.rb =================================================================== --- trunk/test/history.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/history.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -5,10 +5,7 @@ # history files # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchHistoryTests < Test::Unit::TestCase include EtchTests @@ -20,7 +17,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -64,7 +61,7 @@ # Run etch #puts "Running initial history test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(origcontents, get_file_contents(origfile), 'original backup of file') system("cd #{historydir} && co -q -f -r1.1 #{historyfile}") @@ -87,7 +84,7 @@ # Run etch #puts "Running update test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(origcontents, get_file_contents(origfile), 'original backup of file unchanged') assert_equal(updatedsourcecontents, get_file_contents(historyfile), 'history log of file updated') @@ -117,7 +114,7 @@ # Run etch #puts "Running revert test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(origcontents, get_file_contents(@targetfile), 'original contents reverted') @@ -133,7 +130,7 @@ # Run etch #puts "Running revert test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(updatedorigcontents, get_file_contents(@targetfile), 'Updated original contents unchanged') end @@ -181,7 +178,7 @@ # Run etch #puts "Running history setup test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(origcontents + "\n", get_file_contents(origfile), 'original backup of file via setup') assert_equal(sourcecontents + origcontents + "\n", get_file_contents(@targetfile), 'contents using original backup of file via setup') @@ -221,7 +218,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") origcontents = "This is the original text for #{testname}" @@ -250,7 +247,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(origcontents + "\n", get_file_contents(origfile), testname) end @@ -292,7 +289,7 @@ # Run etch #puts "Running history link test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(origfile), 'original backup of link') system("cd #{historydir} && co -q -f -r1.1 #{historyfile}") @@ -342,7 +339,7 @@ # Run etch #puts "Running history directory test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert(File.directory?(origfile), 'original backup of directory') # Verify that etch backed up the original directory properly @@ -393,7 +390,7 @@ # Run etch #puts "Running history directory contents test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # In this case, because we converted a directory to something else the # original will be a tarball of the directory @@ -404,7 +401,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/link.rb =================================================================== --- trunk/test/link.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/link.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of creating and updating symbolic links # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') require 'pathname' class EtchLinkTests < Test::Unit::TestCase @@ -24,7 +21,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -54,7 +51,7 @@ # Run etch #puts "Running initial link test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'link create') @@ -75,7 +72,7 @@ # Run etch #puts "Running link update test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile2, File.readlink(@targetfile), 'link update') @@ -104,7 +101,7 @@ # Run etch #puts "Running link update from non-existent file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'link update from non-existent file') end @@ -130,7 +127,7 @@ # Run etch #puts "Running link to non-existent destination test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link was not created assert(!File.symlink?(@targetfile), 'link to non-existent destination') @@ -154,7 +151,7 @@ # Run etch #puts "Running link to non-existent destination with override test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link was updated properly assert_equal(@destfile, File.readlink(@targetfile), 'link to non-existent destination with override') @@ -183,7 +180,7 @@ # Run etch #puts "Running relative link test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link was updated properly assert_equal(reldestfile, File.readlink(@targetfile), 'relative link') @@ -210,7 +207,7 @@ # Run etch #puts "Running link ownership and permissions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link ownership got set correctly # Most systems don't support give-away chown, so this test won't work @@ -245,7 +242,7 @@ # Run etch #puts "Running duplicate dest instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'duplicate dest instructions') end @@ -269,7 +266,7 @@ # Run etch #puts "Running contradictory dest instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the link wasn't created assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory dest instructions') @@ -298,7 +295,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'duplicate script instructions') end @@ -329,14 +326,13 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the link wasn't created assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory script instructions') end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/local_requests.rb =================================================================== --- trunk/test/local_requests.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/local_requests.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of local requests # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchLocalRequestsTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -71,7 +68,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -123,7 +120,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly # Our whitespace in the heredoc above gets added to the generated file, so @@ -133,7 +130,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/nodegroups.rb =================================================================== --- trunk/test/nodegroups.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/nodegroups.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test etch's handling of node groups and the node group hierarchy # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchNodeGroupTests < Test::Unit::TestCase include EtchTests @@ -20,7 +17,7 @@ # Generate a directory for our test repository # Specify that the node should be put into 'testgroup' in nodes.xml @repodir = initialize_repository(['testgroup']) - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -54,7 +51,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -95,7 +92,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -136,7 +133,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -180,14 +177,13 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that the file wasn't modified assert_equal(oldsourcecontents, get_file_contents(@targetfile), testname) end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/options.rb =================================================================== --- trunk/test/options.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/options.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,10 +4,7 @@ # Test command line options to etch client # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchOptionTests < Test::Unit::TestCase include EtchTests @@ -19,7 +16,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -64,7 +61,7 @@ # Run etch #puts "Running killswitch test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) assert_equal(origcontents, get_file_contents(@targetfile), 'killswitch') end @@ -102,14 +99,14 @@ # Run etch #puts "Running --dry-run test" - run_etch(@port, @testbase, false, '--dry-run') + run_etch(@server, @testbase, false, '--dry-run') assert_equal(origcontents, get_file_contents(@targetfile), '--dry-run') end def test_help output = nil - IO.popen("ruby ../client/etch --help") do |pipe| + IO.popen("ruby #{CLIENTDIR}/etch --help") do |pipe| output = pipe.readlines end # Make sure at least something resembling help output is there @@ -235,7 +232,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, false, "#{@targetfile} #{targetfile2} etchtest1 etchtest2") + run_etch(@server, @testbase, false, "#{@targetfile} #{targetfile2} etchtest1 etchtest2") # Verify that only the requested files were created assert_equal(sourcecontents, get_file_contents(@targetfile), testname + ' file 1') @@ -322,7 +319,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, false, "#{@targetfile} #{targetfile2}") + run_etch(@server, @testbase, false, "#{@targetfile} #{targetfile2}") # Verify that all were created assert_equal(sourcecontents, get_file_contents(@targetfile), testname + ' filesonly file 1') @@ -416,7 +413,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase, false, "etchtest1 #{targetfile2}") + run_etch(@server, @testbase, false, "etchtest1 #{targetfile2}") # Verify that all were created assert_equal(origcontents + testname, get_file_contents(cmdtargetfile1), testname + ' cmdandfile cmd 1') @@ -425,7 +422,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/outputcapture.rb =================================================================== --- trunk/test/outputcapture.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/outputcapture.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -4,13 +4,10 @@ # Test output capturing # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') require 'timeout' -$: << '../client' -$: << '../server/lib' +$: << EtchTests::CLIENTDIR +$: << File.join(EtchTests::SERVERDIR, 'lib') require 'etchclient' class EtchOutputCaptureTests < Test::Unit::TestCase @@ -23,7 +20,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -69,13 +66,13 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Fetch the latest result for this client from the server and verify that # it contains the output from the post command. hostname = Facter['fqdn'].value latest_result_message = '' - Net::HTTP.start('localhost', @port) do |http| + Net::HTTP.start('localhost', @server[:port]) do |http| response = http.get("/results.xml?clients.name=#{hostname}&sort=created_at_reverse") if !response.kind_of?(Net::HTTPSuccess) response.error! @@ -125,7 +122,7 @@ # NOTE: This test is not normally run because the timeout is so long. # Uncomment this run_etch line to run this test. # - #run_etch(@port, @testbase) + #run_etch(@server, @testbase) end rescue Timeout::Error flunk('output capturing did not time out as expected') @@ -133,7 +130,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/scripts.rb =================================================================== --- trunk/test/scripts.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/scripts.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -5,10 +5,7 @@ # creation of links and directories, and control the deletion of files # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchScriptTests < Test::Unit::TestCase include EtchTests @@ -20,7 +17,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -63,7 +60,7 @@ # Run etch #puts "Running script with syntax error test" - run_etch(@port, @testbase, true) + run_etch(@server, @testbase, true) # Verify that etch didn't do anything to the file assert_equal(before_size, File.stat(@targetfile).size, 'script with syntax error size comparison') @@ -96,7 +93,7 @@ # Run etch #puts "Running script with no output" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that etch didn't do anything to the file assert_equal(before_size, File.stat(@targetfile).size, 'script with no output size comparison') @@ -126,7 +123,7 @@ # Run etch #puts "Running file script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -167,7 +164,7 @@ # Run etch #puts "Running file source script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -207,7 +204,7 @@ # Run etch #puts "Running file source script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly correctcontents = '' @@ -243,7 +240,7 @@ # Run etch #puts "Running link script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the link was created properly assert_equal(@destfile, File.readlink(@targetfile), 'link script') @@ -274,7 +271,7 @@ # Run etch #puts "Running link script with no output" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that etch didn't do anything to the file assert_equal(before_readlink, File.readlink(@targetfile), 'link script with no output readlink comparison') @@ -301,7 +298,7 @@ # Run etch #puts "Running directory script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the directory was created assert(File.directory?(@targetfile), 'directory script') @@ -336,7 +333,7 @@ # Run etch #puts "Running directory script with no output" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that etch didn't do anything to the file assert_equal(before_size, File.stat(@targetfile).size, 'directory script with no output size comparison') @@ -364,7 +361,7 @@ # Run etch #puts "Running delete script test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was removed assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), 'delete script') @@ -401,7 +398,7 @@ # Run etch #puts "Running delete script with no output" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that etch didn't do anything to the file assert_equal(before_size, File.stat(@targetfile).size, 'delete script with no output size comparison') @@ -409,7 +406,6 @@ end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) Modified: trunk/test/transitions.rb =================================================================== --- trunk/test/transitions.rb 2009-11-23 22:04:44 UTC (rev 177) +++ trunk/test/transitions.rb 2009-12-03 23:01:12 UTC (rev 178) @@ -5,10 +5,7 @@ # file, etc.) # -require 'test/unit' -require 'etchtest' -require 'tempfile' -require 'fileutils' +require File.join(File.dirname(__FILE__), 'etchtest') class EtchTransitionTests < Test::Unit::TestCase include EtchTests @@ -20,7 +17,7 @@ # Generate a directory for our test repository @repodir = initialize_repository - @port, @pid = start_server(@repodir) + @server = get_server(@repodir) # Create a directory to use as a working directory for the client @testbase = tempdir @@ -61,7 +58,7 @@ # Run etch #puts "Running file to link test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'file to link') @@ -86,7 +83,7 @@ # Run etch #puts "Running file to directory test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert(File.directory?(@targetfile), 'file to directory') end @@ -121,7 +118,7 @@ # Run etch #puts "Running link to file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'link to file') @@ -160,7 +157,7 @@ # Run etch #puts "Running link w/ same contents to file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'link w/ same contents to file') @@ -186,7 +183,7 @@ # Run etch #puts "Running link to directory test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert(File.directory?(@targetfile), 'link to directory') end @@ -222,7 +219,7 @@ # Run etch #puts "Running directory to file test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'directory to file') @@ -249,13 +246,12 @@ # Run etch #puts "Running directory to link test" - run_etch(@port, @testbase) + run_etch(@server, @testbase) assert_equal(@destfile, File.readlink(@targetfile), 'directory to link') end def teardown - stop_server(@pid) remove_repository(@repodir) FileUtils.rm_rf(@testbase) FileUtils.rm_rf(@targetfile) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2010-01-20 22:41:54
|
Revision: 190 http://etch.svn.sourceforge.net/etch/?rev=190&view=rev Author: jheiss Date: 2010-01-20 22:41:41 +0000 (Wed, 20 Jan 2010) Log Message: ----------- Store history logs as individual files rather than in RCS. RCS results in a very cumbersome UI for viewing the history logs, making it unlikely they'll be used. Individual files allows for easy viewing and inspection using standard Unix tools like ls, diff, grep, etc. History logs in the old RCS format are converted automatically to the new format. Add any exception message to the message that is reported to the etch server. Otherwise we just report a non-zero status with no message, which is difficult to debug. We were printing the exception message to stderr, but most users run etch in a cron job that sends stderr to /dev/null. Update the history log after performing a revert so that we capture that activity. Perform another bit of code cleanup in the revert action. Add nonrecursive_copy and nonrecursive_copy_and_rename methods to complement the recursive versions we had already. Modified Paths: -------------- trunk/client/etchclient.rb trunk/test/history.rb Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2010-01-20 22:30:45 UTC (rev 189) +++ trunk/client/etchclient.rb 2010-01-20 22:41:41 UTC (rev 190) @@ -403,7 +403,9 @@ rescue Exception => e status = 1 $stderr.puts e.message + message << e.message $stderr.puts e.backtrace.join("\n") if @debug + message << e.backtrace.join("\n") if @debug end # begin/rescue end # catch @@ -540,8 +542,10 @@ # original file. if config.elements['/config/revert'] origpathbase = File.join(@origbase, file) + origpath = nil # Restore the original file if it is around + revert_occurred = false if File.exist?("#{origpathbase}.ORIG") origpath = "#{origpathbase}.ORIG" origdir = File.dirname(origpath) @@ -553,10 +557,7 @@ puts "Restoring #{origpath} to #{file}" recursive_copy_and_rename(origdir, origbase, file) if (!@dryrun) - - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) + revert_occurred = true elsif File.exist?("#{origpathbase}.TAR") origpath = "#{origpathbase}.TAR" filedir = File.dirname(file) @@ -566,19 +567,24 @@ puts "Restoring #{file} from #{origpath}" system("cd #{filedir} && tar xf #{origpath}") if (!@dryrun) - - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) + revert_occurred = true elsif File.exist?("#{origpathbase}.NOORIG") origpath = "#{origpathbase}.NOORIG" puts "Original #{file} didn't exist, restoring that state" # Remove anything we might have written out for this file remove_file(file) if (!@dryrun) + revert_occurred = true + end - # Now remove the backed-up original so that future runs - # don't do anything + # Update the history log + if revert_occurred + save_history(file) + end + + # Now remove the backed-up original so that future runs + # don't do anything + if origpath remove_file(origpath) if (!@dryrun) end @@ -1696,109 +1702,110 @@ origpath end - + # This subroutine maintains a revision history for the file in @historybase def save_history(file) - histpath = File.join(@historybase, "#{file}.HISTORY") + histdir = File.join(@historybase, "#{file}.HISTORY") + current = File.join(histdir, 'current') + + # Migrate old RCS history + if File.file?(histdir) && File.directory?(File.join(File.dirname(histdir), 'RCS')) + if !@dryrun + puts "Migrating old RCS history to new format" + rcsmax = nil + IO.popen("rlog #{histdir}") do |pipe| + pipe.each do |line| + if line =~ /^head: 1.(.*)/ + rcsmax = $1.to_i + break + end + end + end + if !rcsmax + raise "Failed to parse RCS history rlog output" + end + tmphistdir = tempdir(histdir) + 1.upto(rcsmax) do |rcsrev| + rcsrevcontents = `co -q -p1.#{rcsrev} #{histdir}` + # rcsrev-1 because RCS starts revisions at 1.1 and we start files + # at 0000 + File.open(File.join(tmphistdir, sprintf('%04d', rcsrev-1)), 'w') do |rcsrevfile| + rcsrevfile.write(rcsrevcontents) + end + end + FileUtils.copy(histdir, File.join(tmphistdir, 'current')) + File.delete(histdir) + File.rename(tmphistdir, histdir) + end + end # Make sure the directory tree for this file exists in the # directory we save history in. - histdir = File.dirname(histpath) - if !File.directory?(histdir) - puts "Making directory tree #{histdir}" + if !File.exist?(histdir) + puts "Making history directory #{histdir}" FileUtils.mkpath(histdir) if (!@dryrun) end - # Make sure the corresponding RCS directory exists as well. - histrcsdir = File.join(histdir, 'RCS') - if !File.directory?(histrcsdir) - puts "Making directory tree #{histrcsdir}" - FileUtils.mkpath(histrcsdir) if (!@dryrun) - end - - # If the history log doesn't exist and we didn't just create the - # original backup, that indicates that the original backup was made - # previously but the history log was not started at the same time. - # There are a variety of reasons why this might be the case (the - # original was saved by a previous version of etch that didn't have - # the history log feature, or the original was saved manually by - # someone) but whatever the reason is we want to use the original - # backup to start the history log before updating the history log - # with the current file. - if !File.exist?(histpath) && !@first_update[file] + + # If the history log doesn't exist and we didn't just create the original + # backup then that indicates that the original backup was made previously + # but the history log was not started at the same time. There are a + # variety of reasons why this might be the case (the most likely is that + # the original was saved manually by someone) but whatever the reason is + # we want to use the original backup to start the history log before + # updating the history log with the current file. + if !File.exist?(File.join(histdir, 'current')) && !@first_update[file] origpath = save_orig(file) if File.file?(origpath) && !File.symlink?(origpath) puts "Starting history log with saved original file: " + - "#{origpath} -> #{histpath}" - FileUtils.copy(origpath, histpath) if (!@dryrun) + "#{origpath} -> #{current}" + FileUtils.copy(origpath, current) if (!@dryrun) else puts "Starting history log with 'ls -ld' output for " + - "saved original file: #{origpath} -> #{histpath}" - system("ls -ld #{origpath} > #{histpath} 2>&1") if (!@dryrun) + "saved original file: #{origpath} -> #{current}" + system("ls -ld #{origpath} > #{current} 2>&1") if (!@dryrun) end - # Check the newly created history file into RCS - histbase = File.basename(histpath) - puts "Checking initial history log into RCS: #{histpath}" - if !@dryrun - # The -m flag shouldn't be needed, but it won't hurt - # anything and if something is out of sync and an RCS file - # already exists it will prevent ci from going interactive. - system( - "cd #{histdir} && " + - "ci -q -t-'Original of an etch modified file' " + - "-m'Update of an etch modified file' #{histbase} && " + - "co -q -r -kb #{histbase}") - end set_history_permissions(file) end - - # Copy current file - - # If the file already exists in RCS we need to check out a locked - # copy before updating it - histbase = File.basename(histpath) - rcsstatus = false - if !@dryrun - rcsstatus = system("cd #{histdir} && rlog -R #{histbase} > /dev/null 2>&1") - end - if rcsstatus - # set_history_permissions may set the checked-out file - # writeable, which normally causes co to abort. Thus the -f - # flag. - system("cd #{histdir} && co -q -l -f #{histbase}") if !@dryrun - end - + + # Make temporary copy of file + newcurrent = current+'.new' if File.file?(file) && !File.symlink?(file) - puts "Updating history log: #{file} -> #{histpath}" - FileUtils.copy(file, histpath) if (!@dryrun) + puts "Updating history log: #{file} -> #{current}" + remove_file(newcurrent) + FileUtils.copy(file, newcurrent) if (!@dryrun) else - puts "Updating history log with 'ls -ld' output: " + - "#{histpath}" - system("ls -ld #{file} > #{histpath} 2>&1") if (!@dryrun) + puts "Updating history log with 'ls -ld' output: #{file} -> #{current}" + system("ls -ld #{file} > #{newcurrent} 2>&1") if (!@dryrun) end - - # Check the history file into RCS - puts "Checking history log update into RCS: #{histpath}" - if !@dryrun - # We only need one of the -t or -m flags depending on whether - # the history log already exists or not, rather than try to - # keep track of which one we need just specify both and let RCS - # pick the one it needs. - system( - "cd #{histdir} && " + - "ci -q -t-'Original of an etch modified file' " + - "-m'Update of an etch modified file' #{histbase} && " + - "co -q -r -kb #{histbase}") + + # Roll current to next XXXX if current != XXXX + if File.exist?(current) + nextfile = '0000' + maxfile = Dir.entries(histdir).select{|e|e=~/^\d+/}.max + if maxfile + if compare_file_contents(File.join(histdir, maxfile), File.read(current)) + nextfile = nil + else + nextfile = sprintf('%04d', maxfile.to_i + 1) + end + end + if nextfile + File.rename(current, File.join(histdir, nextfile)) if (!@dryrun) + end end - + + # Move temporary copy to current + File.rename(current+'.new', current) if (!@dryrun) + set_history_permissions(file) end - + # Ensures that the history log file has appropriate permissions to avoid # leaking information. def set_history_permissions(file) origpath = File.join(@origbase, "#{file}.ORIG") - histpath = File.join(@historybase, "#{file}.HISTORY") - + histdir = File.join(@historybase, "#{file}.HISTORY") + # We set the permissions to the more restrictive of the original # file permissions and the current file permissions. origperms = 0777 @@ -1813,17 +1820,15 @@ # Mask off the file type fileperms = st.mode & 07777 end - histperms = origperms & fileperms - - File.chmod(histperms, histpath) if (!@dryrun) - - # Set the permissions on the RCS file too - histbase = File.basename(histpath) - histdir = File.dirname(histpath) - histrcsdir = "#{histdir}/RCS" - histrcspath = "#{histrcsdir}/#{histbase},v" - File.chmod(histperms, histrcspath) if (!@dryrun) + + if File.directory?(histdir) + Dir.foreach(histdir) do |histfile| + next if histfile == '.' + next if histfile == '..' + File.chmod(histperms, File.join(histdir, histfile)) if (!@dryrun) + end + end end def get_local_requests(file) @@ -2202,8 +2207,10 @@ # Note that cp -p will follow symlinks. GNU cp has a -d option to # prevent that, but Solaris cp does not, so we resort to cpio. # GNU cpio has a --quiet option, but Solaris cpio does not. Sigh. + # GNU find and cpio also have -print0/--null to handle filenames with + # spaces or special characters, but that's not standard either. system("cd #{sourcedir} && find #{sourcefile} | cpio -pdum #{destdir}") or - raise "Copy #{sourcedir}/#{sourcefile} to #{destdir} failed" + raise "Recursive copy #{sourcedir}/#{sourcefile} to #{destdir} failed" end def recursive_copy_and_rename(sourcedir, sourcefile, destname) tmpdir = tempdir(destname) @@ -2211,7 +2218,17 @@ File.rename(File.join(tmpdir, sourcefile), destname) Dir.delete(tmpdir) end - + def nonrecursive_copy(sourcedir, sourcefile, destdir) + system("cd #{sourcedir} && echo #{sourcefile} | cpio -pdum #{destdir}") or + raise "Non-recursive copy #{sourcedir}/#{sourcefile} to #{destdir} failed" + end + def nonrecursive_copy_and_rename(sourcedir, sourcefile, destname) + tmpdir = tempdir(destname) + nonrecursive_copy(sourcedir, sourcefile, tmpdir) + File.rename(File.join(tmpdir, sourcefile), destname) + Dir.delete(tmpdir) + end + def lock_file(file) lockpath = File.join(@lockbase, "#{file}.LOCK") Modified: trunk/test/history.rb =================================================================== --- trunk/test/history.rb 2010-01-20 22:30:45 UTC (rev 189) +++ trunk/test/history.rb 2010-01-20 22:41:41 UTC (rev 190) @@ -22,6 +22,9 @@ # Create a directory to use as a working directory for the client @testbase = tempdir #puts "Using #{@testbase} as client working directory" + + @origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") + @historydir = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") end def test_history @@ -29,10 +32,6 @@ # Ensure original file is backed up and history log started # - origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") - historyfile = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") - historydir = File.dirname(historyfile) - # Put some text into the original file so that we can make sure it was # properly backed up. origcontents = "This is the original text\n" @@ -63,15 +62,9 @@ #puts "Running initial history test" run_etch(@server, @testbase) - assert_equal(origcontents, get_file_contents(origfile), 'original backup of file') - system("cd #{historydir} && co -q -f -r1.1 #{historyfile}") - #system("ls -l #{historyfile}") - assert_equal(origcontents, get_file_contents(historyfile), 'history log started in rcs') - system("cd #{historydir} && co -q -f #{historyfile}") - #system("ls -l #{historyfile}") - assert_equal(sourcecontents, get_file_contents(historyfile), 'history log of file started and updated') - rcsexit = system("cd #{historydir} && rlog -h #{historyfile} | grep '^head: 1.2'") - assert(rcsexit, 'history log started and updated in rcs') + assert_equal(origcontents, get_file_contents(@origfile), 'original backup of file') + assert_equal(origcontents, get_file_contents(File.join(@historydir, '0000')), '0000 history file') + assert_equal(sourcecontents, get_file_contents(File.join(@historydir, 'current')), 'current history file') # # Ensure history log is updated and original file does not change @@ -86,10 +79,10 @@ #puts "Running update test" run_etch(@server, @testbase) - assert_equal(origcontents, get_file_contents(origfile), 'original backup of file unchanged') - assert_equal(updatedsourcecontents, get_file_contents(historyfile), 'history log of file updated') - rcsexit = system("cd #{historydir} && rlog -h #{historyfile} | grep '^head: 1.3'") - assert(rcsexit, 'history log updated in rcs') + assert_equal(origcontents, get_file_contents(@origfile), 'original backup of file unchanged') + assert_equal(origcontents, get_file_contents(File.join(@historydir, '0000')), '0000 history file') + assert_equal(sourcecontents, get_file_contents(File.join(@historydir, '0001')), '0001 history file') + assert_equal(updatedsourcecontents, get_file_contents(File.join(@historydir, 'current')), 'updated current history file') # # Test revert feature @@ -117,6 +110,11 @@ run_etch(@server, @testbase) assert_equal(origcontents, get_file_contents(@targetfile), 'original contents reverted') + assert(!File.exist?(@origfile), 'reverted original file') + assert_equal(origcontents, get_file_contents(File.join(@historydir, '0000')), '0000 history file') + assert_equal(sourcecontents, get_file_contents(File.join(@historydir, '0001')), '0001 history file') + assert_equal(updatedsourcecontents, get_file_contents(File.join(@historydir, '0002')), '0002 history file') + assert_equal(origcontents, get_file_contents(File.join(@historydir, 'current')), 'reverted current history file') # # Update the contents of a reverted file and make sure etch doesn't @@ -133,6 +131,8 @@ run_etch(@server, @testbase) assert_equal(updatedorigcontents, get_file_contents(@targetfile), 'Updated original contents unchanged') + assert(!File.exist?(@origfile), 'reverted original file') + assert_equal(origcontents, get_file_contents(File.join(@historydir, 'current')), 'Updated reverted current history file') end def test_history_setup @@ -150,7 +150,6 @@ # original contents. # - origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") origcontents = "This is the original text" FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") @@ -180,7 +179,7 @@ #puts "Running history setup test" run_etch(@server, @testbase) - assert_equal(origcontents + "\n", get_file_contents(origfile), 'original backup of file via setup') + assert_equal(origcontents + "\n", get_file_contents(@origfile), 'original backup of file via setup') assert_equal(sourcecontents + origcontents + "\n", get_file_contents(@targetfile), 'contents using original backup of file via setup') end @@ -220,7 +219,6 @@ #puts "Running '#{testname}' test" run_etch(@server, @testbase) - origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") origcontents = "This is the original text for #{testname}" FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") @@ -249,7 +247,7 @@ #puts "Running '#{testname}' test" run_etch(@server, @testbase) - assert_equal(origcontents + "\n", get_file_contents(origfile), testname) + assert_equal(origcontents + "\n", get_file_contents(@origfile), testname) end def test_history_link @@ -257,10 +255,6 @@ # Ensure original file is backed up when it is a link # - origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") - historyfile = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") - historydir = File.dirname(historyfile) - # Generate another file to use as our link target @destfile = Tempfile.new('etchtest').path @@ -291,9 +285,8 @@ #puts "Running history link test" run_etch(@server, @testbase) - assert_equal(@destfile, File.readlink(origfile), 'original backup of link') - system("cd #{historydir} && co -q -f -r1.1 #{historyfile}") - assert_match("#{@targetfile} -> #{@destfile}", get_file_contents(historyfile), 'history backup of link') + assert_equal(@destfile, File.readlink(@origfile), 'original backup of link') + assert_match("#{@targetfile} -> #{@destfile}", get_file_contents(File.join(@historydir, '0000')), '0000 history file of link') end def test_history_directory @@ -301,10 +294,6 @@ # Ensure original file is backed up when it is a directory # - origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") - historyfile = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") - historydir = File.dirname(historyfile) - # Make the original target a directory File.delete(@targetfile) Dir.mkdir(@targetfile) @@ -341,14 +330,14 @@ #puts "Running history directory test" run_etch(@server, @testbase) - assert(File.directory?(origfile), 'original backup of directory') + assert(File.directory?(@origfile), 'original backup of directory') # Verify that etch backed up the original directory properly - assert_equal(before_uid, File.stat(origfile).uid, 'original directory uid') - assert_equal(before_gid, File.stat(origfile).gid, 'original directory gid') - assert_equal(before_mode, File.stat(origfile).mode, 'original directory mode') + assert_equal(before_uid, File.stat(@origfile).uid, 'original directory uid') + assert_equal(before_gid, File.stat(@origfile).gid, 'original directory gid') + assert_equal(before_mode, File.stat(@origfile).mode, 'original directory mode') # Check that the history log looks reasonable, it should contain an # 'ls -ld' of the directory - assert_match(" #{@targetfile}", get_file_contents(historyfile), 'history backup of directory') + assert_match(" #{@targetfile}", get_file_contents(File.join(@historydir, '0000')), '0000 history file of directory') end def test_history_directory_contents @@ -358,10 +347,7 @@ # differently in that case # - #origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") - origfile = File.join(@testbase, 'orig', "#{@targetfile}.TAR") - historyfile = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") - historydir = File.dirname(historyfile) + origtarfile = File.join(@testbase, 'orig', "#{@targetfile}.TAR") # Make the original target a directory File.delete(@targetfile) @@ -394,12 +380,78 @@ # In this case, because we converted a directory to something else the # original will be a tarball of the directory - assert(File.file?(origfile), 'original backup of directory converted to file') + assert(File.file?(origtarfile), 'original backup of directory converted to file') # The tarball should have two entries, the directory and the 'testfile' # we put inside it - assert_equal('2', `tar tf #{origfile} | wc -l`.chomp.strip, 'original backup of directory contents') + assert_equal('2', `tar tf #{origtarfile} | wc -l`.chomp.strip, 'original backup of directory contents') end - + + def test_history_conversion + # + # Test the conversion of old RCS history logs to the new format + # + + # Mock up an original file and RCS history log + mockorigcontents = "This is the original text\n" + FileUtils.mkdir_p(File.dirname(@origfile)) + File.open(@origfile, 'w') do |file| + file.write(mockorigcontents) + end + historyparent = File.dirname(@historydir) + FileUtils.mkdir_p(historyparent) + File.open(@historydir, 'w') do |file| + file.write(mockorigcontents) + end + histrcsdir = File.join(historyparent, 'RCS') + FileUtils.mkdir_p(histrcsdir) + histbase = File.basename(@historydir) + system( + "cd #{historyparent} && " + + "ci -q -t-'Original of an etch modified file' " + + "-m'Update of an etch modified file' #{histbase} && " + + "co -q -r -kb #{histbase}") + mocksourcecontents = "This is the contents in the RCS history log\n" + system("cd #{historyparent} && co -q -l #{histbase}") + File.open(@historydir, 'w') do |file| + file.write(mocksourcecontents) + end + system( + "cd #{historyparent} && " + + "ci -q -t-'Original of an etch modified file' " + + "-m'Update of an etch modified file' #{histbase} && " + + "co -q -r -kb #{histbase}") + File.open(@targetfile, 'w') do |file| + file.write(mocksourcecontents) + end + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "This is a test\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Run etch + #puts "Running history conversion test" + run_etch(@server, @testbase) + + assert_equal(mockorigcontents, get_file_contents(File.join(@historydir, '0000')), 'RCS conv 0000 history file') + assert_equal(mocksourcecontents, get_file_contents(File.join(@historydir, '0001')), 'RCS conv 0001 history file') + assert_equal(sourcecontents, get_file_contents(File.join(@historydir, 'current')), 'RCS conv current history file') + end + def teardown remove_repository(@repodir) FileUtils.rm_rf(@testbase) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2010-01-20 23:05:13
|
Revision: 192 http://etch.svn.sourceforge.net/etch/?rev=192&view=rev Author: jheiss Date: 2010-01-20 23:05:05 +0000 (Wed, 20 Jan 2010) Log Message: ----------- Rename all of the files with tests to match what Rake::TestTask expects by default, allowing us to clean up the Rakefile a bit. Modified Paths: -------------- trunk/Rakefile Added Paths: ----------- trunk/test/test_actions.rb trunk/test/test_attributes.rb trunk/test/test_auth.rb trunk/test/test_commands.rb trunk/test/test_delete.rb trunk/test/test_depend.rb trunk/test/test_file.rb trunk/test/test_history.rb trunk/test/test_link.rb trunk/test/test_local_requests.rb trunk/test/test_nodegroups.rb trunk/test/test_options.rb trunk/test/test_outputcapture.rb trunk/test/test_scripts.rb trunk/test/test_transitions.rb Removed Paths: ------------- trunk/test/actions.rb trunk/test/attributes.rb trunk/test/auth.rb trunk/test/commands.rb trunk/test/delete.rb trunk/test/depend.rb trunk/test/file.rb trunk/test/history.rb trunk/test/link.rb trunk/test/local_requests.rb trunk/test/nodegroups.rb trunk/test/options.rb trunk/test/outputcapture.rb trunk/test/scripts.rb trunk/test/transitions.rb Modified: trunk/Rakefile =================================================================== --- trunk/Rakefile 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/Rakefile 2010-01-20 23:05:05 UTC (rev 192) @@ -9,6 +9,4 @@ end t.verbose = true - #t.pattern = 'test/*.rb' - t.test_files = Dir.glob('test/*.rb').reject {|test| test =~ /etchtest.rb/} end Deleted: trunk/test/actions.rb =================================================================== --- trunk/test/actions.rb 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/test/actions.rb 2010-01-20 23:05:05 UTC (rev 192) @@ -1,472 +0,0 @@ -#!/usr/bin/ruby -w - -# -# Test etch's handling of various actions: pre, post, setup, test, etc. -# - -require File.join(File.dirname(__FILE__), 'etchtest') - -class EtchActionTests < Test::Unit::TestCase - include EtchTests - - def setup - # Generate a file to use as our etch target/destination - @targetfile = Tempfile.new('etchtest').path - #puts "Using #{@targetfile} as target file" - - # Generate a directory for our test repository - @repodir = initialize_repository - @server = get_server(@repodir) - - # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" - - # Generate another file to use as our link target - @destfile = Tempfile.new('etchtest').path - #puts "Using #{@destfile} as link destination file" - end - - def test_actions - - # - # Basic tests to ensure that actions are performed under normal - # circumstances - # - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <server_setup> - <exec>echo server_setup >> #{@repodir}/server_setup</exec> - </server_setup> - <setup> - <exec>echo setup >> #{@repodir}/setup</exec> - </setup> - <pre> - <exec>echo pre >> #{@repodir}/pre</exec> - </pre> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - <test_before_post> - <exec>echo test_before_post >> #{@repodir}/test_before_post</exec> - </test_before_post> - <post> - <exec_once>echo exec_once >> #{@repodir}/exec_once</exec_once> - <exec_once_per_run>echo exec_once_per_run >> #{@repodir}/exec_once_per_run</exec_once_per_run> - <exec_once_per_run>echo exec_once_per_run >> #{@repodir}/exec_once_per_run</exec_once_per_run> - <exec>echo post >> #{@repodir}/post</exec> - </post> - <test> - <exec>echo test >> #{@repodir}/test</exec> - </test> - </config> - EOF - end - - sourcecontents = "This is a test\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running initial action test" - run_etch(@server, @testbase) - - # Verify that the actions were executed - # The setup actions will get run several times as we loop - # back and forth with the server sending original sums and - # contents. So just verify that they were run at least once. - assert_match("server_setup\n", get_file_contents("#{@repodir}/server_setup"), 'server_setup') - assert_match("setup\n", get_file_contents("#{@repodir}/setup"), 'setup') - assert_equal("pre\n", get_file_contents("#{@repodir}/pre"), 'pre') - assert_equal( - "exec_once\n", get_file_contents("#{@repodir}/exec_once"), 'exec_once') - assert_equal( - "exec_once_per_run\n", - get_file_contents("#{@repodir}/exec_once_per_run"), - 'exec_once_per_run') - assert_equal( - "test_before_post\n", - get_file_contents("#{@repodir}/test_before_post"), - 'test_before_post') - assert_equal("post\n", get_file_contents("#{@repodir}/post"), 'post') - assert_equal("test\n", get_file_contents("#{@repodir}/test"), 'test') - - # Run etch again and make sure that the exec_once command wasn't run - # again - run_etch(@server, @testbase) - - assert_equal("exec_once\n", get_file_contents("#{@repodir}/exec_once"), 'exec_once_2nd_check') - end - - def test_failed_setup - # - # Test a failed setup command to ensure etch aborts - # - - # Put some text into the original file so that we can make sure it - # is not touched. - origcontents = "This is the original text\n" - File.delete(@targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <setup> - <exec>false</exec> - </setup> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "This is a test\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running initial action test" - run_etch(@server, @testbase, true) - - # Verify that the file was not touched - assert_equal(origcontents, get_file_contents(@targetfile), 'failed setup') - end - - def test_failed_pre - # - # Test a failed pre command to ensure etch aborts - # - - # Put some text into the original file so that we can make sure it - # is not touched. - origcontents = "This is the original text\n" - File.delete(@targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <pre> - <exec>false</exec> - </pre> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "This is a test\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running failed pre test" - run_etch(@server, @testbase, true) - - # Verify that the file was not touched - assert_equal(origcontents, get_file_contents(@targetfile), 'failed pre') - end - - def test_failed_test - # - # Run a test where the test action fails, ensure that the original - # target file is restored and any post actions re-run afterwards - # - - # Put some text into the original file so that we can make sure it - # is restored. - origcontents = "This is the original text\n" - File.delete(@targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <overwrite_directory/> - <source> - <plain>source</plain> - </source> - </file> - <post> - <exec>echo post >> #{@repodir}/post</exec> - </post> - <test> - <exec>false</exec> - </test> - </config> - EOF - end - - # Change the source file so that we can see whether the original was - # restored or not - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write("Testing a failed test\n") - end - - # Run etch - #puts "Running failed test test" - run_etch(@server, @testbase) - - # Verify that the original was restored, and that post was run twice - assert_equal(origcontents, get_file_contents(@targetfile), 'failed test target') - assert_equal("post\npost\n", get_file_contents("#{@repodir}/post"), 'failed test post') - end - - def test_failed_test_before_post - # - # Run a test where the test_before_post action fails, ensure that - # post is not run - # - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <overwrite_directory/> - <source> - <plain>source</plain> - </source> - </file> - <test_before_post> - <exec>false</exec> - </test_before_post> - <post> - <exec>echo post >> #{@repodir}/post</exec> - </post> - </config> - EOF - end - - # Run etch - #puts "Running failed test_before_post test" - run_etch(@server, @testbase, true) - - # Verify that post was not run - assert(!File.exist?("#{@repodir}/post"), 'failed test_before_post post') - - # - # Run a test where the test action fails, and the original target file - # is a symlink. Ensure that the symlink is restored. - # - - # Prepare the target - File.delete(@targetfile) if File.exist?(@targetfile) - File.symlink(@destfile, @targetfile) - - # Run etch - #puts "Running failed test symlink test" - run_etch(@server, @testbase, true) - - # Verify that the original symlink was restored - assert_equal(@destfile, File.readlink(@targetfile), 'failed test symlink') - - # - # Run a test where the test action fails, and the original target file - # is a directory. Ensure that the directory is restored. - # - - # Prepare the target - File.delete(@targetfile) if File.exist?(@targetfile) - Dir.mkdir(@targetfile) - File.open("#{@targetfile}/testfile", 'w') { |file| } - - # Run etch - #puts "Running failed test directory test" - run_etch(@server, @testbase, true) - - # Verify that the original directory was restored - assert(File.directory?(@targetfile), 'failed test directory') - assert(File.file?("#{@targetfile}/testfile"), 'failed test directory contents') - - # - # Run a test where the test action fails, and there is no original - # target file. Ensure that the end result is that there is no file left - # behind. - # - - # We can reuse the config.xml from the previous test - - # Clean up from previous runs - if File.exist?(@targetfile) || File.symlink?(@targetfile) - FileUtils.rm_rf(@targetfile) - end - File.delete("#{@repodir}/post") if File.exist?("#{@repodir}/post") - - # Run etch - #puts "Running failed test no original file test" - run_etch(@server, @testbase, true) - - # Verify that the lack of an original file was restored - assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), 'failed test no original file') - end - - def test_nested_target - # - # Run a test where a test action is defined and the target file is in a - # directory that does not exist yet, thus requiring that we make the - # directory before creating the backup (or rather the NOORIG marker in - # this case). We had a bug where that failed, as the code to make the - # directory structure was after the code to make the backup. - # - # I.e. configuration to create /etc/foo/bar, but /etc/foo does not exist. - # The backup that is created when a test is defined (so that we can roll - # back if the test fails) is made as /etc/foo/bar.XXXXX, which requires - # that /etc/foo exist first. - # - - nestedtargetdir = Tempfile.new('etchtest').path - File.delete(nestedtargetdir) - nestedtargetfile = File.join(nestedtargetdir, 'etchnestedtest') - - FileUtils.mkdir_p("#{@repodir}/source/#{nestedtargetfile}") - File.open("#{@repodir}/source/#{nestedtargetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - <test> - <exec>true</exec> - </test> - </config> - EOF - end - - sourcecontents = "Testing a nested target\n" - File.open("#{@repodir}/source/#{nestedtargetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running nested target with test test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(nestedtargetfile), 'nested target with test') - end - - def test_action_with_xml_escape - # - # Test an action requiring XML escape - # The XML spec says that < and & must be escaped almost anywhere - # outside of their use as markup. That includes the character data of - # actions. - # http://www.w3.org/TR/2006/REC-xml-20060816/#syntax - # So if the user wants to use something like && in an action they must - # escape the & with & - # - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - <post> - <exec>true && echo post >> #{@repodir}/post_with_escape</exec> - </post> - </config> - EOF - end - - sourcecontents = "This is a test of a post with XML escapes\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running XML escape test" - run_etch(@server, @testbase) - - # Verify that the action was executed - assert_equal("post\n", get_file_contents("#{@repodir}/post_with_escape"), 'post with escape') - end - - def test_action_with_env - # - # Test an action involving passing an environment variable - # - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - <post> - <exec>TESTVAR=testvalue #{@repodir}/post_with_env</exec> - </post> - </config> - EOF - end - - sourcecontents = "This is a test of a post with an environment variable\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - File.open("#{@repodir}/post_with_env", 'w') do |file| - file.write <<EOF -#!/bin/sh -echo $TESTVAR >> #{@repodir}/post_with_env_output -EOF - end - File.chmod(0755, "#{@repodir}/post_with_env") - - # Run etch - #puts "Running environment variable test" - run_etch(@server, @testbase) - - # Verify that the action was executed - assert_equal("testvalue\n", get_file_contents("#{@repodir}/post_with_env_output"), 'post with environment variable') - end - - def teardown - remove_repository(@repodir) - FileUtils.rm_rf(@testbase) - FileUtils.rm_rf(@targetfile) - FileUtils.rm_f(@destfile) - end -end Deleted: trunk/test/attributes.rb =================================================================== --- trunk/test/attributes.rb 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/test/attributes.rb 2010-01-20 23:05:05 UTC (rev 192) @@ -1,633 +0,0 @@ -#!/usr/bin/ruby -w - -# -# Test etch's handling of attribute filtering in config.xml files -# - -require File.join(File.dirname(__FILE__), 'etchtest') -require 'rubygems' # Might be needed to find facter -require 'facter' - -class EtchAttributeTests < Test::Unit::TestCase - include EtchTests - - def setup - # Generate a file to use as our etch target/destination - @targetfile = Tempfile.new('etchtest').path - #puts "Using #{@targetfile} as target file" - - # Generate a directory for our test repository - @repodir = initialize_repository - @server = get_server(@repodir) - - # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" - end - - def test_group_attributes - # - # Simple group name comparison with the node in 0 groups - # - testname = 'node group comparison, 0 groups' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Negate the simple group name comparison with the node in 0 groups - # - testname = 'negate node group comparison, 0 groups' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="!testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Put the node in one group for the next series of tests - # - hostname = `facter fqdn`.chomp - File.open(File.join(@repodir, 'nodes.xml'), 'w') do |file| - file.puts <<-EOF - <nodes> - <node name="#{hostname}"> - <group>testgroup</group> - </node> - </nodes> - EOF - end - - # - # Simple group name comparison with the node in 1 group - # - testname = 'node group comparison, 1 group' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Negate the simple group name comparison with the node in 1 group - # - testname = 'negate node group comparison, 1 group' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="!testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Regex group name comparison with the node in 1 group - # - testname = 'regex node group comparison, 1 group' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="/test/">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Put the node in two groups for the next series of tests - # - hostname = `facter fqdn`.chomp - File.open(File.join(@repodir, 'nodes.xml'), 'w') do |file| - file.puts <<-EOF - <nodes> - <node name="#{hostname}"> - <group>testgroup</group> - <group>second</group> - </node> - </nodes> - EOF - end - - # - # Simple group name comparison with the node in 2 groups - # - testname = 'node group comparison, 2 groups' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Negate the simple group name comparison with the node in 2 groups - # - testname = 'negate node group comparison, 2 groups' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="!testgroup">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Regex group name comparison with the node in 2 groups - # - testname = 'regex node group comparison, 2 groups' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain group="/test/">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - end - - def test_fact_attributes - Facter.loadfacts - os = Facter['operatingsystem'].value - # Facter frequently leaves extraneous whitespace on this fact, thus - # the strip - osrel = Facter['operatingsystemrelease'].value.strip - - # - # Simple fact comparison - # - testname = 'fact comparison' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystem="#{os}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Negate fact comparison - # - testname = 'negate fact comparison' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystem="!#{os}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Regex fact comparison - # - testname = 'regex fact comparison' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystem="/#{os[0,2]}/">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Negate regex fact comparison - # - testname = 'negate regex fact comparison' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystem="!/#{os[0,2]}/">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Version fact operator comparison - # - testname = 'version fact operator comparison' - - # Try to make up a subset of operatingsystemrelease so that we really - # test the operator functionality and not just equality. I.e. if osrel - # is 2.5.1 we'd like to extract 2.5 - osrelsubset = osrel - osrelparts = osrel.split('.') - if osrelparts.length > 1 - osrelparts.pop - osrelsubset = osrelparts.join('.') - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystemrelease=">=#{osrelsubset}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Negate version fact operator comparison - # - testname = 'negate fact comparison' - - # Put some text into the original file so that we can make sure it is - # not touched. - origcontents = "This is the original text\n" - File.chmod(0644, @targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystemrelease="!>=#{osrel}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not modified - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Version fact operator comparison requiring XML escape - # The XML spec says that < and & must be escaped almost anywhere - # outside of their use as markup. That includes inside attribute values. - # http://www.w3.org/TR/2006/REC-xml-20060816/#syntax - # So if the user wants to use the < or <= operators they must escape - # the < with < - # - testname = 'version fact operator comparison requiring XML escape' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystemrelease="<=#{osrel}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Multiple fact comparison - # - testname = 'multiple fact comparison' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain operatingsystem="#{os}" operatingsystemrelease="#{osrel}">source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - end - - def teardown - remove_repository(@repodir) - FileUtils.rm_rf(@testbase) - FileUtils.rm_rf(@targetfile) - end -end - Deleted: trunk/test/auth.rb =================================================================== --- trunk/test/auth.rb 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/test/auth.rb 2010-01-20 23:05:05 UTC (rev 192) @@ -1,258 +0,0 @@ -#!/usr/bin/ruby -w - -# -# Test etch's handling of client authentication -# - -require File.join(File.dirname(__FILE__), 'etchtest') -require 'net/http' -require 'rexml/document' -require 'facter' - -class EtchAuthTests < Test::Unit::TestCase - include EtchTests - - def setup - # Generate a file to use as our etch target/destination - @targetfile = Tempfile.new('etchtest').path - #puts "Using #{@targetfile} as target file" - - # Generate a directory for our test repository - @repodir = initialize_repository - # These tests set an etchserver.conf. The server only reads that file - # once and caches the settings, so we need to start up new server - # instances for these tests rather than reusing the global test server. - @server = start_server(@repodir) - - # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" - - # Make sure the server will initially think this is a new client - hostname = Facter['fqdn'].value - Net::HTTP.start('localhost', @server[:port]) do |http| - # Find our client id - response = http.get("/clients.xml?name=#{hostname}") - if !response.kind_of?(Net::HTTPSuccess) - response.error! - end - response_xml = REXML::Document.new(response.body) - client_id = nil - if response_xml.elements['/clients/client/id'] - client_id = response_xml.elements['/clients/client/id'].text - end - # Delete our client entry - if client_id - response = http.delete("/clients/#{client_id}.xml") - if !response.kind_of?(Net::HTTPSuccess) - response.error! - end - end - end - end - - # Test authentication when new clients are allowed - def test_auth_allow_new_clients - File.open(File.join(@repodir, 'etchserver.conf'), 'w') do |file| - file.puts 'auth_enabled=true' - file.puts 'auth_deny_new_clients=false' - end - - # - # New client, should work - # - testname = 'auth, allow new clients, new client' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Existing client, should work - # - testname = 'auth, allow new clients, existing client' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - - # - # Existing client, bad signature, should be denied - # - testname = 'auth, allow new clients, existing client, bad signature' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Put some text into the original file so that we can make sure it - # is not touched. - origcontents = "This is the original text\n" - File.delete(@targetfile) - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - # Run etch with the wrong key to force a bad signature - #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true, "--key=#{File.join(File.dirname(__FILE__), 'keys', 'testkey2')}") - - # Verify that the file was not touched - assert_equal(origcontents, get_file_contents(@targetfile), testname) - end - # Test authentication when new clients are denied - def test_auth_deny_new_clients - File.open(File.join(@repodir, 'etchserver.conf'), 'w') do |file| - file.puts 'auth_enabled=true' - file.puts 'auth_deny_new_clients=true' - end - - # - # New client, should fail - # - testname = 'auth, deny new clients, new client' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Put some text into the original file so that we can make sure it - # is not touched. - origcontents = "This is the original text\n" - File.open(@targetfile, 'w') do |file| - file.write(origcontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) - - # Verify that the file was not touched - assert_equal(origcontents, get_file_contents(@targetfile), testname) - - # - # Add this client to the server so that it will now be considered - # an existing client - # - puts "# Starting a second copy of the server and adding this client to the database" - sleep 3 - repodir2 = initialize_repository - server2 = start_server(repodir2) - run_etch(server2, @testbase) - stop_server(server2) - remove_repository(repodir2) - - # - # Existing client, should work - # - testname = 'auth, deny new clients, existing client' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - </config> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(sourcecontents, get_file_contents(@targetfile), testname) - end - - def teardown - stop_server(@server) - remove_repository(@repodir) - FileUtils.rm_rf(@testbase) - FileUtils.rm_rf(@targetfile) - end -end - Deleted: trunk/test/commands.rb =================================================================== --- trunk/test/commands.rb 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/test/commands.rb 2010-01-20 23:05:05 UTC (rev 192) @@ -1,375 +0,0 @@ -#!/usr/bin/ruby -w - -# -# Test etch's handling of configuration commands -# - -require File.join(File.dirname(__FILE__), 'etchtest') - -class EtchCommandTests < Test::Unit::TestCase - include EtchTests - - def setup - # Generate a file to use as a target in commands - @targetfile = Tempfile.new('etchtest').path - #puts "Using #{@targetfile} as target file" - - # Generate a directory for our test repository - @repodir = initialize_repository - @server = get_server(@repodir) - - # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" - end - - def test_commands_basic - # - # Guard initially fails, command fixes it - # - testname = 'guard initially fails, command fixes it' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep '#{testname}' #{@targetfile}</exec> - </guard> - <command> - <exec>printf '#{testname}' >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was created properly - assert_equal(testname, get_file_contents(@targetfile), testname) - end - - def test_commands_failure - # - # Guard initially fails, command doesn't fix it - # - testname = 'guard initially fails, command doesnt fix it' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep '#{testname}' #{@targetfile}</exec> - </guard> - <command> - <exec>echo '#{testname}'</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - # The assertion here is handled by run_etch as we're passing it an - # argument indicating that we expect failure. - #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) - end - - def test_commands_guard_succeeds - # - # Guard initially succeeds - # - testname = 'guard initially succeeds' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep '#{testname}' #{@targetfile}</exec> - </guard> - <command> - <exec>echo failure >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - File.open(@targetfile, 'w') { |file| file.print(testname) } - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was not touched - assert_equal(testname, get_file_contents(@targetfile), testname) - end - - def test_commands_multiple_steps - # - # Multiple steps - # - testname = 'multiple steps' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep firststep #{@targetfile}</exec> - </guard> - <command> - <exec>echo firststep >> #{@targetfile}</exec> - </command> - </step> - <step> - <guard> - <exec>grep secondstep #{@targetfile}</exec> - </guard> - <command> - <exec>echo secondstep >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that both steps ran and in the proper order - assert_equal("firststep\nsecondstep\n", get_file_contents(@targetfile), testname) - end - - def test_commands_multiple_commands - # - # Multiple commands - # - testname = 'multiple commands' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep firstcmd #{@targetfile}</exec> - </guard> - <command> - <exec>echo firstcmd >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - FileUtils.mkdir_p("#{@repodir}/commands/etchtest2") - File.open("#{@repodir}/commands/etchtest2/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep secondcmd #{@targetfile}</exec> - </guard> - <command> - <exec>echo secondcmd >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that both commands ran, ordering doesn't matter - assert_equal(['firstcmd', 'secondcmd'], get_file_contents(@targetfile).split("\n").sort, testname) - end - - def test_commands_depend - # - # Multiple commands with dependency - # - testname = 'multiple commands with dependency' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <guard> - <exec>grep firstcmd #{@targetfile}</exec> - </guard> - <command> - <exec>echo firstcmd >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - FileUtils.mkdir_p("#{@repodir}/commands/etchtest2") - File.open("#{@repodir}/commands/etchtest2/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <depend>etchtest</depend> - <step> - <guard> - <exec>grep secondcmd #{@targetfile}</exec> - </guard> - <command> - <exec>echo secondcmd >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that both commands ran and in the proper order - assert_equal("firstcmd\nsecondcmd\n", get_file_contents(@targetfile), testname) - end - - def test_commands_dependfile - # - # Command with dependency on a file - # - testname = 'command with file dependency' - - targetfile2 = Tempfile.new('etchtest').path - FileUtils.mkdir_p("#{@repodir}/source/#{targetfile2}") - File.open("#{@repodir}/source/#{targetfile2}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <file> - <warning_file/> - <source> - <plain>source</plain> - </source> - </file> - <post> - <exec>sleep 3</exec> - </post> - </config> - EOF - end - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <dependfile>#{targetfile2}</dependfile> - <step> - <guard> - <exec>grep '#{testname}' #{@targetfile}</exec> - </guard> - <command> - <exec>printf '#{testname}' >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - sourcecontents = "Test #{testname}\n" - File.open("#{@repodir}/source/#{targetfile2}/source", 'w') do |file| - file.write(sourcecontents) - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the command-generated file and the regular file were created - # properly - assert_equal(testname, get_file_contents(@targetfile), testname + ' command contents') - assert_equal(sourcecontents, get_file_contents(targetfile2), testname + ' file contents') - # And verify that they were created in the right order - assert(File.stat(@targetfile).mtime > File.stat(targetfile2).mtime, testname + ' ordering') - end - - def test_commands_filtering - # - # Attribute filtering - # Filtering of commands.xml uses the same methods as are used for the - # filtering of config.xml, which is heavily tested. So we just do a - # simple test to make sure that it basically works. - # - testname = 'command attribute filtering' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step group="!testgroup"> - <guard> - <exec>grep notingroup #{@targetfile}</exec> - </guard> - <command> - <exec>echo notingroup >> #{@targetfile}</exec> - </command> - </step> - <step group="testgroup"> - <guard> - <exec>grep yesingroup #{@targetfile}</exec> - </guard> - <command> - <exec>echo yesingroup >> #{@targetfile}</exec> - </command> - </step> - </commands> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that only the desired step executed - assert_equal("notingroup\n", get_file_contents(@targetfile), testname) - end - - def test_commands_dtd_failure - # - # commands.xml doesn't match DTD - # - testname = 'command DTD failure' - - FileUtils.mkdir_p("#{@repodir}/commands/etchtest") - File.open("#{@repodir}/commands/etchtest/commands.xml", 'w') do |file| - file.puts <<-EOF - <commands> - <step> - <bogus/> - </step> - </commands> - EOF - end - - # Run etch - # The assertion here is handled by run_etch as we're passing it an - # argument indicating that we expect failure. - #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) - end - - def teardown - remove_repository(@repodir) - FileUtils.rm_rf(@testbase) - FileUtils.rm_rf(@targetfile) - end -end - Deleted: trunk/test/delete.rb =================================================================== --- trunk/test/delete.rb 2010-01-20 22:43:55 UTC (rev 191) +++ trunk/test/delete.rb 2010-01-20 23:05:05 UTC (rev 192) @@ -1,237 +0,0 @@ -#!/usr/bin/ruby -w - -# -# Test etch's handling of deleting files -# - -require File.join(File.dirname(__FILE__), 'etchtest') - -class EtchDeleteTests < Test::Unit::TestCase - include EtchTests - - def setup - # Generate a file to use as our etch target/destination - @targetfile = Tempfile.new('etchtest').path - #puts "Using #{@targetfile} as target file" - - # Generate a directory for our test repository - @repodir = initialize_repository - @server = get_server(@repodir) - - # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" - - # Generate another file to use as our link target - @destfile = Tempfile.new('etchtest').path - #puts "Using #{@destfile} as link destination file" - end - - def test_delete - - # - # Delete a file - # - testname = 'delete file' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <proceed/> - </delete> - </config> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the file was deleted - assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) - - # - # Delete a link - # - testname = 'delete link' - - # Create the link - File.symlink(@destfile, @targetfile) - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <proceed/> - </delete> - </config> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the link was deleted - assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) - - # - # Delete a directory - # - testname = 'delete directory w/o overwrite_directory' - - # Create the directory with a file inside just to make sure the - # delete handles that properly - Dir.mkdir(@targetfile) if (!File.directory?(@targetfile)) - File.open("#{@targetfile}/testfile", 'w') { |file| } - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <proceed/> - </delete> - </config> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) - - # Verify that the directory was not deleted - assert(File.directory?(@targetfile), testname) - - # - # Delete a directory w/ overwrite_directory - # - testname = 'delete directory w/ overwrite_directory' - - # Create the directory with a file inside just to make sure the - # delete handles that properly - Dir.mkdir(@targetfile) if (!File.directory?(@targetfile)) - File.open("#{@targetfile}/testfile", 'w') { |file| } - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <overwrite_directory/> - <proceed/> - </delete> - </config> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that the directory was deleted - assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) - - # - # Delete a non-existent file - # - testname = 'delete non-existent file' - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <proceed/> - </delete> - </config> - EOF - end - - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) - - # Verify that we still don't have a file. That's rather unlikely, - # this is really more a test that etch doesn't throw an error if - # told to delete something that doesn't exist, which is captured by - # the assert within run_etch. - assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) - - # - # Test duplicate script instructions - # - - FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") - File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| - file.puts <<-EOF - <config> - <delete> - <script>source</script> - <script>source</script> - </delete> - </config> - EOF - end - - File.open(@targetfile, 'w') do |file| - file.puts('Original contents') - end - - File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| - file.puts("@contents << 'true'") - end - - # Run etch - #puts "Running duplicate script instructions test" - run_et... [truncated message content] |
From: <jh...@us...> - 2010-11-25 00:07:50
|
Revision: 225 http://etch.svn.sourceforge.net/etch/?rev=225&view=rev Author: jheiss Date: 2010-11-25 00:07:42 +0000 (Thu, 25 Nov 2010) Log Message: ----------- https://sourceforge.net/apps/trac/etch/ticket/8 Add support for an /etc/etch.conf config file to the client. This allows users to set the etch server, the directory to use for local configuration (if desired instead of using a server), and the SSH key permanently. These were previously only configurable on the command line. The config file also allows the user to set a PATH that will be in force for any commands etch runs. The PATH was previously hard-coded in the client. In Etch::Client.initialize replace the :varbase option with :file_system_root. The :varbase option allowed the test suite to specify an alternative to /var/etch for the client so that the test suite doesn't have to run as root and doesn't interfere with actual etch client usage on the system where the test suite is run. The replacement :file_system_root option allows the test suite to define a base directory under which the client will look for both /var/etch and /etc/etch.conf. This allows the test suite to test various config file settings, again without interfering with actual etch client usage on the development system. Change --test-base to --test-root in the etch executable to reflect the Etch::Client option change. In the start_server method in the test suite implement a check that the server has started up before returning, rather than sleeping for 5 seconds and hoping that is enough time. Under heavy load it sometimes isn't enough time, causing the test suite to fail unnecessarily. And under light load the server starts up much quicker than 5 seconds, so it is nice to not have to wait around unnecessarily. Update the run_etch method in the test suite to take optional arguments in an options hash, rather than as individual arguments. This cleans up the method signature and makes the code that calls run_etch more self-documenting. Added options to allow callers to override the --server and --key options passed to etch, and an option for specifying the testname so that we can pass that to assert. Modified Paths: -------------- trunk/client/Rakefile trunk/client/etch trunk/client/etchclient.rb trunk/test/etchtest.rb trunk/test/test_actions.rb trunk/test/test_attributes.rb trunk/test/test_auth.rb trunk/test/test_commands.rb trunk/test/test_delete.rb trunk/test/test_depend.rb trunk/test/test_file.rb trunk/test/test_history.rb trunk/test/test_link.rb trunk/test/test_local_requests.rb trunk/test/test_nodegroups.rb trunk/test/test_options.rb trunk/test/test_outputcapture.rb trunk/test/test_scripts.rb trunk/test/test_transitions.rb Added Paths: ----------- trunk/client/etch.conf trunk/test/test_conf.rb Modified: trunk/client/Rakefile =================================================================== --- trunk/client/Rakefile 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/client/Rakefile 2010-11-25 00:07:42 UTC (rev 225) @@ -81,10 +81,9 @@ if options[:etcdir] etcdir = File.join(destdir, options[:etcdir]) - # FIXME: Need to add support for etch.conf to the code - #mkdir_p(etcdir) - #cp('etch.conf', etcdir, :preserve => true) - #chmod(0644, File.join(etcdir, 'etch.conf')) + mkdir_p(etcdir) + cp('etch.conf', etcdir, :preserve => true) + chmod(0644, File.join(etcdir, 'etch.conf')) # All of the supporting config files go into a subdirectory etcetchdir = File.join(etcdir, 'etch') mkdir_p(etcetchdir) Modified: trunk/client/etch =================================================================== --- trunk/client/etch 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/client/etch 2010-11-25 00:07:42 UTC (rev 225) @@ -62,8 +62,8 @@ opts.on('--key PRIVATE_KEY', 'Use this private key for signing messages to server.') do |opt| options[:key] = opt end -opts.on('--test-base TESTDIR', 'Use an alternate local working directory.') do |opt| - options[:varbase] = opt +opts.on('--test-root TESTDIR', 'For use by the test suite only.') do |opt| + options[:file_system_root] = opt end opts.on('--debug', 'Print lots of messages about what etch is doing.') do |opt| options[:debug] = opt Added: trunk/client/etch.conf =================================================================== --- trunk/client/etch.conf (rev 0) +++ trunk/client/etch.conf 2010-11-25 00:07:42 UTC (rev 225) @@ -0,0 +1,18 @@ +# The default server url is https://etch +#server = https://etch + +# Etch is usually run from cron, and cron usually executes jobs with a very +# minimal PATH environment variable setting. You may want etch to have a more +# complete PATH setting so that pre and post commands are more readily found. +#path = /bin:/usr/bin:/sbin:/usr/sbin + +# Etch can read configuration from a local directory rather than from a +# server. If set this will override the server setting. +#local = /var/etch/configs + +# Etch will try to find an SSH host key and use it to sign all requests to the +# etch server. Several standard locations for SSH keys are searched by +# default, if your key is not in a standard location you can point etch to it. +# See https://sourceforge.net/apps/trac/etch/wiki/ClientAuthentication +#key = /etc/ssh/ssh_host_rsa_key + Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/client/etchclient.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -41,7 +41,8 @@ CONFIRM_SKIP = 2 CONFIRM_QUIT = 3 PRIVATE_KEY_PATHS = ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh_host_rsa_key"] - CONFIGDIR = '/etc' + DEFAULT_CONFIGDIR = '/etc' + DEFAULT_VARBASE = '/var/etch' # We need these in relation to the output capturing ORIG_STDOUT = STDOUT.dup @@ -52,7 +53,6 @@ def initialize(options) @server = options[:server] ? options[:server] : 'https://etch' @tag = options[:tag] - @varbase = options[:varbase] ? options[:varbase] : '/var/etch' @local = options[:local] ? File.expand_path(options[:local]) : nil @debug = options[:debug] @dryrun = options[:dryrun] @@ -63,11 +63,66 @@ @disableforce = options[:disableforce] @lockforce = options[:lockforce] - # Ensure we have a sane path, particularly since we are often run from - # cron. - # FIXME: Read from config file - ENV['PATH'] = '/bin:/usr/bin:/sbin:/usr/sbin:/opt/csw/bin:/opt/csw/sbin' + @configdir = DEFAULT_CONFIGDIR + @varbase = DEFAULT_VARBASE + @file_system_root = '/' # Not sure if this needs to be more portable + # This option is only intended for use by the test suite + if options[:file_system_root] + @file_system_root = options[:file_system_root] + @varbase = File.join(@file_system_root, @varbase) + @configdir = File.join(@file_system_root, @configdir) + end + + @configfile = File.join(@configdir, 'etch.conf') + + if File.exist?(@configfile) + IO.foreach(@configfile) do |line| + line.chomp! + next if (line =~ /^\s*$/); # Skip blank lines + next if (line =~ /^\s*#/); # Skip comments + line.strip! # Remove leading/trailing whitespace + key, value = line.split(/\s*=\s*/, 2) + if key == 'server' + # A setting for the server to use which comes from upstream + # (generally from a command line option) takes precedence + # over the config file + if !options[:server] + @server = value + # Warn the user, as this could potentially be confusing + # if they don't realize there's a config file lying + # around + warn "Using server #{@server} from #{@configfile}" if @debug + else + # "command line override" isn't necessarily accurate, we don't + # know why the caller passed us an option to override the config + # file, but most of the time it will be due to a command line + # option and I want the message to be easily understood by users. + # If someone can come up with some better wording without turning + # the message into something as long as this comment that would be + # welcome. + warn "Ignoring 'server' option in #{@configfile} due to command line override" if @debug + end + elsif key == 'local' + if !options[:local] && !options[:server] + @local = value + warn "Using local directory #{@local} from #{@configfile}" if @debug + else + warn "Ignoring 'local' option in #{@configfile} due to command line override" if @debug + end + elsif key == 'key' + if !options[:key] + @key = value + warn "Using key #{@key} from #{@configfile}" if @debug + else + warn "Ignoring 'key' option in #{@configfile} due to command line override" if @debug + end + elsif key == 'path' + ENV['PATH'] = value + end + end + end + @origbase = File.join(@varbase, 'orig') @historybase = File.join(@varbase, 'history') @lockbase = File.join(@varbase, 'locks') @@ -141,17 +196,17 @@ http = Net::HTTP.new(@filesuri.host, @filesuri.port) if @filesuri.scheme == "https" # Eliminate the OpenSSL "using default DH parameters" warning - if File.exist?(File.join(CONFIGDIR, 'etch', 'dhparams')) - dh = OpenSSL::PKey::DH.new(IO.read(File.join(CONFIGDIR, 'etch', 'dhparams'))) + if File.exist?(File.join(@configdir, 'etch', 'dhparams')) + dh = OpenSSL::PKey::DH.new(IO.read(File.join(@configdir, 'etch', 'dhparams'))) Net::HTTP.ssl_context_accessor(:tmp_dh_callback) http.tmp_dh_callback = proc { dh } end http.use_ssl = true - if File.exist?(File.join(CONFIGDIR, 'etch', 'ca.pem')) - http.ca_file = File.join(CONFIGDIR, 'etch', 'ca.pem') + if File.exist?(File.join(@configdir, 'etch', 'ca.pem')) + http.ca_file = File.join(@configdir, 'etch', 'ca.pem') http.verify_mode = OpenSSL::SSL::VERIFY_PEER - elsif File.directory?(File.join(CONFIGDIR, 'etch', 'ca')) - http.ca_path = File.join(CONFIGDIR, 'etch', 'ca') + elsif File.directory?(File.join(@configdir, 'etch', 'ca')) + http.ca_path = File.join(@configdir, 'etch', 'ca') http.verify_mode = OpenSSL::SSL::VERIFY_PEER end end Modified: trunk/test/etchtest.rb =================================================================== --- trunk/test/etchtest.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/etchtest.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -5,6 +5,7 @@ require 'test/unit' require 'tempfile' require 'fileutils' +require 'net/http' module EtchTests # Roughly ../server and ../client @@ -104,9 +105,26 @@ # Pick a random port in the 3001-6000 range (range somewhat randomly chosen) port = 3001 + rand(3000) if pid = fork - # FIXME: replace this with a check that the server has started - puts "Giving the server some time to start up" - sleep(5) + # Give the server up to 30s to start, checking every second + serverstarted = false + catch :serverstarted do + 30.times do + begin + Net::HTTP.start('localhost', port) do |http| + response = http.head("/") + if response.kind_of?(Net::HTTPSuccess) + serverstarted = true + throw :serverstarted + end + end + rescue => e + end + sleep(1) + end + end + if !serverstarted + raise "Etch server failed to start" + end else if UNICORN exec("cd #{SERVERDIR} && unicorn_rails -p #{port}") @@ -122,12 +140,29 @@ Process.waitpid(server[:pid]) end - def run_etch(server, testbase, errors_expected=false, extra_args='', port=nil) - extra_args = extra_args + " --debug" - if !port - port = server[:port] + def run_etch(server, testroot, options={}) + extra_args = '' + if options[:extra_args] + extra_args += options[:extra_args] end - if errors_expected + extra_args += " --debug" + + port = server[:port] + if options[:port] + port = options[:port] + end + + server = "--server=http://localhost:#{port}" + if options[:server] + server = options[:server] + end + + key = "--key=#{File.dirname(__FILE__)}/keys/testkey" + if options[:key] + key = options[:key] + end + + if options[:errors_expected] # Warn the user that errors are expected. Otherwise it can be # disconcerting if you're watching the tests run and see errors. #sleep 3 @@ -136,11 +171,11 @@ puts "#" #sleep 3 end - result = system("ruby #{CLIENTDIR}/etch --generate-all --server=http://localhost:#{port} --test-base=#{testbase} --key=#{File.dirname(__FILE__)}/keys/testkey #{extra_args}") - if errors_expected - assert(!result) + result = system("ruby #{CLIENTDIR}/etch --generate-all --test-root=#{testroot} #{server} #{key} #{extra_args}") + if options[:errors_expected] + assert(!result, options[:testname]) else - assert(result) + assert(result, options[:testname]) end end Modified: trunk/test/test_actions.rb =================================================================== --- trunk/test/test_actions.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_actions.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -19,8 +19,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" # Generate another file to use as our link target @destfile = released_tempfile @@ -76,7 +76,7 @@ # Run etch #puts "Running initial action test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the actions were executed # The setup actions will get run several times as we loop @@ -100,7 +100,7 @@ # Run etch again and make sure that the exec_once command wasn't run # again - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal("exec_once\n", get_file_contents("#{@repodir}/exec_once"), 'exec_once_2nd_check') end @@ -142,7 +142,7 @@ # Run etch #puts "Running initial action test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), 'failed setup') @@ -185,7 +185,7 @@ # Run etch #puts "Running failed pre test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), 'failed pre') @@ -234,7 +234,7 @@ # Run etch #puts "Running failed test test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the original was restored, and that post was run twice assert_equal(origcontents, get_file_contents(@targetfile), 'failed test target') @@ -270,7 +270,7 @@ # Run etch #puts "Running failed test_before_post test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that post was not run assert(!File.exist?("#{@repodir}/post"), 'failed test_before_post post') @@ -286,7 +286,7 @@ # Run etch #puts "Running failed test symlink test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the original symlink was restored assert_equal(@destfile, File.readlink(@targetfile), 'failed test symlink') @@ -303,7 +303,7 @@ # Run etch #puts "Running failed test directory test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the original directory was restored assert(File.directory?(@targetfile), 'failed test directory') @@ -325,7 +325,7 @@ # Run etch #puts "Running failed test no original file test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the lack of an original file was restored assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), 'failed test no original file') @@ -372,7 +372,7 @@ # Run etch #puts "Running nested target with test test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(nestedtargetfile), 'nested target with test') @@ -415,7 +415,7 @@ # Run etch #puts "Running XML escape test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the action was executed assert_equal("post\n", get_file_contents("#{@repodir}/post_with_escape"), 'post with escape') @@ -458,7 +458,7 @@ # Run etch #puts "Running environment variable test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the action was executed assert_equal("testvalue\n", get_file_contents("#{@repodir}/post_with_env_output"), 'post with environment variable') @@ -466,7 +466,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) FileUtils.rm_f(@destfile) end Modified: trunk/test/test_attributes.rb =================================================================== --- trunk/test/test_attributes.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_attributes.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -21,8 +21,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_group_attributes @@ -58,9 +58,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -89,9 +87,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -134,9 +130,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -173,9 +167,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -204,9 +196,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -250,9 +240,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -289,9 +277,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -320,9 +306,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -359,9 +343,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -398,9 +380,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -429,9 +409,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -468,9 +446,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -509,9 +485,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -548,9 +522,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was not modified assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -584,9 +556,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -615,9 +585,7 @@ file.write(sourcecontents) end - # Run etch - #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot, :testname => testname) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -626,7 +594,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_auth.rb =================================================================== --- trunk/test/test_auth.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_auth.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -32,8 +32,8 @@ @server = start_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" # Make sure the server will initially think this is a new client hostname = Facter['fqdn'].value @@ -91,7 +91,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -122,7 +122,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -161,7 +161,7 @@ # Run etch with the wrong key to force a bad signature #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true, "--key=#{File.join(File.dirname(__FILE__), 'keys', 'testkey2')}") + run_etch(@server, @testroot, :errors_expected => true, :key => "--key=#{File.join(File.dirname(__FILE__), 'keys', 'testkey2')}") # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -206,7 +206,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file was not touched assert_equal(origcontents, get_file_contents(@targetfile), testname) @@ -219,7 +219,7 @@ sleep 3 repodir2 = initialize_repository server2 = start_server(repodir2) - run_etch(server2, @testbase) + run_etch(server2, @testroot) stop_server(server2) remove_repository(repodir2) @@ -249,7 +249,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -258,7 +258,7 @@ def teardown stop_server(@server) remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_commands.rb =================================================================== --- trunk/test/test_commands.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_commands.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -19,8 +19,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_commands_basic @@ -47,7 +47,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(testname, get_file_contents(@targetfile), testname) @@ -76,10 +76,8 @@ end # Run etch - # The assertion here is handled by run_etch as we're passing it an - # argument indicating that we expect failure. #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) end def test_commands_guard_succeeds @@ -108,7 +106,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was not touched assert_equal(testname, get_file_contents(@targetfile), testname) @@ -146,7 +144,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that both steps ran and in the proper order assert_equal("firststep\nsecondstep\n", get_file_contents(@targetfile), testname) @@ -191,7 +189,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that both commands ran, ordering doesn't matter assert_equal(['firstcmd', 'secondcmd'], get_file_contents(@targetfile).split("\n").sort, testname) @@ -237,7 +235,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that both commands ran and in the proper order assert_equal("firstcmd\nsecondcmd\n", get_file_contents(@targetfile), testname) @@ -291,7 +289,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the command-generated file and the regular file were created # properly @@ -336,7 +334,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that only the desired step executed assert_equal("notingroup\n", get_file_contents(@targetfile), testname) @@ -360,15 +358,13 @@ end # Run etch - # The assertion here is handled by run_etch as we're passing it an - # argument indicating that we expect failure. #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) end def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Added: trunk/test/test_conf.rb =================================================================== --- trunk/test/test_conf.rb (rev 0) +++ trunk/test/test_conf.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -0,0 +1,180 @@ +#!/usr/bin/ruby -w + +# +# Test etch's handling of its configuration file, etch.conf +# + +require File.join(File.dirname(__FILE__), 'etchtest') + +class EtchConfTests < Test::Unit::TestCase + include EtchTests + + def setup + # Generate a file to use as our etch target/destination + @targetfile = released_tempfile + #puts "Using #{@targetfile} as target file" + + # Generate a directory for our test repository + @repodir = initialize_repository + @server = get_server(@repodir) + + # Create a directory to use as a working directory for the client + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" + end + + def test_conf_server + # + # Test the server setting in etch.conf + # + testname = 'etch.conf server setting' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Test that it fails with a bogus etch.conf server setting + Dir.mkdir("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "server = http://bogushost:0" + end + + # The --server option normally used by run_etch will override the config + # file, signal run_etch to leave out the --server option + run_etch(@server, @testroot, :server => '', :errors_expected => true) + + # And confirm that it now succeeds with a correct etch.conf server setting + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "server = http://localhost:#{@server[:port]}" + end + + # The --server option normally used by run_etch will override the config + # file, signal run_etch to leave out the --server option + run_etch(@server, @testroot, :server => '') + assert_equal(sourcecontents, get_file_contents(@targetfile)) + end + + def test_conf_local + # + # Test the local setting in etch.conf + # + testname = 'etch.conf local setting' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Test that it fails with a bogus etch.conf local setting + Dir.mkdir("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "local = /not/a/valid/path" + end + + # Although the config file local setting will override it, tell run_etch + # to leave out the --server option to avoid confusion + run_etch(@server, @testroot, :server => '', :errors_expected => true) + + # And confirm that it now succeeds with a correct etch.conf local setting + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "local = #{@repodir}" + end + + # Although the config file local setting will override it, tell run_etch + # to leave out the --server option to avoid confusion + run_etch(@server, @testroot, :server => '') + assert_equal(sourcecontents, get_file_contents(@targetfile)) + end + + def test_conf_key + # FIXME + + # The --key option normally used by run_etch will override the config + # file, signal run_etch to leave out the --key option + #run_etch(@server, @testroot, :key => '') + end + + def test_conf_path + # + # Test the path setting in etch.conf + # + testname = 'etch.conf path setting' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + <post> + <exec>testpost</exec> + </post> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + Dir.mkdir("#{@repodir}/pathtest") + File.open("#{@repodir}/pathtest/testpost", 'w') do |file| + file.puts '#!/bin/sh' + file.puts "touch #{@repodir}/pathtest/testpost.output" + end + File.chmod(0755, "#{@repodir}/pathtest/testpost") + + # Test that it fails without an etch.conf path setting + run_etch(@server, @testroot) + assert(!File.exist?("#{@repodir}/pathtest/testpost.output")) + + Dir.mkdir("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "path = /bin:/usr/bin:/sbin:/usr/sbin:#{@repodir}/pathtest" + end + + # And confirm that it now succeeds with an etch.conf path setting + run_etch(@server, @testroot) + assert(File.exist?("#{@repodir}/pathtest/testpost.output")) + end + + def teardown + remove_repository(@repodir) + FileUtils.rm_rf(@testroot) + FileUtils.rm_rf(@targetfile) + end +end Modified: trunk/test/test_delete.rb =================================================================== --- trunk/test/test_delete.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_delete.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -19,8 +19,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" # Generate another file to use as our link target @destfile = released_tempfile @@ -47,7 +47,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -73,7 +73,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the link was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -101,7 +101,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the directory was not deleted assert(File.directory?(@targetfile), testname) @@ -130,7 +130,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the directory was deleted assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) @@ -153,7 +153,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that we still don't have a file. That's rather unlikely, # this is really more a test that etch doesn't throw an error if @@ -187,7 +187,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert(!File.exist?(@targetfile), 'duplicate script instructions') @@ -220,7 +220,7 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file wasn't removed assert(File.exist?(@targetfile), 'contradictory script instructions') @@ -229,7 +229,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) FileUtils.rm_rf(@destfile) end Modified: trunk/test/test_depend.rb =================================================================== --- trunk/test/test_depend.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_depend.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -21,8 +21,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_depends @@ -76,7 +76,7 @@ # Run etch #puts "Running initial dependency test" - run_etch(@server, @testbase, false) + run_etch(@server, @testroot) # Verify that the files were created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'dependency file 1') @@ -138,7 +138,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase, false, @targetfile) + run_etch(@server, @testroot, :extra_args => @targetfile) # Verify that the files were created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'single request dependency file 1') @@ -202,7 +202,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true, @targetfile) + run_etch(@server, @testroot, :errors_expected => true, :extra_args => @targetfile) # Verify that the files weren't modified assert_equal(origcontents, get_file_contents(@targetfile), 'circular dependency file 1') @@ -256,7 +256,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the regular file and the command-generated file were created # properly @@ -268,7 +268,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_file.rb =================================================================== --- trunk/test/test_file.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_file.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -19,8 +19,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_files @@ -49,7 +49,7 @@ # Run etch #puts "Running initial file test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = '' @@ -86,7 +86,7 @@ # Run etch #puts "Running initial file test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = '' @@ -127,7 +127,7 @@ # Run etch #puts "Running different warning file test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = '' @@ -164,7 +164,7 @@ # Run etch #puts "Running no warning file test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), 'no warning file') @@ -194,7 +194,7 @@ # Run etch #puts "Running different line comment test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = '' @@ -233,7 +233,7 @@ # Run etch #puts "Running comment open/close test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = "/*\n" @@ -273,7 +273,7 @@ # Run etch #puts "Running warning on second line test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = sourcecontents_firstline @@ -311,7 +311,7 @@ # Run etch #puts "Running no space around warning test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly correctcontents = '' @@ -344,7 +344,7 @@ # Run etch #puts "Running file ownership and permissions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file ownership got set correctly # Most systems don't support give-away chown, so this test won't work @@ -380,7 +380,7 @@ # Run etch #puts "Running file ownership w/ bogus owner/group names" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the ownership defaulted to UID/GID 0 # Most systems don't support give-away chown, so this test won't work @@ -416,7 +416,7 @@ # Run etch #puts "Running always_manage_metadata test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file permissions got set correctly perms = File.stat(@targetfile).mode & 07777 @@ -456,7 +456,7 @@ # Run etch #puts "Running duplicate plain instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate plain instructions') @@ -495,7 +495,7 @@ # Run etch #puts "Running contradictory plain instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory plain instructions') @@ -531,7 +531,7 @@ # Run etch #puts "Running duplicate template instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate template instructions') @@ -570,7 +570,7 @@ # Run etch #puts "Running contradictory template instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory template instructions') @@ -606,7 +606,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file contents were updated assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate script instructions') @@ -645,7 +645,7 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file contents didn't change assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory script instructions') @@ -684,7 +684,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(specialtargetfile), testname) @@ -692,7 +692,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_history.rb =================================================================== --- trunk/test/test_history.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_history.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -20,11 +20,11 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" - @origfile = File.join(@testbase, 'orig', "#{@targetfile}.ORIG") - @historydir = File.join(@testbase, 'history', "#{@targetfile}.HISTORY") + @origfile = File.join(@testroot, 'var', 'etch', 'orig', "#{@targetfile}.ORIG") + @historydir = File.join(@testroot, 'var', 'etch', 'history', "#{@targetfile}.HISTORY") end def test_history @@ -60,7 +60,7 @@ # Run etch #puts "Running initial history test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(origcontents, get_file_contents(@origfile), 'original backup of file') assert_equal(origcontents, get_file_contents(File.join(@historydir, '0000')), '0000 history file') @@ -77,7 +77,7 @@ # Run etch #puts "Running update test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(origcontents, get_file_contents(@origfile), 'original backup of file unchanged') assert_equal(origcontents, get_file_contents(File.join(@historydir, '0000')), '0000 history file') @@ -107,7 +107,7 @@ # Run etch #puts "Running revert test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(origcontents, get_file_contents(@targetfile), 'original contents reverted') assert(!File.exist?(@origfile), 'reverted original file') @@ -128,7 +128,7 @@ # Run etch #puts "Running revert test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(updatedorigcontents, get_file_contents(@targetfile), 'Updated original contents unchanged') assert(!File.exist?(@origfile), 'reverted original file') @@ -177,7 +177,7 @@ # Run etch #puts "Running history setup test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(origcontents + "\n", get_file_contents(@origfile), 'original backup of file via setup') assert_equal(sourcecontents + origcontents + "\n", get_file_contents(@targetfile), 'contents using original backup of file via setup') @@ -217,7 +217,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) origcontents = "This is the original text for #{testname}" @@ -245,7 +245,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(origcontents + "\n", get_file_contents(@origfile), testname) end @@ -283,7 +283,7 @@ # Run etch #puts "Running history link test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile, File.readlink(@origfile), 'original backup of link') assert_match("#{@targetfile} -> #{@destfile}", get_file_contents(File.join(@historydir, '0000')), '0000 history file of link') @@ -328,7 +328,7 @@ # Run etch #puts "Running history directory test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert(File.directory?(@origfile), 'original backup of directory') # Verify that etch backed up the original directory properly @@ -347,7 +347,7 @@ # differently in that case # - origtarfile = File.join(@testbase, 'orig', "#{@targetfile}.TAR") + origtarfile = File.join(@testroot, 'var', 'etch', 'orig', "#{@targetfile}.TAR") # Make the original target a directory File.delete(@targetfile) @@ -376,7 +376,7 @@ # Run etch #puts "Running history directory contents test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # In this case, because we converted a directory to something else the # original will be a tarball of the directory @@ -445,7 +445,7 @@ # Run etch #puts "Running history conversion test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(mockorigcontents, get_file_contents(File.join(@historydir, '0000')), 'RCS conv 0000 history file') assert_equal(mocksourcecontents, get_file_contents(File.join(@historydir, '0001')), 'RCS conv 0001 history file') @@ -454,7 +454,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_link.rb =================================================================== --- trunk/test/test_link.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_link.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -24,8 +24,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" # Generate a couple more files to use as our link targets @destfile = released_tempfile @@ -51,7 +51,7 @@ # Run etch #puts "Running initial link test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile, File.readlink(@targetfile), 'link create') @@ -72,7 +72,7 @@ # Run etch #puts "Running link update test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile2, File.readlink(@targetfile), 'link update') @@ -101,7 +101,7 @@ # Run etch #puts "Running link update from non-existent file test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile, File.readlink(@targetfile), 'link update from non-existent file') end @@ -127,7 +127,7 @@ # Run etch #puts "Running link to non-existent destination test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the link was not created assert(!File.symlink?(@targetfile), 'link to non-existent destination') @@ -151,7 +151,7 @@ # Run etch #puts "Running link to non-existent destination with override test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the link was updated properly assert_equal(@destfile, File.readlink(@targetfile), 'link to non-existent destination with override') @@ -180,7 +180,7 @@ # Run etch #puts "Running relative link test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the link was updated properly assert_equal(reldestfile, File.readlink(@targetfile), 'relative link') @@ -207,7 +207,7 @@ # Run etch #puts "Running link ownership and permissions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the link ownership got set correctly # Most systems don't support give-away chown, so this test won't work @@ -242,7 +242,7 @@ # Run etch #puts "Running duplicate dest instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile, File.readlink(@targetfile), 'duplicate dest instructions') end @@ -266,7 +266,7 @@ # Run etch #puts "Running contradictory dest instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the link wasn't created assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory dest instructions') @@ -295,7 +295,7 @@ # Run etch #puts "Running duplicate script instructions test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) assert_equal(@destfile, File.readlink(@targetfile), 'duplicate script instructions') end @@ -326,7 +326,7 @@ # Run etch #puts "Running contradictory script instructions test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the link wasn't created assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory script instructions') @@ -334,7 +334,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) FileUtils.rm_f(@destfile) FileUtils.rm_f(@destfile2) Modified: trunk/test/test_local_requests.rb =================================================================== --- trunk/test/test_local_requests.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_local_requests.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -19,8 +19,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_local_requests_script @@ -44,7 +44,7 @@ end # Create the local request file - requestdir = File.join(@testbase, 'requests', @targetfile) + requestdir = File.join(@testroot, 'var', 'etch', 'requests', @targetfile) requestfile = File.join(requestdir, 'testrequest') FileUtils.mkdir_p(requestdir) File.open(requestfile, 'w') do |file| @@ -68,7 +68,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -95,7 +95,7 @@ end # Create the local request file - requestdir = File.join(@testbase, 'requests', @targetfile) + requestdir = File.join(@testroot, 'var', 'etch', 'requests', @targetfile) requestfile = File.join(requestdir, 'testrequest') FileUtils.mkdir_p(requestdir) File.open(requestfile, 'w') do |file| @@ -120,7 +120,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly # Our whitespace in the heredoc above gets added to the generated file, so @@ -131,7 +131,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_nodegroups.rb =================================================================== --- trunk/test/test_nodegroups.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_nodegroups.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -20,8 +20,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_group @@ -51,7 +51,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -92,7 +92,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -133,7 +133,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase) + run_etch(@server, @testroot) # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) @@ -177,7 +177,7 @@ # Run etch #puts "Running '#{testname}' test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) # Verify that the file wasn't modified assert_equal(oldsourcecontents, get_file_contents(@targetfile), testname) @@ -185,7 +185,7 @@ def teardown remove_repository(@repodir) - FileUtils.rm_rf(@testbase) + FileUtils.rm_rf(@testroot) FileUtils.rm_rf(@targetfile) end end Modified: trunk/test/test_options.rb =================================================================== --- trunk/test/test_options.rb 2010-11-25 00:05:46 UTC (rev 224) +++ trunk/test/test_options.rb 2010-11-25 00:07:42 UTC (rev 225) @@ -20,8 +20,8 @@ @server = get_server(@repodir) # Create a directory to use as a working directory for the client - @testbase = tempdir - #puts "Using #{@testbase} as client working directory" + @testroot = tempdir + #puts "Using #{@testroot} as client working directory" end def test_killswitch @@ -62,7 +62,7 @@ # Run etch #puts "Running killswitch test" - run_etch(@server, @testbase, true) + run_etch(@server, @testroot, :errors_expected => true) assert_equal(origcontents, get_file_contents(@targetfile), 'killswitch') end @@ -100,7 +100,7 @@ # Run etch #puts "Running --dry-run test" - run_etch(@server, @testbase, false, '--dry-run') + ... [truncated message content] |
From: <jh...@us...> - 2011-01-14 23:56:59
|
Revision: 253 http://etch.svn.sourceforge.net/etch/?rev=253&view=rev Author: jheiss Date: 2011-01-14 23:56:52 +0000 (Fri, 14 Jan 2011) Log Message: ----------- Add support for a detailed_results setting in the client config file, allowing users to log detailed results to a local file in addition to or instead of sending them to the server. Modified Paths: -------------- trunk/client/etch.conf trunk/client/etchclient.rb trunk/test/test_conf.rb Modified: trunk/client/etch.conf =================================================================== --- trunk/client/etch.conf 2011-01-14 23:54:16 UTC (rev 252) +++ trunk/client/etch.conf 2011-01-14 23:56:52 UTC (rev 253) @@ -11,8 +11,15 @@ #local = /var/etch/configs # Etch will try to find an SSH host key and use it to sign all requests to the -# etch server. Several standard locations for SSH keys are searched by -# default, if your key is not in a standard location you can point etch to it. -# See https://sourceforge.net/apps/trac/etch/wiki/ClientAuthentication +# etch server. Several standard locations for host keys are searched by +# default. If your host key is not in a standard location then you can point +# etch to it. +# See http://sourceforge.net/apps/trac/etch/wiki/ClientAuthentication #key = /etc/ssh/ssh_host_rsa_key +# Etch can send detailed results back to the server for viewing in the web UI +# and/or to a local log file. They are sent to the server by default. +# Note that SERVER is ignored when etch is running in local mode. +#detailed_results = SERVER +#detailed_results = /var/etch/results.log + Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2011-01-14 23:54:16 UTC (rev 252) +++ trunk/client/etchclient.rb 2011-01-14 23:56:52 UTC (rev 253) @@ -43,6 +43,7 @@ PRIVATE_KEY_PATHS = ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh_host_rsa_key"] DEFAULT_CONFIGDIR = '/etc' DEFAULT_VARBASE = '/var/etch' + DEFAULT_DETAILED_RESULTS = ['SERVER'] # We need these in relation to the output capturing ORIG_STDOUT = STDOUT.dup @@ -75,6 +76,7 @@ end @configfile = File.join(@configdir, 'etch.conf') + @detailed_results = [] if File.exist?(@configfile) IO.foreach(@configfile) do |line| @@ -119,6 +121,9 @@ end elsif key == 'path' ENV['PATH'] = value + elsif key == 'detailed_results' + warn "Adding detailed results destination '#{value}'" if @debug + @detailed_results << value end end end @@ -130,6 +135,10 @@ warn "No readable private key found, messages to server will not be signed and may be rejected depending on server configuration" end + if @detailed_results.empty? + @detailed_results = DEFAULT_DETAILED_RESULTS + end + @origbase = File.join(@varbase, 'orig') @historybase = File.join(@varbase, 'history') @lockbase = File.join(@varbase, 'locks') @@ -480,13 +489,15 @@ rails_results << "fqdn=#{CGI.escape(@facts['fqdn'])}" rails_results << "status=#{CGI.escape(status.to_s)}" rails_results << "message=#{CGI.escape(message)}" - @results.each do |result| - # Strangely enough this works. Even though the key is not unique to - # each result the Rails parameter parsing code keeps track of keys it - # has seen, and if it sees a duplicate it starts a new hash. - rails_results << "results[][file]=#{CGI.escape(result['file'])}" - rails_results << "results[][success]=#{CGI.escape(result['success'].to_s)}" - rails_results << "results[][message]=#{CGI.escape(result['message'])}" + if @detailed_results.include?('SERVER') + @results.each do |result| + # Strangely enough this works. Even though the key is not unique to + # each result the Rails parameter parsing code keeps track of keys it + # has seen, and if it sees a duplicate it starts a new hash. + rails_results << "results[][file]=#{CGI.escape(result['file'])}" + rails_results << "results[][success]=#{CGI.escape(result['success'].to_s)}" + rails_results << "results[][message]=#{CGI.escape(result['message'])}" + end end puts "Sending results to server #{@resultsuri}" if (@debug) resultspost = Net::HTTP::Post.new(@resultsuri.path) @@ -507,6 +518,27 @@ end end + @detailed_results.each do |detail_dest| + # If any of the destinations look like a file (start with a /) then we + # log to that file + if detail_dest =~ %r{^/} + FileUtils.mkpath(File.dirname(detail_dest)) + File.open(detail_dest, 'a') do |file| + # Add a header for the overall status of the run + file.puts "Etch run at #{Time.now}" + file.puts "Status: #{status}" + if !message.empty? + file.puts "Message:\n#{message}\n" + end + # Then the detailed results + @results.each do |result| + file.puts "File #{result['file']}, result #{result['success']}:\n" + file.puts result['message'] + end + end + end + end + status end Modified: trunk/test/test_conf.rb =================================================================== --- trunk/test/test_conf.rb 2011-01-14 23:54:16 UTC (rev 252) +++ trunk/test/test_conf.rb 2011-01-14 23:56:52 UTC (rev 253) @@ -308,6 +308,102 @@ assert(File.exist?("#{@repodir}/pathtest/testpost.output")) end + def test_conf_detailed_results + # + # Test the detailed_results setting in etch.conf + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file></warning_file> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + # No setting, should log to server by default + testname = 'etch.conf detailed_results setting, not set' + # We add a random component to the contents so that we can distinguish + # our test run from others in the server database + sourcecontents = "Test #{testname}, #{rand}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + run_etch(@server, @testroot, :testname => testname) + assert_match(sourcecontents, latest_result_message, testname) + + # Configure logging to server + testname = 'etch.conf detailed_results setting, log to server' + # We add a random component to the contents so that we can distinguish + # our test run from others in the server database + sourcecontents = "Test #{testname}, #{rand}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + FileUtils.mkdir_p("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "detailed_results = SERVER" + end + run_etch(@server, @testroot, :testname => testname) + assert_match(sourcecontents, latest_result_message, testname) + + # Configure logging to file + logfile = Tempfile.new('etchlog') + testname = 'etch.conf detailed_results setting, log to file' + sourcecontents = "Test #{testname}, #{rand}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + FileUtils.mkdir_p("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "detailed_results = #{logfile.path}" + end + run_etch(@server, @testroot, :testname => testname) + assert_match(sourcecontents, File.read(logfile.path), testname) + # Check that details weren't sent to server + # Odd that assert_no_match requires a Regexp when assert_match accepts a String + assert_no_match(Regexp.new(Regexp.escape(sourcecontents)), latest_result_message, testname) + + # Configure logging to server and file + logfile = Tempfile.new('etchlog') + testname = 'etch.conf detailed_results setting, log to server and file' + # We add a random component to the contents so that we can distinguish + # our test run from others in the server database + sourcecontents = "Test #{testname}, #{rand}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + FileUtils.mkdir_p("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "detailed_results = SERVER" + file.puts "detailed_results = #{logfile.path}" + end + run_etch(@server, @testroot, :testname => testname) + assert_match(sourcecontents, latest_result_message, testname) + assert_match(sourcecontents, File.read(logfile.path), testname) + + # Configure no logging + testname = 'etch.conf detailed_results setting, log nowhere' + sourcecontents = "Test #{testname}, #{rand}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + FileUtils.mkdir_p("#{@testroot}/etc") + File.open("#{@testroot}/etc/etch.conf", 'w') do |file| + file.puts "detailed_results =" + end + run_etch(@server, @testroot, :testname => testname) + # Check that details weren't sent to server + # Odd that assert_no_match requires a Regexp when assert_match accepts a String + assert_no_match(Regexp.new(Regexp.escape(sourcecontents)), latest_result_message, testname) + end + def teardown remove_repository(@repodir) FileUtils.rm_rf(@testroot) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-03-11 01:11:21
|
Revision: 264 http://etch.svn.sourceforge.net/etch/?rev=264&view=rev Author: jheiss Date: 2011-03-11 01:11:15 +0000 (Fri, 11 Mar 2011) Log Message: ----------- Add tests for scripts that call return or exit. Fix handling of scripts that call return. Slightly modify the test of a script with a syntax error to use "syntax_error" rather than "syntax error". It makes it more obvious in the error messages that something unnatural is going on. Modified Paths: -------------- trunk/server/lib/etch.rb trunk/test/test_scripts.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-03-10 00:41:10 UTC (rev 263) +++ trunk/server/lib/etch.rb 2011-03-11 01:11:15 UTC (rev 264) @@ -1384,7 +1384,7 @@ @dlogger.debug "Processing script #{script} for file #{@file}" @contents = '' begin - eval(IO.read(script)) + run_script_stage2(script) rescue Exception => e if e.kind_of?(SystemExit) # The user might call exit within a script. We want the scripts @@ -1397,5 +1397,13 @@ end @contents end + # The user might call return within a script. We want the scripts to act as + # much like a real script as possible. Wrapping the eval in an extra method + # allows us to handle a return within the script seamlessly. If the user + # calls return it triggers a return from this method. Otherwise this method + # returns naturally. Either works for us. + def run_script_stage2(script) + eval(IO.read(script)) + end end Modified: trunk/test/test_scripts.rb =================================================================== --- trunk/test/test_scripts.rb 2011-03-10 00:41:10 UTC (rev 263) +++ trunk/test/test_scripts.rb 2011-03-11 01:11:15 UTC (rev 264) @@ -52,7 +52,7 @@ end File.open("#{@repodir}/source/#{@targetfile}/source.script", 'w') do |file| - file.write('syntax error') + file.write('syntax_error') end # Gather some stats about the file before we run etch @@ -64,8 +64,73 @@ # Verify that etch didn't do anything to the file assert_equal(before_size, File.stat(@targetfile).size, 'script with syntax error size comparison') assert_equal(before_ctime, File.stat(@targetfile).ctime, 'script with syntax error ctime comparison') - + # + # Script that calls return, make sure nothing blows up + # + testname = 'script calls return' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <source> + <script>source.script</script> + </source> + </file> + </config> + EOF + end + + File.open("#{@repodir}/source/#{@targetfile}/source.script", 'w') do |file| + file.write('return') + end + + # Gather some stats about the file before we run etch + before_size = File.stat(@targetfile).size + before_ctime = File.stat(@targetfile).ctime + + #run_etch(@server, @testroot, :errors_expected => false, :testname => testname) + run_etch(@server, @testroot, :testname => testname) + + # Verify that etch didn't do anything to the file + assert_equal(before_size, File.stat(@targetfile).size, testname + ' size comparison') + assert_equal(before_ctime, File.stat(@targetfile).ctime, testname + ' ctime comparison') + + # + # Script that calls exit, make sure nothing blows up + # + testname = 'script calls exit' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <source> + <script>source.script</script> + </source> + </file> + </config> + EOF + end + + File.open("#{@repodir}/source/#{@targetfile}/source.script", 'w') do |file| + file.write('exit') + end + + # Gather some stats about the file before we run etch + before_size = File.stat(@targetfile).size + before_ctime = File.stat(@targetfile).ctime + + run_etch(@server, @testroot, :testname => testname) + + # Verify that etch didn't do anything to the file + assert_equal(before_size, File.stat(@targetfile).size, testname + ' size comparison') + assert_equal(before_ctime, File.stat(@targetfile).ctime, testname + ' ctime comparison') + + # # Run a test where the script doesn't output anything # testname = 'script with no output' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-04-12 01:23:59
|
Revision: 267 http://etch.svn.sourceforge.net/etch/?rev=267&view=rev Author: jheiss Date: 2011-04-12 01:23:53 +0000 (Tue, 12 Apr 2011) Log Message: ----------- Add support for nokogiri as a choice of XML libraries in addition to the existing support for libxml and rexml. Modified Paths: -------------- trunk/server/lib/etch.rb trunk/server/lib/etchserver.rb trunk/test/README Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-04-12 01:21:17 UTC (rev 266) +++ trunk/server/lib/etch.rb 2011-04-12 01:23:53 UTC (rev 267) @@ -3,6 +3,19 @@ require 'digest/sha1' # hexdigest require 'base64' # decode64, encode64 require 'fileutils' # mkdir_p +require 'erb' +require 'versiontype' # Version +require 'logger' + +class Etch + def self.xmllib + @@xmllib + end + def self.xmllib=(lib) + @@xmllib=lib + end +end + # By default we try to use libxml, falling back to rexml if it is not # available. The xmllib environment variable can be used to force one library # or the other, mostly for testing purposes. @@ -10,24 +23,24 @@ if !ENV['xmllib'] || ENV['xmllib'] == 'libxml' require 'rubygems' # libxml is a gem require 'libxml' - @@xmllib = :libxml + Etch.xmllib = :libxml + elsif ENV['xmllib'] == 'nokogiri' + require 'rubygems' # nokogiri is a gem + require 'nokogiri' + Etch.xmllib = :nokogiri else raise LoadError end rescue LoadError if !ENV['xmllib'] || ENV['xmllib'] == 'rexml' require 'rexml/document' - @@xmllib = :rexml + Etch.xmllib = :rexml else raise end end -require 'erb' -require 'versiontype' # Version -require 'logger' class Etch - # FIXME: I'm not really proud of this, it seems like there ought to be a way # to just use one logger. The problem is that on the server we'd like to # use RAILS_DEFAULT_LOGGER for general logging (which is logging to @@ -270,8 +283,10 @@ end # Validate the filtered file against config.dtd - if !Etch.xmlvalidate(config_xml, @config_dtd) - raise "Filtered config.xml for #{file} fails validation" + begin + Etch.xmlvalidate(config_xml, @config_dtd) + rescue Exception => e + raise Etch.wrap_exception(e, "Filtered config.xml for #{file} fails validation:\n" + e.message) end generation_status = :unknown @@ -846,8 +861,10 @@ end # Validate the filtered file against commands.dtd - if !Etch.xmlvalidate(commands_xml, @commands_dtd) - raise "Filtered commands.xml for #{command} fails validation" + begin + Etch.xmlvalidate(commands_xml, @commands_dtd) + rescue Exception => e + raise Etch.wrap_exception(e, "Filtered commands.xml for #{command} fails validation:\n" + e.message) end generation_status = :unknown @@ -1076,102 +1093,154 @@ end end + # These methods provide an abstraction from the underlying XML library in + # use, allowing us to use whatever the user has available and switch between + # libraries easily. + def self.xmlnewdoc - case @@xmllib + case Etch.xmllib when :libxml LibXML::XML::Document.new + when :nokogiri + Nokogiri::XML::Document.new when :rexml REXML::Document.new else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlroot(doc) - case @@xmllib + case Etch.xmllib when :libxml doc.root + when :nokogiri + doc.root when :rexml doc.root else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlsetroot(doc, root) - case @@xmllib + case Etch.xmllib when :libxml doc.root = root + when :nokogiri + doc.root = root when :rexml doc << root else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlload(file) - case @@xmllib + case Etch.xmllib when :libxml LibXML::XML::Document.file(file) + when :nokogiri + Nokogiri::XML(File.open(file)) do |config| + # Nokogiri is tolerant of malformed documents by default. Good when + # parsing HTML, but there's no reason for us to tolerate errors. We + # want to ensure that the user's instructions to us are clear. + config.options = Nokogiri::XML::ParseOptions::STRICT + end when :rexml REXML::Document.new(File.open(file)) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlloaddtd(dtdfile) - case @@xmllib + case Etch.xmllib when :libxml LibXML::XML::Dtd.new(IO.read(dtdfile)) + when :nokogiri + # For some reason there isn't a straightforward way to load a standalone + # DTD in Nokogiri + dtddoctext = '<!DOCTYPE dtd [' + File.read(dtdfile) + ']' + dtddoc = Nokogiri::XML(dtddoctext) + dtddoc.children.first when :rexml nil else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end + # Returns true if validation is successful, or if validation is not + # supported by the XML library in use. Raises an exception if validation + # fails. def self.xmlvalidate(xmldoc, dtd) - case @@xmllib + case Etch.xmllib when :libxml - xmldoc.validate(dtd) + result = xmldoc.validate(dtd) + # LibXML::XML::Document#validate is documented to return false if + # validation fails. However, as currently implemented it raises an + # exception instead. Just in case that behavior ever changes raise an + # exception if a false value is returned. + if result + true + else + raise "Validation failed" + end + when :nokogiri + errors = dtd.validate(xmldoc) + if errors.empty? + true + else + raise errors.join('|') + end when :rexml true else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end - def self.xmlnewelem(name) - case @@xmllib + def self.xmlnewelem(name, doc) + case Etch.xmllib when :libxml LibXML::XML::Node.new(name) + when :nokogiri + Nokogiri::XML::Element.new(name, doc) when :rexml REXML::Element.new(name) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmleach(xmldoc, xpath, &block) - case @@xmllib + case Etch.xmllib when :libxml xmldoc.find(xpath).each(&block) + when :nokogiri + xmldoc.xpath(xpath).each(&block) when :rexml xmldoc.elements.each(xpath, &block) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmleachall(xmldoc, &block) - case @@xmllib + case Etch.xmllib when :libxml if xmldoc.kind_of?(LibXML::XML::Document) xmldoc.root.each_element(&block) else xmldoc.each_element(&block) end + when :nokogiri + if xmldoc.kind_of?(Nokogiri::XML::Document) + xmldoc.root.element_children.each(&block) + else + xmldoc.element_children.each(&block) + end when :rexml if xmldoc.node_type == :document xmldoc.root.elements.each(&block) @@ -1179,23 +1248,25 @@ xmldoc.elements.each(&block) end else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmleachattrall(elem, &block) - case @@xmllib + case Etch.xmllib when :libxml elem.attributes.each(&block) + when :nokogiri + elem.attribute_nodes.each(&block) when :rexml elem.attributes.each_attribute(&block) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlarray(xmldoc, xpath) - case @@xmllib + case Etch.xmllib when :libxml elements = xmldoc.find(xpath) if elements @@ -1203,28 +1274,34 @@ else [] end + when :nokogiri + xmldoc.xpath(xpath).to_a when :rexml xmldoc.elements.to_a(xpath) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlfindfirst(xmldoc, xpath) - case @@xmllib + case Etch.xmllib when :libxml xmldoc.find_first(xpath) + when :nokogiri + xmldoc.at_xpath(xpath) when :rexml xmldoc.elements[xpath] else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmltext(elem) - case @@xmllib + case Etch.xmllib when :libxml elem.content + when :nokogiri + elem.content when :rexml text = elem.text # REXML returns nil rather than '' if there is no text @@ -1234,57 +1311,67 @@ '' end else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlsettext(elem, text) - case @@xmllib + case Etch.xmllib when :libxml elem.content = text + when :nokogiri + elem.content = text when :rexml elem.text = text else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmladd(xmldoc, xpath, name, contents=nil) - case @@xmllib + case Etch.xmllib when :libxml elem = LibXML::XML::Node.new(name) if contents elem.content = contents end xmldoc.find_first(xpath) << elem - elem + when :nokogiri + elem = Nokogiri::XML::Node.new(name, xmldoc) + if contents + elem.content = contents + end + xmldoc.at_xpath(xpath) << elem when :rexml elem = REXML::Element.new(name) if contents elem.text = contents end xmldoc.elements[xpath].add_element(elem) - elem else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlcopyelem(elem, destelem) - case @@xmllib + case Etch.xmllib when :libxml destelem << elem.copy(true) + when :nokogiri + destelem << elem.dup when :rexml - destelem.add_element(elem.dup) + destelem.add_element(elem.clone) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlremove(xmldoc, element) - case @@xmllib + case Etch.xmllib when :libxml element.remove! + when :nokogiri + element.remove when :rexml if xmldoc.node_type == :document xmldoc.root.elements.delete(element) @@ -1292,40 +1379,51 @@ xmldoc.elements.delete(element) end else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlremovepath(xmldoc, xpath) - case @@xmllib + case Etch.xmllib when :libxml xmldoc.find(xpath).each { |elem| elem.remove! } + when :nokogiri + xmldoc.xpath(xpath).each { |elem| elem.remove } when :rexml - xmldoc.delete_element(xpath) + elem = nil + # delete_element only removes the first match, so call it in a loop + # until it returns nil to indicate no matching element remain + begin + elem = xmldoc.delete_element(xpath) + end while elem != nil else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlattradd(elem, attrname, attrvalue) - case @@xmllib + case Etch.xmllib when :libxml elem.attributes[attrname] = attrvalue + when :nokogiri + elem[attrname] = attrvalue when :rexml elem.add_attribute(attrname, attrvalue) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end def self.xmlattrremove(elem, attribute) - case @@xmllib + case Etch.xmllib when :libxml attribute.remove! + when :nokogiri + attribute.remove when :rexml elem.attributes.delete(attribute) else - raise "Unknown @xmllib #{@xmllib}" + raise "Unknown XML library #{Etch.xmllib}" end end Modified: trunk/server/lib/etchserver.rb =================================================================== --- trunk/server/lib/etchserver.rb 2011-04-12 01:21:17 UTC (rev 266) +++ trunk/server/lib/etchserver.rb 2011-04-12 01:23:53 UTC (rev 267) @@ -3,25 +3,6 @@ require 'openssl' require 'time' # Time.parse require 'fileutils' # mkdir_p -# By default we try to use libxml, falling back to rexml if it is not -# available. The xmllib environment variable can be used to force one library -# or the other, mostly for testing purposes. -begin - if !ENV['xmllib'] || ENV['xmllib'] == 'libxml' - require 'rubygems' # libxml is a gem - require 'libxml' - @@xmllib = :libxml - else - raise LoadError - end -rescue LoadError - if !ENV['xmllib'] || ENV['xmllib'] == 'rexml' - require 'rexml/document' - @@xmllib = :rexml - else - raise - end -end require 'logger' require 'etch' @@ -372,11 +353,11 @@ # Generate the XML document to return to the client response_xml = Etch.xmlnewdoc - responseroot = Etch.xmlnewelem('files') + responseroot = Etch.xmlnewelem('files', response_xml) Etch.xmlsetroot(response_xml, responseroot) # Add configs for files we generated if response[:configs] - configs_xml = Etch.xmlnewelem('configs') + configs_xml = Etch.xmlnewelem('configs', response_xml) response[:configs].each do |file, config_xml| # Update the stored record of the config # Exclude configs which correspond to files for which we're requesting @@ -408,18 +389,18 @@ end end if !need_sum.empty? - need_sums_xml = Etch.xmlnewelem('need_sums') + need_sums_xml = Etch.xmlnewelem('need_sums', response_xml) need_sum.each do |need| - need_xml = Etch.xmlnewelem('need_sum') + need_xml = Etch.xmlnewelem('need_sum', response_xml) Etch.xmlsettext(need_xml, need) need_sums_xml << need_xml end responseroot << need_sums_xml end if !need_orig.empty? - need_origs_xml = Etch.xmlnewelem('need_origs') + need_origs_xml = Etch.xmlnewelem('need_origs', response_xml) need_orig.each do |need| - need_xml = Etch.xmlnewelem('need_orig') + need_xml = Etch.xmlnewelem('need_orig', response_xml) Etch.xmlsettext(need_xml, need) need_origs_xml << need_xml end @@ -431,7 +412,7 @@ # "commands", so we have to use something different here as the XML # element we insert all of those into as part of the response. if response[:allcommands] - commands_xml = Etch.xmlnewelem('allcommands') + commands_xml = Etch.xmlnewelem('allcommands', response_xml) response[:allcommands].each do |commandname, command_xml| # Update the stored record of the command config = EtchConfig.find_or_create_by_client_id_and_file(:client_id => @client.id, :file => commandname, :config => command_xml.to_s) @@ -444,19 +425,19 @@ responseroot << commands_xml end if response[:retrycommands] - retrycommands_xml = Etch.xmlnewelem('retrycommands') + retrycommands_xml = Etch.xmlnewelem('retrycommands', response_xml) response[:retrycommands].each_key do |commandname| - retry_xml = Etch.xmlnewelem('retrycommand') + retry_xml = Etch.xmlnewelem('retrycommand', response_xml) Etch.xmlsettext(retry_xml, commandname) retrycommands_xml << retry_xml end responseroot << retrycommands_xml end - # FIXME: clean up XML formatting + # Clean up XML formatting # But only if we're in debug mode, in regular mode nobody but the # machines will see the XML and they don't care if it is pretty. - # Tidy's formatting breaks things, it inserts leading/trailing whitespace into text nodes + # FIXME: Tidy's formatting breaks things, it inserts leading/trailing whitespace into text nodes if @debug && false require 'tidy' Tidy.path = '/sw/lib/libtidy.dylib' Modified: trunk/test/README =================================================================== --- trunk/test/README 2011-04-12 01:21:17 UTC (rev 266) +++ trunk/test/README 2011-04-12 01:23:53 UTC (rev 267) @@ -3,8 +3,8 @@ To execute a specific test method run "rake test TEST=test/file.rb TESTOPTS='--name=test_files'" -To force a particular XML library set xmllib=libxml or xmllib=rexml in -your environment before running the tests. +To force a particular XML library set xmllib=libxml or xmllib=nokogiri or +xmllib=rexml in your environment before running the tests. Some of the older files here have all of their tests in one method. Over time I'm breaking those up into multiple methods so that it is easier to This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-04-12 06:08:39
|
Revision: 268 http://etch.svn.sourceforge.net/etch/?rev=268&view=rev Author: jheiss Date: 2011-04-12 06:08:33 +0000 (Tue, 12 Apr 2011) Log Message: ----------- Add xmlattrvalue method to XML abstraction layer Modified Paths: -------------- trunk/server/lib/etch.rb trunk/test/unit/test_xml_abstraction.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-04-12 01:23:53 UTC (rev 267) +++ trunk/server/lib/etch.rb 2011-04-12 06:08:33 UTC (rev 268) @@ -1414,6 +1414,19 @@ end end + def self.xmlattrvalue(elem, attrname) + case Etch.xmllib + when :libxml + elem.attributes[attrname] + when :nokogiri + elem[attrname] + when :rexml + elem.attributes[attrname] + else + raise "Unknown XML library #{Etch.xmllib}" + end + end + def self.xmlattrremove(elem, attribute) case Etch.xmllib when :libxml Modified: trunk/test/unit/test_xml_abstraction.rb =================================================================== --- trunk/test/unit/test_xml_abstraction.rb 2011-04-12 01:23:53 UTC (rev 267) +++ trunk/test/unit/test_xml_abstraction.rb 2011-04-12 06:08:33 UTC (rev 268) @@ -434,6 +434,17 @@ raise "Unknown XML library #{Etch.xmllib}" end end + def test_xmlattrvalue + file = Tempfile.new('etch_xml_abstraction') + file.puts '<root><element attrname="attrvalue"><child/></element><element attrname="othervalue"/><other/></root>' + file.close + doc = Etch.xmlload(file.path) + + first = Etch.xmlarray(doc, '/root/element').first + second = Etch.xmlarray(doc, '/root/element').last + assert_equal('attrvalue', Etch.xmlattrvalue(first, 'attrname')) + assert_equal('othervalue', Etch.xmlattrvalue(second, 'attrname')) + end def test_xmlattrremove file = Tempfile.new('etch_xml_abstraction') file.puts '<root><element attrname="attrvalue"><child/></element><element attrname="othervalue"/><other/></root>' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-04-26 23:32:53
|
Revision: 322 http://etch.svn.sourceforge.net/etch/?rev=322&view=rev Author: jheiss Date: 2012-04-26 23:32:47 +0000 (Thu, 26 Apr 2012) Log Message: ----------- Move the top-level Gemfile I created a while back into the client directory now that the server directory has its own proper Gemfile. Added Paths: ----------- trunk/client/Gemfile trunk/client/Gemfile.lock Removed Paths: ------------- trunk/Gemfile trunk/Gemfile.lock Deleted: trunk/Gemfile =================================================================== --- trunk/Gemfile 2012-04-24 19:59:57 UTC (rev 321) +++ trunk/Gemfile 2012-04-26 23:32:47 UTC (rev 322) @@ -1,14 +0,0 @@ -source :rubygems -gem 'facter' -gem 'nokogiri' -# Tests will be run with nokogiri by default, but it might be nice to have -# libxml available too if you want to test with it as well. -gem 'libxml-ruby' - -group :server do - gem 'rails', '2.3.14' - gem 'sqlite3' - gem 'will_paginate', '~> 2.3.15' - gem 'searchlogic' -end - Deleted: trunk/Gemfile.lock =================================================================== --- trunk/Gemfile.lock 2012-04-24 19:59:57 UTC (rev 321) +++ trunk/Gemfile.lock 2012-04-26 23:32:47 UTC (rev 322) @@ -1,42 +0,0 @@ -GEM - remote: http://rubygems.org/ - specs: - actionmailer (2.3.14) - actionpack (= 2.3.14) - actionpack (2.3.14) - activesupport (= 2.3.14) - rack (~> 1.1.0) - activerecord (2.3.14) - activesupport (= 2.3.14) - activeresource (2.3.14) - activesupport (= 2.3.14) - activesupport (2.3.14) - facter (1.6.5) - libxml-ruby (2.2.2) - nokogiri (1.5.0) - rack (1.1.3) - rails (2.3.14) - actionmailer (= 2.3.14) - actionpack (= 2.3.14) - activerecord (= 2.3.14) - activeresource (= 2.3.14) - activesupport (= 2.3.14) - rake (>= 0.8.3) - rake (0.9.2) - searchlogic (2.5.8) - activerecord (~> 2.3.12) - activerecord (~> 2.3.12) - sqlite3 (1.3.5) - will_paginate (2.3.16) - -PLATFORMS - ruby - -DEPENDENCIES - facter - libxml-ruby - nokogiri - rails (= 2.3.14) - searchlogic - sqlite3 - will_paginate (~> 2.3.15) Copied: trunk/client/Gemfile (from rev 315, trunk/Gemfile) =================================================================== --- trunk/client/Gemfile (rev 0) +++ trunk/client/Gemfile 2012-04-26 23:32:47 UTC (rev 322) @@ -0,0 +1,7 @@ +source :rubygems +gem 'facter' +gem 'nokogiri' +# Tests will be run with nokogiri by default, but it might be nice to have +# libxml available too if you want to test with it as well. +gem 'libxml-ruby' + Copied: trunk/client/Gemfile.lock (from rev 315, trunk/Gemfile.lock) =================================================================== --- trunk/client/Gemfile.lock (rev 0) +++ trunk/client/Gemfile.lock 2012-04-26 23:32:47 UTC (rev 322) @@ -0,0 +1,14 @@ +GEM + remote: http://rubygems.org/ + specs: + facter (1.6.5) + libxml-ruby (2.2.2) + nokogiri (1.5.0) + +PLATFORMS + ruby + +DEPENDENCIES + facter + libxml-ruby + nokogiri This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-01-17 05:31:45
|
Revision: 255 http://etch.svn.sourceforge.net/etch/?rev=255&view=rev Author: jheiss Date: 2011-01-17 05:31:39 +0000 (Mon, 17 Jan 2011) Log Message: ----------- ticket:9 Add --list-files option. Don't log to local file in dry run mode. Logging to the server has always operated that way, I forgot to make local file logging operate the same way initially. Modified Paths: -------------- trunk/client/etch trunk/client/etchclient.rb trunk/test/test_options.rb Modified: trunk/client/etch =================================================================== --- trunk/client/etch 2011-01-17 05:28:16 UTC (rev 254) +++ trunk/client/etch 2011-01-17 05:31:39 UTC (rev 255) @@ -35,6 +35,13 @@ # entries. options[:dryrun] = 'damp' end +opts.on('--list-files', 'Just list the files that would be configured') do |opt| + options[:listfiles] = opt + # generate all is implied + @generateall = true + # Set :dryrun as a extra measure to make sure we don't change anything + options[:dryrun] = 'listfiles' +end opts.on('--interactive', 'Prompt for confirmation before each change.') do |opt| options[:interactive] = opt end Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2011-01-17 05:28:16 UTC (rev 254) +++ trunk/client/etchclient.rb 2011-01-17 05:31:39 UTC (rev 255) @@ -57,6 +57,7 @@ @local = options[:local] ? File.expand_path(options[:local]) : nil @debug = options[:debug] @dryrun = options[:dryrun] + @listfiles = options[:listfiles] @interactive = options[:interactive] @filenameonly = options[:filenameonly] @fullfile = options[:fullfile] @@ -206,6 +207,9 @@ status = 0 message = '' + # A variable to collect filenames if operating in @listfiles mode + files_to_list = {} + # Prep http instance http = nil if !@local @@ -298,6 +302,11 @@ unlock_all_files end + # It usually takes a few back and forth exchanges with the server to + # exchange all needed data and get a complete set of configuration. + # The number of iterations is capped at 10 to prevent any unplanned + # infinite loops. The limit of 10 was chosen somewhat arbitrarily but + # seems fine in practice. 10.times do # # Send request to server @@ -398,9 +407,13 @@ # needed to create the original files. responsedata[:configs].each_key do |file| puts "Processing config for #{file}" if (@debug) - continue_processing = process_file(file, responsedata) - if !continue_processing - throw :stop_processing + if !@listfiles + continue_processing = process_file(file, responsedata) + if !continue_processing + throw :stop_processing + end + else + files_to_list[file] = true end end responsedata[:need_sums].each_key do |need_sum| @@ -480,6 +493,11 @@ end # begin/rescue end # catch + if @listfiles + puts "Files under management:" + files_to_list.keys.sort.each {|file| puts file} + end + # Send results to server if !@dryrun && !@local rails_results = [] @@ -518,23 +536,25 @@ end end - @detailed_results.each do |detail_dest| - # If any of the destinations look like a file (start with a /) then we - # log to that file - if detail_dest =~ %r{^/} - FileUtils.mkpath(File.dirname(detail_dest)) - File.open(detail_dest, 'a') do |file| - # Add a header for the overall status of the run - file.puts "Etch run at #{Time.now}" - file.puts "Status: #{status}" - if !message.empty? - file.puts "Message:\n#{message}\n" + if !@dryrun + @detailed_results.each do |detail_dest| + # If any of the destinations look like a file (start with a /) then we + # log to that file + if detail_dest =~ %r{^/} + FileUtils.mkpath(File.dirname(detail_dest)) + File.open(detail_dest, 'a') do |file| + # Add a header for the overall status of the run + file.puts "Etch run at #{Time.now}" + file.puts "Status: #{status}" + if !message.empty? + file.puts "Message:\n#{message}\n" + end + # Then the detailed results + @results.each do |result| + file.puts "File #{result['file']}, result #{result['success']}:\n" + file.puts result['message'] + end end - # Then the detailed results - @results.each do |result| - file.puts "File #{result['file']}, result #{result['success']}:\n" - file.puts result['message'] - end end end end Modified: trunk/test/test_options.rb =================================================================== --- trunk/test/test_options.rb 2011-01-17 05:28:16 UTC (rev 254) +++ trunk/test/test_options.rb 2011-01-17 05:31:39 UTC (rev 255) @@ -495,6 +495,47 @@ t.kill end + def test_list_files + # + # Test --list-files + # + testname = '--list-files' + + # Put some text into the original file so that we can make sure it is + # not touched. + origcontents = "This is the original text\n" + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "This is a test\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Test that output from etch is appropriate + #run_etch(@server, @testroot, :extra_args => '--list-files', :testname => testname) + output = `ruby #{CLIENTDIR}/etch --generate-all --test-root=#{@testroot} --key=#{File.dirname(__FILE__)}/keys/testkey --server=http://localhost:#{@server[:port]} --list-files` + assert(output.include?("Files under management:\n#{@targetfile}\n")) + + # Ensure that the target file wasn't touched + assert_equal(origcontents, get_file_contents(@targetfile), testname) + end + def teardown remove_repository(@repodir) FileUtils.rm_rf(@testroot) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-05-04 05:02:11
|
Revision: 274 http://etch.svn.sourceforge.net/etch/?rev=274&view=rev Author: jheiss Date: 2011-05-04 05:02:05 +0000 (Wed, 04 May 2011) Log Message: ----------- Change line that requires etchtest to be compatible with ruby 1.9 Modified Paths: -------------- trunk/Rakefile trunk/test/test_actions.rb trunk/test/test_attributes.rb trunk/test/test_auth.rb trunk/test/test_commands.rb trunk/test/test_conf.rb trunk/test/test_delete.rb trunk/test/test_depend.rb trunk/test/test_file.rb trunk/test/test_history.rb trunk/test/test_link.rb trunk/test/test_local_requests.rb trunk/test/test_nodegroups.rb trunk/test/test_options.rb trunk/test/test_outputcapture.rb trunk/test/test_scripts.rb trunk/test/test_transitions.rb Modified: trunk/Rakefile =================================================================== --- trunk/Rakefile 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/Rakefile 2011-05-04 05:02:05 UTC (rev 274) @@ -3,9 +3,9 @@ # rake test Rake::TestTask.new do |t| # If the user hasn't already set the xmllib environment variable then set it - # to use LibXML so that the tests involving DTD validation are run. + # to use nokogiri so that the tests involving DTD validation are run. if !ENV['xmllib'] - ENV['xmllib'] = 'libxml' + ENV['xmllib'] = 'nokogiri' end t.verbose = true Modified: trunk/test/test_actions.rb =================================================================== --- trunk/test/test_actions.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_actions.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of various actions: pre, post, setup, test, etc. # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchActionTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_attributes.rb =================================================================== --- trunk/test/test_attributes.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_attributes.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of attribute filtering in config.xml files # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'rubygems' # Might be needed to find facter require 'facter' Modified: trunk/test/test_auth.rb =================================================================== --- trunk/test/test_auth.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_auth.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of client authentication # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'net/http' require 'rexml/document' begin Modified: trunk/test/test_commands.rb =================================================================== --- trunk/test/test_commands.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_commands.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of configuration commands # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchCommandTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_conf.rb =================================================================== --- trunk/test/test_conf.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_conf.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of its configuration file, etch.conf # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'net/http' require 'rexml/document' require 'cgi' Modified: trunk/test/test_delete.rb =================================================================== --- trunk/test/test_delete.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_delete.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of deleting files # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchDeleteTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_depend.rb =================================================================== --- trunk/test/test_depend.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_depend.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of dependencies # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchDependTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_file.rb =================================================================== --- trunk/test/test_file.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_file.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of creating and updating regular files # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchFileTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_history.rb =================================================================== --- trunk/test/test_history.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_history.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -5,7 +5,7 @@ # history files # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchHistoryTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_link.rb =================================================================== --- trunk/test/test_link.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_link.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of creating and updating symbolic links # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'pathname' class EtchLinkTests < Test::Unit::TestCase Modified: trunk/test/test_local_requests.rb =================================================================== --- trunk/test/test_local_requests.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_local_requests.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of local requests # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchLocalRequestsTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_nodegroups.rb =================================================================== --- trunk/test/test_nodegroups.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_nodegroups.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test etch's handling of node groups and the node group hierarchy # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchNodeGroupTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_options.rb =================================================================== --- trunk/test/test_options.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_options.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test command line options to etch client # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'webrick' class EtchOptionTests < Test::Unit::TestCase Modified: trunk/test/test_outputcapture.rb =================================================================== --- trunk/test/test_outputcapture.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_outputcapture.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -4,7 +4,7 @@ # Test output capturing # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" require 'timeout' $: << EtchTests::CLIENTDIR $: << File.join(EtchTests::SERVERDIR, 'lib') Modified: trunk/test/test_scripts.rb =================================================================== --- trunk/test/test_scripts.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_scripts.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -5,7 +5,7 @@ # creation of links and directories, and control the deletion of files # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchScriptTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_transitions.rb =================================================================== --- trunk/test/test_transitions.rb 2011-05-04 05:01:00 UTC (rev 273) +++ trunk/test/test_transitions.rb 2011-05-04 05:02:05 UTC (rev 274) @@ -5,7 +5,7 @@ # file, etc.) # -require File.join(File.dirname(__FILE__), 'etchtest') +require "./#{File.dirname(__FILE__)}/etchtest" class EtchTransitionTests < Test::Unit::TestCase include EtchTests This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-05-04 05:39:03
|
Revision: 276 http://etch.svn.sourceforge.net/etch/?rev=276&view=rev Author: jheiss Date: 2011-05-04 05:38:57 +0000 (Wed, 04 May 2011) Log Message: ----------- Find.find in ruby 1.9 doesn't like being called with a non-existent target. So check that directories exist before calling Find.find against them. Fix a few "shadowing outer local variable" warnings from ruby 1.9 Modified Paths: -------------- trunk/client/etchclient.rb trunk/server/lib/etch.rb Modified: trunk/client/etchclient.rb =================================================================== --- trunk/client/etchclient.rb 2011-05-04 05:37:12 UTC (rev 275) +++ trunk/client/etchclient.rb 2011-05-04 05:38:57 UTC (rev 276) @@ -29,6 +29,7 @@ require 'fcntl' # Fcntl::O_* require 'etc' # getpwnam, getgrnam require 'tempfile' # Tempfile +require 'find' # Find.find require 'cgi' require 'timeout' require 'logger' @@ -1803,7 +1804,7 @@ puts "Original file #{file} doesn't exist, saving that state permanently as #{origpath}" end if proceed - File.open(origpath, 'w') { |file| } if (!@dryrun) + File.open(origpath, 'w') { |origfile| } if (!@dryrun) end end @@ -2014,7 +2015,7 @@ else # If there's no file to back up then leave a marker file so # that restore_backup does the right thing - File.open("#{backuppath}.NOORIG", "w") { |file| } + File.open("#{backuppath}.NOORIG", "w") { |markerfile| } end end @@ -2375,7 +2376,7 @@ begin fd = IO::sysopen(lockpath, Fcntl::O_WRONLY|Fcntl::O_CREAT|Fcntl::O_EXCL) puts "Lock acquired for #{file}" if (@debug) - f = IO.open(fd) { |f| f.puts $$ } + f = IO.open(fd) { |lockfile| lockfile.puts $$ } @locked_files[file] = true return rescue Errno::EEXIST @@ -2420,13 +2421,15 @@ # and can be removed. If told to force we remove all lockfiles. def remove_stale_lock_files twohoursago = Time.at(Time.now - 60 * 60 * 2) - Find.find(@lockbase) do |file| - next unless file =~ /\.LOCK$/ - next unless File.file?(file) - - if @lockforce || File.mtime(file) < twohoursago - puts "Removing stale lock file #{file}" - File.delete(file) + if File.exist?(@lockbase) + Find.find(@lockbase) do |file| + next unless file =~ /\.LOCK$/ + next unless File.file?(file) + + if @lockforce || File.mtime(file) < twohoursago + puts "Removing stale lock file #{file}" + File.delete(file) + end end end end Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-05-04 05:37:12 UTC (rev 275) +++ trunk/server/lib/etch.rb 2011-05-04 05:38:57 UTC (rev 276) @@ -170,10 +170,12 @@ filelist = [] if request.empty? @dlogger.debug "Building complete file list for request from #{@fqdn}" - Find.find(@sourcebase) do |path| - if File.directory?(path) && File.exist?(File.join(path, 'config.xml')) - # Strip @sourcebase from start of path - filelist << path.sub(Regexp.new('^' + Regexp.escape(@sourcebase)), '') + if File.exist?(@sourcebase) + Find.find(@sourcebase) do |path| + if File.directory?(path) && File.exist?(File.join(path, 'config.xml')) + # Strip @sourcebase from start of path + filelist << path.sub(Regexp.new('^' + Regexp.escape(@sourcebase)), '') + end end end elsif request[:files] @@ -206,9 +208,11 @@ commandnames = [] if request.empty? @dlogger.debug "Building complete configuration commands for request from #{@fqdn}" - Find.find(@commandsbase) do |path| - if File.directory?(path) && File.exist?(File.join(path, 'commands.xml')) - commandnames << File.basename(path) + if File.exist?(@commandsbase) + Find.find(@commandsbase) do |path| + if File.directory?(path) && File.exist?(File.join(path, 'commands.xml')) + commandnames << File.basename(path) + end end end elsif request[:commands] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-05-19 17:31:21
|
Revision: 287 http://etch.svn.sourceforge.net/etch/?rev=287&view=rev Author: jheiss Date: 2011-05-19 17:31:15 +0000 (Thu, 19 May 2011) Log Message: ----------- Update the DTD files in these directories with some changes made to the testrepo DTD files a while back. Modified Paths: -------------- trunk/etchserver-demo/commands.dtd trunk/etchserver-demo/config.dtd trunk/etchserver-samples/commands.dtd trunk/etchserver-samples/config.dtd Modified: trunk/etchserver-demo/commands.dtd =================================================================== --- trunk/etchserver-demo/commands.dtd 2011-05-05 00:28:08 UTC (rev 286) +++ trunk/etchserver-demo/commands.dtd 2011-05-19 17:31:15 UTC (rev 287) @@ -1,6 +1,7 @@ -<!ELEMENT commands (depend*, step*)> +<!ELEMENT commands (depend*, dependfile*, step*)> <!ELEMENT depend (#PCDATA)> +<!ELEMENT dependfile (#PCDATA)> <!ELEMENT step (guard, command)> <!ELEMENT guard (exec*)> Modified: trunk/etchserver-demo/config.dtd =================================================================== --- trunk/etchserver-demo/config.dtd 2011-05-05 00:28:08 UTC (rev 286) +++ trunk/etchserver-demo/config.dtd 2011-05-19 17:31:15 UTC (rev 287) @@ -1,8 +1,9 @@ -<!ELEMENT config (revert?, depend*, server_setup?, setup?, pre?, (file|link|directory|delete)+, test_before_post?, post?, test?)> +<!ELEMENT config (revert?, depend*, dependcommand*, server_setup?, setup?, pre?, (file|link|directory|delete)+, test_before_post?, post?, test?)> <!ELEMENT revert EMPTY> <!ELEMENT depend (#PCDATA)> +<!ELEMENT dependcommand (#PCDATA)> <!ELEMENT server_setup (exec*)> <!ELEMENT setup (exec*)> Modified: trunk/etchserver-samples/commands.dtd =================================================================== --- trunk/etchserver-samples/commands.dtd 2011-05-05 00:28:08 UTC (rev 286) +++ trunk/etchserver-samples/commands.dtd 2011-05-19 17:31:15 UTC (rev 287) @@ -1,6 +1,7 @@ -<!ELEMENT commands (depend*, step*)> +<!ELEMENT commands (depend*, dependfile*, step*)> <!ELEMENT depend (#PCDATA)> +<!ELEMENT dependfile (#PCDATA)> <!ELEMENT step (guard, command)> <!ELEMENT guard (exec*)> Modified: trunk/etchserver-samples/config.dtd =================================================================== --- trunk/etchserver-samples/config.dtd 2011-05-05 00:28:08 UTC (rev 286) +++ trunk/etchserver-samples/config.dtd 2011-05-19 17:31:15 UTC (rev 287) @@ -1,8 +1,9 @@ -<!ELEMENT config (revert?, depend*, server_setup?, setup?, pre?, (file|link|directory|delete)+, test_before_post?, post?, test?)> +<!ELEMENT config (revert?, depend*, dependcommand*, server_setup?, setup?, pre?, (file|link|directory|delete)+, test_before_post?, post?, test?)> <!ELEMENT revert EMPTY> <!ELEMENT depend (#PCDATA)> +<!ELEMENT dependcommand (#PCDATA)> <!ELEMENT server_setup (exec*)> <!ELEMENT setup (exec*)> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-02 16:13:23
|
Revision: 304 http://etch.svn.sourceforge.net/etch/?rev=304&view=rev Author: jheiss Date: 2012-03-02 16:13:17 +0000 (Fri, 02 Mar 2012) Log Message: ----------- Add a bundler Gemfile to make it easier for new users to get the necessary gems to run the test suite or otherwise experiment. Added Paths: ----------- trunk/Gemfile trunk/Gemfile.lock Added: trunk/Gemfile =================================================================== --- trunk/Gemfile (rev 0) +++ trunk/Gemfile 2012-03-02 16:13:17 UTC (rev 304) @@ -0,0 +1,14 @@ +source :rubygems +gem 'facter' +gem 'nokogiri' +# Tests will be run with nokogiri by default, but it might be nice to have +# libxml available too if you want to test with it as well. +gem 'libxml-ruby' + +group :server do + gem 'rails', '2.3.14' + gem 'sqlite3' + gem 'will_paginate', '~> 2.3.15' + gem 'searchlogic' +end + Added: trunk/Gemfile.lock =================================================================== --- trunk/Gemfile.lock (rev 0) +++ trunk/Gemfile.lock 2012-03-02 16:13:17 UTC (rev 304) @@ -0,0 +1,42 @@ +GEM + remote: http://rubygems.org/ + specs: + actionmailer (2.3.14) + actionpack (= 2.3.14) + actionpack (2.3.14) + activesupport (= 2.3.14) + rack (~> 1.1.0) + activerecord (2.3.14) + activesupport (= 2.3.14) + activeresource (2.3.14) + activesupport (= 2.3.14) + activesupport (2.3.14) + facter (1.6.5) + libxml-ruby (2.2.2) + nokogiri (1.5.0) + rack (1.1.3) + rails (2.3.14) + actionmailer (= 2.3.14) + actionpack (= 2.3.14) + activerecord (= 2.3.14) + activeresource (= 2.3.14) + activesupport (= 2.3.14) + rake (>= 0.8.3) + rake (0.9.2) + searchlogic (2.5.8) + activerecord (~> 2.3.12) + activerecord (~> 2.3.12) + sqlite3 (1.3.5) + will_paginate (2.3.16) + +PLATFORMS + ruby + +DEPENDENCIES + facter + libxml-ruby + nokogiri + rails (= 2.3.14) + searchlogic + sqlite3 + will_paginate (~> 2.3.15) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |