nebulous_stomp 2.0.2 → 3.0.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.hgignore +2 -0
  3. data/.hgtags +1 -0
  4. data/README.md +225 -28
  5. data/feature/connection_example.yaml +24 -0
  6. data/feature/feature_test_spec.rb +247 -0
  7. data/feature/gimme.rb +91 -0
  8. data/lib/nebulous_stomp/listener.rb +107 -0
  9. data/lib/nebulous_stomp/message.rb +132 -265
  10. data/lib/nebulous_stomp/msg/body.rb +169 -0
  11. data/lib/nebulous_stomp/msg/header.rb +98 -0
  12. data/lib/nebulous_stomp/param.rb +16 -35
  13. data/lib/nebulous_stomp/redis_handler.rb +19 -29
  14. data/lib/nebulous_stomp/redis_handler_null.rb +12 -11
  15. data/lib/nebulous_stomp/redis_helper.rb +110 -0
  16. data/lib/nebulous_stomp/request.rb +212 -0
  17. data/lib/nebulous_stomp/stomp_handler.rb +30 -96
  18. data/lib/nebulous_stomp/stomp_handler_null.rb +8 -22
  19. data/lib/nebulous_stomp/target.rb +52 -0
  20. data/lib/nebulous_stomp/version.rb +1 -1
  21. data/lib/nebulous_stomp.rb +63 -50
  22. data/md/LICENSE.txt +20 -2
  23. data/md/nebulous_protocol.md +25 -18
  24. data/spec/listener_spec.rb +104 -0
  25. data/spec/message_spec.rb +227 -116
  26. data/spec/nebulous_spec.rb +44 -9
  27. data/spec/param_spec.rb +16 -33
  28. data/spec/redis_handler_null_spec.rb +0 -2
  29. data/spec/redis_handler_spec.rb +0 -2
  30. data/spec/redis_helper_spec.rb +107 -0
  31. data/spec/request_spec.rb +249 -0
  32. data/spec/stomp_handler_null_spec.rb +33 -34
  33. data/spec/stomp_handler_spec.rb +1 -74
  34. data/spec/target_spec.rb +97 -0
  35. metadata +20 -11
  36. data/lib/nebulous_stomp/nebrequest.rb +0 -259
  37. data/lib/nebulous_stomp/nebrequest_null.rb +0 -37
  38. data/spec/nebrequest_null_spec.rb +0 -219
  39. data/spec/nebrequest_spec.rb +0 -239
  40. data/spec/through_test_spec.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a4ac7c514b6d925e6186924b2dd93a175de94e02
4
- data.tar.gz: 8aca7aa180be4c84fe6ccbe89b172980cd2a56a1
3
+ metadata.gz: 2b884a207187065896c92f83149c9a9701fb4b32
4
+ data.tar.gz: 18ec13584623af59f629a7c1e4ebc2d904c59cf3
5
5
  SHA512:
6
- metadata.gz: abb4de512e2aec3d8720505f9f06d7a00b2d5aa4caba2a1e9dab977f6c36cb6970f791289509cc6fbe96b945d6eeec84a65d7fe86b54d7402b97104dcd71c18d
7
- data.tar.gz: 3e44c452fa7f94cd331cfc637b90b427c5171bd7fa9663b4ebe5118320e8d1ea8554628b57bcecfcc55cbc2f7f69aed9d13f49951c8e1ce82836db55cb7b26d5
6
+ metadata.gz: 25d7c1f7cda1c2a509c837b4de72a998fbca6354bf29f9ec1a9e4931df1a22458b19b9cf57a4bf7e5c61fbb1f3d22ceeb7ff66dc93f1327756c0a98e7293e93b
7
+ data.tar.gz: b9cfecbfdb21aaa42f36162b9baf57221a53706779721a584f5998a3a4f853fd0929789722b1a8ca896231b75123a43fdecfb76a051826f4fd7ff73cebe94f5b
data/.hgignore CHANGED
@@ -17,3 +17,5 @@ syntax: glob
17
17
  mkmf.log
18
18
  .ruby-*
19
19
  .Project
