observed 0.1.1 → 0.2.0.rc1

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.
Files changed (94) hide show
  1. checksums.yaml +9 -9
  2. data/.travis.yml +4 -0
  3. data/README.md +53 -78
  4. data/examples/observed.rb +1 -1
  5. data/exe/observed-oneshot +3 -1
  6. data/features/explicit_routing.feature +33 -0
  7. data/features/oneshot.feature +4 -0
  8. data/features/test_in_single_ruby_source.feature +4 -0
  9. data/integrations/observed-clockwork/features/run_observed_inside_clockwork.feature +6 -7
  10. data/integrations/observed-clockwork/lib/observed/clockwork/version.rb +1 -1
  11. data/integrations/observed-clockwork/lib/observed/clockwork.rb +0 -1
  12. data/integrations/observed-clockwork/observed-clockwork.gemspec +1 -1
  13. data/integrations/observed-eventmachine/.gitignore +17 -0
  14. data/integrations/observed-eventmachine/Gemfile +8 -0
  15. data/integrations/observed-eventmachine/LICENSE.txt +22 -0
  16. data/integrations/observed-eventmachine/README.md +29 -0
  17. data/integrations/observed-eventmachine/Rakefile +1 -0
  18. data/integrations/observed-eventmachine/examples/observed.rb +30 -0
  19. data/integrations/observed-eventmachine/features/integration_via_single_ruby_source.feature +48 -0
  20. data/integrations/observed-eventmachine/features/support/env.rb +8 -0
  21. data/integrations/observed-eventmachine/lib/observed/eventmachine/version.rb +5 -0
  22. data/integrations/observed-eventmachine/lib/observed/eventmachine.rb +70 -0
  23. data/integrations/observed-eventmachine/observed-eventmachine.gemspec +28 -0
  24. data/lib/observed/application/oneshot.rb +14 -37
  25. data/lib/observed/builtin_plugins/file.rb +5 -14
  26. data/lib/observed/builtin_plugins/stdout.rb +7 -14
  27. data/lib/observed/config.rb +4 -4
  28. data/lib/observed/config_builder.rb +154 -87
  29. data/lib/observed/config_dsl.rb +2 -8
  30. data/lib/observed/configurable.rb +61 -3
  31. data/lib/observed/context.rb +90 -0
  32. data/lib/observed/default/observer.rb +2 -5
  33. data/lib/observed/default.rb +0 -1
  34. data/lib/observed/event_bus.rb +31 -0
  35. data/lib/observed/execution_job_factory.rb +95 -0
  36. data/lib/observed/job.rb +163 -0
  37. data/lib/observed/jobbed_event_bus.rb +33 -0
  38. data/lib/observed/logging.rb +40 -0
  39. data/lib/observed/observer.rb +1 -0
  40. data/lib/observed/observer_helpers/timer.rb +13 -5
  41. data/lib/observed/pluggable.rb +11 -0
  42. data/lib/observed/reporter/regexp_matching.rb +2 -1
  43. data/lib/observed/reporter/report_formatting.rb +57 -0
  44. data/lib/observed/reporter.rb +0 -2
  45. data/lib/observed/system.rb +11 -78
  46. data/lib/observed/translator.rb +22 -0
  47. data/lib/observed/version.rb +1 -1
  48. data/lib/observed.rb +10 -12
  49. data/omnibus-observed/.gitignore +9 -0
  50. data/omnibus-observed/Berksfile +3 -0
  51. data/omnibus-observed/Berksfile.lock +52 -0
  52. data/omnibus-observed/Gemfile +4 -0
  53. data/omnibus-observed/README.md +102 -0
  54. data/omnibus-observed/Vagrantfile +93 -0
  55. data/omnibus-observed/config/projects/observed.rb +20 -0
  56. data/omnibus-observed/config/software/observed.rb +19 -0
  57. data/omnibus-observed/package-scripts/observed/makeselfinst +27 -0
  58. data/omnibus-observed/package-scripts/observed/postinst +17 -0
  59. data/omnibus-observed/package-scripts/observed/postrm +9 -0
  60. data/plugins/observed-fluentd/lib/observed/fluentd/version.rb +1 -1
  61. data/plugins/observed-gauge/README.md +5 -0
  62. data/plugins/observed-gauge/lib/observed/gauge/version.rb +1 -1
  63. data/plugins/observed-gauge/lib/observed/gauge.rb +11 -13
  64. data/plugins/observed-gauge/observed-gauge.gemspec +1 -1
  65. data/plugins/observed-gauge/spec/gauge_spec.rb +7 -7
  66. data/plugins/observed-growl/Gemfile +6 -0
  67. data/plugins/observed-growl/lib/observed/growl.rb +80 -0
  68. data/plugins/observed-http/lib/observed/http/version.rb +1 -1
  69. data/plugins/observed-http/lib/observed/http.rb +10 -8
  70. data/plugins/observed-http/observed-http.gemspec +1 -1
  71. data/plugins/observed-http/spec/http_spec.rb +62 -7
  72. data/plugins/observed-http/spec/integration_spec.rb +14 -0
  73. data/plugins/observed-shell/Gemfile +5 -0
  74. data/plugins/observed-shell/lib/observed/shell.rb +54 -0
  75. data/run-integration-tests +81 -0
  76. data/spec/builtin_plugins/stdout_spec.rb +7 -3
  77. data/spec/config_builder_spec.rb +42 -59
  78. data/spec/config_dsl_spec.rb +4 -0
  79. data/spec/configurable_spec.rb +141 -31
  80. data/spec/event_bus_spec.rb +16 -0
  81. data/spec/execution_job_factory_spec.rb +35 -0
  82. data/spec/job_factory_spec.rb +16 -0
  83. data/spec/job_spec.rb +228 -0
  84. data/spec/jobbed_event_bus_spec.rb +38 -0
  85. data/spec/observed_spec.rb +203 -0
  86. data/spec/observer_helpers/timer_spec.rb +187 -0
  87. data/spec/oneshot_spec.rb +7 -2
  88. data/spec/system_spec.rb +5 -39
  89. metadata +55 -12
  90. data/lib/observed/default/reporter.rb +0 -17
  91. data/lib/observed/reader.rb +0 -14
  92. data/lib/observed/writer.rb +0 -14
  93. data/spec/reader_spec.rb +0 -15
  94. data/spec/writer_spec.rb +0 -16
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'observed/configurable'
3
+ require 'observed/pluggable'
3
4
 
