Class: Profiler::TestRunner::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/profiler/test_runner/runner.rb

Class Method Summary collapse

Class Method Details

.build_command(files, framework) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/profiler/test_runner/runner.rb', line 71

def self.build_command(files, framework)
  root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
  absolute_files = files.map { |f| File.join(root, f) }

  case framework.to_sym
  when :rspec
    ["bundle", "exec", "rspec", "--format", "progress", "--color", *absolute_files]
  when :minitest
    ["bundle", "exec", "rails", "test", *absolute_files]
  else
    ["bundle", "exec", "rspec", "--format", "progress", "--color", *absolute_files]
  end
end

.build_envObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/profiler/test_runner/runner.rb', line 87

def self.build_env
  base = ENV.to_h

  # Inject env var overrides configured in the profiler — skip blocked keys
  overrides = Profiler.env_override_store.all_overrides
  overrides.each do |key, entry|
    next if BLOCKED_ENV_KEYS.include?(key.upcase)
    value = entry.is_a?(Hash) ? entry["value"] : entry
    base[key] = value
  end

  # Ensure test environment regardless of overrides
  base["RAILS_ENV"] = "test"
  base["RACK_ENV"]  = "test"

  base
end

.kill(run_id) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/profiler/test_runner/runner.rb', line 15

def self.kill(run_id)
  run = Profiler::TestRunner.run_store.find(run_id)
  return false unless run && run.pid && run.status == "running"

  begin
    Process.kill("TERM", run.pid)
    Profiler::TestRunner.run_store.update(run_id, status: "killed", finished_at: Time.now)
    true
  rescue Errno::ESRCH
    # Process already exited
    false
  end
end

.run_process(run) ⇒ Object



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
# File 'lib/profiler/test_runner/runner.rb', line 44

def self.run_process(run)
  cmd = build_command(run.files, run.framework)
  env = build_env

  Profiler::TestRunner.run_store.update(run.id, status: "running", started_at: Time.now)

  IO.popen([env, *cmd, err: [:child, :out]], "r") do |io|
    Profiler::TestRunner.run_store.update(run.id, pid: io.pid)

    while (chunk = io.read(256))
      break if chunk.empty?

      Profiler::TestRunner.run_store.append_output(run.id, chunk)
    end
  end

  exit_code = $?.exitstatus || 0
  status = exit_code == 0 ? "passed" : "failed"

  Profiler::TestRunner.run_store.update(
    run.id,
    status: status,
    finished_at: Time.now,
    exit_code: exit_code
  )
end

.spawn_async(run) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/profiler/test_runner/runner.rb', line 31

def self.spawn_async(run)
  Thread.new do
    run_process(run)
  rescue => e
    Profiler::TestRunner.run_store.update(
      run.id,
      status: "error",
      finished_at: Time.now
    )
    Profiler::TestRunner.run_store.append_output(run.id, "\n[Profiler] Error: #{e.message}\n")
  end
end

.start(files:, framework:) ⇒ Object



9
10
11
12
13
# File 'lib/profiler/test_runner/runner.rb', line 9

def self.start(files:, framework:)
  run = Profiler::TestRunner.run_store.create(files: files, framework: framework)
  spawn_async(run)
  run
end