20
+
21
+ feature/connection.yaml
data/.hgtags CHANGED
@@ -17,3 +17,4 @@ cff04defabb0895ff2f032087b97ea9616bee6a9 1.14
17
17
  6da65ce15fab9722deb05d8c0ed2d0c8e2cfe2ff 2.0.0
18
18
  9c4ec9af8f6b8a848082bf118be037696ff357c7 2.0.1
19
19
  63eb0028eeedf7cc3938fd8ecda1add9246fb905 2.02
20
+ c4e3ca2874b81f2b8f7008322ff0e5a18f29c35e 3.0.0
data/README.md CHANGED
@@ -1,38 +1,235 @@
1
- Nebulous
1
+ Introduction
2
+ ============
3
+
4
+ A little module that implements The Nebulous Protocol, a way of passing data over STOMP between
5
+ different systems. Specifically, it allows you to send a message, a *Request* and receive another
6
+ message in answer, a *Response*. (Which is not something STOMP does, out of the box).
7
+
8
+ This library covers two specific use cases (three if you are picky):
9
+
10
+ 1) Request-Response: a program that consumes incoming messages, works out what message to send in
11
+ response, and sends it.
12
+
13
+ 2) Question-Answer: a program that sends a request and then waits for a response; the other end of
14
+ the Request-Response use case. We support optional caching of responses in Redis, to speed things up
15
+ if your program is likely to make the same request repeatedly within a short time.
16
+
17
+ 3) Since we are talking to Redis, we expose a basic, simple interface for you to talk to it
18
+ yourself.
19
+
20
+
21
+ Thanks
22
+ ======
23
+
24
+ This code was developed, by me, during working hours at [James Hall & Co.
25
+ Ltd](https://www.jameshall.co.uk/). I'm incredibly greatful that they have permitted me to
26
+ open-source it.
27
+
28
+
29
+
30
+ A Quick Example
31
+ ===============
32
+
33
+ Before we get too bogged down, some code.
34
+
35
+ require "nebulous_stomp"
36
+
37
+ NebulousStomp.init( my_init_hash )
38
+ NebulousStomp.add_target(:target1, my_target)
39
+
40
+ message = NebulousStomp::Message.new(verb: "ping")
41
+ request = NebulousStomp::Request.new(:target1, message)
42
+ response = request.send
43
+
44
+ This example is for the question-answer use case. `response` will contain a NebulousStomp::Message
45
+ -- unless the target fails to respond in time, in which case a NebulousStomp::MessageTimeout will
46
+ be raised.
47
+
48
+
49
+ The Protocol
50
+ ============
51
+
52
+ I natter on about this in far too much detail elsewhere, but the highly condensed version is:
53
+
54
+ * Every request always gets a response; if you don't get one, then something is wrong at the other
55
+ end.
56
+
57
+ * Request-response programs consume all messages on the queue that they listen on. They place the
58
+ response on a *different* queue, the name of which is given by the request.
59
+
60
+ * Each message has a 'unique' ID; the response has the ID of the request it responds to.
61
+
62
+ * Messages can "follow the protocol" by being in the form: verb, parameters, descripton. Requests
63
+ *must* be in this form; responses don't have to be.
64
+
65
+ * The special verb "success" in a response means "I got the message, everything is fine, nothing to
66
+ report here".
67
+
68
+ * The special verb "error" in a response means something went wrong. The description should say
69
+ what.
70
+
71
+
72
+ Targets
73
+ =======
74
+
75
+ When you have a system running a request-response loop, then the simplest way to proceed is to
76
+ assign it a pair of queues on your Stomp server: one for incoming requests, and one for it to post
77
+ responses to.
78
+
79
+ We call such a system a Target. Any other, question-answer, system (which wants to throw Requests at
80
+ that target and get a response) will need to know what those queues are; so we configure a list of
81
+ targets at startup.
82
+
83
+ Note that it is perfectly okay for a target to use more than one request queue (desirable, even,
84
+ if some requests will take time to fulfil). But we don't directly support that in Nebulous: a
85
+ Target is always one request queue, one response queue. In this case, the simplest way forward is
86
+ to define two targets.
87
+
88
+
89
+ Examples
2
90
  ========
3
91
 
4
- A little module that implements the Nebulous Protocol, a way of passing data
5
- over STOMP between different systems. We also support message cacheing via
6
- Redis.
92
+ Request-Response
93
+ ----------------
94
+
95
+ This revisits the example from the start, but with more detail. For completeness, we configure a
96
+ Redis server for caching respsonses (which is optional) and show all the config hashes (which
97
+ certainly want to come from a config file in practice).
98
+
99
+ require "nebulous_stomp"
100
+
101
+ host = {login: "guest", passcode: "guest", host: "10.11.12.13", ssl: false}
102
+ stomp = {hosts: [host], reliable: false}
103
+ redis = {host: '127.0.0.1', port: 6379, db: 0}
104
+
105
+ config = { stompConnectHash: stomp,
106
+ redisCOnnectHash: redis,
107
+ messageTimeout: 5,
108
+ cacheTimeout: 30 }
109
+
110
+ target = { sendQueue: "/queue/in",
111
+ receiveQueue: "/queue/out",
112
+ messageTimeout: 7 }
113
+
114
+ NebulousStomp.init(config)
115
+ NebulousStomp.add_target(:target1, target)
116
+
117
+ message = NebulousStomp::Message.new(verb: "ping")
118
+ request = NebulousStomp::Request.new(:target1, message)
119
+
120
+ response1 = request.send
121
+ response2 = request.send
122
+
123
+ `response1` will be filled from the target; `response2` will be filled from the Redis cache
124
+ (provided that line gets called within 30 seconds of the previous line). (Obviously this is
125
+ pointless and for example only.)
126
+
127
+ The stomp hash is passed unchanged to the Stomp gem; the redis hash is passed unchanged to the
128
+ Redis gem. See these gems for details about what they should contain.
129
+
130
+ Message.new takes a single hash as an argument; it accepts a long list of possible keys, but mostly
131
+ I imagine you will be using 'verb', 'params', and 'desc'. It's worth also noting 'replyTo', which
132
+ sets the queue to reply to; if missing then Request sets it from the Target, of course.
133
+
134
+ This rather specific example contains three seperate timeout values. The message timeout is the
135
+ time we wait for a response before raising MessageTimeout. The value in the config hash is a
136
+ default; in this example it is overidden on the target. The cache timeout is, of course, the time
137
+ that the response is kept on the cache. These values can be further overridden for specific
138
+ messages.
139
+
140
+ Often even with a cache set up, you don't want to use it (for requests that trigger database
141
+ updates, for example); in which case the method to call is `send_no_cache`.
142
+
143
+ Question-Answer
144
+ ---------------
145
+
146
+ require "nebulous_stomp"
147
+
148
+ NebulousStomp.init(config)
149
+ target = NebulousStomp.add_target(:target1, target)
150
+
151
+ listener = NebulousStomp::Listener.new(target)
152
+
153
+ listener.consume_messages do |msg|
154
+ begin
155
+
156
+ case msg.verb
157
+ when "ping"
158
+ listener.reply *msg.respond_with_success
159
+ when "time"
160
+ listener.reply *msg.respond_with_protocol("timeresponse", Time.now)
161
+ else
162
+ listener.reply *msg.respond_with_error("Bad verb #{msg.verb}")
163
+ end
164
+
165
+ rescue
166
+ listener.reply *msg.respond_with_error($!)
167
+ end
168
+ end
169
+
170
+ loop { sleep 5 }
171
+
172
+ This example implements a target that responds to two verbs. In responce to "ping" it sends a
173
+ success verb, indicating it got the message. In response to "time" it sends a "timeresponse" verb
174
+ with the current time as a parameter. For any other verb on its receive queue, it responds with an
175
+ error verb.
176
+
177
+ `Listener.new` requires either a Target object or a queue name. This is different from Request,
178
+ which can take a target name. You can always retreive a Target object yourself, though, like this:
179
+
180
+ target = NebulousParam.get_target(targetname)
181
+
182
+ If you want to respond with a message that does not follow the verb-parameter-description part of
183
+ the protocol, then you can pass an arbitrary message body to `msg.respond()`.
184
+
185
+ Note the error handling. This is especially important because the body that you pass to the
186
+ `consume_messages` method is actually being run in a thread, by the Stomp gem; by default all
187
+ errors will be swallowed silently. As you can see, `message.respond_with_error` can take an
188
+ exception as a parameter.
189
+
190
+ Note also, for the same reason, that your program must hold the main thread open while
191
+ `consume_messages` is running; if the main thread ends, the program stops.
192
+
193
+ Redis
194
+ -----
195
+
196
+ require "nebulous_stomp/redis_helper"
197
+
198
+ # ...parameters get set here...
199
+
200
+ redis = NebulousStomp::RedisHelper.new
201
+
202
+ redis.set(:thing, "thingy")
203
+ redes.set(:gone_in_30_seconds, "thingy", 30)
204
+
205
+ value = redis.get(:thing)
206
+
207
+ redis.del(:thing)
7
208
 
