Class: Buffet::Master
- Inherits:
-
Object
- Object
- Buffet::Master
- Defined in:
- lib/buffet/master.rb
Instance Attribute Summary collapse
-
#failures ⇒ Object
readonly
Returns the value of attribute failures.
-
#slave_exceptions ⇒ Object
readonly
Returns the value of attribute slave_exceptions.
-
#spurious_failures ⇒ Object
readonly
Returns the value of attribute spurious_failures.
-
#stats ⇒ Object
readonly
Returns the value of attribute stats.
Instance Method Summary collapse
- #example_failed(slave_name, details) ⇒ Object
- #example_passed(slave_name, details) ⇒ Object
- #example_pending(slave_name, details) ⇒ Object
-
#initialize(project, slaves, specs, listener) ⇒ Master
constructor
A new instance of Master.
- #next_file_for(slave_name, previous_spec) ⇒ Object
- #order_specs(specs) ⇒ Object
- #run ⇒ Object
- #run_worker(slave) ⇒ Object
- #slave_prepare_failed(slave, ex) ⇒ Object
- #stop_run(ex) ⇒ Object
- #wait_for_workers ⇒ Object
Constructor Details
#initialize(project, slaves, specs, listener) ⇒ Master
Returns a new instance of Master.
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 |
# File 'lib/buffet/master.rb', line 10 def initialize project, slaves, specs, listener @project = project @slaves = slaves @stats = { :examples => 0, :failures => 0, :pending => 0, :spurious_failures => 0 } @slaves_stats = Hash[@slaves.map do |slave| [slave.user_at_host, stats.dup.merge!(:slave => slave, :specs => [])] end] @slave_exceptions = {} @max_slave_prepare_failures = [Settings.allowed_slave_prepare_failures, @slaves.count - 1].min @stats[:slaves] = @slaves_stats @lock = Mutex.new @condition = ConditionVariable.new @failures = [] @spurious_failures = [] @specs = order_specs(specs) @listener = listener @halt_exception = nil # How many times a particular spec file was queued @spec_queue_count = Hash.new { |h, k| h[k] = 0 } # Need this so when we get back an example result from a slave we can know # which spec it is from. This prevents the wrong file from being reported # in the case of shared examples. @current_spec_for_slave = {} # Store spec results on per spec per line basis @spec_results = Hash.new { |h, k| h[k] = [] } end |
Instance Attribute Details
#failures ⇒ Object (readonly)
Returns the value of attribute failures.
8 9 10 |
# File 'lib/buffet/master.rb', line 8 def failures @failures end |
#slave_exceptions ⇒ Object (readonly)
Returns the value of attribute slave_exceptions.
8 9 10 |
# File 'lib/buffet/master.rb', line 8 def slave_exceptions @slave_exceptions end |
#spurious_failures ⇒ Object (readonly)
Returns the value of attribute spurious_failures.
8 9 10 |
# File 'lib/buffet/master.rb', line 8 def spurious_failures @spurious_failures end |
#stats ⇒ Object (readonly)
Returns the value of attribute stats.
8 9 10 |
# File 'lib/buffet/master.rb', line 8 def stats @stats end |
Instance Method Details
#example_failed(slave_name, details) ⇒ Object
155 156 157 158 159 160 161 |
# File 'lib/buffet/master.rb', line 155 def example_failed(slave_name, details) @lock.synchronize do @spec_results[@current_spec_for_slave[slave_name]] << details end @listener.example_failed end |
#example_passed(slave_name, details) ⇒ Object
147 148 149 150 151 152 153 |
# File 'lib/buffet/master.rb', line 147 def example_passed(slave_name, details) @lock.synchronize do @spec_results[@current_spec_for_slave[slave_name]] << details end @listener.example_passed end |
#example_pending(slave_name, details) ⇒ Object
163 164 165 166 167 168 169 170 171 |
# File 'lib/buffet/master.rb', line 163 def example_pending slave_name, details @lock.synchronize do @stats[:examples] += 1 @stats[:pending] += 1 @slaves_stats[slave_name][:pending] += 1 end @listener.example_pending end |
#next_file_for(slave_name, previous_spec) ⇒ Object
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 |
# File 'lib/buffet/master.rb', line 109 def next_file_for(slave_name, previous_spec) file = nil @lock.synchronize do if rerun_spec?(previous_spec) @spec_queue_count[previous_spec] += 1 return previous_spec else if file = @specs.shift @spec_queue_count[file] += 1 @current_spec_for_slave[slave_name] = file @slaves_stats[slave_name][:specs] << file end end end if file slave = nil @lock.synchronize do slave = @slaves_stats[slave_name][:slave] end @listener.spec_taken(slave, file) end file end |
#order_specs(specs) ⇒ Object
41 42 43 44 45 |
# File 'lib/buffet/master.rb', line 41 def order_specs(specs) specs.map do |spec| [`wc -l #{spec}`.to_i, spec] end.sort.reverse.map(&:last) end |
#run ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/buffet/master.rb', line 47 def run start_service @stats[:total_time] = Benchmark.measure do @threads = @slaves.map do |slave| Thread.new do run_worker slave end end wait_for_workers end.real stop_service process_spec_results end |
#run_worker(slave) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/buffet/master.rb', line 65 def run_worker slave time = Benchmark.measure do begin prepare_slave slave rescue CommandError => ex slave_prepare_failed slave, ex rescue Exception => ex stop_run ex else begin run_slave slave rescue Exception => ex stop_run ex end end end.real @lock.synchronize do @slaves_stats[slave.name][:total_time] = time @condition.signal # Tell master this slave is finished end end |
#slave_prepare_failed(slave, ex) ⇒ Object
137 138 139 140 141 142 143 144 145 |
# File 'lib/buffet/master.rb', line 137 def slave_prepare_failed slave, ex @listener.slave_prepare_failed slave, ex @lock.synchronize do slave_exceptions[slave.name] = ex @condition.signal # Alert master this slave failed end end |
#stop_run(ex) ⇒ Object
102 103 104 105 106 107 |
# File 'lib/buffet/master.rb', line 102 def stop_run ex @lock.synchronize do @halt_exception = ex @condition.signal # Alert master end end |
#wait_for_workers ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/buffet/master.rb', line 88 def wait_for_workers @threads.count.times do @lock.synchronize do @condition.wait(@lock) raise @halt_exception if @halt_exception if slave_exceptions.count > @max_slave_prepare_failures raise 'Exceeded maximum number of allowed slave prepare failures' end end end end |