stomper 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/examples/events.rb +4 -0
- data/features/acking_messages.feature +1 -0
- data/features/receipts.feature +9 -0
- data/features/scopes.feature +1 -0
- data/features/send_and_message.feature +2 -0
- data/features/steps/acking_messages_steps.rb +2 -0
- data/features/steps/establish_connection_steps.rb +7 -4
- data/features/steps/frame_transmission_steps.rb +6 -1
- data/features/steps/receipts_steps.rb +2 -21
- data/features/steps/secure_connections_steps.rb +2 -0
- data/features/subscribing.feature +10 -1
- data/features/support/test_stomp_server.rb +21 -7
- data/features/transactions.feature +3 -0
- data/lib/stomper/connection.rb +52 -47
- data/lib/stomper/extensions/common.rb +3 -7
- data/lib/stomper/headers.rb +7 -0
- data/lib/stomper/receivers/threaded.rb +13 -9
- data/lib/stomper/subscription_manager.rb +43 -41
- data/lib/stomper/version.rb +1 -1
- data/spec/stomper/connection_spec.rb +31 -2
- data/spec/stomper/extensions/common_spec.rb +3 -5
- data/spec/stomper/headers_spec.rb +14 -7
- data/spec/stomper/scopes/header_scope_spec.rb +1 -1
- data/spec/stomper/scopes/receipt_scope_spec.rb +1 -1
- data/spec/stomper/scopes/transaction_scope_spec.rb +1 -1
- data/spec/stomper/subscription_manager_spec.rb +38 -20
- metadata +3 -3
data/.gitignore
CHANGED
data/examples/events.rb
CHANGED
@@ -31,6 +31,10 @@ client.on_connection_closed do |con|
|
|
31
31
|
$stdout.puts "Connection has been closed"
|
32
32
|
end
|
33
33
|
|
34
|
+
client.on_connection_terminated do |con|
|
35
|
+
$stdout.puts "Connection closed unexpectedly"
|
36
|
+
end
|
37
|
+
|
34
38
|
client.send("/queue/stomper/test", "hello world")
|
35
39
|
client.disconnect
|
36
40
|
|
@@ -10,6 +10,7 @@ Feature: Acking messages
|
|
10
10
|
| message-id | m-1234 |
|
11
11
|
| subscription | s-5678 |
|
12
12
|
| destination | /queue/testing |
|
13
|
+
#When the client waits for 1 "MESSAGE" frame
|
13
14
|
When the client acks the last MESSAGE
|
14
15
|
And the frame exchange is completed
|
15
16
|
Then the broker should have received an "ACK" frame with headers
|
data/features/receipts.feature
CHANGED
@@ -6,12 +6,14 @@ Feature: Receipts
|
|
6
6
|
Scenario: RECEIPT on SEND
|
7
7
|
Given a 1.1 connection between client and broker
|
8
8
|
When the client sends a receipted message "test message" to "/queue/test"
|
9
|
+
And the client waits for 1 "RECEIPT" frame
|
9
10
|
And the frame exchange is completed
|
10
11
|
Then the client should have received a receipt for the last "SEND"
|
11
12
|
|
12
13
|
Scenario: RECEIPT on SUBSCRIBE
|
13
14
|
Given a 1.1 connection between client and broker
|
14
15
|
When the client subscribes to "/queue/test" with a receipt
|
16
|
+
And the client waits for 1 "RECEIPT" frame
|
15
17
|
And the frame exchange is completed
|
16
18
|
Then the client should have received a receipt for the last "SUBSCRIBE"
|
17
19
|
|
@@ -21,42 +23,49 @@ Feature: Receipts
|
|
21
23
|
| header-name | header-value |
|
22
24
|
| id | s-1234 |
|
23
25
|
When the client unsubscribes from "s-1234" with a receipt
|
26
|
+
And the client waits for 1 "RECEIPT" frame
|
24
27
|
And the frame exchange is completed
|
25
28
|
Then the client should have received a receipt for the last "UNSUBSCRIBE"
|
26
29
|
|
27
30
|
Scenario: RECEIPT on BEGIN
|
28
31
|
Given a 1.1 connection between client and broker
|
29
32
|
When the client begins transaction "t-1234" with a receipt
|
33
|
+
And the client waits for 1 "RECEIPT" frame
|
30
34
|
And the frame exchange is completed
|
31
35
|
Then the client should have received a receipt for the last "BEGIN"
|
32
36
|
|
33
37
|
Scenario: RECEIPT on COMMIT
|
34
38
|
Given a 1.1 connection between client and broker
|
35
39
|
When the client commits transaction "t-1234" with a receipt
|
40
|
+
And the client waits for 1 "RECEIPT" frame
|
36
41
|
And the frame exchange is completed
|
37
42
|
Then the client should have received a receipt for the last "COMMIT"
|
38
43
|
|
39
44
|
Scenario: RECEIPT on ABORT
|
40
45
|
Given a 1.1 connection between client and broker
|
41
46
|
When the client aborts transaction "t-1234" with a receipt
|
47
|
+
And the client waits for 1 "RECEIPT" frame
|
42
48
|
And the frame exchange is completed
|
43
49
|
Then the client should have received a receipt for the last "ABORT"
|
44
50
|
|
45
51
|
Scenario: RECEIPT on ACK
|
46
52
|
Given a 1.1 connection between client and broker
|
47
53
|
When the client acks message "m-1234" from "s-5678" with a receipt
|
54
|
+
And the client waits for 1 "RECEIPT" frame
|
48
55
|
And the frame exchange is completed
|
49
56
|
Then the client should have received a receipt for the last "ACK"
|
50
57
|
|
51
58
|
Scenario: RECEIPT on NACK
|
52
59
|
Given a 1.1 connection between client and broker
|
53
60
|
When the client nacks message "m-1234" from "s-5678" with a receipt
|
61
|
+
And the client waits for 1 "RECEIPT" frame
|
54
62
|
And the frame exchange is completed
|
55
63
|
Then the client should have received a receipt for the last "NACK"
|
56
64
|
|
57
65
|
Scenario: RECEIPT on DISCONNECT
|
58
66
|
Given a 1.1 connection between client and broker
|
59
67
|
When the client disconnects with a receipt
|
68
|
+
And the client waits for 1 "RECEIPT" frame
|
60
69
|
And the frame exchange is completed without client disconnect
|
61
70
|
Then the client should have received a receipt for the last "DISCONNECT"
|
62
71
|
|
data/features/scopes.feature
CHANGED
@@ -15,6 +15,7 @@ Feature: Scopes
|
|
15
15
|
| header-name | header-value |
|
16
16
|
| id | s-9012 |
|
17
17
|
| ack | client-individual |
|
18
|
+
And the frame exchange is completed
|
18
19
|
Then the broker should have received an "ACK" frame with headers
|
19
20
|
| header-name | header-value |
|
20
21
|
| x-my-header | some value |
|
@@ -7,6 +7,7 @@ Feature: Send and message
|
|
7
7
|
Given a 1.1 connection between client and broker
|
8
8
|
And the client subscribes to <destination>
|
9
9
|
When the client sends a <content-type> <body> to <destination>
|
10
|
+
And the client waits for 1 "MESSAGE" frame
|
10
11
|
And the frame exchange is completed
|
11
12
|
Then the client should have received a <content-type> message of <body>
|
12
13
|
|
@@ -19,6 +20,7 @@ Feature: Send and message
|
|
19
20
|
Given a 1.1 connection between client and broker
|
20
21
|
And the client subscribes to <destination>
|
21
22
|
When the client sends a <body> encoded as <encoding> to <destination>
|
23
|
+
And the client waits for 1 "MESSAGE" frame
|
22
24
|
And the frame exchange is completed
|
23
25
|
Then the client should have received a <content-type> message of <body> encoded as <final encoding>
|
24
26
|
|
@@ -3,6 +3,7 @@ When /^the client acks a message by ID "([^"]*)"$/ do |message_id|
|
|
3
3
|
end
|
4
4
|
|
5
5
|
When /^the client acks the last MESSAGE$/ do
|
6
|
+
When("the client waits for 1 \"MESSAGE\" frame")
|
6
7
|
@connection.ack @received_frames.select { |f| f.command == "MESSAGE" }.last
|
7
8
|
end
|
8
9
|
|
@@ -15,6 +16,7 @@ When /^the client acks a message by ID "([^"]*)" and subscription "([^"]*)"$/ do
|
|
15
16
|
end
|
16
17
|
|
17
18
|
When /^the client nacks the last MESSAGE$/ do
|
19
|
+
When("the client waits for 1 \"MESSAGE\" frame")
|
18
20
|
@connection.nack @received_frames.select { |f| f.command == "MESSAGE" }.last
|
19
21
|
end
|
20
22
|
|
@@ -1,6 +1,9 @@
|
|
1
1
|
After do |s|
|
2
|
-
|
3
|
-
|
2
|
+
begin
|
3
|
+
@connection && @connection.stop
|
4
|
+
@broker && @broker.force_stop
|
5
|
+
rescue Exception => ex
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
6
9
|
Given /^a (\d+\.\d+)?\s*connection between client and broker$/ do |version|
|
@@ -12,10 +15,10 @@ Given /^a (\d+\.\d+)?\s*connection between client and broker$/ do |version|
|
|
12
15
|
@connection = Stomper::Connection.new(@broker_uri)
|
13
16
|
@received_frames = []
|
14
17
|
@sent_frames = []
|
15
|
-
@connection.before_transmitting do |
|
18
|
+
@connection.before_transmitting do |f, c|
|
16
19
|
@sent_frames << f
|
17
20
|
end
|
18
|
-
@connection.after_receiving do |
|
21
|
+
@connection.after_receiving do |f, c|
|
19
22
|
@received_frames << f
|
20
23
|
end
|
21
24
|
@connection.start
|
@@ -32,4 +32,9 @@ end
|
|
32
32
|
When /^the frame exchange is completed without client disconnect$/ do
|
33
33
|
@connection.stop
|
34
34
|
@broker.stop
|
35
|
-
end
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^the client waits for (\d+) "([^"]*)" frames?$/ do |count, command|
|
38
|
+
count = count.to_i
|
39
|
+
Thread.pass while @received_frames.select { |f| f.command == command }.size < count
|
40
|
+
end
|
@@ -1,75 +1,56 @@
|
|
1
1
|
When /^the client sends a receipted message "([^"]*)" to "([^"]*)"$/ do |body, destination|
|
2
|
-
@receipts_received ||= {}
|
3
2
|
@connection.send(destination, body) do |r|
|
4
|
-
@receipts_received[r[:'receipt-id']] = r
|
5
3
|
end
|
6
4
|
end
|
7
5
|
|
8
6
|
Then /^the client should have received a receipt for the last "([^"]*)"$/ do |command|
|
9
7
|
fr = @sent_frames.select { |f| f.command == command }.last
|
10
|
-
|
8
|
+
r = @received_frames.select { |f| f.command == 'RECEIPT' && f[:'receipt-id'] == fr[:receipt] }.last
|
9
|
+
r.should_not be_nil
|
11
10
|
end
|
12
11
|
|
13
12
|
When /^the client subscribes to "([^"]*)" with a receipt$/ do |destination|
|
14
|
-
@receipts_received ||= {}
|
15
13
|
@connection.with_receipt do |r|
|
16
|
-
@receipts_received[r[:'receipt-id']] = r
|
17
14
|
end.subscribe(destination)
|
18
15
|
end
|
19
16
|
|
20
17
|
When /^the client unsubscribes from "([^"]*)" with a receipt$/ do |subscription|
|
21
|
-
@receipts_received ||= {}
|
22
18
|
@connection.with_receipt do |r|
|
23
|
-
@receipts_received[r[:'receipt-id']] = r
|
24
19
|
end.unsubscribe(subscription)
|
25
20
|
end
|
26
21
|
|
27
22
|
When /^the client begins transaction "([^"]*)" with a receipt$/ do |tx|
|
28
|
-
@receipts_received ||= {}
|
29
23
|
@connection.with_receipt do |r|
|
30
|
-
@receipts_received[r[:'receipt-id']] = r
|
31
24
|
end.begin(tx)
|
32
25
|
end
|
33
26
|
|
34
27
|
When /^the client aborts transaction "([^"]*)" with a receipt$/ do |tx|
|
35
|
-
@receipts_received ||= {}
|
36
28
|
@connection.with_receipt do |r|
|
37
|
-
@receipts_received[r[:'receipt-id']] = r
|
38
29
|
end.abort(tx)
|
39
30
|
end
|
40
31
|
|
41
32
|
When /^the client commits transaction "([^"]*)" with a receipt$/ do |tx|
|
42
|
-
@receipts_received ||= {}
|
43
33
|
@connection.with_receipt do |r|
|
44
|
-
@receipts_received[r[:'receipt-id']] = r
|
45
34
|
end.commit(tx)
|
46
35
|
end
|
47
36
|
|
48
37
|
When /^the client acks message "([^"]*)" from "([^"]*)" with a receipt$/ do |m_id, sub_id|
|
49
|
-
@receipts_received ||= {}
|
50
38
|
@connection.with_receipt do |r|
|
51
|
-
@receipts_received[r[:'receipt-id']] = r
|
52
39
|
end.ack(m_id, sub_id)
|
53
40
|
end
|
54
41
|
|
55
42
|
When /^the client nacks message "([^"]*)" from "([^"]*)" with a receipt$/ do |m_id, sub_id|
|
56
|
-
@receipts_received ||= {}
|
57
43
|
@connection.with_receipt do |r|
|
58
|
-
@receipts_received[r[:'receipt-id']] = r
|
59
44
|
end.nack(m_id, sub_id)
|
60
45
|
end
|
61
46
|
|
62
47
|
When /^the client disconnects with a receipt$/ do
|
63
|
-
@receipts_received ||= {}
|
64
48
|
@connection.with_receipt do |r|
|
65
|
-
@receipts_received[r[:'receipt-id']] = r
|
66
49
|
end.disconnect
|
67
50
|
end
|
68
51
|
|
69
52
|
When /^the client connects with a receipt$/ do
|
70
|
-
@receipts_received ||= {}
|
71
53
|
@connection.with_receipt do |r|
|
72
|
-
@receipts_received[r[:'receipt-id']] = r
|
73
54
|
end.transmit(Stomper::Frame.new('CONNECT'))
|
74
55
|
end
|
75
56
|
|
@@ -25,6 +25,8 @@ end
|
|
25
25
|
|
26
26
|
Then /^connecting should raise an openssl error$/ do
|
27
27
|
lambda { @connection.connect }.should raise_error(OpenSSL::SSL::SSLError)
|
28
|
+
# It is problematic that this is needed...
|
29
|
+
@broker.stop
|
28
30
|
end
|
29
31
|
|
30
32
|
When /^an SSL post connection check is not performed$/ do
|
@@ -19,6 +19,7 @@ Feature: Subscribing
|
|
19
19
|
| message-id | m-1235 |
|
20
20
|
| subscription | s-5678 |
|
21
21
|
| destination | /queue/testing |
|
22
|
+
And the client waits for 2 "MESSAGE" frames
|
22
23
|
And the frame exchange is completed
|
23
24
|
Then the client should have received a "MESSAGE" frame with headers
|
24
25
|
| header-name | header-value |
|
@@ -50,6 +51,7 @@ Feature: Subscribing
|
|
50
51
|
| header-name | header-value |
|
51
52
|
| message-id | m-1236 |
|
52
53
|
| destination | /queue/testing |
|
54
|
+
And the client waits for 3 "MESSAGE" frame
|
53
55
|
And the frame exchange is completed
|
54
56
|
Then the client should have received a "MESSAGE" frame with headers
|
55
57
|
| header-name | header-value |
|
@@ -73,6 +75,7 @@ Feature: Subscribing
|
|
73
75
|
| message-id | m-1234 |
|
74
76
|
| destination | /queue/testing |
|
75
77
|
| subscription | s-9999 |
|
78
|
+
And the client waits for 1 "MESSAGE" frame
|
76
79
|
And the frame exchange is completed
|
77
80
|
Then the client should have received a "MESSAGE" frame with headers
|
78
81
|
| header-name | header-value |
|
@@ -91,13 +94,15 @@ Feature: Subscribing
|
|
91
94
|
| message-id | m-1234 |
|
92
95
|
| destination | /queue/testing |
|
93
96
|
| subscription | s-5678 |
|
97
|
+
And the client waits for 1 "MESSAGE" frame
|
94
98
|
And the client unsubscribes by ID
|
95
99
|
And the broker sends a "MESSAGE" frame with headers
|
96
100
|
| header-name | header-value |
|
97
101
|
| message-id | m-1235 |
|
98
102
|
| destination | /queue/testing |
|
99
103
|
| subscription | s-5678 |
|
100
|
-
And the client
|
104
|
+
And the client waits for 1 "MESSAGE" frame
|
105
|
+
And the frame exchange is completed
|
101
106
|
Then the default subscription callback should have been triggered 1 time
|
102
107
|
|
103
108
|
Scenario: No callbacks after unsubscribing by frame
|
@@ -110,12 +115,14 @@ Feature: Subscribing
|
|
110
115
|
| message-id | m-1234 |
|
111
116
|
| destination | /queue/testing |
|
112
117
|
| subscription | s-5678 |
|
118
|
+
And the client waits for 1 "MESSAGE" frame
|
113
119
|
And the client unsubscribes by frame
|
114
120
|
And the broker sends a "MESSAGE" frame with headers
|
115
121
|
| header-name | header-value |
|
116
122
|
| message-id | m-1235 |
|
117
123
|
| destination | /queue/testing |
|
118
124
|
| subscription | s-5678 |
|
125
|
+
And the client waits for 1 "MESSAGE" frame
|
119
126
|
And the frame exchange is completed
|
120
127
|
Then the default subscription callback should have been triggered 1 time
|
121
128
|
|
@@ -136,11 +143,13 @@ Feature: Subscribing
|
|
136
143
|
| header-name | header-value |
|
137
144
|
| message-id | m-1235 |
|
138
145
|
| destination | /queue/testing |
|
146
|
+
And the client waits for 2 "MESSAGE" frames
|
139
147
|
And the client unsubscribes from destination "/queue/testing"
|
140
148
|
And the broker sends a "MESSAGE" frame with headers
|
141
149
|
| header-name | header-value |
|
142
150
|
| message-id | m-1235 |
|
143
151
|
| destination | /queue/testing |
|
152
|
+
And the client waits for 1 "MESSAGE" frame
|
144
153
|
And the frame exchange is completed
|
145
154
|
Then the default subscription callback should have been triggered 3 times
|
146
155
|
And the broker should have received an "UNSUBSCRIBE" frame with headers
|
@@ -1,10 +1,15 @@
|
|
1
1
|
class TestStompServer
|
2
|
+
class StopThread < StandardError; end
|
3
|
+
|
2
4
|
attr_accessor :session_class
|
3
5
|
attr_reader :session
|
4
6
|
|
5
7
|
def initialize(version=nil)
|
6
8
|
@port = 61613
|
7
|
-
|
9
|
+
begin
|
10
|
+
@socket = TCPServer.new(@port)
|
11
|
+
rescue Exception => ex
|
12
|
+
end
|
8
13
|
@session = nil
|
9
14
|
@version = version
|
10
15
|
@session_class = StompSession
|
@@ -23,14 +28,14 @@ class TestStompServer
|
|
23
28
|
def stop
|
24
29
|
@session.stop if @session
|
25
30
|
@socket.close rescue nil
|
26
|
-
@listener.
|
31
|
+
@listener.raise(StopThread.new)
|
27
32
|
@listener.join rescue nil
|
28
33
|
end
|
29
34
|
|
30
35
|
def force_stop
|
31
36
|
@session.force_stop if @session
|
32
37
|
@socket.close rescue nil
|
33
|
-
@listener.
|
38
|
+
@listener.raise(StopThread.new)
|
34
39
|
@listener.join rescue nil
|
35
40
|
end
|
36
41
|
|
@@ -54,10 +59,11 @@ class TestStompServer
|
|
54
59
|
connect_to_client(headers)
|
55
60
|
@serializer.extend_for_protocol('1.1') if version == '1.1'
|
56
61
|
@receive_thread = Thread.new do
|
57
|
-
while
|
62
|
+
while true
|
58
63
|
begin
|
59
64
|
read_frame
|
60
65
|
rescue Exception => ex
|
66
|
+
break
|
61
67
|
end
|
62
68
|
end
|
63
69
|
end
|
@@ -70,6 +76,7 @@ class TestStompServer
|
|
70
76
|
|
71
77
|
def force_stop
|
72
78
|
@running = false
|
79
|
+
@receive_thread.raise(StopThread.new)
|
73
80
|
@client_socket.close rescue nil
|
74
81
|
@receive_thread.join rescue nil
|
75
82
|
end
|
@@ -112,8 +119,11 @@ class TestStompServer
|
|
112
119
|
|
113
120
|
def send_frame cmd, headers={}, body=nil
|
114
121
|
frame = cmd.is_a?(Stomper::Frame) ? cmd : Stomper::Frame.new(cmd, headers, body)
|
115
|
-
|
116
|
-
@
|
122
|
+
begin
|
123
|
+
@serializer.write_frame(frame).tap do |f|
|
124
|
+
@sent_frames << f
|
125
|
+
end
|
126
|
+
rescue Exception => ex
|
117
127
|
end
|
118
128
|
end
|
119
129
|
end
|
@@ -135,7 +145,11 @@ class TestSSLStompServer < TestStompServer
|
|
135
145
|
|
136
146
|
def initialize(version=nil, certs=:default)
|
137
147
|
@port = 61612
|
138
|
-
|
148
|
+
begin
|
149
|
+
@tcp_socket = TCPServer.new(@port)
|
150
|
+
rescue Exception => ex
|
151
|
+
retry
|
152
|
+
end
|
139
153
|
@ssl_context = OpenSSL::SSL::SSLContext.new
|
140
154
|
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
141
155
|
cert_files = SSL_CERT_FILES[certs]
|
@@ -10,6 +10,7 @@ Feature: Transactions
|
|
10
10
|
And the client acks a message by ID "m-1234" and subscription "s-5678" within the scope
|
11
11
|
And the client nacks a message by ID "m-9012" and subscription "s-5678" within the scope
|
12
12
|
And the client aborts the transaction scope
|
13
|
+
And the frame exchange is completed
|
13
14
|
Then the broker should have received a "BEGIN" frame with headers
|
14
15
|
| header-name | header-value |
|
15
16
|
| transaction | t-0001 |
|
@@ -30,6 +31,7 @@ Feature: Transactions
|
|
30
31
|
Scenario: Applying a transaction to a successful block
|
31
32
|
Given a 1.1 connection between client and broker
|
32
33
|
When the client executes a successful transaction block named "t-0002"
|
34
|
+
And the frame exchange is completed
|
33
35
|
Then the broker should have received a "BEGIN" frame with headers
|
34
36
|
| header-name | header-value |
|
35
37
|
| transaction | t-0002 |
|
@@ -49,6 +51,7 @@ Feature: Transactions
|
|
49
51
|
Scenario: Applying a transaction to an unsuccessful block
|
50
52
|
Given a 1.1 connection between client and broker
|
51
53
|
When the client executes an unsuccessful transaction block named "t-0002"
|
54
|
+
And the frame exchange is completed
|
52
55
|
Then the broker should have received a "BEGIN" frame with headers
|
53
56
|
| header-name | header-value |
|
54
57
|
| transaction | t-0002 |
|
data/lib/stomper/connection.rb
CHANGED
@@ -170,11 +170,11 @@ class Stomper::Connection
|
|
170
170
|
@receipt_manager = ::Stomper::ReceiptManager.new(self)
|
171
171
|
@connecting = false
|
172
172
|
@disconnecting = false
|
173
|
+
@disconnected = false
|
174
|
+
@socket_mutex = ::Mutex.new
|
173
175
|
|
174
176
|
on_connected do |cf, con|
|
175
177
|
unless connected?
|
176
|
-
@connecting = false
|
177
|
-
@disconnecting = false
|
178
178
|
@version = (cf[:version].nil?||cf[:version].empty?) ? '1.0' : cf[:version]
|
179
179
|
unless @versions.include?(@version)
|
180
180
|
close
|
@@ -192,9 +192,12 @@ class Stomper::Connection
|
|
192
192
|
extend_for_protocol
|
193
193
|
end
|
194
194
|
end
|
195
|
-
|
196
|
-
|
195
|
+
|
196
|
+
before_disconnect do |df, con|
|
197
197
|
@disconnecting = true
|
198
|
+
end
|
199
|
+
on_disconnect do |df, con|
|
200
|
+
@disconnected = true
|
198
201
|
close unless df[:receipt]
|
199
202
|
end
|
200
203
|
end
|
@@ -269,28 +272,34 @@ class Stomper::Connection
|
|
269
272
|
# connection has been established and you're ready to go, otherwise the
|
270
273
|
# socket will be closed and an error will be raised.
|
271
274
|
def connect(headers={})
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
@
|
286
|
-
|
287
|
-
|
288
|
-
|
275
|
+
#@socket_mutex.synchronize do
|
276
|
+
unless @connected
|
277
|
+
@socket = @uri.create_socket(@ssl)
|
278
|
+
@serializer = ::Stomper::FrameSerializer.new(@socket)
|
279
|
+
m_headers = {
|
280
|
+
:'accept-version' => @versions.join(','),
|
281
|
+
:host => @host,
|
282
|
+
:'heart-beat' => @heartbeats.join(','),
|
283
|
+
:login => @login,
|
284
|
+
:passcode => @passcode
|
285
|
+
}
|
286
|
+
@disconnecting = false
|
287
|
+
@disconnected = false
|
288
|
+
@connecting = true
|
289
|
+
transmit create_frame('CONNECT', headers, m_headers)
|
290
|
+
receive.tap do |f|
|
291
|
+
if f.command == 'CONNECTED'
|
292
|
+
@connected_frame = f
|
293
|
+
@connected = true
|
294
|
+
@connecting = false
|
295
|
+
trigger_event(:on_connection_established, self)
|
296
|
+
else
|
297
|
+
close
|
298
|
+
raise ::Stomper::Errors::ConnectFailedError, 'broker did not send CONNECTED frame'
|
299
|
+
end
|
300
|
+
end
|
289
301
|
end
|
290
|
-
end
|
291
|
-
@connected = true
|
292
|
-
trigger_event(:on_connection_established, self) if @connected
|
293
|
-
@connected_frame
|
302
|
+
#end
|
294
303
|
end
|
295
304
|
alias :open :connect
|
296
305
|
|
@@ -362,17 +371,21 @@ class Stomper::Connection
|
|
362
371
|
# @see Stomper::Extensions::Events#on_connection_terminated
|
363
372
|
# @param [true,false] fire_terminated (false) If true, trigger
|
364
373
|
# {Stomper::Extensions::Events#on_connection_terminated}
|
365
|
-
def close
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
374
|
+
def close
|
375
|
+
#@socket_mutex.synchronize do
|
376
|
+
if @connected
|
377
|
+
begin
|
378
|
+
trigger_event(:on_connection_terminated, self) unless @disconnected
|
379
|
+
ensure
|
380
|
+
unless @socket.closed?
|
381
|
+
@socket.shutdown(2) rescue nil
|
382
|
+
@socket.close rescue nil
|
383
|
+
end
|
384
|
+
@connected = false
|
385
|
+
end
|
386
|
+
trigger_event(:on_connection_closed, self)
|
372
387
|
end
|
373
|
-
|
374
|
-
end
|
375
|
-
trigger_event(:on_connection_closed, self)
|
388
|
+
#end
|
376
389
|
end
|
377
390
|
|
378
391
|
# Transmits a frame to the broker. This is a low-level method used internally
|
@@ -389,7 +402,7 @@ class Stomper::Connection
|
|
389
402
|
trigger_transmitted_frame(frame, self)
|
390
403
|
end
|
391
404
|
rescue ::IOError, ::SystemCallError
|
392
|
-
close
|
405
|
+
close
|
393
406
|
raise
|
394
407
|
end
|
395
408
|
end
|
@@ -403,7 +416,7 @@ class Stomper::Connection
|
|
403
416
|
begin
|
404
417
|
@serializer.read_frame.tap do |f|
|
405
418
|
if f.nil?
|
406
|
-
close
|
419
|
+
close
|
407
420
|
else
|
408
421
|
@last_received_at = Time.now
|
409
422
|
trigger_event(:after_receiving, f, self)
|
@@ -411,7 +424,7 @@ class Stomper::Connection
|
|
411
424
|
end
|
412
425
|
end
|
413
426
|
rescue ::IOError, ::SystemCallError
|
414
|
-
close
|
427
|
+
close
|
415
428
|
raise
|
416
429
|
end
|
417
430
|
end
|
@@ -424,14 +437,7 @@ class Stomper::Connection
|
|
424
437
|
# if any data is available it will block until a complete frame has been read.
|
425
438
|
# @return [Stomper::Frame, nil]
|
426
439
|
def receive_nonblock
|
427
|
-
|
428
|
-
trigger_event(:before_receiving, self)
|
429
|
-
if @socket.ready?
|
430
|
-
@serializer.read_frame.tap do |f|
|
431
|
-
trigger_event(:after_receiving, self, f)
|
432
|
-
trigger_received_frame(f, self)
|
433
|
-
end
|
434
|
-
end
|
440
|
+
receive if @socket.ready?
|
435
441
|
end
|
436
442
|
|
437
443
|
# Duration in milliseconds since a frame has been transmitted to the broker.
|
@@ -457,4 +463,3 @@ end
|
|
457
463
|
|
458
464
|
# Alias Stomper::Client to Stomper::Connection
|
459
465
|
::Stomper::Client = ::Stomper::Connection
|
460
|
-
|
@@ -60,13 +60,9 @@ module Stomper::Extensions::Common
|
|
60
60
|
def unsubscribe(frame_or_id, headers={})
|
61
61
|
sub_id = frame_or_id.is_a?(::Stomper::Frame) ? frame_or_id[:id] : frame_or_id
|
62
62
|
raise ArgumentError, 'subscription ID could not be determined' if sub_id.nil? || sub_id.empty?
|
63
|
-
|
64
|
-
transmit create_frame('UNSUBSCRIBE', headers, { :id =>
|
65
|
-
|
66
|
-
subscription_manager.ids_for_destination(sub_id).map do |id|
|
67
|
-
transmit create_frame('UNSUBSCRIBE', headers, { :id => id })
|
68
|
-
end
|
69
|
-
end
|
63
|
+
subscription_manager.remove(sub_id).map do |id|
|
64
|
+
transmit create_frame('UNSUBSCRIBE', headers, { :id => id })
|
65
|
+
end.last
|
70
66
|
end
|
71
67
|
|
72
68
|
# Transmits a BEGIN frame to the broker to start a transaction named by +tx_id+.
|
data/lib/stomper/headers.rb
CHANGED
@@ -12,4 +12,11 @@
|
|
12
12
|
# @see Stomper::Support::Ruby1_9::Headers Implementation for Ruby 1.9
|
13
13
|
class Stomper::Headers
|
14
14
|
include ::Enumerable
|
15
|
+
|
16
|
+
# Returns a new +Hash+ object associating symbolized header names and their
|
17
|
+
# principle values.
|
18
|
+
# @return [Hash]
|
19
|
+
def to_hash
|
20
|
+
to_a.inject({}) { |h, (k,v)| h[k.to_sym] ||= v; h }
|
21
|
+
end
|
15
22
|
end
|
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
# Basic threaded receiver
|
4
4
|
class Stomper::Receivers::Threaded
|
5
|
+
# Stop Receiver
|
6
|
+
class StopReceiver < StandardError; end
|
7
|
+
|
5
8
|
# Returns true if the receiver is currently running, false otherwise.
|
6
9
|
# If the polling thread is terminated due to a raised exception, this
|
7
10
|
# attribute will be false.
|
@@ -20,7 +23,6 @@ class Stomper::Receivers::Threaded
|
|
20
23
|
@running = false
|
21
24
|
@run_mutex = ::Mutex.new
|
22
25
|
@run_thread = nil
|
23
|
-
@raised_while_running = nil
|
24
26
|
end
|
25
27
|
|
26
28
|
# Starts the receiver by creating a new thread to continually poll the
|
@@ -32,14 +34,15 @@ class Stomper::Receivers::Threaded
|
|
32
34
|
is_starting = @run_mutex.synchronize { @running = true unless @running }
|
33
35
|
if is_starting
|
34
36
|
@run_thread = Thread.new do
|
35
|
-
|
36
|
-
|
37
|
-
@running = false if @connection.receive.nil?
|
38
|
-
rescue Exception => ex
|
39
|
-
@running = false
|
40
|
-
raise ex
|
37
|
+
begin
|
38
|
+
until @connection.receive.nil?
|
41
39
|
end
|
40
|
+
rescue ::Stomper::Receivers::Threaded::StopReceiver
|
41
|
+
rescue Exception => ex
|
42
|
+
@running = false
|
43
|
+
raise ex
|
42
44
|
end
|
45
|
+
@running = false
|
43
46
|
end
|
44
47
|
end
|
45
48
|
self
|
@@ -58,11 +61,12 @@ class Stomper::Receivers::Threaded
|
|
58
61
|
def stop
|
59
62
|
stopped = @run_mutex.synchronize { @run_thread.nil? }
|
60
63
|
unless stopped
|
61
|
-
@
|
64
|
+
@run_thread.raise(::Stomper::Receivers::Threaded::StopReceiver.new)
|
62
65
|
begin
|
63
66
|
@run_thread.join
|
64
|
-
rescue IOError
|
67
|
+
rescue ::IOError, ::SystemCallError
|
65
68
|
raise if @connection.connected?
|
69
|
+
rescue ::Stomper::Receivers::Threaded::StopReceiver => ex
|
66
70
|
end
|
67
71
|
@run_thread = nil
|
68
72
|
end
|
@@ -6,10 +6,10 @@ class Stomper::SubscriptionManager
|
|
6
6
|
# @param [Stomper::Connection] connection
|
7
7
|
def initialize(connection)
|
8
8
|
@mon = ::Monitor.new
|
9
|
-
@
|
10
|
-
@dests_to_ids = {}
|
9
|
+
@subscriptions = {}
|
11
10
|
connection.on_message { |m, con| dispatch(m) }
|
12
|
-
connection.on_unsubscribe { |u, con| remove(u) }
|
11
|
+
connection.on_unsubscribe { |u, con| remove(u[:id]) }
|
12
|
+
connection.on_connection_closed { |con| @subscriptions.clear }
|
13
13
|
end
|
14
14
|
|
15
15
|
# Adds a callback handler for a MESSAGE frame that is sent via the subscription
|
@@ -22,58 +22,60 @@ class Stomper::SubscriptionManager
|
|
22
22
|
s_id = subscribe[:id]
|
23
23
|
dest = subscribe[:destination]
|
24
24
|
@mon.synchronize do
|
25
|
-
@
|
26
|
-
@dests_to_ids[dest] ||= []
|
27
|
-
@dests_to_ids[dest] << s_id
|
25
|
+
@subscriptions[s_id] = Subscription.new(subscribe, callback)
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
31
|
-
#
|
32
|
-
# @param [String]
|
33
|
-
# @return [
|
34
|
-
def
|
35
|
-
@mon.synchronize { @callbacks.key? id }
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns true if the subscription destination is registered
|
39
|
-
# @param [String] destination
|
40
|
-
# @return [true,false]
|
41
|
-
def subscribed_destination?(destination)
|
42
|
-
@mon.synchronize { @dests_to_ids.key? destination }
|
43
|
-
end
|
44
|
-
|
45
|
-
# Returns an array of subscription IDs that correspond to
|
46
|
-
# the given subscription destination. If the destination is unknown,
|
47
|
-
# returns +nil+.
|
48
|
-
# @param [String] destination
|
49
|
-
# @return [Array<String>, nil]
|
50
|
-
def ids_for_destination(destination)
|
51
|
-
@mon.synchronize { @dests_to_ids[destination] && @dests_to_ids[destination].dup }
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
def remove(unsub)
|
56
|
-
s_id = unsub[:id]
|
29
|
+
# Removes a subscription by ID or destination.
|
30
|
+
# @param [String] sub_id ID or destination of the subscription
|
31
|
+
# @return [Array<String>] array of subscription IDs matching +sub_id+
|
32
|
+
def remove(sub_id)
|
57
33
|
@mon.synchronize do
|
58
|
-
@
|
59
|
-
|
60
|
-
|
34
|
+
if @subscriptions.key? sub_id
|
35
|
+
@subscriptions.delete sub_id
|
36
|
+
[sub_id]
|
37
|
+
else
|
38
|
+
@subscriptions.values.inject([]) do |ids, sub|
|
39
|
+
if sub.destination == sub_id
|
40
|
+
@subscriptions.delete sub.id
|
41
|
+
ids << sub.id
|
42
|
+
end
|
43
|
+
ids
|
44
|
+
end
|
61
45
|
end
|
62
|
-
@callbacks.delete(s_id)
|
63
46
|
end
|
64
47
|
end
|
65
48
|
|
49
|
+
# Returns all current subscriptions in the form of their SUBSCRIBE frames.
|
50
|
+
# @return [Array<Stomper::Frame>]
|
51
|
+
def subscriptions
|
52
|
+
@mon.synchronize { @subscriptions.values }
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
66
56
|
def dispatch(message)
|
67
57
|
s_id = message[:subscription]
|
68
58
|
dest = message[:destination]
|
69
59
|
if s_id.nil? || s_id.empty?
|
70
|
-
|
71
|
-
@
|
72
|
-
|
73
|
-
|
60
|
+
@mon.synchronize do
|
61
|
+
@subscriptions.values.map do |sub|
|
62
|
+
(sub.destination == dest) && sub
|
63
|
+
end
|
64
|
+
end.each { |cb| cb && cb.call(message) }
|
74
65
|
else
|
75
|
-
cb = @mon.synchronize { @
|
66
|
+
cb = @mon.synchronize { @subscriptions[s_id] }
|
76
67
|
cb && cb.call(message)
|
77
68
|
end
|
78
69
|
end
|
70
|
+
|
71
|
+
class Subscription
|
72
|
+
attr_reader :frame, :callback
|
73
|
+
def initialize(fr, cb)
|
74
|
+
@frame = fr
|
75
|
+
@callback = cb
|
76
|
+
end
|
77
|
+
def id; @frame[:id]; end
|
78
|
+
def destination; @frame[:destination]; end
|
79
|
+
def call(m); @callback.call(m); end
|
80
|
+
end
|
79
81
|
end
|
data/lib/stomper/version.rb
CHANGED
@@ -271,9 +271,17 @@ module Stomper
|
|
271
271
|
it "should close the socket if reading a frame returns nil" do
|
272
272
|
@connection.connect
|
273
273
|
@serializer.should_receive(:read_frame).and_return(nil)
|
274
|
-
@connection.should_receive(:close)
|
274
|
+
@connection.should_receive(:close)
|
275
275
|
@connection.receive.should be_nil
|
276
276
|
end
|
277
|
+
|
278
|
+
it "should close the socket if reading a frame returns nil" do
|
279
|
+
@connection.connect
|
280
|
+
@socket.should_receive(:ready?).and_return(true)
|
281
|
+
@serializer.should_receive(:read_frame).and_return(nil)
|
282
|
+
@connection.should_receive(:close)
|
283
|
+
@connection.receive_nonblock.should be_nil
|
284
|
+
end
|
277
285
|
end
|
278
286
|
|
279
287
|
describe "connection state events" do
|
@@ -356,12 +364,33 @@ module Stomper
|
|
356
364
|
lambda { @connection.receive }.should raise_error(IOError)
|
357
365
|
triggered.should be_true
|
358
366
|
end
|
367
|
+
|
368
|
+
it "should not trigger on_connection_terminated if the socket raises an error after disconnecting" do
|
369
|
+
triggered = false
|
370
|
+
@connection.on_connection_terminated { triggered = true }
|
371
|
+
@connection.connect
|
372
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT'))
|
373
|
+
@connection.disconnect
|
374
|
+
@connection.should_receive(:alive?).at_least(:once).and_return(true)
|
375
|
+
@serializer.should_receive(:read_frame).and_raise(IOError.new('Error while reading frame'))
|
376
|
+
lambda { @connection.receive }.should raise_error(IOError)
|
377
|
+
triggered.should be_false
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should trigger on_connection_terminated if the socket raises an error before DISCONNECT is written" do
|
381
|
+
triggered = false
|
382
|
+
@connection.on_connection_terminated { triggered = true }
|
383
|
+
@connection.connect
|
384
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).and_raise(IOError.new('Error before DISCONNECT'))
|
385
|
+
lambda { @connection.disconnect }.should raise_error(IOError)
|
386
|
+
triggered.should be_true
|
387
|
+
end
|
359
388
|
|
360
389
|
it "should trigger on_connection_terminated if the socket raises a SystemCallError while receiving" do
|
361
390
|
triggered = false
|
362
391
|
@connection.on_connection_terminated { triggered = true }
|
363
392
|
@connection.connect
|
364
|
-
@serializer.
|
393
|
+
@serializer.should_receive(:read_frame).and_raise(SystemCallError.new('syscall error'))
|
365
394
|
lambda { @connection.receive }.should raise_error(SystemCallError)
|
366
395
|
triggered.should be_true
|
367
396
|
end
|
@@ -45,13 +45,13 @@ module Stomper::Extensions
|
|
45
45
|
end
|
46
46
|
|
47
47
|
it "should transmit an UNSUBSCRIBE frame for a given subscription ID" do
|
48
|
-
@subscription_manager.should_receive(:
|
48
|
+
@subscription_manager.should_receive(:remove).with('subscription-1234').and_return(['subscription-1234'])
|
49
49
|
@common.should_receive(:transmit).with(stomper_frame_with_headers({'id' => 'subscription-1234'}, 'UNSUBSCRIBE'))
|
50
50
|
@common.unsubscribe('subscription-1234')
|
51
51
|
end
|
52
52
|
|
53
53
|
it "should transmit an UNSUBSCRIBE frame for a given SUBSCRIBE frame" do
|
54
|
-
@subscription_manager.should_receive(:
|
54
|
+
@subscription_manager.should_receive(:remove).with('id-in-frame-4321').and_return(['id-in-frame-4321'])
|
55
55
|
subscribe = ::Stomper::Frame.new('SUBSCRIBE', { :id => 'id-in-frame-4321' })
|
56
56
|
@common.should_receive(:transmit).with(stomper_frame_with_headers({'id' => 'id-in-frame-4321'}, 'UNSUBSCRIBE'))
|
57
57
|
@common.unsubscribe(subscribe)
|
@@ -94,9 +94,7 @@ module Stomper::Extensions
|
|
94
94
|
# as well.
|
95
95
|
@common.should_receive(:transmit).with(stomper_frame_with_headers({:id => '1234'}, 'UNSUBSCRIBE'))
|
96
96
|
@common.should_receive(:transmit).with(stomper_frame_with_headers({:id => '4567'}, 'UNSUBSCRIBE'))
|
97
|
-
@subscription_manager.should_receive(:
|
98
|
-
@subscription_manager.should_receive(:subscribed_destination?).with('/queue/test').and_return(true)
|
99
|
-
@subscription_manager.should_receive(:ids_for_destination).with('/queue/test').and_return(['1234', '4567'])
|
97
|
+
@subscription_manager.should_receive(:remove).with('/queue/test').and_return(['1234', '4567'])
|
100
98
|
@common.unsubscribe("/queue/test")
|
101
99
|
end
|
102
100
|
end
|
@@ -28,13 +28,6 @@ module Stomper
|
|
28
28
|
@headers['test header'].should == ''
|
29
29
|
end
|
30
30
|
|
31
|
-
it "should return an array of header key/value pairs" do
|
32
|
-
@headers['header 1'] = 'testing'
|
33
|
-
@headers['other header'] = 19
|
34
|
-
@headers[:tom] = 'servo'
|
35
|
-
@headers.to_a.should == [ ['header 1', 'testing'], ['other header', '19'], ['tom', 'servo'] ]
|
36
|
-
end
|
37
|
-
|
38
31
|
it "should preserve the order of keys" do
|
39
32
|
expected_keys = []
|
40
33
|
20.times do |n|
|
@@ -110,6 +103,20 @@ module Stomper
|
|
110
103
|
['header 3', 'h3 value 2'] ]
|
111
104
|
end
|
112
105
|
|
106
|
+
it "should be convertable to a hash of principle values" do
|
107
|
+
@headers.append('header 1', 'h1 value 1')
|
108
|
+
@headers.append('header 1', 'h1 value 2')
|
109
|
+
@headers.append('header 1', 'h1 value 3')
|
110
|
+
@headers['header 2'] = 'h2 value 1'
|
111
|
+
@headers['header 3'] = 'h3 value 1'
|
112
|
+
@headers.append('header 3', 'h3 value 2')
|
113
|
+
@headers.to_hash.should == {
|
114
|
+
:'header 1' => 'h1 value 1',
|
115
|
+
:'header 2' => 'h2 value 1',
|
116
|
+
:'header 3' => 'h3 value 1'
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
113
120
|
it "should set a header value to the first encountered in a chain of appends" do
|
114
121
|
@headers.append('header 1', 'first value')
|
115
122
|
@headers.append('header 1', 'second value')
|
@@ -7,7 +7,7 @@ module Stomper::Scopes
|
|
7
7
|
@connection = mock("connection", :is_a? => true, :version => '1.1')
|
8
8
|
@headers = { :global_1 => 'turbo', 'global_2' => 'is me', :persistent => true }
|
9
9
|
@connection.stub!(:subscription_manager).and_return(mock('subscription manager', {
|
10
|
-
:
|
10
|
+
:remove => ['no-real-destination']
|
11
11
|
}))
|
12
12
|
@scope = HeaderScope.new(@connection, @headers)
|
13
13
|
end
|
@@ -8,7 +8,7 @@ module Stomper::Scopes
|
|
8
8
|
@connection = mock("connection", :is_a? => true, :version => '1.1')
|
9
9
|
@connection.stub!(:receipt_manager => @receipt_manager)
|
10
10
|
@connection.stub!(:subscription_manager).and_return(mock('subscription manager', {
|
11
|
-
:
|
11
|
+
:remove => ['/queue/test']
|
12
12
|
}))
|
13
13
|
@scope = ReceiptScope.new(@connection, {})
|
14
14
|
end
|
@@ -7,7 +7,7 @@ module Stomper::Scopes
|
|
7
7
|
@connection = mock("connection", :is_a? => true, :version => '1.1')
|
8
8
|
@headers = { :transaction => 'tx-1234' }
|
9
9
|
@connection.stub!(:subscription_manager).and_return(mock('subscription manager', {
|
10
|
-
:
|
10
|
+
:remove => ['no-real-destination']
|
11
11
|
}))
|
12
12
|
@scope = TransactionScope.new(@connection, @headers)
|
13
13
|
@connection.should_receive(:transmit).at_most(:once).with(stomper_frame_with_headers(@headers, 'BEGIN'))
|
@@ -11,6 +11,7 @@ module Stomper
|
|
11
11
|
receipt = mock('receipt')
|
12
12
|
@connection.should_receive(:on_message)
|
13
13
|
@connection.should_receive(:on_unsubscribe)
|
14
|
+
@connection.should_receive(:on_connection_closed)
|
14
15
|
@subscription_manager = SubscriptionManager.new(@connection)
|
15
16
|
end
|
16
17
|
|
@@ -19,36 +20,53 @@ module Stomper
|
|
19
20
|
@connection.extend ::Stomper::Extensions::Events
|
20
21
|
@subscription_manager = SubscriptionManager.new(@connection)
|
21
22
|
@subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '1234', :destination => '/queue/testing'})
|
22
|
-
@unsubscribe_frame = ::Stomper::Frame.new('UNSUBSCRIBE', {:id => '1234'})
|
23
23
|
end
|
24
24
|
|
25
|
-
it "should correctly report
|
25
|
+
it "should correctly report subscriptoins" do
|
26
26
|
@subscription_manager.add(@subscribe_frame, lambda { |m| true })
|
27
|
-
@subscription_manager.
|
28
|
-
@subscription_manager.
|
29
|
-
@subscription_manager.
|
30
|
-
@subscription_manager.
|
27
|
+
@subscription_manager.subscriptions.any? { |s| s.id == '1234' }.should be_true
|
28
|
+
@subscription_manager.subscriptions.any? { |s| s.id == '4321' }.should be_false
|
29
|
+
@subscription_manager.remove('1234')
|
30
|
+
@subscription_manager.subscriptions.any? { |s| s.id == '1234' }.should be_false
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it "should correctly report subscribed destinations" do
|
34
34
|
@subscription_manager.add(@subscribe_frame, lambda { |m| true })
|
35
|
-
@subscription_manager.
|
36
|
-
@subscription_manager.
|
37
|
-
@subscription_manager.
|
38
|
-
@subscription_manager.
|
35
|
+
@subscription_manager.subscriptions.any? { |s| s.destination == '/queue/testing' }.should be_true
|
36
|
+
@subscription_manager.subscriptions.any? { |s| s.destination == '/queue/test' }.should be_false
|
37
|
+
@subscription_manager.remove('/queue/testing')
|
38
|
+
@subscription_manager.subscriptions.any? { |s| s.destination == '/queue/testing' }.should be_false
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should correctly map subscribed destinations to their IDs" do
|
42
|
-
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/
|
43
|
-
|
42
|
+
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/test_further'})
|
43
|
+
@subscription_manager.add(@subscribe_frame, lambda { |m| true })
|
44
|
+
@subscription_manager.add(alt_subscribe_frame, lambda { |m| true })
|
45
|
+
@subscription_manager.subscriptions.map { |s| s.id }.should == ['1234', '4567']
|
46
|
+
@subscription_manager.remove('/queue/testing')
|
47
|
+
@subscription_manager.subscriptions.map { |s| s.id }.should == ['4567']
|
48
|
+
@subscription_manager.remove('/queue/test_further')
|
49
|
+
@subscription_manager.subscriptions.should be_empty
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should clear out all remaining subscriptions when the connection is closed" do
|
53
|
+
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/test_further'})
|
44
54
|
@subscription_manager.add(@subscribe_frame, lambda { |m| true })
|
45
55
|
@subscription_manager.add(alt_subscribe_frame, lambda { |m| true })
|
46
|
-
@subscription_manager.
|
47
|
-
@subscription_manager.
|
48
|
-
@
|
49
|
-
@subscription_manager.
|
50
|
-
|
51
|
-
|
56
|
+
@subscription_manager.remove('4567')
|
57
|
+
@subscription_manager.subscriptions.map { |s| s.id }.should == ['1234']
|
58
|
+
@connection.__send__(:trigger_event, :on_connection_closed, @connection)
|
59
|
+
@subscription_manager.subscriptions.should be_empty
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should trigger subscriptions for MESSAGE frames with only a destination" do
|
63
|
+
triggered = [0, 0]
|
64
|
+
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/testing'})
|
65
|
+
@subscription_manager.add(@subscribe_frame, lambda { |m| triggered[0] += 1 })
|
66
|
+
@subscription_manager.add(alt_subscribe_frame, lambda { |m| triggered[1] += 1 })
|
67
|
+
@connection.__send__(:trigger_received_frame, ::Stomper::Frame.new('MESSAGE', { :destination => '/queue/testing' }))
|
68
|
+
@connection.__send__(:trigger_received_frame, ::Stomper::Frame.new('MESSAGE', { :subscription => '4567' }))
|
69
|
+
triggered.should == [1, 2]
|
52
70
|
end
|
53
71
|
|
54
72
|
it "should allow a subscription handler to be registered within a callback" do
|
@@ -76,7 +94,7 @@ module Stomper
|
|
76
94
|
triggered.should == 1
|
77
95
|
end
|
78
96
|
|
79
|
-
it "should allow a
|
97
|
+
it "should allow a subscription handler to be registered within a callback in separate threads" do
|
80
98
|
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/testing'})
|
81
99
|
triggered = [false, false]
|
82
100
|
started_r1 = false
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 2
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 2.0.
|
8
|
+
- 1
|
9
|
+
version: 2.0.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ian D. Eccles
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-02-
|
17
|
+
date: 2011-02-27 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|