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 Classes: CommandMatcher, StrategyHooker

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



780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
# File 'lib/uttk/strategies/Strategy.rb', line 780

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



776
777
778
# File 'lib/uttk/strategies/Strategy.rb', line 776

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

Instance Method Details

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

Abort the test explicitly.



694
695
696
697
# File 'lib/uttk/strategies/Strategy.rb', line 694

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

#assert_cmd(matcher, my, ref) ⇒ Object

Examples:

assert_cmd @matcher, @data, :output => /foo*/, :error => '', :exit => 0
assert_cmd UM::StreamMatcher, @data, :output => 'foo.txt'.to_path

The given matcher is used to match command data contents.



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

def assert_cmd matcher, my, ref
  matcher_result = command_matcher[matcher, ref, my]
  @log << matcher_result
  fail if matcher_result.failure?
  return matcher_result
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



737
738
739
# File 'lib/uttk/strategies/Strategy.rb', line 737

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

#display_unexpected_synflow_exc(exc, arg) ⇒ Object



741
742
743
# File 'lib/uttk/strategies/Strategy.rb', line 741

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

#fail(*args) ⇒ Object

Force the test to fail



689
690
691
# File 'lib/uttk/strategies/Strategy.rb', line 689

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

#mk_system_runner(env = {}) ⇒ Object

FIXME move them to separate files



467
468
469
470
# File 'lib/uttk/strategies/Strategy.rb', line 467

def mk_system_runner env={}
  hooker = StrategyHooker.new @symtbl, @log, env
  OCmd::Runners::System.new.hooker_subscribe hooker
end

#name=(anObject) ⇒ Object



715
716
717
718
719
720
721
722
# File 'lib/uttk/strategies/Strategy.rb', line 715

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

#passObject

Force the test to pass



668
669
670
# File 'lib/uttk/strategies/Strategy.rb', line 668

def pass
  raise_status PassStatus.new
end

#raise_error(message = nil) ⇒ Object

Force an Error status



683
684
685
686
# File 'lib/uttk/strategies/Strategy.rb', line 683

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)


733
734
735
# File 'lib/uttk/strategies/Strategy.rb', line 733

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

#skip(*args) ⇒ Object

Skip the test (by default the weight is 0%)



673
674
675
# File 'lib/uttk/strategies/Strategy.rb', line 673

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_pass(message = nil) ⇒ Object

Skip the test: the weight is 100%.



678
679
680
# File 'lib/uttk/strategies/Strategy.rb', line 678

def skip_pass ( message=nil )
  raise_status SkipStatus.new(PassStatus.new.weight, message)
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



752
753
754
# File 'lib/uttk/strategies/Strategy.rb', line 752

def strategy
  self.class
end

#strategy=(aClass) ⇒ Object



756
757
758
759
760
761
# File 'lib/uttk/strategies/Strategy.rb', line 756

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



746
747
748
749
750
# File 'lib/uttk/strategies/Strategy.rb', line 746

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

#symtbl(aSymtbl = nil) ⇒ Object



768
769
770
771
772
773
774
# File 'lib/uttk/strategies/Strategy.rb', line 768

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

#symtbl=(aSymtbl) ⇒ Object



763
764
765
766
# File 'lib/uttk/strategies/Strategy.rb', line 763

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

#testify(symtbl, &block) ⇒ Object

Build methods



704
705
706
707
708
709
# File 'lib/uttk/strategies/Strategy.rb', line 704

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

#timeout=(other) ⇒ Object



725
726
727
728
729
730
731
# File 'lib/uttk/strategies/Strategy.rb', line 725

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

#to_sObject



711
712
713
# File 'lib/uttk/strategies/Strategy.rb', line 711

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