# ==================================================================== # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ==================================================================== require "fileutils" require "pathname" # Tale of a hack... # # Here we are, %SVN-WC-ROOT%/subversion/bindings/swig/ruby/test/util.rb, # trying to require %SVN-WC-ROOT%/subversion/bindings/swig/ruby/svn/util.rb, # all the while supporting both Ruby 1.8 and 1.9. Simply using this, # # require "svn/util" # # works for Ruby 1.8 if the CWD is subversion/bindings/swig/ruby # when we are running the tests, e.g.: # # %SVN-WC-ROOT%/subversion/bindings/swig/ruby>ruby test\run-test.rb # # This is because the CWD is included in the load path when Ruby 1.8 # searches for required files. But this doesn't work for Ruby 1.9, # which doesn't include the CWD this way, so instead we could use this: # # require "./svn/util" # # But that only works if ./svn/util is relative to the CWD (again if the # CWD is %SVN-WC-ROOT%/subversion/bindings/swig/ruby). However, if we run # the tests from a different CWD and specify # %SVN-WC-ROOT%/subversion/bindings/swig/ruby as an additional $LOAD_PATH # using the ruby -I option, then that fails on both 1.8 and 1.9 with a # LoadError. # # The usual solution in a case like this is to use require_relative, # # require_relative "../svn/util" # # But that's only available in Ruby 1.9. We could require the backports gem # but there is a simple workaround, just calculate the full path of util: require File.join(File.dirname(__FILE__), '../svn/util') require "tmpdir" require "my-assertions" class Time unless instance_methods.include?("to_int") alias to_int to_i end end require 'greek_tree' module SvnTestUtil def setup_default_variables @author = ENV["USER"] || "sample-user" @password = "sample-password" @realm = "sample realm" @svnserve_host = "127.0.0.1" @svnserve_ports = (64152..64282).collect{|x| x.to_s} @tmp_path = Dir.mktmpdir @wc_path = File.join(@tmp_path, "wc") @import_path = File.join(@tmp_path, "import") @repos_path = File.join(@tmp_path, "repos") @svnserve_pid_file = File.join(@tmp_path, "svnserve.pid") @full_repos_path = File.expand_path(@repos_path) @repos_uri = "file://#{@full_repos_path.sub(/^\/?/, '/')}" @config_path = File.join(@tmp_path, "config") @greek = Greek.new(@tmp_path, @import_path, @wc_path, @repos_uri) end def setup_basic(need_svnserve=false) @need_svnserve = need_svnserve setup_default_variables setup_tmp setup_tmp(@import_path) setup_repository add_hooks setup_svnserve if @need_svnserve setup_config setup_wc add_authentication GC.stress = true if GC.respond_to?(:stress=) and $DEBUG end def teardown_basic GC.stress = false if GC.respond_to?(:stress=) teardown_svnserve if @need_svnserve teardown_repository teardown_wc teardown_config teardown_tmp gc end def gc if $DEBUG before_pools = Svn::Core::Pool.number_of_pools puts puts "before pools: #{before_pools}" end gc_enable do GC.start end if $DEBUG after_pools = Svn::Core::Pool.number_of_pools puts "after pools: #{after_pools}" STDOUT.flush end end def change_gc_status(prev_disabled) begin yield ensure if prev_disabled GC.disable else GC.enable end end end def gc_disable(&block) change_gc_status(GC.disable, &block) end def gc_enable(&block) change_gc_status(GC.enable, &block) end def setup_tmp(path=@tmp_path) remove_recursively_with_retry(path) FileUtils.mkdir_p(path) end def teardown_tmp(path=@tmp_path) remove_recursively_with_retry(path) end def setup_repository(path=@repos_path, config={}, fs_config={}) require "svn/repos" remove_recursively_with_retry(path) FileUtils.mkdir_p(File.dirname(path)) @repos = Svn::Repos.create(path, config, fs_config) @fs = @repos.fs end def teardown_repository(path=@repos_path) @fs.close unless @fs.nil? @repos.close unless @repos.nil? remove_recursively_with_retry(path) @repos = nil @fs = nil end def setup_wc teardown_wc make_context("") { |ctx| ctx.checkout(@repos_uri, @wc_path) } end def teardown_wc remove_recursively_with_retry(@wc_path) end def setup_config teardown_config Svn::Core::Config.ensure(@config_path) end def teardown_config remove_recursively_with_retry(@config_path) end def add_authentication passwd_file = "passwd" File.open(@repos.svnserve_conf, "w") do |conf| conf.print <<-CONF [general] anon-access = none auth-access = write password-db = #{passwd_file} realm = #{@realm} CONF end File.open(File.join(@repos.conf_dir, passwd_file), "w") do |f| f.print <<-PASSWD [users] #{@author} = #{@password} PASSWD end end def add_hooks add_pre_revprop_change_hook end def youngest_rev @fs.youngest_rev end def root(rev=nil) @fs.root(rev) end def prop(name, rev=nil) @fs.prop(name, rev) end def make_context(log) ctx = Svn::Client::Context.new ctx.set_log_msg_func do |items| [true, log] end ctx.add_username_prompt_provider(0) do |cred, realm, username, may_save| cred.username = @author cred.may_save = false end ctx.config = Svn::Core::Config.config(@config_path) setup_auth_baton(ctx.auth_baton) return ctx unless block_given? begin yield ctx ensure ctx.destroy end end def setup_auth_baton(auth_baton) auth_baton[Svn::Core::AUTH_PARAM_CONFIG_DIR] = @config_path auth_baton[Svn::Core::AUTH_PARAM_DEFAULT_USERNAME] = @author end def normalize_line_break(str) if Svn::Util.windows? str.gsub(/\n/, "\r\n") else str end end def setup_greek_tree make_context("setup greek tree") { |ctx| @greek.setup(ctx) } end def remove_recursively_with_retry(path) retries = 0 while (retries+=1) < 100 && File.exist?(path) begin FileUtils.rm_r(path, :secure=>true) rescue sleep 0.1 end end assert(!File.exist?(path), "#{Dir.glob(path+'/**/*').join("\n")} should not exist after #{retries} attempts to delete") end module Svnserve def setup_svnserve @svnserve_port = nil @repos_svnserve_uri = nil # Look through the list of potential ports until we're able to # successfully start svnserve on a free one. @svnserve_ports.each do |port| @svnserve_pid = fork { STDERR.close exec("svnserve", "--listen-host", @svnserve_host, "--listen-port", port, "-d", "--foreground") } pid, status = Process.waitpid2(@svnserve_pid, Process::WNOHANG) if status and status.exited? if $DEBUG STDERR.puts "port #{port} couldn't be used for svnserve" end else # svnserve started successfully. Note port number and cease # startup attempts. @svnserve_port = port @repos_svnserve_uri = "svn://#{@svnserve_host}:#{@svnserve_port}#{@full_repos_path}" # Avoid a race by waiting a short time for svnserve to start up. # Without this, tests can fail with "Connection refused" errors. sleep 1 break end end if @svnserve_port.nil? msg = "Can't run svnserve because available port " msg << "isn't exist in [#{@svnserve_ports.join(', ')}]" raise msg end end def teardown_svnserve if @svnserve_pid Process.kill(:TERM, @svnserve_pid) begin Process.waitpid(@svnserve_pid) rescue Errno::ECHILD end end end def add_pre_revprop_change_hook File.open(@repos.pre_revprop_change_hook, "w") do |hook| hook.print <<-HOOK #!/bin/sh REPOS="$1" REV="$2" USER="$3" PROPNAME="$4" if [ "$PROPNAME" = "#{Svn::Core::PROP_REVISION_LOG}" -a \ "$USER" = "#{@author}" ]; then exit 0 fi exit 1 HOOK end FileUtils.chmod(0755, @repos.pre_revprop_change_hook) end end module SetupEnvironment def setup_test_environment(top_dir, base_dir, ext_dir) svnserve_dir = File.join(top_dir, 'subversion', 'svnserve') ENV["PATH"] = "#{svnserve_dir}:#{ENV['PATH']}" FileUtils.ln_sf(File.join(base_dir, ".libs"), ext_dir) end end if Svn::Util.windows? require 'windows_util' include Windows::Svnserve extend Windows::SetupEnvironment else include Svnserve extend SetupEnvironment end end