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
| @@ -0,0 +1,215 @@ | |
| 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 Hop < ::OFlow::Actor
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              def initialize(task, options)
         | 
| 16 | 
            +
                super
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def perform(op, box)
         | 
| 20 | 
            +
                task.info("#{op} #{box.contents}")
         | 
| 21 | 
            +
                task.ship(op, box)
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            end # Hop
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            class FlowNestTest < ::Test::Unit::TestCase
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def test_flow_nest
         | 
| 29 | 
            +
                trigger = nil
         | 
| 30 | 
            +
                collector = nil
         | 
| 31 | 
            +
                ::OFlow::Env.flow(:nest, :opt1 => 1) { |f|
         | 
| 32 | 
            +
                  # use collector as the log
         | 
| 33 | 
            +
                  f.task(:log, Collector) { |t|
         | 
| 34 | 
            +
                    collector = t.actor
         | 
| 35 | 
            +
                  }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # starts off the process
         | 
| 38 | 
            +
                  trigger = f.task(:trigger, Hop) { |t|
         | 
| 39 | 
            +
                    t.link(nil, :deep, nil)
         | 
| 40 | 
            +
                  }
         | 
| 41 | 
            +
                  # a nested flow
         | 
| 42 | 
            +
                  f.flow(:deep) { |f2|
         | 
| 43 | 
            +
                    f2.route(nil, :one, nil)
         | 
| 44 | 
            +
                    f2.task(:one, Hop) { |t|
         | 
| 45 | 
            +
                      t.link(nil, :two, nil)
         | 
| 46 | 
            +
                    }
         | 
| 47 | 
            +
                    f2.task(:two, Hop) { |t|
         | 
| 48 | 
            +
                      t.link(nil, :flow, :bye)
         | 
| 49 | 
            +
                    }
         | 
| 50 | 
            +
                    f2.link(:bye, :out, nil)
         | 
| 51 | 
            +
                  }
         | 
| 52 | 
            +
                  f.task(:out, Hop) { |t|
         | 
| 53 | 
            +
                      t.link(nil, :done, nil)
         | 
| 54 | 
            +
                  }
         | 
| 55 | 
            +
                  f.task(:done, ::OFlow::Actors::Ignore)
         | 
| 56 | 
            +
                }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # see if the flow was constructed correctly
         | 
| 59 | 
            +
                assert_equal(%|OFlow::Env {
         | 
| 60 | 
            +
              nest (OFlow::Flow) {
         | 
| 61 | 
            +
                log (Collector) {
         | 
| 62 | 
            +
                }
         | 
| 63 | 
            +
                trigger (Hop) {
         | 
| 64 | 
            +
                   => deep:
         | 
| 65 | 
            +
                }
         | 
| 66 | 
            +
                deep (OFlow::Flow) {
         | 
| 67 | 
            +
                  one (Hop) {
         | 
| 68 | 
            +
                     => two:
         | 
| 69 | 
            +
                  }
         | 
| 70 | 
            +
                  two (Hop) {
         | 
| 71 | 
            +
                     => flow:bye
         | 
| 72 | 
            +
                  }
         | 
| 73 | 
            +
                   * one:
         | 
| 74 | 
            +
                  bye => out:
         | 
| 75 | 
            +
                }
         | 
| 76 | 
            +
                out (Hop) {
         | 
| 77 | 
            +
                   => done:
         | 
| 78 | 
            +
                }
         | 
| 79 | 
            +
                done (OFlow::Actors::Ignore) {
         | 
| 80 | 
            +
                }
         | 
| 81 | 
            +
              }
         | 
| 82 | 
            +
            }|, ::OFlow::Env.describe())
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                # run it and check the output
         | 
| 85 | 
            +
                trigger.receive(:go, ::OFlow::Box.new(7))
         | 
| 86 | 
            +
                ::OFlow::Env.flush()
         | 
| 87 | 
            +
                assert_equal([['go 7', ':nest:trigger'],
         | 
| 88 | 
            +
                              [' 7', ':nest:deep:one'],
         | 
| 89 | 
            +
                              [' 7', ':nest:deep:two'],
         | 
| 90 | 
            +
                              [' 7', ':nest:out']
         | 
| 91 | 
            +
                             ], collector.collection)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                ::OFlow::Env.clear()
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              def test_flow_nest_deep
         | 
