oflow 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +182 -0
- data/lib/oflow/actor.rb +76 -0
- data/lib/oflow/actors/errorhandler.rb +32 -0
- data/lib/oflow/actors/ignore.rb +22 -0
- data/lib/oflow/actors/log.rb +175 -0
- data/lib/oflow/actors/relay.rb +23 -0
- data/lib/oflow/actors/timer.rb +126 -0
- data/lib/oflow/actors.rb +11 -0
- data/lib/oflow/box.rb +195 -0
- data/lib/oflow/env.rb +52 -0
- data/lib/oflow/errors.rb +74 -0
- data/lib/oflow/flow.rb +75 -0
- data/lib/oflow/haserrorhandler.rb +48 -0
- data/lib/oflow/haslinks.rb +64 -0
- data/lib/oflow/haslog.rb +72 -0
- data/lib/oflow/hasname.rb +31 -0
- data/lib/oflow/hastasks.rb +209 -0
- data/lib/oflow/inspector.rb +501 -0
- data/lib/oflow/link.rb +43 -0
- data/lib/oflow/pattern.rb +8 -0
- data/lib/oflow/stamp.rb +39 -0
- data/lib/oflow/task.rb +415 -0
- data/lib/oflow/test/action.rb +21 -0
- data/lib/oflow/test/actorwrap.rb +62 -0
- data/lib/oflow/test.rb +8 -0
- data/lib/oflow/tracker.rb +109 -0
- data/lib/oflow/version.rb +5 -0
- data/lib/oflow.rb +23 -0
- data/test/actors/log_test.rb +57 -0
- data/test/actors/timer_test.rb +56 -0
- data/test/actorwrap_test.rb +48 -0
- data/test/all_tests.rb +27 -0
- data/test/box_test.rb +127 -0
- data/test/collector.rb +23 -0
- data/test/flow_basic_test.rb +93 -0
- data/test/flow_cfg_error_test.rb +94 -0
- data/test/flow_log_test.rb +87 -0
- data/test/flow_nest_test.rb +215 -0
- data/test/flow_rescue_test.rb +133 -0
- data/test/flow_tracker_test.rb +82 -0
- data/test/stutter.rb +21 -0
- data/test/task_test.rb +98 -0
- data/test/tracker_test.rb +59 -0
- metadata +93 -0
    
        data/lib/oflow.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            module OFlow
         | 
| 3 | 
            +
            end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'oflow/errors'
         | 
| 6 | 
            +
            require 'oflow/stamp'
         | 
| 7 | 
            +
            require 'oflow/hasname'
         | 
| 8 | 
            +
            require 'oflow/hastasks'
         | 
| 9 | 
            +
            require 'oflow/haslinks'
         | 
| 10 | 
            +
            require 'oflow/haserrorhandler'
         | 
| 11 | 
            +
            require 'oflow/haslog'
         | 
| 12 | 
            +
            require 'oflow/pattern'
         | 
| 13 | 
            +
            require 'oflow/tracker'
         | 
| 14 | 
            +
            require 'oflow/box'
         | 
| 15 | 
            +
            require 'oflow/actor'
         | 
| 16 | 
            +
            require 'oflow/task'
         | 
| 17 | 
            +
            require 'oflow/link'
         | 
| 18 | 
            +
            require 'oflow/flow'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            require 'oflow/actors'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'oflow/env'
         | 
| 23 | 
            +
            require 'oflow/inspector'
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../../lib"),
         | 
| 6 | 
            +
              File.join(File.dirname(__FILE__), "..")
         | 
| 7 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'test/unit'
         | 
| 10 | 
            +
            require 'stringio'
         | 
| 11 | 
            +
            require 'oflow'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class LogTest < ::Test::Unit::TestCase
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def test_log
         | 
| 16 | 
            +
                stream = StringIO.new()
         | 
