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.

Methods

Included Modules

Abstract AttributedClass

Classes and Modules

Module Uttk::Strategies::Strategy::AttributedClass
Module Uttk::Strategies::Strategy::UttkTimeout
Class Uttk::Strategies::Strategy::CommandMatcher
Class Uttk::Strategies::Strategy::StrategyHooker

Attributes

status  [R]  Accessors

Public Class methods

Create a new Strategy with the given optional document.

[Source]

# 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

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 776
      def self.to_yaml_type
        name.sub(/^Uttk::Strategies/, '!S')
      end

Public Instance methods

Abort the test explicitly.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 694
      def abort ( message='abort explicitly' )
        @symtbl[:flow] << :abort
        raise_status AbortStatus.new(message)
      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.

[Source]

# 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.

[Source]

# 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
call( log=@symtbl[:log] )

Alias for run

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 737
      def display_unexpected_exc ( exc )
        @log.error_unexpected_exception = exc
      end

[Source]

# File lib/uttk/strategies/Strategy.rb, line 741
      def display_unexpected_synflow_exc ( exc, arg )
        @log.error_unexpected_synflow_exception = arg
      end

Force the test to fail

[Source]

# File lib/uttk/strategies/Strategy.rb, line 689
      def fail ( *args )
        raise_status_custom FailStatus, *args
      end

[Source]

# 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

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 715
      def name= ( anObject )
        case anObject
        when nil, ''
          @name = nil
        else
          @name = anObject.to_s
        end
      end

Force the test to pass

[Source]

# File lib/uttk/strategies/Strategy.rb, line 668
      def pass
        raise_status PassStatus.new
      end

Force an Error status

[Source]

# File lib/uttk/strategies/Strategy.rb, line 683
      def raise_error ( message=nil )
        @symtbl[:flow] << :error
        raise_status ErrorStatus.new(message)
      end

Reject

[Source]

# 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

[Source]

# 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

[Source]

# 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%)

[Source]

# File lib/uttk/strategies/Strategy.rb, line 673
      def skip ( *args )
        raise_status_custom SkipStatus, *args
      end

[Source]

# 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%.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 678
      def skip_pass ( message=nil )
        raise_status SkipStatus.new(PassStatus.new.weight, message)
      end

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 752
      def strategy
        self.class
      end

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 746
      def symbols= ( symbols )
        symbols.each do |k, v|
          @symbols[k] = v
        end
      end

[Source]

# File lib/uttk/strategies/Strategy.rb, line 768
      def symtbl (aSymtbl=nil)
        if aSymtbl.nil?
          @symtbl
        else
          self.symtbl = aSymtbl
        end
      end

[Source]

# File lib/uttk/strategies/Strategy.rb, line 763
      def symtbl= ( aSymtbl )
        @symtbl = aSymtbl
        @log ||= @symtbl[:log]
      end

[Source]

# 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

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 704
      def testify ( symtbl, &block )
        test = dup
        test.symtbl ||= symtbl
        block[test] if block
        test
      end

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 711
      def to_s
        @name || @log.path.to_s || super
      end

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 544
        def to_uttk_log log
          each do |r|
            log << r
          end
        end

[Source]

# 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

[Source]

# 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

Protected Instance methods

Here you can do some tasks when the test is aborted.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 634
      def abort_hook
      end

Exploit the results and assert when you want

[Source]

# File lib/uttk/strategies/Strategy.rb, line 455
      def assertion
      end

This can be overrided to specify which attribute is assign at last.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 276
      def assign_at_last
        nil
      end

Assign an attribute safely from a key:String and a value.

[Source]

# 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

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 460
      def check_post_assertion
        check_assertion('post-assertions', @post_assertion)
      end

[Source]

# 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.

[Source]

# 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.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 629
      def error_hook
      end

Here you can do some tasks when the test failed.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 624
      def failed_hook
      end

Here you can do some tasks when the test is passed.

[Source]

# 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.

[Source]

# 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

[Source]

# File lib/uttk/strategies/Strategy.rb, line 653
      def raise_status ( status )
        @thread.raise(status)
      end

[Source]

# 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.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 449
      def run_impl
      end

Here you can do some task when the test is skiped.

[Source]

# File lib/uttk/strategies/Strategy.rb, line 639
      def skip_hook
      end

[Validate]