| 97 | 
            +
                trigger = nil
         | 
| 98 | 
            +
                collector = nil
         | 
| 99 | 
            +
                ::OFlow::Env.flow(:nest_deep, :opt1 => 1) { |f|
         | 
| 100 | 
            +
                  # use collector as the log
         | 
| 101 | 
            +
                  f.task(:log, Collector) { |t|
         | 
| 102 | 
            +
                    collector = t.actor
         | 
| 103 | 
            +
                  }
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  # starts off the process
         | 
| 106 | 
            +
                  trigger = f.task(:trigger, Hop) { |t|
         | 
| 107 | 
            +
                    t.link(nil, :deep, nil)
         | 
| 108 | 
            +
                  }
         | 
| 109 | 
            +
                  # a nested flow
         | 
| 110 | 
            +
                  f.flow(:deep) { |f2|
         | 
| 111 | 
            +
                    f2.route(nil, :deeper, nil)
         | 
| 112 | 
            +
                    f2.flow(:deeper) { |f3|
         | 
| 113 | 
            +
                      f3.route(nil, :one, nil)
         | 
| 114 | 
            +
                      f3.task(:one, Hop) { |t|
         | 
| 115 | 
            +
                        t.link(nil, :two, nil)
         | 
| 116 | 
            +
                      }
         | 
| 117 | 
            +
                      f3.task(:two, Hop) { |t|
         | 
| 118 | 
            +
                        t.link(nil, :flow, :bye)
         | 
| 119 | 
            +
                      }
         | 
| 120 | 
            +
                      f3.link(:bye, :flow, :bye)
         | 
| 121 | 
            +
                    }
         | 
| 122 | 
            +
                    f2.link(:bye, :out, nil)
         | 
| 123 | 
            +
                  }
         | 
| 124 | 
            +
                  f.task(:out, Hop) { |t|
         | 
| 125 | 
            +
                    t.link(nil, :done, nil)
         | 
| 126 | 
            +
                  }
         | 
| 127 | 
            +
                  f.task(:done, ::OFlow::Actors::Ignore)
         | 
| 128 | 
            +
                }
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                # see if the flow was constructed correctly
         | 
| 131 | 
            +
                assert_equal(%|OFlow::Env {
         | 
| 132 | 
            +
              nest_deep (OFlow::Flow) {
         | 
| 133 | 
            +
                log (Collector) {
         | 
| 134 | 
            +
                }
         | 
| 135 | 
            +
                trigger (Hop) {
         | 
| 136 | 
            +
                   => deep:
         | 
| 137 | 
            +
                }
         | 
| 138 | 
            +
                deep (OFlow::Flow) {
         | 
| 139 | 
            +
                  deeper (OFlow::Flow) {
         | 
| 140 | 
            +
                    one (Hop) {
         | 
| 141 | 
            +
                       => two:
         | 
| 142 | 
            +
                    }
         | 
| 143 | 
            +
                    two (Hop) {
         | 
| 144 | 
            +
                       => flow:bye
         | 
| 145 | 
            +
                    }
         | 
| 146 | 
            +
                     * one:
         | 
| 147 | 
            +
                    bye => flow:bye
         | 
| 148 | 
            +
                  }
         | 
| 149 | 
            +
                   * deeper:
         | 
| 150 | 
            +
                  bye => out:
         | 
| 151 | 
            +
                }
         | 
| 152 | 
            +
                out (Hop) {
         | 
| 153 | 
            +
                   => done:
         | 
| 154 | 
            +
                }
         | 
| 155 | 
            +
                done (OFlow::Actors::Ignore) {
         | 
| 156 | 
            +
                }
         | 
| 157 | 
            +
              }
         | 
| 158 | 
            +
            }|, ::OFlow::Env.describe())
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                # run it and check the output
         | 
| 161 | 
            +
                trigger.receive(:go, ::OFlow::Box.new(7))
         | 
| 162 | 
            +
                ::OFlow::Env.flush()
         | 
