1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
#!/usr/bin/env ruby
#
# Copyright 2006,2007,2008,2009,2010,2012 Martin Pärtel <martin.partel@gmail.com>
#
# This file is part of bindfs.
#
# bindfs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# bindfs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with bindfs. If not, see <http://www.gnu.org/licenses/>.
#
require 'ruby18_hacks.rb'
require 'shellwords' unless $ruby_18_hacks_enabled # Ruby 1.8 doesn't have shellwords
require 'fileutils'
include FileUtils
# Set the default umask for all tests
File.umask 0022
EXECUTABLE_PATH = '../src/bindfs'
TESTDIR_NAME = 'tmp_test_bindfs'
# If set to an array of test names, only those will be run
$only_these_tests = nil
def fail(msg, error = nil, options = {})
options = {:exit => false}.merge(options)
$stderr.puts(msg)
if error.is_a?(Exception)
$stderr.puts(error.message + "\n " + error.backtrace.join("\n "))
elsif error != nil
$stderr.puts(error.to_s)
end
exit! 1 if options[:exit]
end
def fail!(msg, error = nil, options = {})
options = {:exit => true}.merge(options)
fail(msg, error, options)
end
def wait_for(options = {}, &condition)
options = {
:initial_sleep => 0.01,
:sleep_ramp_up => 2,
:max_sleep => 0.5,
:max_time => 5
}.merge(options)
start_time = Time.now
sleep_time = options[:initial_sleep]
while !`mount`.include?(`pwd`.strip)
sleep sleep_time
sleep_time = [sleep_time * options[:sleep_ramp_up], options[:max_sleep]].min
if Time.now - start_time > options[:max_time]
return false
end
end
true
end
def with_umask(umask, &block)
old_umask = File.umask(umask)
begin
block.call
ensure
File.umask(old_umask)
end
end
def valgrind_options
opt = ARGV.find {|s| s.start_with?('--valgrind') }
if opt == nil
nil
elsif opt =~ /^--valgrind=(.*)$/
$1
else
''
end
end
# Prepares a test environment with a mounted directory
def testenv(bindfs_args, options = {}, &block)
options = {
:title => bindfs_args,
:valgrind => valgrind_options != nil,
:valgrind_opts => valgrind_options,
:srcdir_name => 'src',
:mntdir_name => 'mnt'
}.merge(options)
# todo: less repetitive and more careful error handling and cleanup
puts "--- #{options[:title]} ---"
puts "[ #{bindfs_args} ]"
srcdir = options[:srcdir_name]
mntdir = options[:mntdir_name]
begin
Dir.mkdir TESTDIR_NAME
rescue Exception => ex
fail!("ERROR creating testdir at #{TESTDIR_NAME}", ex)
end
begin
Dir.chdir TESTDIR_NAME
Dir.mkdir srcdir
Dir.mkdir mntdir
rescue Exception => ex
fail!("ERROR preparing testdir at #{TESTDIR_NAME}", ex)
end
bindfs_pid = nil
begin
extra_args = "-f"
# Don't rely on user_allow_other in /etc/fuse.conf.
# On FreeBSD it isn't even possible to set that.
extra_args += " --no-allow-other" if Process.uid != 0
cmd = "../#{EXECUTABLE_PATH} #{bindfs_args} #{extra_args} #{Shellwords.escape(srcdir)} #{Shellwords.escape(mntdir)}"
if options[:valgrind]
cmd = "valgrind --error-exitcode=100 #{options[:valgrind_opts]} #{cmd}"
end
bindfs_pid = Process.fork do
exec cmd
exit! 127
end
rescue Exception => ex
fail!("ERROR running bindfs", ex)
end
# Wait for bindfs to be ready.
if !wait_for { `mount`.include?(Dir.pwd) }
fail!("ERROR: Mount point did not appear in `mount`")
end
testcase_ok = true
begin
block.call(bindfs_pid)
rescue Exception => ex
fail("ERROR: testcase `#{options[:title]}' failed", ex)
testcase_ok = false
end
if File.exist?("bindfs.log")
system("cat bindfs.log")
end
begin
unless system(umount_cmd + ' ' + Shellwords.escape(mntdir))
raise Exception.new(umount_cmd + " failed with status #{$?}")
end
Process.wait bindfs_pid
rescue Exception => ex
fail("ERROR: failed to umount")
testcase_ok = false
end
if !$?.success?
fail("exit status: #{$?}")
testcase_ok = false
end
begin
Dir.chdir '..'
rescue Exception => ex
fail!("ERROR: failed to exit test env")
end
unless system "rm -Rf #{TESTDIR_NAME}"
fail!("ERROR: failed to clear test directory")
end
if testcase_ok
puts "OK"
else
exit! 1
end
end
# Like testenv but skips the test if not running as root
def root_testenv(bindfs_args, options = {}, &block)
if Process.uid == 0
testenv(bindfs_args, options, &block)
else
puts "--- #{bindfs_args} ---"
puts "[ #{bindfs_args} ]"
puts "SKIP (requires root)"
end
end
# Like testenv but skips the test if not running as non-root.
# TODO: make all tests runnable as root
def nonroot_testenv(bindfs_args, options = {}, &block)
if Process.uid != 0
testenv(bindfs_args, options, &block)
else
puts "--- #{bindfs_args} ---"
puts "[ #{bindfs_args} ]"
puts "SKIP (requires running as non-root)"
end
end
def umount_cmd
if `which fusermount`.strip.empty?
then 'umount'
else 'fusermount -uz'
end
end
def assert
raise Exception.new('test failed') unless yield
end
def assert_exception(ex)
begin
yield
rescue ex
return
end
raise Exception.new('expected exception ' + ex.to_s)
end
|