4
5
  module ConfigurableSpec
5
6
  class Foo
@@ -11,55 +12,164 @@ module ConfigurableSpec
11
12
 
12
13
  default :bar => 345
13
14
  end
15
+
16
+ module ConfigurableModule
17
+ include Observed::Configurable
18
+
19
+ attribute :baz
20
+ end
21
+
22
+ module IntermediateModule
23
+ include Observed::Configurable
24
+ include ConfigurableModule
25
+
26
+ attribute :bar, default: 234
27
+ end
28
+
29
+ class ConfigurableModuleIncluder
30
+ include Observed::Configurable
31
+ include ConfigurableModule
32
+
33
+ attribute :bar, default: 234
34
+ default :bar => 345
35
+ attribute :foo, default: 123
36
+ end
37
+
38
+ class IntermediateModuleIncluder
39
+ include Observed::Configurable
40
+ include IntermediateModule
41
+
42
+ default :bar => 345
43
+ attribute :foo, default: 123
44
+ end
45
+
46
+ class SpecialCMI < ConfigurableModuleIncluder
47
+ include Observed::Configurable
48
+ end
49
+
50
+ class SpecialIMI < IntermediateModuleIncluder
51
+ include Observed::Configurable
52
+ end
53
+
54
+ class Plugin
55
+ include Observed::Configurable
56
+ include Observed::Pluggable
57
+ include ConfigurableModule
58
+ attribute :bar, default: 234
59
+ default :bar => 345
60
+ end
61
+
62
+ class PluginImpl < Plugin
63
+ include Observed::Configurable
64
+ attribute :foo, default: 123
65
+ end
66
+
67
+ class Overriding
68
+ include Observed::Configurable
69
+ include IntermediateModule
70
+
71
+ def foo
72
+ @attributes[:foo] || 123
73
+ end
74
+
75
+ default :bar => 345
76
+ attribute :foo, default: 1234
77
+ end
14
78
  end