| 163 | 
            +
                assert_equal([['go 7', ':nest_deep:trigger'],
         | 
| 164 | 
            +
                              [' 7', ':nest_deep:deep:deeper:one'],
         | 
| 165 | 
            +
                              [' 7', ':nest_deep:deep:deeper:two'],
         | 
| 166 | 
            +
                              [' 7', ':nest_deep:out']
         | 
| 167 | 
            +
                             ], collector.collection)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                ::OFlow::Env.clear()
         | 
| 170 | 
            +
              end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
              def test_flow_nest_label
         | 
| 173 | 
            +
                trigger = nil
         | 
| 174 | 
            +
                collector = nil
         | 
| 175 | 
            +
                ::OFlow::Env.flow(:nest) { |f|
         | 
| 176 | 
            +
                  # use collector as the log
         | 
| 177 | 
            +
                  f.task(:log, Collector) { |t|
         | 
| 178 | 
            +
                    collector = t.actor
         | 
| 179 | 
            +
                  }
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  # starts off the process
         | 
| 182 | 
            +
                  trigger = f.task(:trigger, Hop) { |t|
         | 
| 183 | 
            +
                    t.link(:go, :deep, :first)
         | 
| 184 | 
            +
                  }
         | 
| 185 | 
            +
                  # a nested flow
         | 
| 186 | 
            +
                  f.flow(:deep) { |f2|
         | 
| 187 | 
            +
                    f2.route(:first, :one, :hip)
         | 
| 188 | 
            +
                    f2.task(:one, Hop) { |t|
         | 
| 189 | 
            +
                      t.link(:hip, :two, :hop)
         | 
| 190 | 
            +
                    }
         | 
| 191 | 
            +
                    f2.task(:two, Hop) { |t|
         | 
| 192 | 
            +
                      t.link(:hop, :flow, :get_out)
         | 
| 193 | 
            +
                    }
         | 
| 194 | 
            +
                    f2.link(:get_out, :out, :finish)
         | 
| 195 | 
            +
                  }
         | 
| 196 | 
            +
                  f.task(:out, Hop) { |t|
         | 
| 197 | 
            +
                      t.link(:finish, :done, nil)
         | 
| 198 | 
            +
                  }
         | 
| 199 | 
            +
                  f.task(:done, ::OFlow::Actors::Ignore)
         | 
| 200 | 
            +
                }
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                # run it and check the output
         | 
| 203 | 
            +
                trigger.receive(:go, ::OFlow::Box.new(7))
         | 
| 204 | 
            +
                ::OFlow::Env.flush()
         | 
| 205 | 
            +
                assert_equal([['go 7', ':nest:trigger'],
         | 
| 206 | 
            +
                              ['hip 7', ':nest:deep:one'],
         | 
| 207 | 
            +
                              ['hop 7', ':nest:deep:two'],
         | 
| 208 | 
            +
                              ['finish 7', ':nest:out']
         | 
| 209 | 
            +
                             ], collector.collection)
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                ::OFlow::Env.clear()
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
             | 
| 215 | 
            +
            end # FlowNestTest
         | 
| @@ -0,0 +1,133 @@ | |
| 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 Crash < ::OFlow::Actor
         | 
| 14 | 
            +
              def initialize(task, options)
         | 
| 15 | 
            +
                super
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def perform(op, box)
         | 
| 19 | 
            +
                nil.crash()
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            end # Crash
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            class FlowRescueTest < ::Test::Unit::TestCase
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              # Make sure the error handler works and forwards to the 'error' task if it
         | 
| 27 | 
            +
              # exists.
         | 
| 28 | 
            +
              def test_flow_rescue_task
         | 
| 29 | 
            +
                trigger = nil
         | 
| 30 | 
            +
                collector = nil
         | 
| 31 | 
            +
                ::OFlow::Env.flow('rescue') { |f|
         | 
| 32 | 
            +
                  trigger = f.task('crash', Crash)
         | 
| 33 | 
            +
                  f.task(:collector, Collector) { |t|
         | 
| 34 | 
            +
                    collector = t.actor
         | 
| 35 | 
            +
                  }
         | 
| 36 | 
            +
                  f.task(:error, ::OFlow::Actors::Relay) { |t|
         | 
| 37 | 
            +
                    t.link(nil, 'collector', 'error')
         | 
| 38 | 
            +
                  }
         | 
| 39 | 
            +
                  f.task(:log, ::OFlow::Actors::Relay) { |t|
         | 
| 40 | 
            +
                    t.link(nil, 'collector', 'log')
         | 
| 41 | 
            +
                  }
         | 
| 42 | 
            +
                }
         | 
