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
|
#!/usr/bin/env ruby
HELP = <<EOS
Runs the bindfs test suite in all vagrant boxes in parallel.
Usage: test.rb [--nohalt] [vm1 [...]]
Options:
-h --help Print this and exit.
--nohalt Don't halt VMs when done.
If VM names are given, only those are tested.
Bugs:
- Spurious "Connection to 127.0.0.1 closed." messages can appear, and the
terminal may need a `reset` after this command finishes.
EOS
require 'fileutils'
Dir.chdir(File.dirname(__FILE__))
halt_vms = true
specifically_selected_vms = []
ARGV.each do |arg|
if arg == '-h' || arg == '--help'
puts HELP
exit
elsif arg == '--nohalt'
halt_vms = false
elsif !arg.start_with?('-')
specifically_selected_vms << arg
else
raise "Unknown option: #{arg}"
end
end
dirs = Dir.glob('*/Vagrantfile').map { |path| File.dirname(path) }
unless specifically_selected_vms.empty?
dirs = dirs.select { |dir| ARGV.include?(dir) }
end
def with_retries(n, options = {}, &block)
options = {
sleep: 0,
sleep_jitter: 0,
}.merge options
loop do
begin
return block.call
rescue
raise $! if n <= 0
puts "Retrying #{n} more times after catching: #{$!}"
end
sleep(options[:sleep] + (Random.rand - 0.5) * options[:sleep_jitter])
n -= 1
end
end
puts "Running #{dirs.size} VMs in parallel: #{dirs.join(' ')}"
puts "You can follow the progress of each VM by tailing vagrant/*/test.log"
puts "Note: if your terminal goes wonky after this command, type 'reset'"
mutex = Thread::Mutex.new # protects `$stdout` and `errors`
errors = []
threads = dirs.map do |dir|
Thread.new do
begin
File.open(dir + "/test.log", "wb") do |logfile|
run_and_log = -> (command) do
logfile.puts ""
logfile.puts "##### #{command} #####"
logfile.flush
pid = Process.spawn(command, chdir: dir, out: logfile, err: :out)
Process.waitpid(pid)
$?.success?
end
# parallel `vagrant up` commands can be flaky with VirtualBox due to lock contention,
# so give it a few retries.
with_retries(3, sleep: 1.0, sleep_jitter: 0.5) do
unless run_and_log.call "vagrant up"
raise "vagrant up failed"
end
end
unless run_and_log.call "vagrant rsync"
raise "vagrant rsync failed"
end
unless run_and_log.call "vagrant ssh -c 'cd /bindfs && sudo rm -Rf tests/tmp_test_bindfs && ./configure && make distclean && ./configure && make && make check && sudo make check'"
mutex.synchronize do
errors << "VM #{dir} tests failed."
end
end
if halt_vms
unless run_and_log.call "vagrant halt"
raise "vagrant halt failed"
end
end
end
rescue
mutex.synchronize do
errors << "VM #{dir} error: #{$!}"
end
ensure
mutex.synchronize do
puts "Finished VM: #{dir}"
end
end
end
end
threads.each(&:join)
if errors.empty?
puts "OK"
else
unless errors.empty?
puts
puts "Errors:"
errors.each { |err| puts " #{err}" }
puts
puts "See test.log in a failed VM's directory for more information"
puts
end
end
|