15
79
 
16
80
  describe Observed::Configurable do
17
81
 
18
- context 'without parameters for the constructor' do
19
- subject {
20
- ConfigurableSpec::Foo.new
21
- }
82
+ shared_examples_for 'a configurable object' do
22
83
  it 'uses default values for attributes' do
23
- expect(subject.foo).to eq(123)
84
+ expect(subject.new.foo).to eq(123)
24
85
  end
86
+
25
87
  it 'overrides default values on `attribute name, :default => default_value`' do
26
- expect(subject.bar).to eq(345)
88
+ expect(subject.new.bar).to eq(345)
27
89
  end
90
+
28
91
  it 'raises errors when attributes without values are read' do
29
- expect { subject.baz }.to raise_error
92
+ expect { subject.new.baz }.to raise_error
93
+ end
94
+
95
+ context 'when configured via the `configure` method' do
96
+ it 'prefers arguments of the method over defaults' do
97
+ instance = subject.new
98
+
99
+ instance.configure foo: 1, bar: 2
100
+
101
+ expect(instance.foo).to eq(1)
102
+ expect(instance.bar).to eq(2)
103
+ end
104
+ end
105
+
106
+ context 'when configured via constructor parameters' do
107
+ context 'when the keys are symbols' do
108
+ it 'prefers values from constructor parameters over defaults' do
109
+ instance = subject.new({foo: 1, bar: 2, baz: 3})
110
+ expect(instance.foo).to eq(1)
111
+ expect(instance.bar).to eq(2)
112
+ expect(instance.baz).to eq(3)
113
+ end
114
+ end
115
+ context 'when the keys are strings' do
116
+ it 'does not prefer constructor parameters' do
117
+ instance = subject.new({'foo' => 1, 'bar' => 2, 'baz' => 3})
118
+ expect(instance.foo).to eq(123)
119
+ expect(instance.bar).to eq(345)
120
+ expect { instance.baz }.to raise_error
121
+ end
122
+ end
30
123
  end
31
124
  end
32
125
 
33
- context 'with parameters for the constructor' do
126
+ context 'when included in a class' do
34
127
  subject {
35
- ConfigurableSpec::Foo.new({foo: 1, bar: 2, baz: 3})
128
+ ConfigurableSpec::Foo
36
129
  }
37
- it 'prefers values from constructor parameters over defaults' do
38
- expect(subject.foo).to eq(1)
39
- expect(subject.bar).to eq(2)
40
- expect(subject.baz).to eq(3)
41
- end
130
+ it_behaves_like 'a configurable object'
42
131
  end
43
132
 
44
- context 'configured through `configure(args)` method' do
133
+ context 'when included in a module' do
45
134
  subject {
46
- foo = ConfigurableSpec::Foo.new
47
- foo.configure(args)
48
- foo
135
+ ConfigurableSpec::ConfigurableModuleIncluder
49
136
  }
50
- shared_examples_for 'values are set' do
51
- it 'prefers values from `configure(args)` over defaults' do
52
- expect(subject.foo).to eq(1)
53
- expect(subject.bar).to eq(2)
54
- expect(subject.baz).to eq(3)
55
- end
56
- end
57
- context 'when args has symbol keys' do
58
- let(:args) {
59
- {foo: 1, bar: 2, baz: 3}
60
- }
61
- it_behaves_like 'values are set'
62
- end
137
+ it_behaves_like 'a configurable object'
138
+ end
139
+
140
+ context 'when included via a intermediate module' do
141
+ subject {
142
+ ConfigurableSpec::IntermediateModuleIncluder
143
+ }
144
+ it_behaves_like 'a configurable object'
145
+ end
146
+
147
+ context 'when extended from a class which is a Plugin' do
148
+ subject {
149
+ ConfigurableSpec::PluginImpl
150
+ }
151
+ it_behaves_like 'a configurable object'
152
+ end
153
+
154
+ context 'when inherited from a class included the intermediate module' do
155
+ subject {
156
+ ConfigurableSpec::SpecialIMI
157
+ }
158
+ it_behaves_like 'a configurable object'
159
+ end
160
+
161
+ context 'when inherited from a class included the module includes it' do
162
+ subject {
163
+ ConfigurableSpec::SpecialCMI
164
+ }
165
+ it_behaves_like 'a configurable object'
166
+ end
167
+
168
+ context 'when there is a method named exactly same as the attribute' do
169
+ subject {
170
+ ConfigurableSpec::Overriding
171
+ }
172
+ it_behaves_like 'a configurable object'
63
173
  end