| 43 | 
            +
                trigger.receive(:knock, ::OFlow::Box.new(7))
         | 
| 44 | 
            +
                ::OFlow::Env.flush()
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                assert_equal(collector.collection.size, 1)
         | 
| 47 | 
            +
                assert_equal(collector.collection[0][0].class, NoMethodError)
         | 
| 48 | 
            +
                assert_equal(collector.collection[0][1], ':rescue:crash')
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                ::OFlow::Env.clear()
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              # Make sure the error handler on the flow is used to handle errors.
         | 
| 54 | 
            +
              def test_flow_rescue_var
         | 
| 55 | 
            +
                trigger = nil
         | 
| 56 | 
            +
                collector = nil
         | 
| 57 | 
            +
                ::OFlow::Env.flow('rescue') { |f|
         | 
| 58 | 
            +
                  trigger = f.task('crash', Crash)
         | 
| 59 | 
            +
                  f.error_handler = f.task(:collector, Collector) { |t|
         | 
| 60 | 
            +
                    collector = t.actor
         | 
| 61 | 
            +
                  }
         | 
| 62 | 
            +
                  f.task(:log, ::OFlow::Actors::Relay) { |t|
         | 
| 63 | 
            +
                    t.link(nil, 'collector', 'log')
         | 
| 64 | 
            +
                  }
         | 
| 65 | 
            +
                }
         | 
| 66 | 
            +
                trigger.receive(:knock, ::OFlow::Box.new(7))
         | 
| 67 | 
            +
                ::OFlow::Env.flush()
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                assert_equal(collector.collection.size, 1)
         | 
| 70 | 
            +
                assert_equal(collector.collection[0][0].class, NoMethodError)
         | 
| 71 | 
            +
                assert_equal(collector.collection[0][1], ':rescue:crash')
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                ::OFlow::Env.clear()
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              # Make sure the error handler on the flow is used to handle errors.
         | 
| 77 | 
            +
              def test_flow_rescue_env
         | 
| 78 | 
            +
                trigger = nil
         | 
| 79 | 
            +
                collector = nil
         | 
| 80 | 
            +
                ::OFlow::Env.flow('rescue') { |f|
         | 
| 81 | 
            +
                  trigger = f.task('crash', Crash)
         | 
| 82 | 
            +
                  ::OFlow::Env.error_handler = f.task(:collector, Collector) { |t|
         | 
| 83 | 
            +
                    collector = t.actor
         | 
| 84 | 
            +
                  }
         | 
| 85 | 
            +
                  f.task(:log, ::OFlow::Actors::Relay) { |t|
         | 
| 86 | 
            +
                    t.link(nil, 'collector', 'log')
         | 
| 87 | 
            +
                  }
         | 
| 88 | 
            +
                }
         | 
| 89 | 
            +
                trigger.receive(:knock, ::OFlow::Box.new(7))
         | 
| 90 | 
            +
                ::OFlow::Env.flush()
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                assert_equal(1, collector.collection.size)
         | 
| 93 | 
            +
                assert_equal(NoMethodError, collector.collection[0][0].class)
         | 
| 94 | 
            +
                assert_equal(':rescue:crash', collector.collection[0][1])
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                ::OFlow::Env.clear()
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              # Make sure the default error handler on the flow passes a message to the log.
         | 
| 100 | 
            +
              def test_flow_rescue_env_log
         | 
| 101 | 
            +
                trigger = nil
         | 
| 102 | 
            +
                collector = nil
         | 
| 103 | 
            +
                ::OFlow::Env.flow('rescue') { |f|
         | 
| 104 | 
            +
                  trigger = f.task('crash', Crash)
         | 
| 105 | 
            +
                  ::OFlow::Env.log = f.task(:collector, Collector) { |t|
         | 
| 106 | 
            +
                    collector = t.actor
         | 
| 107 | 
            +
                  }
         | 
| 108 | 
            +
                }
         | 
