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
| | # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
$stdout.sync = $stderr.sync = Thread.abort_on_exception = true
$-w = true if RUBY_VERSION.to_f >= 2.0
require 'thread'
require 'fileutils'
def rubyv
puts RUBY_DESCRIPTION
end
# Global Test Lock, to protect:
# Process.wait*, Dir.chdir, ENV, trap, require, etc...
GTL = Mutex.new
# fork-aware coverage data gatherer, see also test/covshow.rb
if ENV["COVERAGE"]
require "coverage"
COVMATCH = %r{(/lib/yahns\b|extras/).*rb\z}
COVDUMPFILE = File.expand_path("coverage.dump")
def __covmerge
res = Coverage.result
# do not create the file, Makefile does this before any tests run
File.open(COVDUMPFILE, IO::RDWR) do |covtmp|
covtmp.binmode
covtmp.sync = true
# we own this file (at least until somebody tries to use NFS :x)
covtmp.flock(File::LOCK_EX)
prev = covtmp.read
prev = prev.empty? ? {} : Marshal.load(prev)
res.each do |filename, counts|
# filter out stuff that's not in our project
COVMATCH =~ filename or next
# For compatibility with https://bugs.ruby-lang.org/issues/9508
# TODO: support those features if that gets merged into mainline
unless Array === counts
counts = counts[:lines]
end
merge = prev[filename] || []
merge = merge
counts.each_with_index do |count, i|
count or next
merge[i] = (merge[i] || 0) + count
end
prev[filename] = merge
end
covtmp.rewind
covtmp.truncate(0)
covtmp.write(Marshal.dump(prev))
covtmp.flock(File::LOCK_UN)
end
end
Coverage.start
# we need to nest at_exit to fire after minitest runs
at_exit { at_exit { __covmerge } }
end
gem 'minitest'
begin # favor minitest 5
require 'minitest'
Testcase = Minitest::Test
mtobj = Minitest
rescue NameError, LoadError # but support minitest 4
require 'minitest/unit'
Testcase = Minitest::Unit::TestCase
mtobj = MiniTest::Unit.new
end
# Not using minitest/autorun because that doesn't guard against redundant
# extra runs with fork. We cannot use exit! in the tests either
# (since users/apps hosted on yahns _should_ expect exit, not exit!).
TSTART_PID = $$
at_exit do
# skipping @@after_run stuff in minitest since we don't need it
case $!
when nil, SystemExit
exit(mtobj.run(ARGV)) if $$ == TSTART_PID
end
end
require "tempfile"
require 'tmpdir'
class Dir
def Dir.mktmpdir
begin
d = "#{Dir.tmpdir}/#$$.#{rand}"
Dir.mkdir(d)
rescue Errno::EEXIST
end while true
return d unless block_given?
begin
yield d
ensure
FileUtils.remove_entry(d)
end
end
end unless Dir.respond_to?(:mktmpdir)
def tmpfile(*args)
tmp = Tempfile.new(*args)
tmp.sync = true
tmp.binmode
tmp
end
require 'io/wait'
# needed for Rubinius 2.0.0, we only use IO#nread in tests
class IO
# this ignores buffers
def nread
buf = "\0" * 8
ioctl(0x541B, buf)
buf.unpack("l_")[0]
end
end if ! IO.method_defined?(:nread) && RUBY_PLATFORM =~ /linux/
def cloexec_pipe
IO.pipe.each { |io| io.close_on_exec = true }
end
def require_exec(cmd)
ENV["PATH"].split(/:/).each do |path|
return true if File.executable?("#{path}/#{cmd}")
end
skip "#{cmd} not found in PATH"
false
end
class DieIfUsed
def each
abort "body.each called after response hijack\n"
end
def close
abort "body.close called after response hijack\n"
end
end
require 'yahns'
# needed for parallel (MT) tests)
require 'yahns/rack'
|