stomper 1.0.0 → 2.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 (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