| 17 | 
            +
                log = ::OFlow::Task.new(nil, 'log', ::OFlow::Actors::Log,
         | 
| 18 | 
            +
                                        :stream => stream,
         | 
| 19 | 
            +
                                        :severity => Logger::INFO,
         | 
| 20 | 
            +
                                        :formatter => proc { |sev, time, prog, msg| "#{sev}: #{msg}\n" })
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                log.receive(:fatal, ::OFlow::Box.new(['dead msg', 'Dead']))
         | 
| 23 | 
            +
                log.receive(:error, ::OFlow::Box.new(['oops msg', 'Oops']))
         | 
| 24 | 
            +
                log.receive(:warn, ::OFlow::Box.new(['duck msg', 'Duck']))
         | 
| 25 | 
            +
                log.receive(:info, ::OFlow::Box.new(['something msg', 'Something']))
         | 
| 26 | 
            +
                log.receive(:debug, ::OFlow::Box.new(['bugs msg', 'Bugs']))
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                log.flush()
         | 
| 29 | 
            +
                assert_equal(%{FATAL: dead msg
         | 
| 30 | 
            +
            ERROR: oops msg
         | 
| 31 | 
            +
            WARN: duck msg
         | 
| 32 | 
            +
            INFO: something msg
         | 
| 33 | 
            +
            }, stream.string)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                log.shutdown()
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def test_log_filename
         | 
| 39 | 
            +
                filename = 'filename_test.log'
         | 
