| Class | Uttk::Strategies::Strategy |
| In: |
lib/uttk/strategies/Strategy.rb
|
| Parent: | Object |
This is the base class for anything testable. It provides some basics attributes like the name of the test.
| status | [R] | Accessors |
Create a new Strategy with the given optional document.
# 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
# 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
# File lib/uttk/strategies/Strategy.rb, line 776 def self.to_yaml_type name.sub(/^Uttk::Strategies/, '!S') end
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.
# 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 a hsh keeping at last the attribute referenced by assign_at_last.
# 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
# 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
# File lib/uttk/strategies/Strategy.rb, line 737 def display_unexpected_exc ( exc ) @log.error_unexpected_exception = exc end
# File lib/uttk/strategies/Strategy.rb, line 741 def display_unexpected_synflow_exc ( exc, arg ) @log.error_unexpected_synflow_exception = arg end
# 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
FIXME move them to separate files
# 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
# File lib/uttk/strategies/Strategy.rb, line 715 def name= ( anObject ) case anObject when nil, '' @name = nil else @name = anObject.to_s end end
Reject
# File lib/uttk/strategies/Strategy.rb, line 293 def reject ( *att ) @reject += att.map! { |a| a.to_sym } end
Runs this test, proceding like this:
- check_pre_assertion - prologue - run_impl - assertion - check_post_assertion - epilogue
# 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
# File lib/uttk/strategies/Strategy.rb, line 733 def running? defined? @status and @status.is_a? RunningStatus end
Skip the test (by default the weight is 0%)
# File lib/uttk/strategies/Strategy.rb, line 673 def skip ( *args ) raise_status_custom SkipStatus, *args end
# 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 the test: the weight is 100%.
# File lib/uttk/strategies/Strategy.rb, line 678 def skip_pass ( message=nil ) raise_status SkipStatus.new(PassStatus.new.weight, message) end
# 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
# 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
FIXME: I‘m not well dumped
# File lib/uttk/strategies/Strategy.rb, line 746 def symbols= ( symbols ) symbols.each do |k, v| @symbols[k] = v end end
# File lib/uttk/strategies/Strategy.rb, line 768 def symtbl (aSymtbl=nil) if aSymtbl.nil? @symtbl else self.symtbl = aSymtbl end end
# File lib/uttk/strategies/Strategy.rb, line 763 def symtbl= ( aSymtbl ) @symtbl = aSymtbl @log ||= @symtbl[:log] end
# File lib/uttk/strategies/Strategy.rb, line 586 def symtbl_gsub symtbl command = @command.symtbl_gsub symtbl args = @args.symtbl_gsub symtbl dir = @dir.symtbl_gsub symtbl if command || args || dir self.class.new(command || @command, args || @args, dir || @dir) else nil end end
# File lib/uttk/strategies/Strategy.rb, line 580 def symtbl_gsub! symtbl res = @command.symtbl_gsub!(symtbl) res = @args.symtbl_gsub!(symtbl) || res res = @dir.symtbl_gsub!(symtbl) || res (res)? self : nil end
Build methods
# File lib/uttk/strategies/Strategy.rb, line 704 def testify ( symtbl, &block ) test = dup test.symtbl ||= symtbl block[test] if block test end
# 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
# File lib/uttk/strategies/Strategy.rb, line 553 def to_uttk_log log raise ArgumentError, "no name for this matcher result" if @name.nil? log.new_node @name do log.reason = message unless message.empty? if data.nil? or data.is_a? MatchData log.my = my.to_s_for_uttk_log unless my.nil? log.ref = ref.to_s_for_uttk_log unless ref.nil? else log.diff = data.output.read end end end
# File lib/uttk/strategies/Strategy.rb, line 566 def to_uttk_log log raise ArgumentError, "no name for this matcher result" if @name.nil? log["#{@name}_reason"] = message unless message.empty? if data.nil? or data.is_a? MatchData log["my_#@name"] = my.to_s_for_uttk_log unless my.nil? log["ref_#@name"] = ref.to_s_for_uttk_log unless ref.nil? else log["#{@name}_diff"] = data.output.read end end
Custom accessors
# 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
Here you can do some tasks when the test is aborted.
# File lib/uttk/strategies/Strategy.rb, line 634 def abort_hook end
Exploit the results and assert when you want
# File lib/uttk/strategies/Strategy.rb, line 455 def assertion end
Assign an attribute safely from a key:String and a value.
# File lib/uttk/strategies/Strategy.rb, line 262 def assign_one(key, val, silent=false) return if [:strategy].include? key.to_sym meth = key.to_s + '=' if !val.nil? if respond_to?(meth) or respond_to?(:method_missing) send(meth, val) elsif not silent @log.warn { "Attribute #{key} not found for #{self.class}" } end end end
# File lib/uttk/strategies/Strategy.rb, line 395 def check_assertion ( header, assertion ) if assertion.is_a?(Proc) instance_eval(&assertion) else instance_eval(assertion.to_s) end end
# File lib/uttk/strategies/Strategy.rb, line 460 def check_post_assertion check_assertion('post-assertions', @post_assertion) end
# File lib/uttk/strategies/Strategy.rb, line 404 def check_pre_assertion check_assertion('pre-assertion', @pre_assertion) end
Display conclusions. Here you can finish some tasks even when the test fails. Exceptions are absolutly forbidden in this method.
# File lib/uttk/strategies/Strategy.rb, line 615 def epilogue unless @save.nil? @save.each { |k,v| send("#{k}=", v) } @save.clear end end
Here you can do some tasks when an error occur during the test.
# File lib/uttk/strategies/Strategy.rb, line 629 def error_hook end
Here you can do some tasks when the test failed.
# File lib/uttk/strategies/Strategy.rb, line 624 def failed_hook end
Here you can do some tasks when the test is passed.
# File lib/uttk/strategies/Strategy.rb, line 644 def pass_hook end
Display test attributes. Attributes displayed and their order is specified by the class attribute attributes.
# File lib/uttk/strategies/Strategy.rb, line 412 def prologue if @symtbl[:loader].nil? raise ArgumentError, 'no loader in the symtbl' end @save = {} res = OHash.new check_attributes each_attribute do |attr, val| next if val.nil? name = attr.name if attr.expand? and new_val = val.symtbl_gsub(@symtbl) @save[name] = val val = new_val send("#{name}=", val) end if attr.visible? and not @reject.include? name res[name] = val unless val == attr.default or name == :name end end @symbols.each do |k, v| @symtbl[k] = v end unless self.name.nil? or @reject.include? :name if @symtbl[:pathname].nil? @symtbl[:pathname] = ('/' + self.name).to_sym else @symtbl[:pathname] = "#{@symtbl[:pathname]}/#{self.name}""#{@symtbl[:pathname]}/#{self.name}" end @log.new_node(self.name, :type => self.class) end @log << res end
Assertions
# File lib/uttk/strategies/Strategy.rb, line 653 def raise_status ( status ) @thread.raise(status) end
# File lib/uttk/strategies/Strategy.rb, line 658 def raise_status_custom ( status_class, *args ) weight, message = args.partition { |x| x.is_a? Weights::Weight } if weight.size > 1 or message.size > 1 raise ArgumentError, 'too much arguments' end raise_status status_class.new(weight[0], message[0]) end
Compute really the test, only this method can be time checked.
# File lib/uttk/strategies/Strategy.rb, line 449 def run_impl end