Class: Ace::TestRunner::Suite::Orchestrator

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/test_runner/suite/orchestrator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Orchestrator

Returns a new instance of Orchestrator.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 12

def initialize(config)
  @config = config
  @packages = config.dig("test_suite", "packages") || []
  @results = {}
  @running_processes = {}
  @completed_packages = []
  @waiting_packages = []
  @failed_packages = []

  # Use ace-config's project root detection
  require "ace/support/config"
  @project_root = Ace::Support::Config.find_project_root

  # Resolve package paths relative to project root
  resolve_package_paths! if @project_root
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



10
11
12
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 10

def config
  @config
end

#packagesObject (readonly)

Returns the value of attribute packages.



10
11
12
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 10

def packages
  @packages
end

#resultsObject (readonly)

Returns the value of attribute results.



10
11
12
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 10

def results
  @results
end

#running_processesObject (readonly)

Returns the value of attribute running_processes.



10
11
12
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 10

def running_processes
  @running_processes
end

Instance Method Details

#runObject



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
# File 'lib/ace/test_runner/suite/orchestrator.rb', line 29

def run
  validate_packages!
  test_options = (@config.dig("test_suite", "test_options") || {}).dup
  report_root = normalize_report_root(test_options["report_dir"])
  test_options["report_dir"] = report_root if report_root

  display_manager = create_display_manager
  process_monitor = ProcessMonitor.new(
    @config.dig("test_suite", "max_parallel") || 10,
    package_timeout: @config.dig("test_suite", "timeout")
  )

  # Enrich packages with historical duration data for scheduling
  estimator = DurationEstimator.new(report_root: report_root)
  estimator.enrich_packages(@packages)

  # Sort by expected duration (descending), then priority (ascending)
  # This ensures slowest packages start first, preventing end-of-run bottlenecks
  sorted_packages = @packages.sort_by { |p| [-(p["expected_duration"] || 0), p["priority"] || 999] }

  # Initialize display
  display_manager.initialize_display

  # Start processes
  sorted_packages.each do |package|
    process_monitor.start_package(package, test_options) do |pkg, status, output|
      display_manager.update_package(pkg, status, output)

      if status[:completed]
        @completed_packages << pkg
        @results[pkg["name"]] = status
      end
    end
  end

  # Wait for all processes to complete
  while process_monitor.running?
    process_monitor.check_processes
    display_manager.refresh
    sleep(@config.dig("test_suite", "display", "update_interval") || 0.1)
  end

  # Final display
  display_manager.show_final_results

  # Aggregate results
  aggregator = ResultAggregator.new(@packages, report_root: report_root, runtime_results: @results)
  summary = aggregator.aggregate

  display_manager.show_summary(summary)

  # Return exit code based on results
  (summary[:packages_failed] > 0) ? 1 : 0
rescue Interrupt
  process_monitor&.stop_all(reason: :interrupt)
  raise
rescue StandardError
  process_monitor&.stop_all(reason: :error)
  raise
end