| 109 | 
            +
                trigger.receive(:knock, ::OFlow::Box.new(7))
         | 
| 110 | 
            +
                ::OFlow::Env.flush()
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                assert_equal(1, collector.collection.size)
         | 
| 113 | 
            +
                assert_equal(["NoMethodError: undefined method `crash' for nil:NilClass",
         | 
| 114 | 
            +
                              "/flow_rescue_test.rb:0:in `perform'",
         | 
| 115 | 
            +
                              "/task.rb:0:in `block in initialize'"],
         | 
| 116 | 
            +
                             simplify(collector.collection[0][0]))
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                assert_equal(':rescue:crash', collector.collection[0][1])
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                ::OFlow::Env.clear()
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
              def simplify(bt)
         | 
| 124 | 
            +
                bt.split("\n").map do |line|
         | 
| 125 | 
            +
                  i = line.index(/\/\w+\.rb\:\d+/)
         | 
| 126 | 
            +
                  unless i.nil?
         | 
| 127 | 
            +
                    line = line[i..-1]
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                  line.gsub(/\d+/, '0')
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            end # FlowRescueTest
         | 
| @@ -0,0 +1,82 @@ | |
| 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 Throw < ::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 # Throw
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            class Catch < ::OFlow::Actor
         | 
| 26 | 
            +
              attr_reader :ball
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def initialize(task, options)
         | 
| 29 | 
            +
                super
         | 
| 30 | 
            +
                @ball = nil
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def perform(op, box)
         | 
| 34 | 
            +
                @ball = box
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            end # Catch
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            class FlowTrackerTest < ::Test::Unit::TestCase
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def test_flow_tracker
         | 
| 42 | 
            +
                trigger = nil
         | 
| 43 | 
            +
                catcher = nil
         | 
