Class: Uttk::Strategies::Strategy

Inherits:
Object
  • Object
show all
Includes:
Abstract, AttributedClass
Defined in:
lib/uttk/strategies/Strategy.rb

Overview

This is the base class for anything testable. It provides some basics attributes like the name of the test.

Defined Under Namespace

Modules: UttkTimeout

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = nil, &block) ⇒ Strategy

Create a new Strategy with the given optional document.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/uttk/strategies/Strategy.rb', line 47

def initialize ( name=nil, &block )
  @status = StartStatus.new
  @symbols = {}
  @symtbl = nil
  initialize_attributes
  @save = nil
  @reject = Set.new
  self.name = name
  if block
    if block.arity == -1
      instance_eval(&block)
    else
      block[self]
    end
  end
end

Instance Attribute Details

#statusObject (readonly)

Accessors



39
40
41
# File 'lib/uttk/strategies/Strategy.rb', line 39

def status
  @status
end

Class Method Details

.to_form(b) ⇒ Object



630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# File 'lib/uttk/strategies/Strategy.rb', line 630

def self.to_form ( b )
  b.form_tag do
    b.table :class => 'uttk_attributes' do
      attributes.each do |attribute|
        b.tr :class => 'uttk_attribute' do
          b.td(:class => 'uttk_attribute_description') do
            b.itext! "#{attribute.name} (#{attribute.descr}): "
          end
          b.td(:class => 'uttk_attribute_field') do
            attribute.to_form(b)
          end
        end
      end
    end
  end
end

.to_yaml_typeObject



626
627
628
# File 'lib/uttk/strategies/Strategy.rb', line 626

def self.to_yaml_type
  name.sub(/^Uttk::Strategies/, '!S')
end

Instance Method Details

#abort(message = 'abort explicitly') ⇒ Object

Abort the test explicitly.



544
545
546
547
# File 'lib/uttk/strategies/Strategy.rb', line 544

def abort ( message='abort explicitly' )
  @symtbl[:flow] << :abort
  raise_status AbortStatus.new(message)
end

#assign(hsh) ⇒ Object

Assign a hsh keeping at last the attribute referenced by assign_at_last.



283
284
285
286
287
# File 'lib/uttk/strategies/Strategy.rb', line 283

def assign(hsh)
  last = assign_at_last
  hsh.each_pair { |key, val| assign_one(key, val) if key.to_sym != last }
  assign_one(last, hsh[last]) if hsh.has_key? last
end

#clean_instance_variablesObject



386
387
388
389
390
391
392
393
# File 'lib/uttk/strategies/Strategy.rb', line 386

def clean_instance_variables
  attrs = Set.new(self.class.attributes.map { |a| "@#{a.name}" })
  vars = Set.new(instance_variables)
  exceptions = Set.new(%w[ @status @thread @symtbl ])
  (vars - attrs - exceptions).each do |var|
    remove_instance_variable var
  end
end

#display_unexpected_exc(exc) ⇒ Object



587
588
589
# File 'lib/uttk/strategies/Strategy.rb', line 587

def display_unexpected_exc ( exc )
  @log.error_unexpected_exception = exc
end

#display_unexpected_synflow_exc(exc, arg) ⇒ Object



591
592
593
# File 'lib/uttk/strategies/Strategy.rb', line 591

def display_unexpected_synflow_exc ( exc, arg )
  @log.error_unexpected_synflow_exception = arg
end

#fail(*args) ⇒ Object

Force the test to fail



539
540
541
# File 'lib/uttk/strategies/Strategy.rb', line 539

def fail ( *args )
  raise_status_custom FailStatus, *args
end

#initialize_flow_factoryObject



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/uttk/strategies/Strategy.rb', line 297

def initialize_flow_factory
  factory = SynFlowFactory.new
  factory <<
    {
      :start_st           => {
                               :prologue       => :prologue_st,
                               :not_running?   => :start_st,
                               :end_run_impl   => :after_run_st,
                               # :abort          => :start_st,
                               :error          => :error_st
                             },

      :prologue_st        => {
                               :begin_run_impl => :run_impl_st,
                               :error          => :error_st
                             },

      :run_impl_st        => {
                               :prologue       => :prologue_st,
                               :end_run_impl   => :after_run_st,
                               :abort          => :abort_st,
                               :error          => :error_st
                             },

      :after_run_st       => {
                               :epilogue       => :epilogue_st,
                               :error          => :error_st
                             },

      :epilogue_st        => {
                               :finish         => :start_st,
                               :error          => :error_st
                             },

      :abort_st           => {
                               :end_run_impl   => :after_run_abort_st,
                               :abort          => :abort_st,
                               :error          => :error_st
                             },

      :after_run_abort_st => {
                               :epilogue       => :epilogue_abort_st,
                               :abort          => :after_run_abort_st,
                               :error          => :error_st
                             },

      :epilogue_abort_st  => {
                               :finish         => :start_st,
                               :error          => :error_st
                             },

      :error_st           => {
                               :prologue       => :prologue_st,
                               :begin_run_impl => :run_impl_st,
                               :end_run_impl   => :after_run_st,
                               :epilogue       => :epilogue_st,
                               :finish         => :start_st,
                               :no_running?    => :error_st,
                               :error          => :error_st,
                               :abort          => :abort_st
                             },
    }
  factory.initial = :start_st
  @symtbl[:flow_factory] = factory
  @symtbl[:flow] = factory.new_flow
