stomper 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.gitignore +5 -0
  2. data/{spec/spec.opts → .rspec} +0 -2
  3. data/Gemfile +4 -0
  4. data/LICENSE +201 -201
  5. data/README.md +130 -0
  6. data/Rakefile +5 -0
  7. data/examples/basic.rb +38 -0
  8. data/examples/events.rb +54 -0
  9. data/features/acking_messages.feature +147 -0
  10. data/features/disconnecting.feature +12 -0
  11. data/features/establish_connection.feature +44 -0
  12. data/features/protocol_version_negotiation.feature +61 -0
  13. data/features/receipts.feature +72 -0
  14. data/features/scopes.feature +32 -0
  15. data/features/secure_connections.feature +38 -0
  16. data/features/send_and_message.feature +28 -0
  17. data/features/steps/acking_messages_steps.rb +39 -0
  18. data/features/steps/disconnecting_steps.rb +8 -0
  19. data/features/steps/establish_connection_steps.rb +74 -0
  20. data/features/steps/frame_transmission_steps.rb +35 -0
  21. data/features/steps/protocol_version_negotiation_steps.rb +15 -0
  22. data/features/steps/receipts_steps.rb +79 -0
  23. data/features/steps/scopes_steps.rb +52 -0
  24. data/features/steps/secure_connections_steps.rb +41 -0
  25. data/features/steps/send_and_message_steps.rb +35 -0
  26. data/features/steps/subscribing_steps.rb +36 -0
  27. data/features/steps/threaded_receiver_steps.rb +8 -0
  28. data/features/steps/transactions_steps.rb +0 -0
  29. data/features/subscribing.feature +151 -0
  30. data/features/support/env.rb +11 -0
  31. data/features/support/header_helpers.rb +12 -0
  32. data/features/support/ssl/README +6 -0
  33. data/features/support/ssl/broker_cert.csr +17 -0
  34. data/features/support/ssl/broker_cert.pem +72 -0
  35. data/features/support/ssl/broker_key.pem +27 -0
  36. data/features/support/ssl/client_cert.csr +17 -0
  37. data/features/support/ssl/client_cert.pem +72 -0
  38. data/features/support/ssl/client_key.pem +27 -0
  39. data/features/support/ssl/demoCA/cacert.pem +17 -0
  40. data/features/support/ssl/demoCA/index.txt +2 -0
  41. data/features/support/ssl/demoCA/index.txt.attr +1 -0
  42. data/features/support/ssl/demoCA/index.txt.attr.old +1 -0
  43. data/features/support/ssl/demoCA/index.txt.old +1 -0
  44. data/features/support/ssl/demoCA/newcerts/01.pem +72 -0
  45. data/features/support/ssl/demoCA/newcerts/02.pem +72 -0
  46. data/features/support/ssl/demoCA/private/cakey.pem +17 -0
  47. data/features/support/ssl/demoCA/serial +1 -0
  48. data/features/support/ssl/demoCA/serial.old +1 -0
  49. data/features/support/test_stomp_server.rb +150 -0
  50. data/features/threaded_receiver.feature +11 -0
  51. data/features/transactions.feature +66 -0
  52. data/lib/stomper.rb +30 -20
  53. data/lib/stomper/connection.rb +442 -102
  54. data/lib/stomper/errors.rb +59 -0
  55. data/lib/stomper/extensions.rb +10 -0
  56. data/lib/stomper/extensions/common.rb +258 -0
  57. data/lib/stomper/extensions/events.rb +213 -0
  58. data/lib/stomper/extensions/heartbeat.rb +101 -0
  59. data/lib/stomper/extensions/scoping.rb +56 -0
  60. data/lib/stomper/frame.rb +54 -0
  61. data/lib/stomper/frame_serializer.rb +217 -0
  62. data/lib/stomper/headers.rb +15 -0
  63. data/lib/stomper/receipt_manager.rb +36 -0
  64. data/lib/stomper/receivers.rb +7 -0
  65. data/lib/stomper/receivers/threaded.rb +71 -0
  66. data/lib/stomper/scopes.rb +9 -0
  67. data/lib/stomper/scopes/header_scope.rb +49 -0
  68. data/lib/stomper/scopes/receipt_scope.rb +44 -0
  69. data/lib/stomper/scopes/transaction_scope.rb +109 -0
  70. data/lib/stomper/sockets.rb +66 -28
  71. data/lib/stomper/subscription_manager.rb +79 -0
  72. data/lib/stomper/support.rb +68 -0
  73. data/lib/stomper/support/1.8/frame_serializer.rb +53 -0
  74. data/lib/stomper/support/1.8/headers.rb +183 -0
  75. data/lib/stomper/support/1.9/frame_serializer.rb +64 -0
  76. data/lib/stomper/support/1.9/headers.rb +172 -0
  77. data/lib/stomper/support/ruby.rb +13 -0
  78. data/lib/stomper/uris.rb +49 -0
  79. data/lib/stomper/version.rb +7 -0
  80. data/spec/spec_helper.rb +13 -9
  81. data/spec/stomper/connection_spec.rb +712 -0
  82. data/spec/stomper/extensions/common_spec.rb +187 -0
  83. data/spec/stomper/extensions/events_spec.rb +78 -0
  84. data/spec/stomper/extensions/heartbeat_spec.rb +103 -0
  85. data/spec/stomper/extensions/scoping_spec.rb +21 -0
  86. data/spec/stomper/frame_serializer_1.8_spec.rb +318 -0
  87. data/spec/stomper/frame_serializer_spec.rb +316 -0
  88. data/spec/stomper/frame_spec.rb +36 -0
  89. data/spec/stomper/headers_spec.rb +224 -0
  90. data/spec/stomper/receipt_manager_spec.rb +91 -0
  91. data/spec/stomper/receivers/threaded_spec.rb +116 -0
  92. data/spec/stomper/scopes/header_scope_spec.rb +42 -0
  93. data/spec/stomper/scopes/receipt_scope_spec.rb +51 -0
  94. data/spec/stomper/scopes/transaction_scope_spec.rb +183 -0
  95. data/spec/stomper/sockets_spec.rb +113 -0
  96. data/spec/stomper/subscription_manager_spec.rb +107 -0
  97. data/spec/stomper/support_spec.rb +69 -0
  98. data/spec/stomper/uris_spec.rb +54 -0
  99. data/spec/stomper_spec.rb +9 -0
  100. data/spec/support/custom_argument_matchers.rb +57 -0
  101. data/spec/support/existential_frame_matchers.rb +19 -0
  102. data/spec/support/frame_header_matchers.rb +10 -0
  103. data/stomper.gemspec +30 -0
  104. metadata +272 -97
  105. data/AUTHORS +0 -21
  106. data/CHANGELOG +0 -20
  107. data/README.rdoc +0 -120
  108. data/lib/stomper/client.rb +0 -34
  109. data/lib/stomper/frame_reader.rb +0 -73
  110. data/lib/stomper/frame_writer.rb +0 -21
  111. data/lib/stomper/frames.rb +0 -39
  112. data/lib/stomper/frames/abort.rb +0 -10
  113. data/lib/stomper/frames/ack.rb +0 -25
  114. data/lib/stomper/frames/begin.rb +0 -11
  115. data/lib/stomper/frames/client_frame.rb +0 -89
  116. data/lib/stomper/frames/commit.rb +0 -10
  117. data/lib/stomper/frames/connect.rb +0 -10
  118. data/lib/stomper/frames/connected.rb +0 -30
  119. data/lib/stomper/frames/disconnect.rb +0 -10
  120. data/lib/stomper/frames/error.rb +0 -21
  121. data/lib/stomper/frames/message.rb +0 -48
  122. data/lib/stomper/frames/receipt.rb +0 -19
  123. data/lib/stomper/frames/send.rb +0 -10
  124. data/lib/stomper/frames/server_frame.rb +0 -38
  125. data/lib/stomper/frames/subscribe.rb +0 -42
  126. data/lib/stomper/frames/unsubscribe.rb +0 -19
  127. data/lib/stomper/open_uri_interface.rb +0 -41
  128. data/lib/stomper/receipt_handlers.rb +0 -23
  129. data/lib/stomper/receiptor.rb +0 -38
  130. data/lib/stomper/subscriber.rb +0 -76
  131. data/lib/stomper/subscription.rb +0 -128
  132. data/lib/stomper/subscriptions.rb +0 -95
  133. data/lib/stomper/threaded_receiver.rb +0 -59
  134. data/lib/stomper/transaction.rb +0 -185
  135. data/lib/stomper/transactor.rb +0 -50
  136. data/lib/stomper/uri.rb +0 -55
  137. data/spec/client_spec.rb +0 -29
  138. data/spec/connection_spec.rb +0 -22
  139. data/spec/frame_reader_spec.rb +0 -37
  140. data/spec/frame_writer_spec.rb +0 -27
  141. data/spec/frames/client_frame_spec.rb +0 -66
  142. data/spec/frames/indirect_frame_spec.rb +0 -45
  143. data/spec/frames/server_frame_spec.rb +0 -85
  144. data/spec/open_uri_interface_spec.rb +0 -132
  145. data/spec/receiptor_spec.rb +0 -35
  146. data/spec/shared_connection_examples.rb +0 -79
  147. data/spec/subscriber_spec.rb +0 -77
  148. data/spec/subscription_spec.rb +0 -157
  149. data/spec/subscriptions_spec.rb +0 -145
  150. data/spec/threaded_receiver_spec.rb +0 -33
  151. data/spec/transaction_spec.rb +0 -139
  152. data/spec/transactor_spec.rb +0 -46
