nebulous_stomp 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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