8
- There are two use cases:
209
+ Obviously this is not so much an example as it is some random calls to RedisHelper. But hopefully
210
+ it is fairly self-explanatory.
9
211
 
10
- First, sending a request for information and waiting for a response, which
11
- might come from a cache of previous responses, if you allow it. To do
12
- this you should create a Nebulous::NebRequest, which will return a
13
- Nebulous::Message.
14
212
 
15
- Second, the other end of the deal: hanging around waiting for requests and
16
- sending responses. To do this, you need to use the Nebulous::StompHandler
17
- class, which will again furnish Nebulous::Meessage objects, and allow you to
18
- create them.
213
+ A list of classes
214
+ =================
19
215
 
20
- Some configuratuion is required: see Nebulous.init, Nebulous.add_target &
21
- Nebulous.add_logger.
216
+ To help you drill down to the API documentation. These are the externally-facing classes:
22
217
 
23
- Since you are setting the Redis connection details as part of initialisation,
24
- you can also use it to connect to Redis, if you want. See
25
- Nebulous::RedisHandler.
218
+ * Listener -- implements the request-response use case
219
+ * Message -- a Nebulous message
220
+ * NebulousStomp -- main class
221
+ * RedisHelper -- implements the Redis use case
222
+ * Request -- implements the Request-Response use case; a wrapper for Message
223
+ * Target -- represents a single Target
224
+
225
+ These classes are used internally:
26
226
 
