aboutsummaryrefslogtreecommitdiffstats
path: root/railties/Rakefile
blob: 51f46d18176c369024618672368a516025588f90 (plain) (blame)
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
# frozen_string_literal: true

require "rake/testtask"

task default: :test

task :package

desc "Run all unit tests"
task test: "test:isolated"

namespace :test do
  task :isolated do
    estimated_duration = {
      "test/application/test_runner_test.rb" => 201,
      "test/application/assets_test.rb" => 131,
      "test/application/rake/migrations_test.rb" => 65,
      "test/generators/scaffold_generator_test.rb" => 57,
      "test/generators/plugin_test_runner_test.rb" => 57,
      "test/application/test_test.rb" => 52,
      "test/application/configuration_test.rb" => 49,
      "test/generators/app_generator_test.rb" => 43,
      "test/application/rake/dbs_test.rb" => 43,
      "test/application/rake_test.rb" => 33,
      "test/generators/plugin_generator_test.rb" => 30,
      "test/railties/engine_test.rb" => 27,
      "test/generators/scaffold_controller_generator_test.rb" => 23,
      "test/railties/generators_test.rb" => 19,
      "test/application/console_test.rb" => 16,
      "test/engine/commands_test.rb" => 15,
      "test/application/routing_test.rb" => 15,
      "test/application/mailer_previews_test.rb" => 15,
      "test/application/rake/multi_dbs_test.rb" => 13,
      "test/application/asset_debugging_test.rb" => 12,
      "test/application/bin_setup_test.rb" => 11,
      "test/engine/test_test.rb" => 10,
      "test/application/runner_test.rb" => 10,
    }
    estimated_duration.default = 1

    dash_i = [
      "test",
      "lib",
      "../activesupport/lib",
      "../actionpack/lib",
      "../actionview/lib",
      "../activemodel/lib"
    ].map { |dir| File.expand_path(dir, __dir__) }

    dash_i.reverse_each do |x|
      $:.unshift(x) unless $:.include?(x)
    end
    $-w = true

    require "bundler/setup" unless defined?(Bundler)
    require "active_support"

    # Only generate the template app once.
    require_relative "test/isolation/abstract_unit"

    failing_files = []

    dirs = (ENV["TEST_DIR"] || ENV["TEST_DIRS"] || "**").split(",")
    test_options = ENV["TESTOPTS"].to_s.split(/[\s]+/)

    test_patterns = dirs.map { |dir| "test/#{dir}/*_test.rb" }
    test_files = Dir[*test_patterns].select do |file|
      !file.start_with?("test/fixtures/") && !file.start_with?("test/isolation/assets/")
    end

    if ENV["BUILDKITE_PARALLEL_JOB_COUNT"]
      n = ENV["BUILDKITE_PARALLEL_JOB"].to_i
      m = ENV["BUILDKITE_PARALLEL_JOB_COUNT"].to_i

      buckets = Array.new(m) { [] }
      allocations = Array.new(m) { 0 }
      test_files.sort_by { |file| [-estimated_duration[file], file] }.each do |file|
        idx = allocations.index(allocations.min)
        buckets[idx] << file
        allocations[idx] += estimated_duration[file]
      end

      puts "Running #{buckets[n].size} of #{test_files.size} test files, estimated duration #{allocations[n]}s"

      test_files = buckets[n]
    end

    test_files.each do |file|
      puts "--- #{file}"
      fake_command = Shellwords.join([
        FileUtils::RUBY,
        "-w",
        *dash_i.map { |dir| "-I#{Pathname.new(dir).relative_path_from(Pathname.pwd)}" },
        file,
      ])
      puts fake_command

      if Process.respond_to?(:fork)
        # We could run these in parallel, but pretty much all of the
        # railties tests already run in parallel, so ¯\_(⊙︿⊙)_/¯
        Process.waitpid fork {
          ARGV.clear.concat test_options
          Rake.application = nil

          load file
        }
      else
        Process.wait spawn(fake_command)
      end

      unless $?.success?
        failing_files << file
        puts "^^^ +++"
      end
    end

    puts "--- All tests completed"
    unless failing_files.empty?
      puts "^^^ +++"
      puts
      puts "Failed in:"
      failing_files.each do |file|
        puts "  #{file}"
      end
      puts

      exit 1
    end
  end
end

Rake::TestTask.new("test:regular") do |t|
  t.libs << "test" << "#{__dir__}/../activesupport/lib"
  t.pattern = "test/**/*_test.rb"
  t.warning = true
  t.verbose = true
  t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end