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
|
#!/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.
--print-logs Prints each VM's logs when it completes.
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
print_logs = false
specifically_selected_vms = []
ARGV.each do |arg|
if arg == '-h' || arg == '--help'
puts HELP
exit
elsif arg == '--nohalt'
halt_vms = false
elsif arg == '--print-logs'
print_logs = true
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| specifically_selected_vms.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", "w+b") do |logfile|
run_and_log = -> (command) do
logfile.puts ""
logfile.puts "##### #{command} #####"
logfile.flush
pid = Process.spawn(command, chdir: dir, out: logfile, err: logfile)
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
if print_logs
puts File.read(dir + "/test.log")
puts
end
end
end
end
threads.each(&:join)
if errors.empty?
puts "All 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
exit 1
end
end
|