27
- a complete list of classes & modules:
227
+ * Param -- helper class to store and return configuration
228
+ * RedisHandler -- internal class to wrap the Redis gem
229
+ * RedisHandlerNull -- a "mock" version of RedisHandler for use in testing
230
+ * StompHandler -- internal class to wrap the Stomp gem
231
+ * StompHandlerNull -- a "mock" version of StompHandler for use in testing
28
232
 
29
- * Nebulous
30
- * Nebulous::Param
31
- * Nebulous::NebRequest
32
- * Nebulous::NebRequestNull
33
- * Nebulous::Message
34
- * Nebulous::StompHandler
35
- * Nebulous::StompHandlerNull
36
- * Nebulous::RedisHandler
37
- * Nebulous::RedisHandlerNull
233
+ You might find the null classes useful in your own tests; both Listener and Request allow the
234
+ injection of mock handler objects. You must require them seperately, though.
38
235
 
@@ -0,0 +1,24 @@
1
+ ---
2
+
3
+ :init:
4
+ :stompConnectHash:
5
+ hosts:
6
+ - login: guest
7
+ passcode: guest
8
+ host: '10.11.12.13'
9
+ port: 61613
10
+ ssl: false
11
+ reliable: false
12
+
13
+ :redisConnectHash:
14
+ host: '127.0.0.1'
15
+ port: 6379
16
+ db : 0
17
+
18
+ :messageTimeout: 2
19
+ :cacheTimeout : 10
20
+
21
+ :target:
22
+ :sendQueue: '/queue/featuretestsend'
23
+ :receiveQueue: '/queue/featuretestreceive'
24
+
@@ -0,0 +1,247 @@
1
+ require 'nebulous_stomp'
2
+ require 'nebulous_stomp/redis_helper'
3
+ require 'nebulous_stomp/redis_handler'
4
+
5
+ require_relative 'gimme'
6
+
7
+
8
+ ##
9
+ # These are the feature tests for Nebulous. They are not run when you type `rspec`; that only gets
10
+ # you the unit tests. You have to name this directory to run it: `rspec feature`.
11
+ #
12
+ # These tests require an actual, working STOMP server and an actual, working Redis server (and ones
13
+ # which you don't mind sending test messages to, at that). You should configure connection to this
14
+ # in features/connection.yaml; an example file is provided, features/connection_example.yaml.
15
+ #
16
+ describe 'stomp use cases:' do
17
+
18
+ def init_nebulous(configfile)
19
+ config = YAML.load(File.open configfile)
20
+ NebulousStomp.init config[:init]
21
+ NebulousStomp.add_target("featuretest", config[:target] )
22
+ end
23
+
24
+ def new_request(verb)
25
+ message = NebulousStomp::Message.new(verb: verb)
26
+ NebulousStomp::Request.new("featuretest", message)
27
+ end
28
+
29
+ before(:all) do
30
+ init_nebulous 'feature/connection.yaml'
31
+ Thread.new{ Gimme.new("feature/connection.yaml").run; sleep 15 }
32
+ end
33
+
34
+ let(:hash) do
35
+ { "verb" => "foo",
36
+ "parameters" => "bar",
37
+ "description" => "baz" }
38
+
39
+ end
40
+
41
+ let(:redis) { NebulousStomp::RedisHelper.new }
42
+
43
+ # Plain redis access for debugging
44
+ def redis_backdoor(cmd, arg)
45
+ hash = NebulousStomp::Param.get :redisConnectHash
46
+ handler = NebulousStomp::RedisHandler.new hash
47
+ handler.connect unless handler.connected?
48
+ handler.send(cmd.to_sym, arg.to_s)
49
+ end
50
+
51
+ # Plain stomp access for debugging
52
+ def stomp_backdoor(cmd, queue, msg=nil)
53
+ hash = NebulousStomp::Param.get :stompConnectHash
54
+ handler = NebulousStomp::StompHandler.new hash
55
+
56
+ case cmd
57
+ when :send
58
+ handler.send_message(queue, msg)
59
+ return true
60
+ when :listen
61
+ messages = []
62
+ handler.listen_with_timeout(queue, 1) {|msg| messages << msg; false } rescue nil
63
+ return messages, handler.connected?
64
+ end
65
+ end
66
+
67
+
68
+ ##
69
+ # tests for the request-response use case - a server that consumes messages and responds with
70
+ # other messages.
71
+ #
72
+ # Note that it's the Gimme class, in the thread above, that is actually doing the responding; we
73
+ # just send a message to it and check the response.
74
+ #
75
+ describe "request-response:" do
76
+
77
+ it "can respond to a message with a success verb" do
78
+ response = new_request("gimmesuccess").send_no_cache
79
+
80
+ expect( response ).to be_kind_of(NebulousStomp::Message)
81
+ expect( response.verb ).to eq "success"
82
+ end
83
+
84
+ it "can respond to a message with an error verb" do
85
+ response = new_request("gimmeerror").send_no_cache
86
+
87
+ expect( response ).to be_kind_of(NebulousStomp::Message)
88
+ expect( response.verb ).to eq "error"
89
+ end
90
+
91
+ it "can respond to a message with a specific Protocol message" do
92
+ response = new_request("gimmeprotocol").send_no_cache
93
+
94
+ expect( response ).to be_kind_of(NebulousStomp::Message)
95
+ expect( response.verb ).to eq hash["verb"]
96
+ end
97
+
98
+ it "can respond to a message with a non-Protocol message" do
99
+ message = NebulousStomp::Message.new(verb: 'gimmemessage', contentType: 'text')
100
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
101
+
102
+ expect( response ).to be_kind_of(NebulousStomp::Message)
103
+ expect( response.verb ).to be_nil
104
+ expect( response.body ).to eq "weird message body"
105
+ end
106
+
107
+ it "can send a message >32k" do
108
+ message = NebulousStomp::Message.new( verb: 'gimmebigmessage',
109
+ params: "32",
110
+ contentType: 'text' )
111
+
112
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
113
+
114
+ expect( response ).to be_kind_of(NebulousStomp::Message)
115
+ expect( response.body.size ).to be > (1024 * 32)
116
+ expect( response.body[0..2] ).to eq "foo"
117
+ expect( response.body[-3..-1] ).to eq "bar"
118
+ end
119
+
120
+ it "can send a message >128k" do
121
+ message = NebulousStomp::Message.new( verb: 'gimmebigmessage',
122
+ params: "128",
123
+ contentType: 'text' )
124
+
125
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
126
+
127
+ expect( response ).to be_kind_of(NebulousStomp::Message)
128
+ expect( response.body.size ).to be > (1024 * 128)
129
+ expect( response.body[0..2] ).to eq "foo"
130
+ expect( response.body[-3..-1] ).to eq "bar"
131
+ end
132
+
133
+ it "can send a message >512k" do
134
+ message = NebulousStomp::Message.new( verb: 'gimmebigmessage',
135
+ params: "512",
136
+ contentType: 'text' )
137
+
138
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
139
+
140
+ expect( response ).to be_kind_of(NebulousStomp::Message)
141
+ expect( response.body.size ).to be > (1024 * 512)
142
+ expect( response.body[0..2] ).to eq "foo"
143
+ expect( response.body[-3..-1] ).to eq "bar"
144
+ end
145
+
146
+ end
147
+ ##
148
+
149
+
150
+ ##
151
+ # Tests for the question-and-answer use case -- a process that sends a request to a
152
+ # request-response server and waits for an answering response
153
+ #
154
+ describe "question-and-answer:" do
155
+
156
+
157
+ it "can send a JSON message and get a JSON response" do
158
+ message = NebulousStomp::Message.new(verb: 'gimmeprotocol', contentType: 'application/json')
159
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
160
+
161
+ expect( response.content_type ).to eq 'application/json'
162
+ expect( response.body ).to eq hash
163
+ expect( response.stomp_body ).to eq hash.to_json
164
+ end
165
+
166
+ it "can send a text message and get a text response" do
167
+ message = NebulousStomp::Message.new(verb: 'gimmeprotocol', contentType: 'application/text')
168
+ response = NebulousStomp::Request.new("featuretest", message).send_no_cache
169
+
170
+ expect( response.content_type ).to eq 'application/text'
171
+ expect( response.body ).to eq hash
172
+
173
+ hash.each do |k,v|
174
+ expect( response.stomp_body ).to match(/#{k}: *#{v}/)
175
+ end
176
+ end
177
+
178
+ it "can cache a response in Redis" do
179
+ message = NebulousStomp::Message.new(verb: 'gimmeprotocol', contentType: 'application/text')
180
+ request = NebulousStomp::Request.new("featuretest", message)
181
+ signature = {verb:"gimmeprotocol"}.to_json
182
+
183
+ redis_backdoor(:del, signature)
184
+ request.send
185
+ expect( redis_backdoor(:get, signature) ).not_to be_nil
186
+ end
187
+
188
+ it "will receive its response without disturbing any others" do
189
+ msg1 = NebulousStomp::Message.new(verb: 'backdoor', contentType: 'application/text')
190
+ msg2 = NebulousStomp::Message.new(verb: 'gimmeprotocol', contentType: 'application/text')
191
+ target = NebulousStomp.get_target(:featuretest)
192
+
193
+ # Place msg1 on the queue directly
194
+ stomp_backdoor(:send, target.send_queue, msg1)
195
+
196
+ # Send Msg2 to the target, so that Gimme puts the response on the queue and then we read it
197
+ response2 = NebulousStomp::Request.new(target, msg2).send_no_cache
198
+
199
+ # Now read the messages left on the queue
200
+ leftovers, connected = stomp_backdoor(:listen, target.send_queue)
201
+
202
+ expect( response2 ).to be_kind_of NebulousStomp::Message
203
+ expect( response2.verb ).to eq "foo"
204
+ expect( leftovers.map(&:verb) ).to include("backdoor")
205
+ expect( leftovers.map(&:verb) ).not_to include("foo")
206
+ expect( connected ).to be_truthy
207
+ end
208
+
209
+ end
210
+ ##
211
+
212
+
213
+ ##
214
+ # Tests for the Redis use case -- user wants to access Redis so we grant them access through our
215
+ # connection to it.
216
+ #
217
+ describe "redis:" do
218
+
219
+ it "can set a value in the store" do
220
+ redis.del(:foo) rescue nil
221
+ redis.set(:foo, "bar")
222
+ expect( redis.get(:foo) ).to eq "bar"
223
+ end
224
+
225
+ it "can set a value in the store with a timeout" do
226
+ redis.set(:foo, "bar", 1)
227
+ expect( redis.get :foo ).to eq "bar"
228
+ sleep 2
229
+ expect( redis.get :foo ).to be_nil
230
+ end
231
+
232
+ it "can get a value from the store" do
233
+ redis.set(:foo, bar: "baz")
234
+ expect( redis.get(:foo) ).to eq( {bar: "baz"} )
235
+ end
236
+
237
+ it "can remove a value from the store" do
238
+ redis.set(:foo, "bar")
239
+ redis.del(:foo)
240
+ expect( redis.get :foo ).to be_nil
241
+ end
242
+
243
+ end
244
+ ##
245
+
246
+ end
247
+
data/feature/gimme.rb ADDED
@@ -0,0 +1,91 @@
1
+ $: << "./lib" if __FILE__ == $0
2
+
3
+ require 'nebulous_stomp'
4
+ require 'yaml'
5
+ require "pry"
6
+
7
+
8
+ ##
9
+ # A little request-reponse server for the feature test
10
+ #
11
+ class Gimme
12
+
13
+ def initialize(configfile)
14
+ @config = load_config configfile
15
+ @target = init_nebulous
16
+ #@listener = NebulousStomp::Listener.new(@target)
17
+ @listener = NebulousStomp::Listener.new("/queue/featuretestreceive")
18
+ end
19
+
20
+ def run
21
+ @listener.consume_messages{|msg| reply msg}
22
+ end
23
+
24
+ def quit
25
+ @listener.quit
26
+ end
27
+
28
+ private
29
+
30
+ def load_config(file)
31
+ YAML.load(File.open file)
32
+ end
33
+
34
+ def init_nebulous
35
+ NebulousStomp.init @config[:init]
36
+ NebulousStomp.add_target("featuretest", @config[:target] )
37
+ end
38
+
39
+ def reply(msg)
40
+ queue, message =
41
+ case msg.verb
42
+ when "gimmesuccess"
43
+ msg.respond_with_success
44
+
45
+ when "gimmeerror"
46
+ msg.respond_with_error("the error you wanted")
47
+
48
+ when "gimmeprotocol"
49
+ msg.respond_with_protocol("foo", "bar", "baz")
50
+
51
+ when "gimmemessage"
52
+ msg.respond("weird message body")
53
+
54
+ when "gimmebigmessage"
55
+ body = big_body msg.params
56
+ msg.respond body
57
+
58
+ else fail "unknown verb #{msg.verb} in Gimme"
59
+ end
60
+
61
+ @listener.reply(queue, message)
62
+
63
+ rescue
64
+ puts "ERROR: #{$!}"
65
+ $!.backtrace.each{|e| puts e }
66
+ end
67
+
68
+ def big_body(params)
69
+ kb = params.to_f; fail "not a size" if kb == 0
70
+
71
+ body = "foo"
72
+ body << "Q" * (1024 * kb)
73
+ body << "bar"
74
+
75
+ body
76
+ end
77
+
78
+ end
79
+
80
+
81
+ if __FILE__ == $0
82
+
83
+ begin
84
+ g = Gimme.new('./feature/connection.yaml')
85
+ g.run
86
+ loop { sleep 5 }
87
+ ensure
88
+ g.quit
89
+ end
90
+
91
+ end