64
174
 
65
175
  end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'observed/event_bus'
3
+
4
+ describe Observed::EventBus do
5
+ it 'calls the handler for the emitted event' do
6
+ handler_one_called = false
7
+ handler_two_called = false
8
+ bus = Observed::EventBus.new
9
+ expect { bus.emit('foo') }.to_not raise_error
10
+ expect { bus.on_receive(/^bar$/) { handler_one_called = true } }.to_not raise_error
11
+ expect { bus.on_receive(/^baz$/) { handler_two_called = true } }.to_not raise_error
12
+ expect { bus.emit('bar') }.to_not raise_error
13
+ expect(handler_one_called).to be_true
14
+ expect(handler_two_called).to be_false
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'observed/execution_job_factory'
3
+
4
+ describe Observed::ExecutionJobFactory do
5
+ subject {
6
+ Observed::ExecutionJobFactory.new
7
+ }
8
+ it 'should convert observers, translators, reporters to jobs' do
9
+ output = mock('output')
10
+
11
+ the_observer = Class.new(Observed::Observer) do
12
+ def observe(data)
13
+ data.merge(b:2)
14
+ end
15
+ end.new
16
+ the_reporter = Class.new(Observed::Reporter) do
17
+ attribute :output
18
+ def report(tag, time, data)
19
+ output.write(tag: tag, time: time, data: data)
20
+ end
21
+ end.new(output: output)
22
+ the_translator = Class.new(Observed::Translator) do
23
+ def translate(tag, time, data)
24
+ data.merge(c:3)
25
+ end
26
+ end.new
27
+ job = subject.convert_to_job(the_observer)
28
+ .then(subject.convert_to_job(the_translator))
29
+ .then(subject.convert_to_job(the_reporter))
30
+ tag = 'the_tag'
31
+ time = Time.now
32
+ output.expects(:write).with(tag: tag, time: time, data: {a:1,b:2,c:3})
33
+ job.now({a:1}, {tag: tag, time: time})
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'observed/job'
3
+
4
+ describe Observed::JobFactory do
5
+ context 'when the executor not given' do
6
+ it 'fails to initialize' do
7
+ expect { Observed::JobFactory.new() }.to raise_error
8
+ end
9
+ end
10
+
11
+ context 'when a logger given' do
12
+ it 'may prefer the given logger over the default one' do
13
+ Observed::JobFactory.new(executor: mock('executor'), logger: ::Logger.new(STDERR))
14
+ end
15
+ end
16
+ end
data/spec/job_spec.rb ADDED
@@ -0,0 +1,228 @@
1
+ require 'spec_helper'
2
+ require 'observed/job'
3
+
4
+ describe Observed::MutableJob do
5
+ let(:factory) {
6
+ Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
7
+ }
8
+
9
+ it 'yields the given block' do
10
+ yielded = nil
11
+ job = factory.mutable_job { |data|
12
+ data
13
+ }
14
+ job.now({a:1}, {b:2}) do |data, options|
15
+ yielded = [data, options]
16
+ end
17
+ expect(yielded).to eq([{a:1}, {b:2}])
18
+ end
19
+
20
+ it 'executes the job regardless of whether or not a block is given' do
21
+ executed = nil
22
+ job = factory.mutable_job { |data, options|
23
+ executed = [data, options]
24
+ data
25
+ }
26
+ job.now({a:1}, {b:2})
27
+ expect(executed).to eq([{a:1}, {b:2}])
28
+ end
29
+ end
30
+
31
+ describe Observed::ParallelJob do
32
+ let(:factory) {
33
+ Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
34
+ }
35
+
36
+ it 'yields the given block' do
37
+ job1 = factory.job { |data, |
38
+ data.merge(c:3)
39
+ }
40
+ job2 = factory.job { |data|
41
+ data.merge(d:4)
42
+ }
43
+ par = Observed::ParallelJob.new([job1, job2])
44
+ yielded = []
45
+ par.now({a:1}, {b:2}) do |data, options|
46
+ yielded.push([data, options])
47
+ end
48
+ expect(yielded).to eq([[{a:1,c:3},{b:2}], [{a:1,d:4},{b:2}]])
49
+ end
50
+
51
+ it 'executes the job regardless of whether or not a block is given' do
52
+ executed = []
53
+ job1 = factory.job { |data, options|
54
+ r = data.merge(c:3)
55
+ executed.push([r, options])
56
+ r
57
+ }
58
+ job2 = factory.job { |data, options|
59
+ r = data.merge(d:4)
60
+ executed.push([r, options])
61
+ r
62
+ }
63
+ par = Observed::ParallelJob.new([job1, job2])
64
+ par.now({a:1}, {b:2})
65
+ expect(executed).to eq([[{a:1,c:3},{b:2}], [{a:1,d:4},{b:2}]])
66
+ end
67
+ end
68
+
69
+ describe Observed::SequenceJob do
70
+ let(:factory) {
71
+ Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
72
+ }
73
+
74
+ it 'yields the given block' do
75
+ job1 = factory.job { |data|
76
+ data.merge(c:3)
77
+ }
78
+ job2 = factory.job { |data|
79
+ data.merge(d:4)
80
+ }
81
+ seq = Observed::SequenceJob.new(job1, job2)
82
+ yielded = []
83
+ seq.now({a:1}, {b:2}) do |data, options|
84
+ yielded.push([data, options])
85
+ end
86
+ expect(yielded).to eq([[{a:1,c:3,d:4},{b:2}]])
87
+ end
88
+
89
+ it 'executes the job regardless of whether or not a block is given' do
90
+ executed = []
91
+ job1 = factory.job { |data, options|
92
+ r = data.merge(c:3)
93
+ executed.push([r, options])
94
+ r
95
+ }
96
+ job2 = factory.job { |data, options|
97
+ r = data.merge(d:4)
98
+ executed.push([r, options])
99
+ r
100
+ }
101
+ seq = Observed::SequenceJob.new(job1, job2)
102
+ seq.now({a:1}, {b:2})
103
+ expect(executed).to eq([[{a:1,c:3},{b:2}], [{a:1,c:3,d:4},{b:2}]])
104
+ end
105
+ end
106
+
107
+ describe Observed::Job do
108
+ context 'in simple use cases' do
109
+ let(:factory) {
110
+ Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
111
+ }
112
+ context 'when the options as input are given' do
113
+ it 'propagates the options from the input' do
114
+ job1 = factory.job { |data, options|
115
+ expect(options).to eq({b:2})
116
+ data
117
+ }
118
+ job2 = factory.job { |_, options|
119
+ expect(options).to eq({b:2})
120
+ }
121
+ seq = job1.then(job2)
122
+ seq.now({a:1}, {b:2})
123
+ end
124
+ it 'allows to override the options from the input in subsequent jobs' do
125
+ job1 = factory.job { |data, options|
126
+ expect(options).to eq({b:2})
127
+ [data, {b:3}]
128
+ }
129
+ job2 = factory.job { |_, options|
130
+ expect(options).to eq({b:3})
131
+ }
132
+ seq = job1.then(job2)
133
+ seq.now({a:1}, {b:2})
134
+ end
135
+ end
136
+ context 'when the options as input are not given' do
137
+ it 'provides nil in the block parameter and allows to override it in subsequent jobs' do
138
+ job1 = factory.job { |data, options|
139
+ expect(options).to be_nil
140
+ [data, {b:3}]
141
+ }
142
+ job2 = factory.job { |_, options|
143
+ expect(options).to eq({b:3})
144
+ }
145
+ seq = job1.then(job2)
146
+ seq.now({a:1})
147
+ end
148
+ end
149
+ end
150
+ context 'when used in an immutable way' do
151
+ it 'propagates the resulting data to next jobs' do
152
+ factory = Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
153
+ output = mock('output')
154
+ input_data = { input: 1 }
155
+ a = factory.job { |data|
156
+ data.merge(a: 2)
157
+ }
158
+ b = factory.job { |data, options|
159
+ data.merge(b: 3)
160
+ }
161
+ c = factory.job { |data, options|
162
+ output.write data.merge(c: 4)
163
+ }
164
+ d = factory.job { |data|
165
+ output.write data.merge(d: 5)
166
+ }
167
+ foo = a.then(b).then(c, d)
168
+ output.expects(:write).with({input:1,a:2,b:3,c:4})
169
+ output.expects(:write).with({input:1,a:2,b:3,d:5})
170
+ foo.now(input_data)
171
+ end
172
+ end
173
+
174
+ context 'when used in a mutable way' do
175
+ it 'propagates the resulting data to next jobs' do
176
+ factory = Observed::JobFactory.new(:executor => Observed::BlockingJobExecutor.new)
177
+ output = mock('output')
178
+ input_data = { input: 1 }
179
+ a = factory.mutable_job { |data|
180
+ data.merge(a: 2)
181
+ }
182
+ b = factory.job { |data, options|
183
+ data.merge(b: 3)
184
+ }
185
+ c = factory.job { |data, options|
186
+ output.write data.merge(c: 4)
187
+ }
188
+ d = factory.job { |data|
189
+ output.write data.merge(d: 5)
190
+ }
191
+ a.then(b).then(c, d)
192
+ output.expects(:write).with({input:1,a:2,b:3,c:4})
193
+ output.expects(:write).with({input:1,a:2,b:3,d:5})
194
+ a.now(input_data)
195
+ end
196
+ end
197
+
198
+ context 'when listeners given' do
199
+ it 'notifies listeners with resulting data' do
200
+
201
+ listener = mock('listener')
202
+ factory = Observed::JobFactory.new(
203
+ :executor => Observed::BlockingJobExecutor.new,
204
+ :listener => listener
205
+ )
206
+ output = mock('output')
207
+ input_data = { input: 1 }
208
+ a = factory.job { |data|
209
+ data.merge(a: 2)
210
+ }
211
+ b = factory.job { |data, options|
212
+ data.merge(b: 3)
213
+ }
214
+ c = factory.job { |data, options|
215
+ output.write data.merge(c: 4)
216
+ }
217
+ d = factory.job { |data|
218
+ output.write data.merge(d: 5)
219
+ }
220
+ foo = a.then(b).then(c, d)
221
+ output.expects(:write).with({input:1,a:2,b:3,c:4})
222
+ output.expects(:write).with({input:1,a:2,b:3,d:5})
223
+ listener.expects(:on_result).with({input:1,a:2}, {opt:1})
224
+ listener.expects(:on_result).with({input:1,a:2,b:3}, {opt:1})
225
+ foo.now(input_data, {opt:1})
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ require 'observed/job'
4
+ require 'observed/jobbed_event_bus'
5
+
6
+ describe Observed::JobbedEventBus do
7
+ let(:out) {
8
+ mock('out')
9
+ }
10
+ let(:factory) {
11
+ executor = Observed::BlockingJobExecutor.new
12
+ Observed::JobFactory.new(executor: executor)
13
+ }
14
+ let(:the_job) {
15
+ factory.job { |data, options|
16
+ out.write data, options
17
+ }
18
+ }
19
+ let(:bus) {
20
+ Observed::JobbedEventBus.new(job_factory: factory)
21
+ }
22
+ it 'should invoke jobs when the corresponding events are emitted' do
23
+ bus.emit('foo')
24
+ bus.receive(/^bar$/).then(the_job)
25
+ bus.emit('baz')
26
+ out.expects(:write).with({a:1}, {b:2})
27
+ bus.emit('bar', {a:1}, {b:2})
28
+ bus.emit('blah')
29
+ end
30
+ it 'should return the job to emit events' do
31
+ bus.pipe_to_emit('foo').now
32
+ bus.receive(/^bar$/).then(the_job)
33
+ bus.pipe_to_emit('baz').now
34
+ out.expects(:write).with({a:1}, {b:2})
35
+ bus.pipe_to_emit('bar').now({a:1}, {b:2})
36
+ bus.pipe_to_emit('blah').now
37
+ end
38
+ end