Skip to content

Commit 4246668

Browse files
committed
Collect test results and print profile summary at the end
1 parent bc2e492 commit 4246668

File tree

2 files changed

+57
-16
lines changed

2 files changed

+57
-16
lines changed

railties/Rakefile

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,13 @@ namespace :test do
6666

6767
# Only generate the template app once.
6868
require_relative "test/isolation/abstract_unit"
69+
require "minitest/rails_plugin"
6970

7071
failing_files = []
7172

7273
dirs = (ENV["TEST_DIR"] || ENV["TEST_DIRS"] || "**").split(",")
7374
test_options = ENV["TESTOPTS"].to_s.split(/[\s]+/)
74-
test_options << "--profile" if ENV["CI"]
75+
test_options << "--profile" if ENV["BUILDKITE"]
7576

7677
test_patterns = dirs.map { |dir| "test/#{dir}/*_test.rb" }
7778
test_files = Dir[*test_patterns].select do |file|
@@ -95,6 +96,8 @@ namespace :test do
9596
test_files = buckets[n]
9697
end
9798

99+
output_file = Tempfile.new("railties_test_reporter")
100+
98101
test_files.each do |file|
99102
puts "--- #{file}"
100103
fake_command = Shellwords.join([
@@ -109,6 +112,7 @@ namespace :test do
109112
# We could run these in parallel, but pretty much all of the
110113
# railties tests already run in parallel, so ¯\_(⊙︿⊙)_/¯
111114
Process.waitpid fork {
115+
ENV["RAILTIES_OUTPUT_FILE"] = output_file.path
112116
ARGV.clear.concat test_options
113117
Rake.application = nil
114118

@@ -124,9 +128,22 @@ namespace :test do
124128
end
125129
end
126130

127-
puts "--- All tests completed"
131+
puts "+++ All tests completed"
132+
133+
if ENV["BUILDKITE"]
134+
TestResult = Struct.new(:NAME, :failures, :assertions, :klass, :time, :source_location, :location)
135+
profile = Minitest::ProfileReporter.new($stdout, profile: 10)
136+
output_file.rewind
137+
output_file.each_line do |result|
138+
data = JSON.parse(result)
139+
profile.results << TestResult.new(*data.values)
140+
end
141+
142+
profile.summary
143+
end
144+
128145
unless failing_files.empty?
129-
puts "^^^ +++"
146+
puts "+++"
130147
puts
131148
puts "Failed in:"
132149
failing_files.each do |file|
@@ -136,6 +153,9 @@ namespace :test do
136153

137154
exit 1
138155
end
156+
ensure
157+
output_file&.close
158+
output_file&.unlink
139159
end
140160
end
141161

@@ -144,6 +164,6 @@ Rake::TestTask.new("test:regular") do |t|
144164
t.pattern = "test/**/*_test.rb"
145165
t.warning = true
146166
t.verbose = true
147-
t.options = "--profile" if ENV["CI"]
167+
t.options = "--profile" if ENV["BUILDKITE"]
148168
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
149169
end

railties/lib/minitest/rails_plugin.rb

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,58 @@ def aggregated_results(*)
2626
end
2727

2828
class ProfileReporter < Reporter
29+
attr_accessor :results
30+
2931
def initialize(io = $stdout, options = {})
3032
super
3133
@results = []
3234
@count = options[:profile]
3335
end
3436

3537
def record(result)
36-
@results << result
38+
if output_file = ENV["RAILTIES_OUTPUT_FILE"]
39+
File.open(output_file, "a") do |f|
40+
# Round-trip for re-serialization
41+
data = JSON.parse(result.to_json)
42+
data[:location] = result.location
43+
f.puts(data.to_json)
44+
end
45+
else
46+
@results << result
47+
end
3748
end
3849

3950
def passed?
4051
true
4152
end
4253

4354
def report
44-
total_time = @results.sum(&:time)
55+
# Skip if we're outputting to a file
56+
return if ENV["RAILTIES_OUTPUT_FILE"]
57+
print_summary
58+
end
59+
60+
def summary
61+
print_summary
62+
end
63+
64+
private
65+
def print_summary
66+
total_time = @results.sum(&:time)
4567

46-
@results.sort! { |a, b| b.time <=> a.time }
47-
slow_results = @results.take(@count)
48-
slow_tests_total_time = slow_results.sum(&:time)
68+
@results.sort! { |a, b| b.time <=> a.time }
69+
slow_results = @results.take(@count)
70+
slow_tests_total_time = slow_results.sum(&:time)
4971

50-
ratio = (total_time == 0) ? 0.0 : (slow_tests_total_time / total_time) * 100
72+
ratio = (total_time == 0) ? 0.0 : (slow_tests_total_time / total_time) * 100
5173

52-
io.puts("\nTop %d slowest tests (%.2f seconds, %.1f%% of total time):\n" % [slow_results.size, slow_tests_total_time, ratio])
53-
slow_results.each do |result|
54-
io.puts(" %s\n %.4f seconds %s\n" % [result.location, result.time, source_location(result)])
74+
io.puts("\nTop %d slowest tests (%.2f seconds, %.1f%% of total time):\n" % [slow_results.size, slow_tests_total_time, ratio])
75+
slow_results.each do |result|
76+
io.puts(" %s\n %.4f seconds %s\n" % [result.location, result.time, source_location(result)])
77+
end
78+
io.puts("\n")
5579
end
56-
io.puts("\n")
57-
end
5880

59-
private
6081
def source_location(result)
6182
filename, line = result.source_location
6283
return "" unless filename

0 commit comments

Comments
 (0)