end

#name=(anObject) ⇒ Object



565
566
567
568
569
570
571
572
# File 'lib/uttk/strategies/Strategy.rb', line 565

def name= ( anObject )
  case anObject
  when nil, ''
    @name = nil
  else
    @name = anObject.to_s
  end
end

#passObject

Force the test to pass



523
524
525
# File 'lib/uttk/strategies/Strategy.rb', line 523

def pass
  raise_status PassStatus.new
end

#raise_error(message = nil) ⇒ Object

Force an Error status



533
534
535
536
# File 'lib/uttk/strategies/Strategy.rb', line 533

def raise_error ( message=nil )
  @symtbl[:flow] << :error
  raise_status ErrorStatus.new(message)
end

#reject(*att) ⇒ Object

Reject



293
294
295
# File 'lib/uttk/strategies/Strategy.rb', line 293

def reject ( *att )
  @reject += att.map! { |a| a.to_sym }
end

#run(log = @symtbl[:log]) ⇒ Object Also known as: call

Runs this test, proceding like this:

- check_pre_assertion
- prologue
- run_impl
- assertion
- check_post_assertion
- epilogue


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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/uttk/strategies/Strategy.rb', line 95

def run ( log=@symtbl[:log] )
  unless @status.is_a? StartStatus
    raise_error("This test was already run (#{self} : #{self.class})")
  end
  @log = log
  @benchmark = []
  initialize_flow_factory if @symtbl[:flow_factory].nil?
  flow = @symtbl[:flow]
  flow << :prologue

  @status = RunningStatus.new
  @thread = Thread.current

  aborted = nil
  weight_copy = nil

  @upper = @log.upper
  begin
    begin

      # Pre assertion
      pre_assertion_failed = nil
      begin
        unless r = check_pre_assertion()
          pre_assertion_failed = "Pre assertion failed (#{r.inspect})"
        end
      rescue Exception => ex
        pre_assertion_failed = "Pre assertion failed (#{ex})"
      end
      if pre_assertion_failed
        @log.new_node(to_s)
        @symtbl[:flow] << :error
        skip(pre_assertion_failed)
      end

      begin
        @benchmark << Benchmark.measure('prologue') do
          prologue()
          weight_copy = @weight
        end
        # @log.flow_id = flow.i

      # Catch all other exceptions and wrapped them in an error.
      rescue Exception => ex
        raise_error(ex)
      end

      msg = "abort '%name' with timeout #{@timeout}s"
      specific_abort = TimeoutAbortStatus.new(msg)

      begin
        flow << :begin_run_impl
        skip_if_cached
        skip_wrt_rpath_and_rpath_exclude
        UttkTimeout.timeout(@timeout, flow, specific_abort) do
          @benchmark << Benchmark.measure('run') do
            run_impl()
          end
        end
      ensure
        flow << :end_run_impl
      end

      # Post assertion
      post_assertion_failed = nil
      begin
        unless r = check_post_assertion()
          post_assertion_failed = "Post assertion failed (#{r.inspect})"
        end
      rescue Exception => ex
        post_assertion_failed = "Post assertion failed (#{ex})"
      end
      fail(post_assertion_failed) if post_assertion_failed


      # Assertion
      assertion()


      raise_error('no status given')

    # Forward StatusException
    rescue Status => ex
      # Put the exception in `aborted' if it dosen't concern me and abort.
      if ex.is_a? TimeoutAbortStatus
        aborted = ex if ex != specific_abort
        ex.reason.gsub!('%name', @name.to_s)
      end
      raise ex

    # Catch all others exceptions and wrapped them in an error.
    rescue Exception => ex
      raise_error(ex)
    end

  # Threat Status exceptions
  rescue Status => ex
    begin

      flow << :epilogue
      @status = ex
      # Call the specific hook (pass_hook, failed_hook...).
      send(ex.hook_name)
      unless pre_assertion_failed
        @benchmark << Benchmark.measure('epilogue') do
          epilogue()
        end
      end
    rescue SynFlow::Error => ex
      display_unexpected_synflow_exc ex, :epilogue

    rescue Exception => ex
      display_unexpected_exc ex
    end

  rescue Exception => ex
    display_unexpected_exc ex
  end

  begin
    if @symtbl[:benchmark] and (not @reject.include?(:benchmark))
      @log.new_node(:benchmark, :ordered => true) do
        @benchmark.each { |b| @log << b }
      end
    end
    @log << status unless @reject.include?(:status)
    @status.weight *= weight_copy
    @upper.up
    if cache = @symtbl[:cache]
      cache[@symtbl[:pathname]] =
      {
        :status => @status,
        :symtbl => @symtbl.local
      }
    end
    @reject.clear if defined? @reject
    clean_instance_variables
    flow << :finish
  rescue SynFlow::Error => ex
    display_unexpected_synflow_exc ex, :finish
  rescue Exception => ex
    display_unexpected_exc ex
  end
  raise aborted unless aborted.nil?
  return @status