| 44 | 
            +
                ::OFlow::Env.flow(:nest, :opt1 => 1) { |f|
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # starts off the process
         | 
| 47 | 
            +
                  trigger = f.task(:trigger, Throw) { |t|
         | 
| 48 | 
            +
                    t.link(nil, :deep, nil)
         | 
| 49 | 
            +
                  }
         | 
| 50 | 
            +
                  # a nested flow
         | 
| 51 | 
            +
                  f.flow(:deep) { |f2|
         | 
| 52 | 
            +
                    f2.route(nil, :one, nil)
         | 
| 53 | 
            +
                    f2.task(:one, Throw) { |t|
         | 
| 54 | 
            +
                      t.link(nil, :two, nil)
         | 
| 55 | 
            +
                    }
         | 
| 56 | 
            +
                    f2.task(:two, Throw) { |t|
         | 
| 57 | 
            +
                      t.link(nil, :flow, :bye)
         | 
| 58 | 
            +
                    }
         | 
| 59 | 
            +
                    f2.link(:bye, :out, nil)
         | 
| 60 | 
            +
                  }
         | 
| 61 | 
            +
                  f.task(:out, Throw) { |t|
         | 
| 62 | 
            +
                      t.link(nil, :done, nil)
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
                  catcher = f.task(:done, Catch)
         | 
| 65 | 
            +
                }
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                # run it and check the output
         | 
| 68 | 
            +
                trigger.receive(:go, ::OFlow::Box.new(7, ::OFlow::Tracker.create('test')))
         | 
| 69 | 
            +
                ::OFlow::Env.flush()
         | 
| 70 | 
            +
                assert_equal(["test-",
         | 
| 71 | 
            +
                              ":nest:trigger-go",
         | 
| 72 | 
            +
                              ":nest:deep-",
         | 
| 73 | 
            +
                              ":nest:deep:one-",
         | 
| 74 | 
            +
                              ":nest:deep:two-",
         | 
| 75 | 
            +
                              ":nest:deep-bye",
         | 
| 76 | 
            +
                              ":nest:out-",
         | 
| 77 | 
            +
                              ":nest:done-"], catcher.actor.ball.tracker.track.map {|s| s.where })
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                ::OFlow::Env.clear()
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            end # FlowTrackerTest
         | 
    
        data/test/stutter.rb
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 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 Stutter < ::OFlow::Actor
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              def initialize(task, options)
         | 
| 13 | 
            +
                super
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def perform(op, box)
         | 
| 17 | 
            +
                task.ship(:collector, ::OFlow::Box.new([task.full_name, op, box.contents]))
         | 
| 18 | 
            +
                task.ship(op, box)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            end # Stutter
         | 
    
        data/test/task_test.rb
    ADDED
    
    | @@ -0,0 +1,98 @@ | |
| 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 | 
            +
            class Gather < ::OFlow::Actor
         | 
| 12 | 
            +
              attr_accessor :requests
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def initialize(task, options)
         | 
| 15 | 
            +
                super
         | 
| 16 | 
            +
                @requests = {}
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def perform(op, box)
         | 
| 20 | 
            +
                if @requests[op].nil?
         | 
| 21 | 
            +
                  @requests[op] = [box]
         | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  @requests[op] << box
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            end # Gather
         | 
| 28 | 
            +
             | 
| 29 | 
            +
             | 
| 30 | 
            +
            class TaskTest < ::Test::Unit::TestCase
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def test_task_queue_count
         | 
| 33 | 
            +
                task = ::OFlow::Task.new(nil, 'test', Gather)
         | 
| 34 | 
            +
                assert_equal(0, task.queue_count())
         | 
| 35 | 
            +
                task.stop()
         | 
| 36 | 
            +
                task.receive(:dance, ::OFlow::Box.new('two step'))
         | 
| 37 | 
            +
                assert_equal(1, task.queue_count())
         | 
| 38 | 
            +
                task.receive(:dance, ::OFlow::Box.new('twist'))
         | 
| 39 | 
            +
                assert_equal(2, task.queue_count())
         | 
| 40 | 
            +
                task.shutdown()
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              def test_task_perform
         | 
| 44 | 
            +
                task = ::OFlow::Task.new(nil, 'test', Gather)
         | 
| 45 | 
            +
                task.receive(:dance, ::OFlow::Box.new('two step'))
         | 
| 46 | 
            +
                task.flush()
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                requests = task.actor.requests
         | 
| 49 | 
            +
                assert_equal(1, requests.size)
         | 
| 50 | 
            +
                boxes = requests[:dance]
         | 
| 51 | 
            +
                assert_equal(1, boxes.size)
         | 
| 52 | 
            +
                box = boxes[0]
         | 
| 53 | 
            +
                assert_equal(false, box.nil?)
         | 
| 54 | 
            +
                assert_equal('two step', box.contents)
         | 
| 55 | 
            +
                task.shutdown()
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def test_task_perform_shutdown
         | 
| 59 | 
            +
                task = ::OFlow::Task.new(nil, 'test', Gather)
         | 
| 60 | 
            +
                task.receive(:dance, ::OFlow::Box.new('two step'))
         | 
| 61 | 
            +
                task.shutdown(true)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                requests = task.actor.requests
         | 
| 64 | 
            +
                assert_equal(1, requests.size)
         | 
| 65 | 
            +
                boxes = requests[:dance]
         | 
| 66 | 
            +
                assert_equal(1, boxes.size)
         | 
| 67 | 
            +
                box = boxes[0]
         | 
| 68 | 
            +
                assert_equal(false, box.nil?)
         | 
| 69 | 
            +
                assert_equal('two step', box.contents)
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              def test_task_raise_after_close
         | 
| 73 | 
            +
                task = ::OFlow::Task.new(nil, 'test', Gather)
         | 
| 74 | 
            +
                task.shutdown()
         | 
| 75 | 
            +
                assert_raise(ThreadError) { task.start() }
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def test_task_max_queue_count
         | 
| 79 | 
            +
                task = ::OFlow::Task.new(nil, 'test', Gather, :max_queue_count => 4, :req_timeout => 0.1)
         | 
| 80 | 
            +
                task.stop()
         | 
| 81 | 
            +
                6.times do |i|
         | 
| 82 | 
            +
                  begin
         | 
| 83 | 
            +
                    task.receive(:dance, ::OFlow::Box.new(i))
         | 
| 84 | 
            +
                  rescue ::OFlow::BusyError
         | 
| 85 | 
            +
                    # expected for all over first 4
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
                task.start()
         | 
| 89 | 
            +
                task.shutdown(true)
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                requests = task.actor.requests
         | 
| 92 | 
            +
                boxes = requests[:dance]
         | 
| 93 | 
            +
                assert_equal(4, boxes.size)
         | 
| 94 | 
            +
                nums = boxes.map { |box| box.contents }
         | 
| 95 | 
            +
                assert_equal([0, 1, 2, 3], nums)
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            end # TaskTest
         | 
| @@ -0,0 +1,59 @@ | |
| 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 TrackerTest < ::Test::Unit::TestCase
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def test_tracker_new
         | 
| 18 | 
            +
                t = ::OFlow::Tracker.create('here')
         | 
| 19 | 
            +
                t2 = ::OFlow::Tracker.create('here')
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                assert_not_equal(t.id, t2.id, 'id must be unique')
         | 
| 22 | 
            +
                assert_equal('here', t.track[0].location)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def test_tracker_track
         | 
| 26 | 
            +
                t = ::OFlow::Tracker.create('here')
         | 
| 27 | 
            +
                t2 = t.receive('there', 'op1')
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                assert_equal('here', t.track[0].location)
         | 
| 30 | 
            +
                assert_equal('here', t2.track[0].location)
         | 
| 31 | 
            +
                assert_equal('there', t2.track[1].location)
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_tracker_merge
         | 
| 35 | 
            +
                t = ::OFlow::Tracker.create('here')
         | 
| 36 | 
            +
                # 2 different paths
         | 
| 37 | 
            +
                t2 = t.receive('there', 'op1')
         | 
| 38 | 
            +
                t3 = t.receive('everywhere', 'op2')
         | 
| 39 | 
            +
                # should not happen but should handle merging when not back to a common place
         | 
| 40 | 
            +
                t4 = t2.merge(t3)
         | 
| 41 | 
            +
                assert_equal('here', t4.track[0].location)
         | 
| 42 | 
            +
                assert_equal(true, t4.track[1].is_a?(Array))
         | 
| 43 | 
            +
                assert_equal(2, t4.track[1].size)
         | 
| 44 | 
            +
                assert_equal('there', t4.track[1][0][0].location)
         | 
| 45 | 
            +
                assert_equal('everywhere', t4.track[1][1][0].location)
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # back to a common location
         | 
| 48 | 
            +
                t2 = t2.receive('home', 'op1')
         | 
| 49 | 
            +
                t3 = t3.receive('home', 'op1')
         | 
| 50 | 
            +
                t4 = t2.merge(t3)
         | 
| 51 | 
            +
                assert_equal('here', t4.track[0].location)
         | 
| 52 | 
            +
                assert_equal(true, t4.track[1].is_a?(Array))
         | 
| 53 | 
            +
                assert_equal(2, t4.track[1].size)
         | 
| 54 | 
            +
                assert_equal('there', t4.track[1][0][0].location)
         | 
| 55 | 
            +
                assert_equal('everywhere', t4.track[1][1][0].location)
         | 
| 56 | 
            +
                assert_equal('home', t4.track[2].location)
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            end # TrackerTest
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: oflow
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Peter Ohler
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2014-02-04 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies: []
         | 
| 13 | 
            +
            description: Operations Workflow in Ruby. This implements a workflow/process flow
         | 
| 14 | 
            +
              using multiple task nodes that each have their own queues and execution thread.
         | 
| 15 | 
            +
            email: peter@ohler.com
         | 
| 16 | 
            +
            executables: []
         | 
| 17 | 
            +
            extensions: []
         | 
| 18 | 
            +
            extra_rdoc_files:
         | 
| 19 | 
            +
            - README.md
         | 
| 20 | 
            +
            files:
         | 
| 21 | 
            +
            - LICENSE
         | 
| 22 | 
            +
            - README.md
         | 
| 23 | 
            +
            - lib/oflow.rb
         | 
| 24 | 
            +
            - lib/oflow/actor.rb
         | 
| 25 | 
            +
            - lib/oflow/actors.rb
         | 
| 26 | 
            +
            - lib/oflow/actors/errorhandler.rb
         | 
| 27 | 
            +
            - lib/oflow/actors/ignore.rb
         | 
| 28 | 
            +
            - lib/oflow/actors/log.rb
         | 
| 29 | 
            +
            - lib/oflow/actors/relay.rb
         | 
| 30 | 
            +
            - lib/oflow/actors/timer.rb
         | 
| 31 | 
            +
            - lib/oflow/box.rb
         | 
| 32 | 
            +
            - lib/oflow/env.rb
         | 
| 33 | 
            +
            - lib/oflow/errors.rb
         | 
| 34 | 
            +
            - lib/oflow/flow.rb
         | 
| 35 | 
            +
            - lib/oflow/haserrorhandler.rb
         | 
| 36 | 
            +
            - lib/oflow/haslinks.rb
         | 
| 37 | 
            +
            - lib/oflow/haslog.rb
         | 
| 38 | 
            +
            - lib/oflow/hasname.rb
         | 
| 39 | 
            +
            - lib/oflow/hastasks.rb
         | 
| 40 | 
            +
            - lib/oflow/inspector.rb
         | 
| 41 | 
            +
            - lib/oflow/link.rb
         | 
| 42 | 
            +
            - lib/oflow/pattern.rb
         | 
| 43 | 
            +
            - lib/oflow/stamp.rb
         | 
| 44 | 
            +
            - lib/oflow/task.rb
         | 
| 45 | 
            +
            - lib/oflow/test.rb
         | 
| 46 | 
            +
            - lib/oflow/test/action.rb
         | 
| 47 | 
            +
            - lib/oflow/test/actorwrap.rb
         | 
| 48 | 
            +
            - lib/oflow/tracker.rb
         | 
| 49 | 
            +
            - lib/oflow/version.rb
         | 
| 50 | 
            +
            - test/actors/log_test.rb
         | 
| 51 | 
            +
            - test/actors/timer_test.rb
         | 
| 52 | 
            +
            - test/actorwrap_test.rb
         | 
| 53 | 
            +
            - test/all_tests.rb
         | 
| 54 | 
            +
            - test/box_test.rb
         | 
| 55 | 
            +
            - test/collector.rb
         | 
| 56 | 
            +
            - test/flow_basic_test.rb
         | 
| 57 | 
            +
            - test/flow_cfg_error_test.rb
         | 
| 58 | 
            +
            - test/flow_log_test.rb
         | 
| 59 | 
            +
            - test/flow_nest_test.rb
         | 
| 60 | 
            +
            - test/flow_rescue_test.rb
         | 
| 61 | 
            +
            - test/flow_tracker_test.rb
         | 
| 62 | 
            +
            - test/stutter.rb
         | 
| 63 | 
            +
            - test/task_test.rb
         | 
| 64 | 
            +
            - test/tracker_test.rb
         | 
| 65 | 
            +
            homepage: http://www.ohler.com/oflow
         | 
| 66 | 
            +
            licenses:
         | 
| 67 | 
            +
            - MIT
         | 
| 68 | 
            +
            - GPL-3.0
         | 
| 69 | 
            +
            metadata: {}
         | 
| 70 | 
            +
            post_install_message: 
         | 
| 71 | 
            +
            rdoc_options:
         | 
| 72 | 
            +
            - "--main"
         | 
| 73 | 
            +
            - README.md
         | 
| 74 | 
            +
            require_paths:
         | 
| 75 | 
            +
            - lib
         | 
| 76 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 77 | 
            +
              requirements:
         | 
| 78 | 
            +
              - - ">="
         | 
| 79 | 
            +
                - !ruby/object:Gem::Version
         | 
| 80 | 
            +
                  version: '0'
         | 
| 81 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 82 | 
            +
              requirements:
         | 
| 83 | 
            +
              - - ">="
         | 
| 84 | 
            +
                - !ruby/object:Gem::Version
         | 
| 85 | 
            +
                  version: '0'
         | 
| 86 | 
            +
            requirements: []
         | 
| 87 | 
            +
            rubyforge_project: oflow
         | 
| 88 | 
            +
            rubygems_version: 2.2.0
         | 
| 89 | 
            +
            signing_key: 
         | 
| 90 | 
            +
            specification_version: 4
         | 
| 91 | 
            +
            summary: Operations Workflow in Ruby
         | 
| 92 | 
            +
            test_files: []
         | 
| 93 | 
            +
            has_rdoc: true
         |