| 40 | 
            +
                %x{rm -f #{filename}}
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                log = ::OFlow::Task.new(nil, 'log', ::OFlow::Actors::Log,
         | 
| 43 | 
            +
                                        :filename => filename,
         | 
| 44 | 
            +
                                        :severity => Logger::INFO,
         | 
| 45 | 
            +
                                        :formatter => proc { |sev, time, prog, msg| "#{sev}: #{msg}\n" })
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                log.receive(:info, ::OFlow::Box.new(['first entry', 'One']))
         | 
| 48 | 
            +
                log.flush()
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                output = File.read(filename).split("\n")[1..-1]
         | 
| 51 | 
            +
                assert_equal(['INFO: first entry'], output)
         | 
| 52 | 
            +
                %x{rm #{filename}}
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                log.shutdown()
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            end # LogTest
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../../lib"),
         | 
| 6 | 
            +
              File.join(File.dirname(__FILE__), "..")
         | 
| 7 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'test/unit'
         | 
| 10 | 
            +
            require 'oflow'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            require 'collector'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            class TimerTest < ::Test::Unit::TestCase
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def test_timer_repeat
         | 
| 17 | 
            +
                period = 0.1
         | 
| 18 | 
            +
                timer = nil
         | 
| 19 | 
            +
                collector = nil
         | 
| 20 | 
            +
                ::OFlow::Env.flow('one-time') { |f|
         | 
| 21 | 
            +
                  f.task('once', ::OFlow::Actors::Timer, repeat: 4, period: period) { |t|
         | 
| 22 | 
            +
                    timer = t
         | 
| 23 | 
            +
                    t.link(:ping, :collector, :tick)
         | 
| 24 | 
            +
                  }
         | 
| 25 | 
            +
                  f.task(:collector, Collector) { |t|
         | 
| 26 | 
            +
                    collector = t.actor
         | 
| 27 | 
            +
                  }
         | 
| 28 | 
            +
                }
         | 
| 29 | 
            +
                ::OFlow::Env.flush()
         | 
| 30 | 
            +
                prev = nil
         | 
| 31 | 
            +
                ticks = collector.collection.map do |t|
         | 
| 32 | 
            +
                  tf = t[2].to_f
         | 
| 33 | 
            +
                  if prev.nil?
         | 
| 34 | 
            +
                    tick = [t[1], tf, 0.0]
         | 
| 35 | 
            +
                  else
         | 
| 36 | 
            +
                    tick = [t[1], tf, tf - prev]
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  prev = tf
         | 
| 39 | 
            +
                  tick
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                ticks.size.times do |i|
         | 
| 43 | 
            +
                  tick = ticks[i]
         | 
| 44 | 
            +
                  assert_equal(i + 1, tick[0])
         | 
| 45 | 
            +
                  next if 0 == i
         | 
| 46 | 
            +
                  dif = tick[2] - period
         | 
| 47 | 
            +
                  limit = period / 10 # 10% accuracy
         | 
| 48 | 
            +
                  assert(-limit < dif && dif < limit, "Verify timer fires are within 10% of expected. (dif: #{dif}, limit: #{limit})")
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                ::OFlow::Env.clear()
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              # TBD more tests on start, stop, combinations of options, and error conditions
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            end # TimerTest
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'test/unit'
         | 
| 9 | 
            +
            require 'oflow'
         | 
| 10 | 
            +
            require 'oflow/test'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            class Nonsense < ::OFlow::Actor
         | 
| 13 | 
            +
              def initialize(task, options)
         | 
| 14 | 
            +
                super
         | 
| 15 | 
            +
                @cnt = 0
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def perform(op, box)
         | 
| 19 | 
            +
                @cnt += 1
         | 
| 20 | 
            +
                task.ship(:start, ::OFlow::Box.new(@cnt))
         | 
| 21 | 
            +
                task.ship(op, box)
         | 
| 22 | 
            +
                task.info("finished #{@cnt}")
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            end # Nonsense
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            class ActorWrapTest < ::Test::Unit::TestCase
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def test_actorwrap
         | 
| 30 | 
            +
                wrap = ::OFlow::Test::ActorWrap.new('wrapper', Nonsense)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                wrap.receive(:first, ::OFlow::Box.new('word'))
         | 
| 33 | 
            +
                history = wrap.history.map { |action| action.to_s }
         | 
| 34 | 
            +
                assert_equal(['start: 1', 'first: word', 'log: [:info, "finished 1", ":test:wrapper"]'], history)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                wrap.receive(:second, ::OFlow::Box.new('This is a sentence.'))
         | 
| 37 | 
            +
                history = wrap.history.map { |action| action.to_s }
         | 
| 38 | 
            +
                assert_equal(['start: 1', 'first: word', 'log: [:info, "finished 1", ":test:wrapper"]',
         | 
| 39 | 
            +
                             'start: 2', 'second: This is a sentence.', 'log: [:info, "finished 2", ":test:wrapper"]'], history)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                wrap.reset()
         | 
| 42 | 
            +
                assert_equal([], wrap.history)
         | 
| 43 | 
            +
                wrap.receive(:third, ::OFlow::Box.new('word'))
         | 
| 44 | 
            +
                history = wrap.history.map { |action| action.to_s }
         | 
| 45 | 
            +
                assert_equal(['start: 3', 'third: word', 'log: [:info, "finished 3", ":test:wrapper"]'], history)
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            end # ActorWrapTest
         | 
    
        data/test/all_tests.rb
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'test/unit'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'box_test'
         | 
| 12 | 
            +
            require 'task_test'
         | 
| 13 | 
            +
            require 'tracker_test'
         | 
| 14 | 
            +
            require 'actorwrap_test'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            require 'flow_basic_test'
         | 
| 17 | 
            +
            require 'flow_rescue_test'
         | 
| 18 | 
            +
            require 'flow_log_test'
         | 
| 19 | 
            +
            require 'flow_cfg_error_test'
         | 
| 20 | 
            +
            require 'flow_rescue_test'
         | 
| 21 | 
            +
            require 'flow_nest_test'
         | 
| 22 | 
            +
            require 'flow_tracker_test'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            # Actor tests
         | 
| 25 | 
            +
            require 'actors/log_test'
         | 
| 26 | 
            +
            require 'actors/timer_test'
         | 
| 27 | 
            +
             | 
    
        data/test/box_test.rb
    ADDED
    
    | @@ -0,0 +1,127 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
         | 
| 5 | 
            +
            # required. That can be set in the RUBYOPT environment variable.
         | 
| 6 | 
            +
            # export RUBYOPT=-w
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            $VERBOSE = true
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            $: << File.join(File.dirname(__FILE__), "../lib")
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            require 'test/unit'
         | 
| 13 | 
            +
            require 'oflow'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            class Access
         | 
| 16 | 
            +
              attr_accessor :x, :y
         | 
| 17 | 
            +
              def initialize(x, y)
         | 
| 18 | 
            +
                @x = x
         | 
| 19 | 
            +
                @y = y
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end # Access
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            class BoxTest < ::Test::Unit::TestCase
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def test_box_new
         | 
| 26 | 
            +
                data = { a: [1, 'first'], b: true }
         | 
| 27 | 
            +
                t = ::OFlow::Tracker.create('test')
         | 
| 28 | 
            +
                box = ::OFlow::Box.new(data, t)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                assert_equal(data, box.contents, 'data should be the same as what was passed in')
         | 
| 31 | 
            +
                assert_equal(t, box.tracker, 'tracker should be the same as what was passed in')
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_box_freeze
         | 
| 35 | 
            +
                data = { a: [1, 'first'], b: true }
         | 
| 36 | 
            +
                t = ::OFlow::Tracker.create('test')
         | 
| 37 | 
            +
                box = ::OFlow::Box.new(data, t).freeze()
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                assert_equal(true, box.frozen?, 'box should be frozen')
         | 
| 40 | 
            +
                assert_equal(true, box.contents.frozen?, 'contents should be frozen')
         | 
| 41 | 
            +
                assert_equal(true, box.contents[:a].frozen?, 'members of contents should be frozen')
         | 
| 42 | 
            +
                assert_equal(true, box.contents[:a][1].frozen?, 'members of contentes should be frozen all the way down')
         | 
| 43 | 
            +
                assert_equal(true, box.tracker.frozen?, 'tracker should be frozen')
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              def test_box_thaw
         | 
| 47 | 
            +
                data = { a: [1, 'first'], b: true }
         | 
| 48 | 
            +
                t = ::OFlow::Tracker.create('test')
         | 
| 49 | 
            +
                box = ::OFlow::Box.new(data, t).freeze()
         | 
| 50 | 
            +
                # make sure it is frozen first.
         | 
| 51 | 
            +
                assert_equal(true, box.frozen?, 'box should be frozen')
         | 
| 52 | 
            +
                box = box.thaw()
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                assert_equal(false, box.frozen?, 'box should not be frozen')
         | 
| 55 | 
            +
                assert_equal(false, box.contents.frozen?, 'contents not should be frozen')
         | 
| 56 | 
            +
                assert_equal(false, box.contents[:a].frozen?, 'members of contents should not be frozen')
         | 
| 57 | 
            +
                assert_equal(false, box.contents[:a][1].frozen?, 'members of contentes should not be frozen all the way down')
         | 
| 58 | 
            +
                assert_equal(true, box.tracker.frozen?, 'tracker should still be frozen')
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def test_box_receive
         | 
| 62 | 
            +
                data = { a: [1, 'first'], b: true }
         | 
| 63 | 
            +
                t = ::OFlow::Tracker.create('test')
         | 
| 64 | 
            +
                box = ::OFlow::Box.new(data, t).freeze()
         | 
| 65 | 
            +
                # make sure it is frozen first.
         | 
| 66 | 
            +
                assert_equal(true, box.frozen?, 'box should be frozen')
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                rbox = box.receive('here', 'try')
         | 
| 69 | 
            +
                assert_equal(false, rbox.frozen?, 'box should not be frozen')
         | 
| 70 | 
            +
                assert_equal(true, box.contents.frozen?, 'contents should be frozen')
         | 
| 71 | 
            +
                assert_equal(2, rbox.tracker.track.size, 'track should have 2 entries')
         | 
| 72 | 
            +
                assert_equal('test-', rbox.tracker.track[0].where, 'check track entry 0')
         | 
| 73 | 
            +
                assert_equal('here-try', rbox.tracker.track[1].where, 'check track entry 1')
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              def test_box_get
         | 
| 77 | 
            +
                data = { a: [1, 'first'], b: true, 'c' => 'see', d: Access.new([7, 3], :y) }
         | 
| 78 | 
            +
                box = ::OFlow::Box.new(data).freeze()
         | 
| 79 | 
            +
                # Hash access
         | 
| 80 | 
            +
                assert_equal(true, box.get('b'), 'get b')
         | 
| 81 | 
            +
                assert_equal('see', box.get('c'), 'get c')
         | 
| 82 | 
            +
                assert_equal(nil, box.get('x'), 'get x')
         | 
| 83 | 
            +
                # Array access
         | 
| 84 | 
            +
                assert_equal(1, box.get('a:0'), 'get a:0')
         | 
| 85 | 
            +
                assert_equal('first', box.get('a:1'), 'get a:1')
         | 
| 86 | 
            +
                assert_equal(nil, box.get('a:2'), 'get a:2')
         | 
| 87 | 
            +
                # nil path
         | 
| 88 | 
            +
                assert_equal(data, box.get(nil), 'get nil')
         | 
| 89 | 
            +
                assert_equal(data, box.get(''), 'get nil')
         | 
| 90 | 
            +
                # Object
         | 
| 91 | 
            +
                assert_equal([7, 3], box.get('d:x'), 'get d:x')
         | 
| 92 | 
            +
                assert_equal(7, box.get('d:x:0'), 'get d:x:0')
         | 
| 93 | 
            +
                assert_equal(:y, box.get('d:y'), 'get d:y')
         | 
| 94 | 
            +
                assert_equal(nil, box.get('d:z'), 'get d:z')
         | 
| 95 | 
            +
                # more bad paths
         | 
| 96 | 
            +
                assert_equal(nil, box.get('b:0'), 'get b:0')
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              def test_box_set
         | 
| 100 | 
            +
                data = { a: [1, 'first'], b: true, 'c' => 'see', d: Access.new([7, 3], :y) }
         | 
| 101 | 
            +
                box = ::OFlow::Box.new(data).freeze()
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                b2 = box.set('b', false)
         | 
| 104 | 
            +
                assert_equal(false, b2.get('b'), 'get b')
         | 
| 105 | 
            +
                assert_equal(true, box.contents[:a].frozen?, 'other contents should be frozen')
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                b2 = box.set('a:0', 3)
         | 
| 108 | 
            +
                assert_equal(3, b2.get('a:0'), 'get a:0')
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                b2 = box.set('a:2', 5)
         | 
| 111 | 
            +
                assert_equal(5, b2.get('a:2'), 'get a:2')
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                b2 = box.set('c', 'mite')
         | 
| 114 | 
            +
                assert_equal('mite', b2.get('c'), 'get c')
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                b2 = box.set('e:ha', 'new')
         | 
| 117 | 
            +
                assert_equal('new', b2.get('e:ha'), 'get e:ha')
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                b2 = box.set('f:1', 'new')
         | 
| 120 | 
            +
                assert_equal(Array, b2.get('f').class, 'get f class')
         | 
| 121 | 
            +
                assert_equal(nil, b2.get('f:0'), 'get f:0')
         | 
| 122 | 
            +
                assert_equal('new', b2.get('f:1'), 'get f:1')
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                assert_raise(::OFlow::FrozenError) { box.set('d:x:1', 'three') }
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            end # BoxTest
         | 
    
        data/test/collector.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'oflow'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            class Collector < ::OFlow::Actor
         | 
| 11 | 
            +
              attr_accessor :collection
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def initialize(task, options)
         | 
| 14 | 
            +
                super
         | 
| 15 | 
            +
                @collection = []
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def perform(op, box)
         | 
| 19 | 
            +
                @collection << box.contents
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            end # Collector
         | 
| 23 | 
            +
             | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'test/unit'
         | 
| 9 | 
            +
            require 'oflow'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'collector'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class Stutter < ::OFlow::Actor
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def initialize(task, options)
         | 
| 16 | 
            +
                super
         | 
| 17 | 
            +
                @collector = nil
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def perform(op, box)
         | 
| 21 | 
            +
                if @collector.nil?
         | 
| 22 | 
            +
                  @collector = task.ship(:collector, ::OFlow::Box.new([task.full_name, op, box.contents]))
         | 
| 23 | 
            +
                else
         | 
| 24 | 
            +
                  @collector.ship(::OFlow::Box.new([task.full_name, op, box.contents, 'with_link']))
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
                task.ship(op, box)
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            end # Stutter
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            class FlowBasicTest < ::Test::Unit::TestCase
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def test_flow_basic
         | 
| 34 | 
            +
                trigger = nil
         | 
| 35 | 
            +
                collector = nil
         | 
| 36 | 
            +
                ::OFlow::Env.flow('basic', :opt1 => 1) { |f|
         | 
| 37 | 
            +
                  # collects results
         | 
| 38 | 
            +
                  f.task(:collector, Collector) { |t|
         | 
| 39 | 
            +
                    collector = t.actor
         | 
| 40 | 
            +
                  }
         | 
| 41 | 
            +
                  # starts off the process
         | 
| 42 | 
            +
                  trigger = f.task('trigger', Stutter) { |t|
         | 
| 43 | 
            +
                    t.link(:collector, 'collector', 'trigger')
         | 
| 44 | 
            +
                    t.link(:once, 'dub', :twice)
         | 
| 45 | 
            +
                  }
         | 
| 46 | 
            +
                  # sends to self and then ends with no other task to ship to
         | 
| 47 | 
            +
                  f.task('dub', Stutter, :opt1 => 7) { |t|
         | 
| 48 | 
            +
                    t.link(:collector, 'collector', 'dub')
         | 
| 49 | 
            +
                    t.link(:twice, 'dub', :once)
         | 
| 50 | 
            +
                    t.link(:once, 'ignore', nil)
         | 
| 51 | 
            +
                  }
         | 
| 52 | 
            +
                  f.task(:ignore, ::OFlow::Actors::Ignore)
         | 
| 53 | 
            +
                }
         | 
| 54 | 
            +
                # see if the flow was constructed correctly
         | 
| 55 | 
            +
                assert_equal(%|OFlow::Env {
         | 
| 56 | 
            +
              basic (OFlow::Flow) {
         | 
| 57 | 
            +
                collector (Collector) {
         | 
| 58 | 
            +
                }
         | 
| 59 | 
            +
                trigger (Stutter) {
         | 
| 60 | 
            +
                  collector => collector:trigger
         | 
| 61 | 
            +
                  once => dub:twice
         | 
| 62 | 
            +
                }
         | 
| 63 | 
            +
                dub (Stutter) {
         | 
| 64 | 
            +
                  collector => collector:dub
         | 
| 65 | 
            +
                  twice => dub:once
         | 
| 66 | 
            +
                  once => ignore:
         | 
| 67 | 
            +
                }
         | 
| 68 | 
            +
                ignore (OFlow::Actors::Ignore) {
         | 
| 69 | 
            +
                }
         | 
| 70 | 
            +
              }
         | 
| 71 | 
            +
            }|, ::OFlow::Env.describe())
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                # run it and check the output
         | 
| 74 | 
            +
                trigger.receive(:once, ::OFlow::Box.new(7))
         | 
| 75 | 
            +
                ::OFlow::Env.flush()
         | 
| 76 | 
            +
                assert_equal([[':basic:trigger', :once, 7],
         | 
| 77 | 
            +
                              [':basic:dub', :twice, 7],
         | 
| 78 | 
            +
                              [':basic:dub', :once, 7, 'with_link'],
         | 
| 79 | 
            +
                             ], collector.collection)
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                # run again and make sure all tasks use links
         | 
| 82 | 
            +
                collector.collection = []
         | 
| 83 | 
            +
                trigger.receive(:once, ::OFlow::Box.new(7))
         | 
| 84 | 
            +
                ::OFlow::Env.flush()
         | 
| 85 | 
            +
                assert_equal([[':basic:trigger', :once, 7, 'with_link'],
         | 
| 86 | 
            +
                              [':basic:dub', :twice, 7, 'with_link'],
         | 
| 87 | 
            +
                              [':basic:dub', :once, 7, 'with_link'],
         | 
| 88 | 
            +
                             ], collector.collection)
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                ::OFlow::Env.clear()
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            end # FlowBasicTest
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'test/unit'
         | 
| 9 | 
            +
            require 'oflow'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'collector'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class Dummy < ::OFlow::Actor
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def initialize(task, options)
         | 
| 16 | 
            +
                super
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def perform(op, box)
         | 
| 20 | 
            +
                task.ship(op, box)
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            end # Dummy
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            class Miss < ::OFlow::Actor
         | 
| 26 | 
            +
              
         | 
| 27 | 
            +
              def initialize(task, options)
         | 
| 28 | 
            +
                super
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def perform(op, box)
         | 
| 32 | 
            +
                case op
         | 
| 33 | 
            +
                when :one
         | 
| 34 | 
            +
                  task.ship(:one, box)
         | 
| 35 | 
            +
                when :two
         | 
| 36 | 
            +
                  task.ship(:two, box)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def inputs()
         | 
| 41 | 
            +
                [ ::OFlow::Actor::Spec.new(:fixnum, Fixnum),
         | 
| 42 | 
            +
                  ::OFlow::Actor::Spec.new(:float, nil) ]
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def outputs()
         | 
| 46 | 
            +
                [ ::OFlow::Actor::Spec.new(:fixnum, Fixnum),
         | 
| 47 | 
            +
                  ::OFlow::Actor::Spec.new(:float, Float) ]
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            end # Miss
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            class FlowCfgErrTest < ::Test::Unit::TestCase
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def test_flow_link_unresolved
         | 
| 55 | 
            +
                begin
         | 
| 56 | 
            +
                  ::OFlow::Env.flow('unresolved', :opt1 => 1) { |f|
         | 
| 57 | 
            +
                    f.task(:one, Dummy) { |t|
         | 
| 58 | 
            +
                      t.link(:two, :two, nil)
         | 
| 59 | 
            +
                    }
         | 
| 60 | 
            +
                    f.task(:three, Dummy) { |t|
         | 
| 61 | 
            +
                      t.link(:second, :two, nil)
         | 
| 62 | 
            +
                    }
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
                  assert(false, "expected a ValidateError")
         | 
| 65 | 
            +
                rescue ::OFlow::ValidateError => ve
         | 
| 66 | 
            +
                  assert_equal([":unresolved:one: Failed to find task 'two'.",
         | 
| 67 | 
            +
                                ":unresolved:three: Failed to find task 'two'."], ve.problems.map { |p| p.to_s })
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
                ::OFlow::Env.clear()
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              def test_flow_link_missing
         | 
| 73 | 
            +
                begin
         | 
| 74 | 
            +
                  ::OFlow::Env.flow('miss-me') { |f|
         | 
| 75 | 
            +
                    f.task(:sort, Miss) { |t|
         | 
| 76 | 
            +
                      t.link(:fixnum, :fix, nil)
         | 
| 77 | 
            +
                    }
         | 
| 78 | 
            +
                    f.task(:fix, Dummy) { |t|
         | 
| 79 | 
            +
                      t.link(:repeat, :sort, :float)
         | 
| 80 | 
            +
                      t.link(:wrong, :sort, :complex)
         | 
| 81 | 
            +
                    }
         | 
| 82 | 
            +
                  }
         | 
| 83 | 
            +
                  assert(false, "expected a ValidateError")
         | 
| 84 | 
            +
                rescue ::OFlow::ValidateError => ve
         | 
| 85 | 
            +
                  assert_equal([":miss-me:sort: Missing link for 'float'.",
         | 
| 86 | 
            +
                                ":miss-me:fix: 'complex' not allowed on ':miss-me:sort'."], ve.problems.map { |p| p.to_s })
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
                ::OFlow::Env.clear()
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              # TBD missing links for output spec
         | 
| 92 | 
            +
             | 
| 93 | 
            +
             | 
| 94 | 
            +
            end # FlowCfgErrTest
         | 
| @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # encoding: UTF-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [ File.dirname(__FILE__),
         | 
| 5 | 
            +
              File.join(File.dirname(__FILE__), "../lib")
         | 
| 6 | 
            +
            ].each { |path| $: << path unless $:.include?(path) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'test/unit'
         | 
| 9 | 
            +
            require 'oflow'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'collector'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            class Noise < ::OFlow::Actor
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def initialize(task, options)
         | 
| 16 | 
            +
                super
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def perform(op, box)
         | 
| 20 | 
            +
                task.info("op: #{op}, box: #{box.contents}")
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            end # Noise
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            class FlowLogTest < ::Test::Unit::TestCase
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              # Make sure the log works and relays to a log task if it exists.
         | 
| 28 | 
            +
              def test_flow_log_relay
         | 
| 29 | 
            +
                trigger = nil
         | 
| 30 | 
            +
                collector = nil
         | 
| 31 | 
            +
                ::OFlow::Env.flow('log_relay') { |f|
         | 
| 32 | 
            +
                  trigger = f.task('noise', Noise)
         | 
| 33 | 
            +
                  f.task(:log, Collector) { |t|
         | 
| 34 | 
            +
                    collector = t.actor
         | 
| 35 | 
            +
                  }
         | 
| 36 | 
            +
                }
         | 
| 37 | 
            +
                trigger.receive(:speak, ::OFlow::Box.new(7))
         | 
| 38 | 
            +
                ::OFlow::Env.flush()
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                assert_equal(collector.collection.size, 1)
         | 
| 41 | 
            +
                assert_equal(collector.collection[0][0], 'op: speak, box: 7')
         | 
| 42 | 
            +
                assert_equal(collector.collection[0][1], ':log_relay:noise')
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                ::OFlow::Env.clear()
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # Make sure the log in the flow var is used.
         | 
| 48 | 
            +
              def test_flow_log_var
         | 
| 49 | 
            +
                trigger = nil
         | 
| 50 | 
            +
                collector = nil
         | 
| 51 | 
            +
                ::OFlow::Env.flow('log_relay') { |f|
         | 
| 52 | 
            +
                  trigger = f.task('noise', Noise)
         | 
| 53 | 
            +
                  f.log = f.task(:collector, Collector) { |t|
         | 
| 54 | 
            +
                    collector = t.actor
         | 
| 55 | 
            +
                  }
         | 
| 56 | 
            +
                }
         | 
| 57 | 
            +
                trigger.receive(:speak, ::OFlow::Box.new(7))
         | 
| 58 | 
            +
                ::OFlow::Env.flush()
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                assert_equal(collector.collection.size, 1)
         | 
| 61 | 
            +
                assert_equal(collector.collection[0][0], 'op: speak, box: 7')
         | 
| 62 | 
            +
                assert_equal(collector.collection[0][1], ':log_relay:noise')
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                ::OFlow::Env.clear()
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              # Make sure the log in the Env var is used.
         | 
| 68 | 
            +
              def test_flow_log_env
         | 
| 69 | 
            +
                trigger = nil
         | 
| 70 | 
            +
                collector = nil
         | 
| 71 | 
            +
                ::OFlow::Env.flow('log_relay') { |f|
         | 
| 72 | 
            +
                  trigger = f.task('noise', Noise)
         | 
| 73 | 
            +
                  ::OFlow::Env.log = f.task(:collector, Collector) { |t|
         | 
| 74 | 
            +
                    collector = t.actor
         | 
| 75 | 
            +
                  }
         | 
| 76 | 
            +
                }
         | 
| 77 | 
            +
                trigger.receive(:speak, ::OFlow::Box.new(7))
         | 
| 78 | 
            +
                ::OFlow::Env.flush()
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                assert_equal(collector.collection.size, 1)
         | 
| 81 | 
            +
                assert_equal(collector.collection[0][0], 'op: speak, box: 7')
         | 
| 82 | 
            +
                assert_equal(collector.collection[0][1], ':log_relay:noise')
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                ::OFlow::Env.clear()
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            end # FlowLogTest
         |