@@ -1,35 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Stomper
4
- describe Receiptor do
5
- class MockConcreteReceipter
6
- include Stomper::Receiptor
7
- end
8
-
9
- before(:each) do
10
- @client = MockConcreteReceipter.new
11
- end
12
-
13
- describe "expected interface" do
14
- end
15
-
16
- describe "receipt handling" do
17
- before(:each) do
18
- @client.should_receive(:connected?).any_number_of_times.and_return(true)
19
- @client.should_receive(:send_without_receipt_handler).with('/queue/to','message body',a_kind_of(Hash)).at_least(:once).and_return(nil)
20
- end
21
-
22
- it "should dispatch a receipt when sent with a block" do
23
- @client.should_receive(:receive_without_receipt_dispatch).once.and_return(Stomper::Frames::Receipt.new({ :'receipt-id' => 'msg-0001' }, ''))
24
- receipt_processed = false
25
- @client.send('/queue/to', 'message body', :receipt => 'msg-0001') do |r|
26
- receipt_processed = true
27
- end
28
- @client.receipt_handlers.size.should == 1
29
- @client.receive_with_receipt_dispatch
30
- receipt_processed.should be_true
31
- @client.receipt_handlers.size.should == 0
32
- end
33
- end
34
- end
35
- end
@@ -1,79 +0,0 @@
1
- shared_examples_for "All Client Connections" do
2
- describe "connection initializers" do
3
- describe "from uri" do
4
- it "should accept the stomp:/// uri (no host specified)" do
5
- lambda { @connection.class.new("stomp:///") }.should_not raise_error
6
- end
7
-
8
- it "should accept a uri specifying just the host" do
9
- lambda { @connection.class.new("stomp://localhost/") }.should_not raise_error
10
- end
11
-
12
- it "should accept a uri specifying host and port" do
13
- lambda { @connection.class.new("stomp://localhost:61613/") }.should_not raise_error
14
- end
15
-
16
- it "should accept a uri specifying host, port and credentials" do
17
- lambda { @connection.class.new("stomp://test_user:s3cr3tz@localhost:61613/") }.should_not raise_error
18
- end
19
-
20
- it "should accept a uri specifying a secure connection" do
21
- lambda { @connection.class.new("stomp+ssl://localhost") }.should_not raise_error
22
- end
23
-
24
- it "should not accept a bogus URI" do
25
- lambda { @connection.class.new("stomp://localhost:garbage") }.should raise_error
26
- end
27
-
28
- end
29
- end
30
-
31
- describe "connection control" do
32
- it "should provide the appropriate all connection control and status methods" do
33
- @connection.should respond_to(:connect)
34
- @connection.should respond_to(:disconnect)
35
- @connection.should respond_to(:close)
36
- @connection.should respond_to(:connected?)
37
- end
38
-
39
- it "should not report it is connected after close is called" do
40
- @connection.connect
41
- @connection.connected?.should be_true
42
- @connection.close
43
- @connection.connected?.should be_false
44
- end
45
-
46
- it "should not report it is connected after disconnect is called" do
47
- @connection.connect
48
- @connection.connected?.should be_true
49
- @connection.disconnect
50
- @connection.connected?.should be_false
51
- end
52
- end
53
-
54
- describe "connection IO" do
55
- it "should provide methods for receiving frames and writing frames" do
56
- @connection.should respond_to(:transmit)
57
- @connection.should respond_to(:receive)
58
- end
59
- it "should transmit frames" do
60
- @connection.connect
61
- @frame = nil
62
- @connection.transmit(Stomper::Frames::Subscribe.new("/topic/test_topic"))
63
- @connection.transmit(Stomper::Frames::Send.new("/topic/test_topic", "hello"))
64
- @frame = @connection.receive while @frame.nil?
65
- @frame.should be_an_instance_of(Stomper::Frames::Message)
66
- @frame.body.should == "hello"
67
- end
68
- end
69
-
70
- describe "exception handling" do
71
- it "should close and propagate when an exception is raised on transmit" do
72
- pending
73
- end
74
-
75
- it "should close and propagate when an exception is raised on receive" do
76
- pending
77
- end
78
- end
79
- end
@@ -1,77 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Stomper
4
- describe Subscriber do
5
- class MockConcreteSubscriber
6
- include Stomper::Subscriber
7
- end
8
-
9
- before(:each) do
10
- @client = MockConcreteSubscriber.new
11
- end
12
-
13
- describe "expected interface" do
14
- it "should provide a subscribe method" do
15
- @client.should respond_to(:subscribe)
16
- @client.should_receive(:transmit).with(an_instance_of(Stomper::Frames::Subscribe)).twice.and_return(nil)
17
- @client.subscribe("/queue/to", {:additional => 'header'})
18
- @client.subscribe("/queue/to")
19
- end
20
- it "should provide an unsubscribe method" do
21
- @client.should respond_to(:unsubscribe)
22
- @client.should_receive(:transmit).with(an_instance_of(Stomper::Frames::Subscribe)).twice.and_return(nil)
23
- @client.subscribe("/queue/to", {:id => 'subscription-id'})
24
- @client.subscribe("/queue/to")
25
- @client.should_receive(:transmit).with(an_instance_of(Stomper::Frames::Unsubscribe)).twice.and_return(nil)
26
- @client.unsubscribe("/queue/to", 'subscription-id')
27
- @client.unsubscribe("/queue/to")
28
- end
29
- end
30
-
31
- describe "subscribing to queue" do
32
- before(:each) do
33
- @message_sent = Stomper::Frames::Message.new({:destination => "/queue/test"}, "test message")
34
- @client.should_receive(:connected?).any_number_of_times.and_return(true)
35
- @client.should_receive(:transmit).with(a_kind_of(Stomper::Frames::ClientFrame)).at_least(:once).and_return(nil)
36
- end
37
-
38
- it "should subscribe to a destination with a block" do
39
- @client.should_receive(:receive_without_message_dispatch).once.and_return(@message_sent)
40
- @message_received = nil
41
- @client.subscribe("/queue/test") do |msg|
42
- @message_received = msg
43
- end
44
- @client.receive_with_message_dispatch
45
- @message_received.should == @message_sent
46
- end
47
-
48
- it "should not unsubscribe from all destinations when a subscription id is provided" do
49
- @client.subscribe("/queue/test", { :id => 'subscription-1' }) do |msg|
50
- @message_received = msg
51
- end
52
- @client.subscribe("/queue/test") do |msg|
53
- @message_received = msg
54
- end
55
- @client.subscribe("/queue/test", :id => 'subscription-2') do |msg|
56
- @message_received = msg
57
- end
58
- @client.unsubscribe("/queue/test", 'subscription-1')
59
- @client.subscriptions.size.should == 2
60
- end
61
-
62
- it "should not unsubscribe from non-naive subscriptions when only a destination is supplied" do
63
- @client.subscribe("/queue/test", { :id => 'subscription-1' }) do |msg|
64
- @message_received = msg
65
- end
66
- @client.subscribe("/queue/test") do |msg|
67
- @message_received = msg
68
- end
69
- @client.subscribe("/queue/test") do |msg|
70
- @message_received = msg
71
- end
72
- @client.unsubscribe("/queue/test")
73
- @client.subscriptions.size.should == 1
74
- end
75
- end
76
- end
77
- end
@@ -1,157 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Stomper
4
- describe Subscription do
5
- before(:each) do
6
- @subscription = Subscription.new("/queue/test/1", 'subscription-1')
7
- end
8
-
9
- describe "basic expectations" do
10
- it "should be constructable from a parameter list, providing sensible defaults for omitted arguments" do
11
- @subscription.destination.should == "/queue/test/1"
12
- @subscription.ack.should == :auto
13
- @subscription.selector.should be_nil
14
-
15
- @subscription = Subscription.new("/queue/test/2", 'subscription-1', 'client', 'a > 3')
16
- @subscription.destination.should == "/queue/test/2"
17
- @subscription.ack.should == :client
18
- @subscription.selector.should == 'a > 3'
19
- end
20
-
21
- it "should be constructable from a hash, providing sensible defaults for omitted arguments" do
22
- @subscription = Subscription.new({ :destination => '/queue/test/2' })
23
- @subscription.destination.should == "/queue/test/2"
24
- @subscription.ack.should == :auto
25
-
26
- @subscription = Subscription.new({:destination => "/queue/test/3", :ack => :client, :id => 'subscription-3', :selector => 'b < 10' })
27
- @subscription.destination.should == "/queue/test/3"
28
- @subscription.ack.should == :client
29
- @subscription.id.should_not be_nil
30
- @subscription.selector.should == "b < 10"
31
- end
32
-
33
- it "should use the specified ID for subscribing and unsubscribing" do
34
- @subscription.id.should_not be_nil
35
- @subscription.id.should_not be_empty
36
- @subscription.id.should == @subscription.to_subscribe.id
37
- @subscription.id.should == @subscription.to_unsubscribe.id
38
- end
39
-
40
- it "should provide a meaningful ID when the ack mode is not auto" do
41
- @client_ack_subscription = Subscription.new("/queue/test/1",nil,'client')
42
- @client_ack_subscription.id.should_not be_nil
43
- end
44
-
45
- it "should provide a meaningful ID when the selector is specified" do
46
- @selector_subscription = Subscription.new("/queue/test/1",nil,'auto',"a > 3.5")
47
- @selector_subscription.id.should_not be_nil
48
- end
49
-
50
- it "should provide a SUBSCRIBE frame" do
51
- @subscription.should respond_to(:to_subscribe)
52
- @frame = @subscription.to_subscribe
53
- @frame.destination.should == "/queue/test/1"
54
- @frame.id.should_not be_nil
55
- @frame.ack.should == "auto"
56
- end
57
- end
58
-
59
- describe "message acceptance" do
60
- it "should accept a message without a subscription header only when the subscription is 'naive'" do
61
- @matching_subscription_1 = Subscription.new("/queue/test/1")
62
- @matching_subscription_2 = Subscription.new("/queue/test/1", nil, :auto)
63
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1'},"test message")
64
- @subscription.accepts?(@message).should be_false
65
- @matching_subscription_1.accepts?(@message).should be_true
66
- @matching_subscription_2.accepts?(@message).should be_true
67
- end
68
-
69
- it "should be able to accept messages by destination" do
70
- @non_matching_subscription = Subscription.new("/queue/test/another")
71
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @subscription.id},"test message")
72
- @subscription.accepts?(@message).should be_true
73
- @non_matching_subscription.accepts?(@message).should be_false
74
- end
75
-
76
- it "should accept messages only if the same destination and subscription" do
77
- @alternate_subscription = Subscription.new("/queue/test/1", 'subscription-2')
78
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @subscription.id},"test message")
79
- @subscription.accepts?(@message).should be_true
80
- @alternate_subscription.accepts?(@message).should be_false
81
- end
82
-
83
- it "should accept messages by the subscription id if the message has a subscription" do
84
- @non_matching_subscription = Subscription.new("/queue/test/1")
85
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @subscription.id},"test message")
86
- @subscription.accepts?(@message).should be_true
87
- @non_matching_subscription.accepts?(@message).should be_false
88
- end
89
-
90
- it "should not accept messages with the same destination when its ack mode is not 'auto' and no subscription header was specified" do
91
- @non_matching_subscription = Subscription.new("/queue/test/1", nil, 'client')
92
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1'},"test message")
93
- @non_matching_subscription.accepts?(@message).should be_false
94
- end
95
-
96
- it "should not accept messages with the same destination when it has a selector and no subscription header was specified" do
97
- @non_matching_subscription = Subscription.new("/queue/test/1", nil, 'auto', 'rating > 3.0')
98
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1'},"test message")
99
- @non_matching_subscription.accepts?(@message).should be_false
100
- end
101
-
102
- # Either insist that the #id method return something meaningful in non-trivial situations
103
- # as part of the expected behavior of the interface, or change this test!
104
- # We now insist on it, so this test is valid.
105
- it "should accept messages when it has a selector and the subscription header was specified" do
106
- @non_matching_subscription = Subscription.new("/queue/test/1", nil, 'auto', 'rating > 3.0')
107
- # To test this without insisting that the #id field be equivalent to the subscribe frame's header
108
- # go this way:
109
-
110
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @non_matching_subscription.id},"test message")
111
- @non_matching_subscription.accepts?(@message).should be_true
112
- end
113
- end
114
-
115
- describe "message delivery" do
116
- it "should call its callback when an applicable message arrives for its destination" do
117
- called_back = false
118
- @subscription_with_block = Subscription.new("/queue/test/1", 'subscription-test') do |msg|
119
- called_back = (msg == @message)
120
- end
121
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @subscription_with_block.id},"test message")
122
- @subscription_with_block.perform(@message)
123
- called_back.should be_true
124
- end
125
-
126
- it "should not call its callback when given a message for a different destination" do
127
- called_back = false
128
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1'},"test message")
129
- @subscription_with_block = Subscription.new("/queue/test/another", 'subscription-test') do |msg|
130
- called_back = (msg == @message)
131
- end
132
- @subscription_with_block.perform(@message)
133
- called_back.should be_false
134
- end
135
-
136
- it "should call its callback when a message arrives for its subscription id" do
137
- called_back = false
138
- @subscription_with_block = Subscription.new("/queue/test/another", 'subscription-test') do |msg|
139
- called_back = (msg == @message)
140
- end
141
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => @subscription_with_block.id},"test message")
142
- @subscription_with_block.perform(@message)
143
- called_back.should be_true
144
- end
145
-
146
- it "should not call its callback when a message arrives for its subscription id, even on the same " do
147
- called_back = false
148
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1', :subscription => 'subscription-not-test'},"test message")
149
- @subscription_with_block = Subscription.new("/queue/test/another", 'subscription-test') do |msg|
150
- called_back = (msg == @message)
151
- end
152
- @subscription_with_block.perform(@message)
153
- called_back.should be_false
154
- end
155
- end
156
- end
157
- end
@@ -1,145 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Stomper
4
- describe Subscriptions do
5
- before(:each) do
6
- @subscriptions = Subscriptions.new
7
- end
8
-
9
- describe "adding subscriptions" do
10
- it "should add a subscription given a subscription object" do
11
- @subscriptions << Subscription.new('/queue/test/3', 'subscription-3', nil, 'b < 10')
12
- @subscriptions.size.should == 1
13
- @subscriptions.first.destination.should == "/queue/test/3"
14
- @subscriptions.first.ack.should == :auto
15
- @subscriptions.first.selector.should == 'b < 10'
16
- @subscriptions.first.id.should_not be_nil
17
- end
18
- end
19
-
20
- describe "enumerable" do
21
- it "should provide an each method" do
22
- @subscriptions.should respond_to(:each)
23
- end
24
- it "should be enumerable" do
25
- @subscriptions.is_a?(Enumerable).should be_true
26
- end
27
- end
28
-
29
- describe "thread safe" do
30
- # How do you test this?
31
- it "should synchronize adding subscriptions" do
32
- @subscriptions << Subscription.new("/queue/test/1")
33
- @subscriptions << Subscription.new("/queue/test/2")
34
- @subscriptions << Subscription.new("/queue/test/3")
35
- Thread.new { sleep(0.1); @subscriptions << Subscription.new("/queue/test/4") }
36
- # In general, this next step should execute before the thread has a chance to
37
- # but the sleep in the map should mean that our thread gets woken up before
38
- # map finishes. However, destinations should NEVER contain "/queue/test/4"
39
- # because map should be synchronized.
40
- destinations = @subscriptions.map { |sub| sleep(0.1); sub.destination }
41
- destinations.size.should == 3
42
- destinations.should == ['/queue/test/1', '/queue/test/2', '/queue/test/3']
43
- @subscriptions.size.should == 4
44
- @subscriptions.last.destination.should == "/queue/test/4"
45
- end
46
-
47
- it "should synchronize removing subscriptions" do
48
- @subscriptions << Subscription.new("/queue/test/1")
49
- @subscriptions << Subscription.new("/queue/test/2")
50
- @subscriptions << Subscription.new("/queue/test/3")
51
- sync_thread = Thread.new { sleep(0.1); @subscriptions.remove("/queue/test/1") }
52
- destinations = @subscriptions.map { |sub| sleep(0.1); sub.destination }
53
- destinations.size.should == 3
54
- destinations.should == ['/queue/test/1', '/queue/test/2', '/queue/test/3']
55
- sync_thread.join
56
- @subscriptions.size.should == 2
57
- @subscriptions.first.destination.should == "/queue/test/2"
58
- end
59
-
60
- end
61
-
62
- describe "message delivery" do
63
- it "should deliver messages to matching subscriptions" do
64
- received_1 = false
65
- received_2 = false
66
- received_3 = false
67
- @subscriptions << Subscription.new("/queue/test/1") { |msg| received_1 = true }
68
- @subscriptions << Subscription.new("/queue/test/1", 'subscription-2') { |msg| received_2 = true }
69
- @subscriptions << Subscription.new("/queue/test/2") { |msg| received_3 = true }
70
- @message = Stomper::Frames::Message.new({:destination => '/queue/test/1'},"test message")
71
- @subscriptions.perform(@message)
72
- received_1.should be_true
73
- received_2.should be_false
74
- received_3.should be_false
75
- end
76
- end
77
-
78
- describe "unsubscribing" do
79
- it "should remove all naive subscriptions when unsubscribing with a string destination" do
80
- @removed_subscriptions = [Subscription.new("/queue/test/1"), Subscription.new("/queue/test/1")]
81
- @removed_subscriptions.each { |sub| @subscriptions << sub }
82
- @subscriptions << Subscription.new("/queue/test/2")
83
- @subscriptions << Subscription.new("/queue/test/1", 'subscription-4')
84
- @to_remove = @subscriptions.remove("/queue/test/1")
85
- @subscriptions.size.should == 2
86
- @subscriptions.should_not include(@removed_subscriptions.first)
87
- @subscriptions.should_not include(@removed_subscriptions.last)
88
- @to_remove.size.should == 2
89
- @to_remove.should include(@removed_subscriptions.first)
90
- @to_remove.should include(@removed_subscriptions.last)
91
- end
92
- it "should remove all subscriptions that accept messages for a supplied subscription ID" do
93
- @removed_subscription = Subscription.new("/queue/test/1", 'subscription-4')
94
- @subscriptions << Subscription.new("/queue/test/1")
95
- @subscriptions << Subscription.new("/queue/test/1")
96
- @subscriptions << Subscription.new("/queue/test/2")
97
- @subscriptions << @removed_subscription
98
- @to_remove = @subscriptions.remove(nil, @removed_subscription.id)
99
- @subscriptions.size.should == 3
100
- @subscriptions.should_not include(@removed_subscription)
101
- @to_remove.size.should == 1
102
- @to_remove.should include(@removed_subscription)
103
- end
104
- it "should remove subscriptions as expected when parameter is a hash specifying the ID" do
105
- @removed_subscription = Subscription.new("/queue/test/1", 'subscription-4')
106
- @subscriptions << Subscription.new("/queue/test/1")
107
- @subscriptions << Subscription.new("/queue/test/1")
108
- @subscriptions << Subscription.new("/queue/test/2")
109
- @subscriptions << @removed_subscription
110
- @to_remove = @subscriptions.remove({ :id => @removed_subscription.id })
111
- @subscriptions.size.should == 3
112
- @subscriptions.should_not include(@removed_subscription)
113
- @to_remove.size.should == 1
114
- @to_remove.should include(@removed_subscription)
115
- end
116
- it "should remove subscriptions as expected when parameter is a hash specifying the destination" do
117
- @removed_subscriptions = [Subscription.new("/queue/test/1"), Subscription.new("/queue/test/1")]
118
- @removed_subscriptions.each { |sub| @subscriptions << sub }
119
- @subscriptions << Subscription.new("/queue/test/2")
120
- @subscriptions << Subscription.new("/queue/test/1", 'subscription-4')
121
- @to_remove = @subscriptions.remove( { :destination => "/queue/test/1" })
122
- @subscriptions.size.should == 2
123
- @subscriptions.should_not include(@removed_subscriptions.first)
124
- @subscriptions.should_not include(@removed_subscriptions.last)
125
- @to_remove.size.should == 2
126
- @to_remove.should include(@removed_subscriptions.first)
127
- @to_remove.should include(@removed_subscriptions.last)
128
- end
129
- it "should remove subscriptions as expected when parameter is a Subscription" do
130
- @removed_subscription = Subscription.new("/queue/test/1", 'subscription-4')
131
- @subscriptions << Subscription.new("/queue/test/1")
132
- @subscriptions << Subscription.new("/queue/test/1")
133
- @subscriptions << Subscription.new("/queue/test/2")
134
- @subscriptions << @removed_subscription
135
- @to_remove = @subscriptions.remove(@removed_subscription)
136
- @to_remove.size.should == 1
137
- @to_remove.should include(@removed_subscription)
138
- @to_remove = @subscriptions.remove(Subscription.new("/queue/test/1", nil, :client))
139
- @to_remove.should be_empty
140
- @subscriptions.size.should == 3
141
- @subscriptions.should_not include(@removed_subscription)
142
- end
143
- end
144
- end
145
- end