Module: ParallelTests::Tasks

Defined in:
lib/parallel_tests/tasks.rb

Class Method Summary collapse

Class Method Details

.build_run_command(type, args) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/parallel_tests/tasks.rb', line 108

def build_run_command(type, args)
  count, pattern, options, pass_through = ParallelTests::Tasks.parse_args(args)
  test_framework = {
    'spec' => 'rspec',
    'test' => 'test',
    'features' => 'cucumber',
    'features-spinach' => 'spinach'
  }.fetch(type)

  type = 'features' if test_framework == 'spinach'

  # Using the relative path to find the binary allow to run a specific version of it
  executable = File.expand_path('../../bin/parallel_test', __dir__)
  executable = ParallelTests.with_ruby_binary(executable)

  command = [*executable, type, '--type', test_framework]
  command += ['-n', count.to_s] if count
  command += ['--pattern', pattern] if pattern
  command += ['--test-options', options] if options
  command += Shellwords.shellsplit pass_through if pass_through
  command
end

.check_for_pending_migrationsObject



66
67
68
69
70
71
72
73
# File 'lib/parallel_tests/tasks.rb', line 66

def check_for_pending_migrations
  ["db:abort_if_pending_migrations", "app:db:abort_if_pending_migrations"].each do |abort_migrations|
    if Rake::Task.task_defined?(abort_migrations)
      Rake::Task[abort_migrations].invoke
      break
    end
  end
end

.configured_databasesObject



131
132
133
134
135
# File 'lib/parallel_tests/tasks.rb', line 131

def configured_databases
  return [] unless defined?(ActiveRecord) && rails_61_or_greater?

  @@configured_databases ||= ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
end

.for_each_database(&block) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/parallel_tests/tasks.rb', line 137

def for_each_database(&block)
  # Use nil to represent all databases
  block&.call(nil)

  # skip if not rails or old rails version
  return if !defined?(ActiveRecord::Tasks::DatabaseTasks) || !ActiveRecord::Tasks::DatabaseTasks.respond_to?(:for_each)

  ActiveRecord::Tasks::DatabaseTasks.for_each(configured_databases) do |name|
    block&.call(name)
  end
end

.load_libObject



12
13
14
15
# File 'lib/parallel_tests/tasks.rb', line 12

def load_lib
  $LOAD_PATH << File.expand_path('..', __dir__)
  require "parallel_tests"
end

.parse_args(args) ⇒ Object

parallel:spec[:count, :pattern, :options, :pass_through]



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/parallel_tests/tasks.rb', line 76

def parse_args(args)
  # order as given by user
  args = [args[:count], args[:pattern], args[:options], args[:pass_through]]

  # count given or empty ?
  # parallel:spec[2,models,options]
  # parallel:spec[,models,options]
  count = args.shift if args.first.to_s =~ /^\d*$/
  num_processes = (count.to_s.empty? ? nil : Integer(count))
  pattern = args.shift
  options = args.shift
  pass_through = args.shift

  [num_processes, pattern, options, pass_through]
end

.purge_before_loadObject



17
18
19
20
21
# File 'lib/parallel_tests/tasks.rb', line 17

def purge_before_load
  if Gem::Version.new(Rails.version) > Gem::Version.new('4.2.0')
    Rake::Task.task_defined?('db:purge') ? 'db:purge' : 'app:db:purge'
  end
end

.rails_envObject



8
9
10
# File 'lib/parallel_tests/tasks.rb', line 8

def rails_env
  'test'
end

.run_in_parallel(cmd, options = {}) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/parallel_tests/tasks.rb', line 23

def run_in_parallel(cmd, options = {})
  load_lib

  # Using the relative path to find the binary allow to run a specific version of it
  executable = File.expand_path('../../bin/parallel_test', __dir__)
  command = ParallelTests.with_ruby_binary(executable)
  command += ['--exec', Shellwords.join(cmd)]
  command += ['-n', options[:count]] unless options[:count].to_s.empty?
  command << '--non-parallel' if options[:non_parallel]

  abort unless system(*command)
end

.schema_format_based_on_rails_versionObject



92
93
94
95
96
97
98
# File 'lib/parallel_tests/tasks.rb', line 92

def schema_format_based_on_rails_version
  if rails_7_or_greater?
    ActiveRecord.schema_format
  else
    ActiveRecord::Base.schema_format
  end
end

.schema_type_based_on_rails_versionObject



100
101
102
103
104
105
106
# File 'lib/parallel_tests/tasks.rb', line 100

def schema_type_based_on_rails_version
  if rails_61_or_greater? || schema_format_based_on_rails_version == :ruby
    "schema"
  else
    "structure"
  end
end

.suppress_output(command, ignore_regex) ⇒ Object

this is a crazy-complex solution for a very simple problem: removing certain lines from the output without changing the exit-status normally I’d not do this, but it has been lots of fun and a great learning experience :)

  • sed does not support | without -r

  • grep changes 0 exitstatus to 1 if nothing matches

  • sed changes 1 exitstatus to 0

  • pipefail makes pipe fail with exitstatus of first failed command

  • pipefail is not supported in (zsh)

  • defining a new rake task like silence_schema would force users to load parallel_tests in test env

  • simple system “set -o pipefail” returns nil even though set -o pipefail exists with 0



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/parallel_tests/tasks.rb', line 47

def suppress_output(command, ignore_regex)
  activate_pipefail = "set -o pipefail"
  remove_ignored_lines = %{(grep -v #{Shellwords.escape(ignore_regex)} || true)}

  # remove nil values (ex: #purge_before_load returns nil)
  command.compact!

  if system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null")
    shell_command = "#{activate_pipefail} && (#{Shellwords.shelljoin(command)}) | #{remove_ignored_lines}"
    ['/bin/bash', '-c', shell_command]
  else
    command
  end
end

.suppress_schema_load_output(command) ⇒ Object



62
63
64
# File 'lib/parallel_tests/tasks.rb', line 62

def suppress_schema_load_output(command)
  ParallelTests::Tasks.suppress_output(command, "^   ->\\|^-- ")
end