langis 0.1.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.
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/NOTICE +4 -0
- data/README.md +533 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/generators/langis_config_generator.rb +7 -0
- data/generators/templates/langis_config.rb +44 -0
- data/lib/langis.rb +60 -0
- data/lib/langis/dsl.rb +346 -0
- data/lib/langis/engine.rb +146 -0
- data/lib/langis/middleware.rb +135 -0
- data/lib/langis/rackish.rb +118 -0
- data/lib/langis/sinks.rb +138 -0
- data/spec/langis/dsl_spec.rb +301 -0
- data/spec/langis/engine_spec.rb +168 -0
- data/spec/langis/middleware_spec.rb +196 -0
- data/spec/langis/rackish_spec.rb +33 -0
- data/spec/langis/sinks/delayed_job_sink_spec.rb +227 -0
- data/spec/langis/sinks/redis_resque_sink_spec.rb +232 -0
- data/spec/redis.conf +132 -0
- data/spec/spec_helper.rb +8 -0
- metadata +171 -0
@@ -0,0 +1,301 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
# Just a plain old middleware class for these specs
|
4
|
+
class TestMiddleware
|
5
|
+
def initialize(app, service, value)
|
6
|
+
@app = app
|
7
|
+
@service = service
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
def call(env)
|
11
|
+
@service.my_expected_method(@value)
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'Langis Dsl Config' do
|
17
|
+
it 'should handle an empty dsl block' do
|
18
|
+
config = Langis::Dsl.langis_plumbing do
|
19
|
+
end
|
20
|
+
pipes = config.build_pipes
|
21
|
+
pipes.should be_empty
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should handle raise error on missing sink' do
|
25
|
+
begin
|
26
|
+
config = Langis::Dsl.langis_plumbing do
|
27
|
+
intake :intake_1 do
|
28
|
+
flow_to :non_existent_sink
|
29
|
+
end
|
30
|
+
end
|
31
|
+
pipes = config.build_pipes
|
32
|
+
fail 'did not raise PipingConfigError'
|
33
|
+
rescue Langis::Dsl::PipingConfigError => e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should create a single intake with a single app' do
|
38
|
+
config = Langis::Dsl.langis_plumbing do
|
39
|
+
intake :intake_1 do
|
40
|
+
flow_to :sink_1
|
41
|
+
end
|
42
|
+
for_sink :sink_1 do
|
43
|
+
end
|
44
|
+
end
|
45
|
+
pipes = config.build_pipes
|
46
|
+
pipes.size.should eql 1
|
47
|
+
pipes['intake_1'].size.should eql 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should create one intake with a three apps' do
|
51
|
+
config = Langis::Dsl.langis_plumbing do
|
52
|
+
intake :intake_1 do
|
53
|
+
flow_to :sink_1
|
54
|
+
flow_to :sink_2, :sink_3
|
55
|
+
end
|
56
|
+
for_sink :sink_1 do
|
57
|
+
end
|
58
|
+
for_sink :sink_2 do
|
59
|
+
end
|
60
|
+
for_sink :sink_3 do
|
61
|
+
end
|
62
|
+
end
|
63
|
+
pipes = config.build_pipes
|
64
|
+
pipes.size.should eql 1
|
65
|
+
pipes['intake_1'].size.should eql 3
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should create ignore unreferenced sinks, executing proper sink' do
|
69
|
+
env = {
|
70
|
+
:envkey => 1
|
71
|
+
}
|
72
|
+
|
73
|
+
# Create 3 mocks where 1 is called and the other 2 are uncalled.
|
74
|
+
service1= mock 'service1'
|
75
|
+
service2 = mock 'service2'
|
76
|
+
service2.should_receive(:call).with(env).once
|
77
|
+
service3 = mock 'service3'
|
78
|
+
|
79
|
+
# Now create the config.
|
80
|
+
config = Langis::Dsl.langis_plumbing do
|
81
|
+
intake :intake_1 do
|
82
|
+
flow_to :sink_2
|
83
|
+
end
|
84
|
+
for_sink :sink_1 do
|
85
|
+
run service1
|
86
|
+
end
|
87
|
+
for_sink :sink_2 do
|
88
|
+
run service2
|
89
|
+
end
|
90
|
+
for_sink :sink_3 do
|
91
|
+
run service3
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# build the pipes and run the test.
|
96
|
+
pipes = config.build_pipes
|
97
|
+
pipes.size.should eql 1
|
98
|
+
pipes['intake_1'].size.should eql 1
|
99
|
+
pipes['intake_1'][0].call(env)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should create two intakes with a three apps each' do
|
103
|
+
config = Langis::Dsl.langis_plumbing do
|
104
|
+
intake :intake_1, :intake_2 do
|
105
|
+
flow_to :sink_1
|
106
|
+
flow_to :sink_2, :sink_3
|
107
|
+
end
|
108
|
+
for_sink :sink_1 do
|
109
|
+
end
|
110
|
+
for_sink :sink_2 do
|
111
|
+
end
|
112
|
+
for_sink :sink_3 do
|
113
|
+
end
|
114
|
+
end
|
115
|
+
pipes = config.build_pipes
|
116
|
+
pipes.size.should eql 2
|
117
|
+
pipes['intake_1'].size.should eql 3
|
118
|
+
pipes['intake_2'].size.should eql 3
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should have sinks that run middleware in order' do
|
122
|
+
env = {}
|
123
|
+
first_value = 1
|
124
|
+
second_value = 2
|
125
|
+
service = mock 'middleware_service'
|
126
|
+
service.should_receive(:my_expected_method).once.with(first_value).ordered
|
127
|
+
service.should_receive(:my_expected_method).once.with(second_value).ordered
|
128
|
+
config = Langis::Dsl.langis_plumbing do
|
129
|
+
intake :intake_1 do
|
130
|
+
flow_to :sink_1
|
131
|
+
end
|
132
|
+
for_sink :sink_1 do
|
133
|
+
use TestMiddleware, service, first_value
|
134
|
+
use TestMiddleware, service, second_value
|
135
|
+
end
|
136
|
+
end
|
137
|
+
pipes = config.build_pipes
|
138
|
+
pipes['intake_1'].size.should eql 1
|
139
|
+
pipes['intake_1'][0].call(env)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should have sinks that run middleware in order, with a final app' do
|
143
|
+
env = {}
|
144
|
+
first_value = 1
|
145
|
+
second_value = 2
|
146
|
+
service = mock 'middleware_service'
|
147
|
+
service.should_receive(:my_expected_method).once.with(first_value).ordered
|
148
|
+
service.should_receive(:my_expected_method).once.with(second_value).ordered
|
149
|
+
service.should_receive(:call).once.with(an_instance_of(Hash))
|
150
|
+
config = Langis::Dsl.langis_plumbing do
|
151
|
+
intake :intake_1 do
|
152
|
+
flow_to :sink_1
|
153
|
+
end
|
154
|
+
for_sink :sink_1 do
|
155
|
+
use TestMiddleware, service, first_value
|
156
|
+
use TestMiddleware, service, second_value
|
157
|
+
run service
|
158
|
+
end
|
159
|
+
end
|
160
|
+
pipes = config.build_pipes
|
161
|
+
pipes['intake_1'].size.should eql 1
|
162
|
+
pipes['intake_1'][0].call(env)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should have separate sinks that run middleware and app in order' do
|
166
|
+
env = {}
|
167
|
+
first_value = 1
|
168
|
+
second_value = 2
|
169
|
+
service1 = mock 'middleware_service1'
|
170
|
+
service1.should_receive(:my_expected_method).once.with(first_value).ordered
|
171
|
+
service1.should_receive(:my_expected_method).once.with(second_value).ordered
|
172
|
+
service1.should_receive(:call).once.with(an_instance_of(Hash))
|
173
|
+
service2 = mock 'middleware_service2'
|
174
|
+
service2.should_receive(:my_expected_method).once.with(first_value).ordered
|
175
|
+
service2.should_receive(:my_expected_method).once.with(second_value).ordered
|
176
|
+
service2.should_receive(:call).once.with(an_instance_of(Hash))
|
177
|
+
config = Langis::Dsl.langis_plumbing do
|
178
|
+
intake :intake_1 do
|
179
|
+
flow_to :sink_1, :sink_2
|
180
|
+
end
|
181
|
+
for_sink :sink_1 do
|
182
|
+
use TestMiddleware, service1, first_value
|
183
|
+
use TestMiddleware, service1, second_value
|
184
|
+
run service1
|
185
|
+
end
|
186
|
+
for_sink :sink_2 do
|
187
|
+
use TestMiddleware, service2, first_value
|
188
|
+
use TestMiddleware, service2, second_value
|
189
|
+
run service2
|
190
|
+
end
|
191
|
+
end
|
192
|
+
pipes = config.build_pipes
|
193
|
+
pipes['intake_1'].size.should eql 2
|
194
|
+
pipes['intake_1'][0].call(env)
|
195
|
+
pipes['intake_1'][1].call(env)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should allow message through with a set type' do
|
199
|
+
message_type = 'MyMessageType'
|
200
|
+
message_type_2 = 'MyMessageType2'
|
201
|
+
env = {
|
202
|
+
Langis::MESSAGE_TYPE_KEY => message_type
|
203
|
+
}
|
204
|
+
service = mock 'middleware_service'
|
205
|
+
service.should_receive(:call).once.with(
|
206
|
+
hash_including(Langis::MESSAGE_TYPE_KEY => message_type))
|
207
|
+
config = Langis::Dsl.langis_plumbing do
|
208
|
+
intake :intake_1 do
|
209
|
+
flow_to :sink_1, :when => message_type
|
210
|
+
end
|
211
|
+
for_sink :sink_1 do
|
212
|
+
run service
|
213
|
+
end
|
214
|
+
end
|
215
|
+
pipes = config.build_pipes
|
216
|
+
pipes['intake_1'].size.should eql 1
|
217
|
+
pipes['intake_1'][0].call(env)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should allow message through a filter looking for a list of types' do
|
221
|
+
message_type = 'MyMessageType'
|
222
|
+
message_type_2 = 'MyMessageType2'
|
223
|
+
env = {
|
224
|
+
Langis::MESSAGE_TYPE_KEY => message_type
|
225
|
+
}
|
226
|
+
service = mock 'middleware_service'
|
227
|
+
service.should_receive(:call).once.with(
|
228
|
+
hash_including(Langis::MESSAGE_TYPE_KEY => message_type))
|
229
|
+
config = Langis::Dsl.langis_plumbing do
|
230
|
+
intake :intake_1 do
|
231
|
+
flow_to :sink_1, :when => [message_type.to_sym, message_type_2.to_sym]
|
232
|
+
end
|
233
|
+
for_sink :sink_1 do
|
234
|
+
run service
|
235
|
+
end
|
236
|
+
end
|
237
|
+
pipes = config.build_pipes
|
238
|
+
pipes['intake_1'].size.should eql 1
|
239
|
+
pipes['intake_1'][0].call(env)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'should filter by message types given by array' do
|
243
|
+
message_type = 'MyMessageType'
|
244
|
+
message_type_2 = 'MyMessageType2'
|
245
|
+
env = {
|
246
|
+
Langis::MESSAGE_TYPE_KEY => 'NotTheRightType'
|
247
|
+
}
|
248
|
+
# Service should receive zero calls.
|
249
|
+
service = mock 'middleware_service'
|
250
|
+
config = Langis::Dsl.langis_plumbing do
|
251
|
+
intake :intake_1 do
|
252
|
+
flow_to :sink_1, :when => [message_type.to_sym, message_type_2.to_sym]
|
253
|
+
end
|
254
|
+
for_sink :sink_1 do
|
255
|
+
run service
|
256
|
+
end
|
257
|
+
end
|
258
|
+
pipes = config.build_pipes
|
259
|
+
pipes['intake_1'].size.should eql 1
|
260
|
+
pipes['intake_1'][0].call(env)
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should run the check_valve middleware for all routes' do
|
264
|
+
value = 'TestMiddlewareValue'
|
265
|
+
env = {
|
266
|
+
:envkey => 1
|
267
|
+
}
|
268
|
+
service1= mock 'service1'
|
269
|
+
service1.should_receive(:call).with(env).once
|
270
|
+
service2 = mock 'service2'
|
271
|
+
service2.should_receive(:call).with(env).once
|
272
|
+
service3 = mock 'service3'
|
273
|
+
service3.should_receive(:call).with(env).once
|
274
|
+
check_valve_service = mock 'check_valve'
|
275
|
+
check_valve_service.
|
276
|
+
should_receive(:my_expected_method).with(value).exactly(3).times
|
277
|
+
config = Langis::Dsl.langis_plumbing do
|
278
|
+
intake :intake_1 do
|
279
|
+
flow_to :sink_1, :sink_2, :sink_3
|
280
|
+
end
|
281
|
+
for_sink :sink_1 do
|
282
|
+
run service1
|
283
|
+
end
|
284
|
+
for_sink :sink_2 do
|
285
|
+
run service2
|
286
|
+
end
|
287
|
+
for_sink :sink_3 do
|
288
|
+
run service3
|
289
|
+
end
|
290
|
+
check_valve do
|
291
|
+
use TestMiddleware, check_valve_service, value
|
292
|
+
end
|
293
|
+
end
|
294
|
+
pipes = config.build_pipes
|
295
|
+
pipes.size.should eql 1
|
296
|
+
pipes['intake_1'].size.should eql 3
|
297
|
+
pipes['intake_1'].each do |sink|
|
298
|
+
sink.call(env)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
# We want an ipmlementation of EventMachine::Channel without EventMachine
|
4
|
+
# to run inside these tests.
|
5
|
+
class NonEvmChannel
|
6
|
+
def initialize
|
7
|
+
@list = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscribe(*args, &block)
|
11
|
+
@list << args[0]
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(*args)
|
15
|
+
@list.each do |subscriber|
|
16
|
+
subscriber.call *args
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# We need EventMachine defer without EventMachine.
|
22
|
+
class EventMachineStub
|
23
|
+
def self.defer(op = nil, callback = nil)
|
24
|
+
if callback
|
25
|
+
callback.call(op.call)
|
26
|
+
else
|
27
|
+
op.call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'EventMachineEngine' do
|
33
|
+
it 'should pump a message to one intake' do
|
34
|
+
my_message = 'pingy pong'
|
35
|
+
env = {
|
36
|
+
Langis::MESSAGE_KEY => my_message,
|
37
|
+
Langis::INTAKE_KEY => 'intake_1'
|
38
|
+
}
|
39
|
+
service = mock 'service'
|
40
|
+
service.should_receive(:call).with(env).once
|
41
|
+
config = Langis::Dsl.langis_plumbing do
|
42
|
+
intake :intake_1, :intake_2 do
|
43
|
+
flow_to :sink_1
|
44
|
+
end
|
45
|
+
for_sink :sink_1 do
|
46
|
+
run service
|
47
|
+
end
|
48
|
+
end
|
49
|
+
engine = Langis::Engine::EventMachineEngine.new(config.build_pipes,
|
50
|
+
:evm => EventMachineStub,
|
51
|
+
:evm_channel => NonEvmChannel)
|
52
|
+
engine.pump my_message, :intake_1
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should pump a message to multiple intakes' do
|
56
|
+
my_message = 'pingy pong'
|
57
|
+
env1 = {
|
58
|
+
Langis::MESSAGE_KEY => my_message,
|
59
|
+
Langis::INTAKE_KEY => 'intake_1'
|
60
|
+
}
|
61
|
+
env2 = {
|
62
|
+
Langis::MESSAGE_KEY => my_message,
|
63
|
+
Langis::INTAKE_KEY => 'intake_2'
|
64
|
+
}
|
65
|
+
service = mock 'service'
|
66
|
+
service.should_receive(:call).with(env1).once
|
67
|
+
service.should_receive(:call).with(env2).once
|
68
|
+
config = Langis::Dsl.langis_plumbing do
|
69
|
+
intake :intake_1, :intake_2 do
|
70
|
+
flow_to :sink_1
|
71
|
+
end
|
72
|
+
for_sink :sink_1 do
|
73
|
+
run service
|
74
|
+
end
|
75
|
+
end
|
76
|
+
engine = Langis::Engine::EventMachineEngine.new(config.build_pipes,
|
77
|
+
:evm => EventMachineStub,
|
78
|
+
:evm_channel => NonEvmChannel)
|
79
|
+
engine.pump my_message, :intake_1, :intake_2
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should handle success callbacks' do
|
83
|
+
my_message = 'pingy pong'
|
84
|
+
return_message = [200, {}, ['']]
|
85
|
+
env = {
|
86
|
+
Langis::MESSAGE_KEY => my_message,
|
87
|
+
Langis::INTAKE_KEY => 'intake_1'
|
88
|
+
}
|
89
|
+
service = mock 'service'
|
90
|
+
service.should_receive(:call).with(env).once.and_return(return_message)
|
91
|
+
success_channel = mock 'success channel'
|
92
|
+
success_channel.should_receive(:push).with(return_message).once
|
93
|
+
config = Langis::Dsl.langis_plumbing do
|
94
|
+
intake :intake_1, :intake_2 do
|
95
|
+
flow_to :sink_1
|
96
|
+
end
|
97
|
+
for_sink :sink_1 do
|
98
|
+
run service
|
99
|
+
end
|
100
|
+
end
|
101
|
+
engine = Langis::Engine::EventMachineEngine.new(config.build_pipes,
|
102
|
+
:evm => EventMachineStub,
|
103
|
+
:evm_channel => NonEvmChannel,
|
104
|
+
:success_channel => success_channel)
|
105
|
+
engine.pump my_message, :intake_1
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should handle error callback' do
|
109
|
+
my_message = 'pingy pong'
|
110
|
+
my_error = RuntimeError.new
|
111
|
+
env = {
|
112
|
+
Langis::MESSAGE_KEY => my_message,
|
113
|
+
Langis::INTAKE_KEY => 'intake_1'
|
114
|
+
}
|
115
|
+
error_result = [
|
116
|
+
Langis::SERVER_ERROR,
|
117
|
+
{
|
118
|
+
Langis::MESSAGE_KEY => my_message,
|
119
|
+
Langis::INTAKE_KEY => 'intake_1',
|
120
|
+
Langis::X_EXCEPTION => my_error
|
121
|
+
},
|
122
|
+
['']
|
123
|
+
]
|
124
|
+
service = mock 'service'
|
125
|
+
service.should_receive(:call).with(env).once.and_raise(my_error)
|
126
|
+
error_channel = mock 'error channel'
|
127
|
+
error_channel.should_receive(:push).with(error_result).once
|
128
|
+
config = Langis::Dsl.langis_plumbing do
|
129
|
+
intake :intake_1, :intake_2 do
|
130
|
+
flow_to :sink_1
|
131
|
+
end
|
132
|
+
for_sink :sink_1 do
|
133
|
+
run service
|
134
|
+
end
|
135
|
+
end
|
136
|
+
engine = Langis::Engine::EventMachineEngine.new(config.build_pipes,
|
137
|
+
:evm => EventMachineStub,
|
138
|
+
:evm_channel => NonEvmChannel,
|
139
|
+
:error_channel => error_channel)
|
140
|
+
engine.pump my_message, :intake_1
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should set the MESSAGE_TYPE field if the message responds to :message_type' do
|
144
|
+
my_type = 'MyMessageType'
|
145
|
+
my_message = mock 'message'
|
146
|
+
my_message.should_receive(:respond_to?).with(:message_type).once.and_return true
|
147
|
+
my_message.should_receive(:message_type).once.and_return(my_type)
|
148
|
+
env = {
|
149
|
+
Langis::MESSAGE_TYPE_KEY => my_type,
|
150
|
+
Langis::MESSAGE_KEY => my_message,
|
151
|
+
Langis::INTAKE_KEY => 'intake_1'
|
152
|
+
}
|
153
|
+
service = mock 'service'
|
154
|
+
service.should_receive(:call).with(env)
|
155
|
+
config = Langis::Dsl.langis_plumbing do
|
156
|
+
intake :intake_1, :intake_2 do
|
157
|
+
flow_to :sink_1
|
158
|
+
end
|
159
|
+
for_sink :sink_1 do
|
160
|
+
run service
|
161
|
+
end
|
162
|
+
end
|
163
|
+
engine = Langis::Engine::EventMachineEngine.new(config.build_pipes,
|
164
|
+
:evm => EventMachineStub,
|
165
|
+
:evm_channel => NonEvmChannel)
|
166
|
+
engine.pump my_message, :intake_1
|
167
|
+
end
|
168
|
+
end
|