end

#running?Boolean

Returns:

  • (Boolean)


583
584
585
# File 'lib/uttk/strategies/Strategy.rb', line 583

def running?
  defined? @status and @status.is_a? RunningStatus
end

#skip(*args) ⇒ Object

Skip the test



528
529
530
# File 'lib/uttk/strategies/Strategy.rb', line 528

def skip ( *args )
  raise_status_custom SkipStatus, *args
end

#skip_if_cachedObject



364
365
366
367
368
369
370
371
372
# File 'lib/uttk/strategies/Strategy.rb', line 364

def skip_if_cached
  if cache = @symtbl[:use_cache]
    me = cache[@symtbl[:pathname].to_sym]
    if me and @symtbl[:cache_proc][self, me[:status]]
      @symtbl.local.merge!(me[:symtbl])
      skip(@wclass.new(me[:status].weight))
    end
  end
end

#skip_wrt_rpath_and_rpath_excludeObject



374
375
376
377
378
379
380
381
382
383
384
# File 'lib/uttk/strategies/Strategy.rb', line 374

def skip_wrt_rpath_and_rpath_exclude
  re = @symtbl[:rpath]
  re_ex = @symtbl[:rpath_exclude]
  lpath = @log.path
  if re and not lpath.lpath_prefix re
    skip(@wclass.new(:PASS))
  end
  if re_ex and lpath.rpath_prefix re_ex
    skip(@wclass.new(:PASS))
  end
end

#strategyObject



602
603
604
# File 'lib/uttk/strategies/Strategy.rb', line 602

def strategy
  self.class
end

#strategy=(aClass) ⇒ Object



606
607
608
609
610
611
# File 'lib/uttk/strategies/Strategy.rb', line 606

def strategy= ( aClass )
  if aClass != Strategy and aClass != self.class
    raise ArgumentError, "Cannot change the strategy class " +
                         "of a test (#{aClass} != #{self.class})"
  end
end

#symbols=(symbols) ⇒ Object

FIXME: I’m not well dumped



596
597
598
599
600
# File 'lib/uttk/strategies/Strategy.rb', line 596

def symbols= ( symbols )
  symbols.each do |k, v|
    @symbols[k] = v
  end
end

#symtbl(aSymtbl = nil) ⇒ Object



618
619
620
621
622
623
624
# File 'lib/uttk/strategies/Strategy.rb', line 618

def symtbl (aSymtbl=nil)
  if aSymtbl.nil?
    @symtbl
  else
    self.symtbl = aSymtbl
  end
end

#symtbl=(aSymtbl) ⇒ Object



613
614
615
616
# File 'lib/uttk/strategies/Strategy.rb', line 613

def symtbl= ( aSymtbl )
  @symtbl = aSymtbl
  @log ||= @symtbl[:log]
end

#testify(symtbl, &block) ⇒ Object

Build methods



554
555
556
557
558
559
# File 'lib/uttk/strategies/Strategy.rb', line 554

def testify ( symtbl, &block )
  test = dup
  test.symtbl ||= symtbl
  block[test] if block
  test
end

#timeout=(other) ⇒ Object



575
576
577
578
579
580
581
# File 'lib/uttk/strategies/Strategy.rb', line 575

def timeout=(other)
  if other >= 0
    @timeout = other
  else
    raise(ArgumentError, "`#{other}' - timeout delay must be >= 0")
  end
end

#to_sObject



561
562
563
# File 'lib/uttk/strategies/Strategy.rb', line 561

def to_s
  @name || @log.path.to_s || super
end

#wclass=(other) ⇒ Object

Custom accessors



249
250
251
252
253
254
255
# File 'lib/uttk/strategies/Strategy.rb', line 249

def wclass=(other)
  if other.is_a?(Class)
    @wclass = other
  else
    @wclass = Uttk::Weights.const_get(other.to_s)
  end
end