thrift_amqp_transport 0.1.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.
- data/History.txt +7 -0
- data/Manifest.txt +14 -0
- data/README.txt +93 -0
- data/Rakefile +36 -0
- data/lib/thrift_amqp/server_transport.rb +54 -0
- data/lib/thrift_amqp/transport.rb +91 -0
- data/lib/thrift_amqp_transport.rb +12 -0
- data/spec/integration/oneway_spec.rb +116 -0
- data/spec/integration/test.thrift +3 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/server_transport_spec.rb +64 -0
- data/spec/unit/transport_spec.rb +115 -0
- data/thrift_amqp_transport.gemspec +34 -0
- metadata +79 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
lib/thrift_amqp/server_transport.rb
|
6
|
+
lib/thrift_amqp/transport.rb
|
7
|
+
lib/thrift_amqp_transport.rb
|
8
|
+
spec/integration/oneway_spec.rb
|
9
|
+
spec/integration/test.thrift
|
10
|
+
spec/spec.opts
|
11
|
+
spec/spec_helper.rb
|
12
|
+
spec/unit/server_transport_spec.rb
|
13
|
+
spec/unit/transport_spec.rb
|
14
|
+
thrift_amqp_transport.gemspec
|
data/README.txt
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
= Thrift AMQP transport
|
2
|
+
|
3
|
+
== DESCRIPTION
|
4
|
+
|
5
|
+
Transports thrift messages over a the advanced message queue protocol. (AMQP)
|
6
|
+
Because of the unconnected broadcasting nature of the message queue, this
|
7
|
+
transport supports only one-way communication.
|
8
|
+
|
9
|
+
The usage scenario is that you would use this to broadcast information about
|
10
|
+
services (1 producer, n consumers) and then create point to point connections
|
11
|
+
from client to service using normal (TCP) thrift. You gain the advantage of
|
12
|
+
using only one interface definition language (IDL).
|
13
|
+
|
14
|
+
== SYNOPSIS
|
15
|
+
|
16
|
+
Using the following interface definition:
|
17
|
+
|
18
|
+
service AwesomeService {
|
19
|
+
// a little hommage
|
20
|
+
oneway void battleCry(1:string battlecry);
|
21
|
+
}
|
22
|
+
|
23
|
+
On the server (consumer of messages):
|
24
|
+
|
25
|
+
class MyAwesomeHandler
|
26
|
+
def battleCry(message)
|
27
|
+
puts messages
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
handler = MyAwesomeHandler.new()
|
32
|
+
processor = AwesomeService::Processor.new(handler)
|
33
|
+
|
34
|
+
# Connecting to the exchange called 'battle_cry'. This must match the
|
35
|
+
# clients setting.
|
36
|
+
server_transport = Thrift::AMQP::ServerTransport.new('battle_cry')
|
37
|
+
|
38
|
+
server = Thrift::SimpleServer.new(processor, transport)
|
39
|
+
|
40
|
+
server.serve # never returns
|
41
|
+
|
42
|
+
On the client:
|
43
|
+
|
44
|
+
transport = Thrift::AMQP::Transport.connect('battle_cry')
|
45
|
+
protocol = Thrift::BinaryProtocol.new(transport)
|
46
|
+
client = AwesomeService::Client.new(protocol)
|
47
|
+
|
48
|
+
client.battleCry('chunky bacon!') # prints 'chunky bacon!' on the server
|
49
|
+
|
50
|
+
== SPECIFICATION
|
51
|
+
|
52
|
+
To run the specs, just type
|
53
|
+
|
54
|
+
rake specs
|
55
|
+
|
56
|
+
Integration tests need a AMQP-Server to run on localhost. This has so far only
|
57
|
+
been tested with RabbitMQ. (http://www.rabbitmq.com/)
|
58
|
+
|
59
|
+
rake thrift
|
60
|
+
rake integration
|
61
|
+
|
62
|
+
== REQUIREMENTS
|
63
|
+
|
64
|
+
rabbitmq: local server for integration tests
|
65
|
+
thrift: full installation needed if you want to compile service descriptions
|
66
|
+
bunny
|
67
|
+
|
68
|
+
|
69
|
+
== LICENSE
|
70
|
+
|
71
|
+
(The MIT License)
|
72
|
+
|
73
|
+
Copyright (c) 2009 Kaspar Schiess
|
74
|
+
|
75
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
76
|
+
a copy of this software and associated documentation files (the
|
77
|
+
'Software'), to deal in the Software without restriction, including
|
78
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
79
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
80
|
+
permit persons to whom the Software is furnished to do so, subject to
|
81
|
+
the following conditions:
|
82
|
+
|
83
|
+
The above copyright notice and this permission notice shall be
|
84
|
+
included in all copies or substantial portions of the Software.
|
85
|
+
|
86
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
87
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
88
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
89
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
90
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
91
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
92
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
93
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
|
3
|
+
namespace :hoe do # Too much out of the box...
|
4
|
+
Hoe.spec 'thrift_amqp_transport' do
|
5
|
+
developer('Kaspar Schiess', 'eule@space.ch')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Runs all unit examples."
|
10
|
+
Spec::Rake::SpecTask.new('spec:unit') do |t|
|
11
|
+
t.spec_files = FileList['spec/unit/*_spec.rb']
|
12
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Runs all integration examples."
|
16
|
+
Spec::Rake::SpecTask.new('spec:integration') do |t|
|
17
|
+
t.spec_files = FileList['spec/integration/*_spec.rb']
|
18
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Runs all examples."
|
22
|
+
Spec::Rake::SpecTask.new('spec:all') do |t|
|
23
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
24
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
compile_integration = file 'spec/integration/gen-rb/test.rb' => %w(spec/integration/test.thrift) do
|
29
|
+
rm_rf 'spec/integration/gen-rb' rescue nil
|
30
|
+
sh %Q{thrift --gen rb -o spec/integration spec/integration/test.thrift }
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Compiles thrift IDL definitions into Ruby code."
|
34
|
+
task :thrift => compile_integration
|
35
|
+
|
36
|
+
task :default => 'spec:all'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# Server transport for using oneway thrift over an AMQP-queue.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
#
|
7
|
+
# class MyAwesomeHandler
|
8
|
+
# def battleCry(message)
|
9
|
+
# puts messages
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# handler = MyAwesomeHandler.new()
|
14
|
+
# processor = AwesomeService::Processor.new(handler)
|
15
|
+
#
|
16
|
+
# # Connecting to the exchange called 'battle_cry'. This must match the
|
17
|
+
# # clients setting.
|
18
|
+
# server_transport = Thrift::AMQP::ServerTransport.new('battle_cry')
|
19
|
+
#
|
20
|
+
# server = Thrift::SimpleServer.new(processor, transport)
|
21
|
+
#
|
22
|
+
# server.serve # never returns
|
23
|
+
#
|
24
|
+
class Thrift::AMQP::ServerTransport < Thrift::BaseServerTransport
|
25
|
+
# Initializes a connection to the AMQP queue. If you provide a headers
|
26
|
+
# argument, only messages that match ALL headers will be accepted.
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
#
|
30
|
+
# Thrift::AMQP::ServerTransport.new('queue', :version => 1)
|
31
|
+
# # Will only match messages that have 'version' == '1'
|
32
|
+
#
|
33
|
+
def initialize(exchange_name, headers={})
|
34
|
+
@exchange_name = exchange_name
|
35
|
+
@header_filter = transform_hash_to_string(headers)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Part of the server
|
39
|
+
def listen
|
40
|
+
@transport = Thrift::AMQP::Transport.connect(@exchange_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def accept
|
44
|
+
@transport
|
45
|
+
end
|
46
|
+
private
|
47
|
+
def transform_hash_to_string(hash)
|
48
|
+
hash.inject({}) do |new_hash, (k,v)|
|
49
|
+
new_hash[k.to_s] = v.to_s
|
50
|
+
|
51
|
+
new_hash
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
# Transport of thrift messages (oneway) using an AMQP backend.
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# transport = Thrift::AMQP::Transport.connect('battle_cry')
|
7
|
+
# protocol = Thrift::BinaryProtocol.new(transport)
|
8
|
+
# client = AwesomeService::Client.new(protocol)
|
9
|
+
#
|
10
|
+
# client.battleCry('chunky bacon!') # prints 'chunky bacon!' on the server
|
11
|
+
#
|
12
|
+
class Thrift::AMQP::Transport < Thrift::BaseTransport
|
13
|
+
POLL_SLEEP = 0.01
|
14
|
+
|
15
|
+
# Connects the transport to the queue. Since client and server use much of
|
16
|
+
# the same method to to this (and since queues/exchanges must be declared
|
17
|
+
# with the same parameters), this is code shared between the server and
|
18
|
+
# the client.
|
19
|
+
#
|
20
|
+
# Parameters:
|
21
|
+
# * +exchange_name+ - The name of the exchange to connect to.
|
22
|
+
# * +headers+ - The headers to look for (receive) or the headers to send.
|
23
|
+
# Client and server should provide the same arguments.
|
24
|
+
#
|
25
|
+
def self.connect(exchange_name, headers={})
|
26
|
+
connection = Bunny.new
|
27
|
+
connection.start
|
28
|
+
|
29
|
+
exchange = begin
|
30
|
+
connection.exchange(exchange_name,
|
31
|
+
:type => :fanout)
|
32
|
+
rescue Bunny::ProtocolError
|
33
|
+
raise "Could not create exchange #{@exchange_name}, maybe it exists (with different params)?"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Make sure the queue exists. The server doesn't use this, but no harm
|
37
|
+
# in creating this anyway.
|
38
|
+
queue = connection.queue(exchange_name,
|
39
|
+
:auto_delete => true)
|
40
|
+
queue.bind(exchange)
|
41
|
+
|
42
|
+
instance = new(connection, exchange, queue)
|
43
|
+
instance
|
44
|
+
end
|
45
|
+
|
46
|
+
# Constructs a transport based on an existing connection and a message
|
47
|
+
# exchange (of the headers type).
|
48
|
+
#
|
49
|
+
# It might be more simple to use the Transport.connect method.
|
50
|
+
#
|
51
|
+
def initialize(connection, exchange, queue)
|
52
|
+
@connection = connection
|
53
|
+
@exchange = exchange
|
54
|
+
@queue = queue
|
55
|
+
|
56
|
+
@buffered_message = ''
|
57
|
+
@write_buffer = ''
|
58
|
+
end
|
59
|
+
|
60
|
+
def read(sz)
|
61
|
+
# loop and pop until we have something to show
|
62
|
+
loop do
|
63
|
+
if buffered_message?
|
64
|
+
return buffered_message.slice!(0,sz) || ''
|
65
|
+
end
|
66
|
+
|
67
|
+
self.buffered_message = @queue.pop
|
68
|
+
sleep POLL_SLEEP unless buffered_message?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def write(buffer)
|
73
|
+
write_buffer << buffer
|
74
|
+
end
|
75
|
+
def flush
|
76
|
+
@exchange.publish(write_buffer)
|
77
|
+
self.write_buffer = ''
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
attr_accessor :buffered_message
|
82
|
+
attr_accessor :write_buffer
|
83
|
+
|
84
|
+
def buffered_message?
|
85
|
+
not (
|
86
|
+
buffered_message == :queue_empty ||
|
87
|
+
buffered_message.nil? ||
|
88
|
+
buffered_message.empty?
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
4
|
+
begin
|
5
|
+
require 'test'
|
6
|
+
rescue LoadError
|
7
|
+
puts "No test interface found. Maybe you should run 'rake thrift' first?"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "AMQP Transport Integration (oneway)" do
|
11
|
+
EXCHANGE_NAME = 'integration_spec_oneway'
|
12
|
+
|
13
|
+
class SpecHandler
|
14
|
+
attr_reader :messages
|
15
|
+
def initialize
|
16
|
+
@messages = []
|
17
|
+
end
|
18
|
+
def sendMessage(message)
|
19
|
+
@messages << message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SpecTestServer
|
24
|
+
attr_reader :handler
|
25
|
+
def initialize()
|
26
|
+
@handler = SpecHandler.new()
|
27
|
+
@processor = Test::Processor.new(handler)
|
28
|
+
@server_transport = Thrift::AMQP::ServerTransport.new(EXCHANGE_NAME)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Spins the server and makes it read the next +message_count+ messages.
|
32
|
+
#
|
33
|
+
def spin_server(message_count)
|
34
|
+
@server_transport.listen
|
35
|
+
client = @server_transport.accept
|
36
|
+
prot = Thrift::BinaryProtocol.new(client)
|
37
|
+
|
38
|
+
messages_left = message_count
|
39
|
+
while messages_left > 0
|
40
|
+
@processor.process(prot, prot)
|
41
|
+
messages_left -= 1
|
42
|
+
end
|
43
|
+
ensure
|
44
|
+
client.close
|
45
|
+
end
|
46
|
+
|
47
|
+
def close
|
48
|
+
@server_transport.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'with a server in the background' do
|
53
|
+
attr_reader :server, :client
|
54
|
+
before(:each) do
|
55
|
+
# Server setup
|
56
|
+
@server = SpecTestServer.new
|
57
|
+
|
58
|
+
# Client setup
|
59
|
+
begin
|
60
|
+
@transport = Thrift::AMQP::Transport.connect(EXCHANGE_NAME)
|
61
|
+
protocol = Thrift::BinaryProtocol.new(@transport)
|
62
|
+
@client = Test::Client.new(protocol)
|
63
|
+
rescue Bunny::ServerDownError
|
64
|
+
raise "Could not connect - is your local RabbitMQ running?"
|
65
|
+
end
|
66
|
+
|
67
|
+
@transport.open
|
68
|
+
end
|
69
|
+
after(:each) do
|
70
|
+
@server.close
|
71
|
+
@transport.close
|
72
|
+
|
73
|
+
# Try to kill the exchange and the queue
|
74
|
+
connection = Bunny.new
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should successfully send a message" do
|
78
|
+
client.sendMessage("a message")
|
79
|
+
|
80
|
+
server.spin_server 1
|
81
|
+
server.handler.messages.should include('a message')
|
82
|
+
end
|
83
|
+
it "should send several messages" do
|
84
|
+
10.times do |i|
|
85
|
+
client.sendMessage("a message (#{i})")
|
86
|
+
end
|
87
|
+
|
88
|
+
server.spin_server 10
|
89
|
+
server.handler.messages.should have(10).messages
|
90
|
+
end
|
91
|
+
context "with a second server" do
|
92
|
+
attr_reader :second_server
|
93
|
+
before(:each) do
|
94
|
+
# Server setup
|
95
|
+
@second_server = SpecTestServer.new
|
96
|
+
end
|
97
|
+
after(:each) do
|
98
|
+
second_server.close
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should allow only one server to receive the message/call" do
|
102
|
+
10.times do |i|
|
103
|
+
client.sendMessage("a message (#{i})")
|
104
|
+
end
|
105
|
+
|
106
|
+
server.spin_server 5
|
107
|
+
second_server.spin_server 5
|
108
|
+
|
109
|
+
messages = server.handler.messages + second_server.handler.messages
|
110
|
+
10.times do |i|
|
111
|
+
messages.should include("a message (#{i})")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec'
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
|
5
|
+
require 'thrift_amqp_transport'
|
6
|
+
|
7
|
+
unless defined?(PROJECT_BASE)
|
8
|
+
PROJECT_BASE = File.join(File.dirname(__FILE__), '..')
|
9
|
+
end
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
config.mock_with :flexmock
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_defaults(mock, hash)
|
16
|
+
hash.each do |k, v|
|
17
|
+
mock.should_receive(k).and_return(v).by_default
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Thrift::AMQP::ServerTransport do
|
4
|
+
it "should be constructed with an exchange name" do
|
5
|
+
Thrift::AMQP::ServerTransport.new('exchange')
|
6
|
+
end
|
7
|
+
it "should be constructed with an exchange and a set of headers" do
|
8
|
+
Thrift::AMQP::ServerTransport.new('exchange', :foo => :bar)
|
9
|
+
end
|
10
|
+
|
11
|
+
context '#new(exchange)' do
|
12
|
+
attr_reader :transport
|
13
|
+
attr_reader :bunny, :queue, :exchange
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@transport = Thrift::AMQP::ServerTransport.new('exchange')
|
17
|
+
|
18
|
+
# Stub Bunny subsystem
|
19
|
+
@bunny = flexmock(:bunny)
|
20
|
+
@exchange = flexmock(:exchange, :name => 'exchange')
|
21
|
+
@queue = flexmock(:queue)
|
22
|
+
|
23
|
+
set_defaults(bunny,
|
24
|
+
:start => nil,
|
25
|
+
:exchange => exchange,
|
26
|
+
:queue => queue)
|
27
|
+
|
28
|
+
set_defaults(queue,
|
29
|
+
:bind => nil)
|
30
|
+
|
31
|
+
flexmock(Bunny, :new => bunny)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#listen (1: setup the connection)" do
|
35
|
+
it "should create a bunny connection" do
|
36
|
+
bunny.should_receive(:start).once
|
37
|
+
|
38
|
+
transport.listen
|
39
|
+
end
|
40
|
+
it "should create an exchange of type headers" do
|
41
|
+
bunny.should_receive(:exchange).with('exchange', Hash).once
|
42
|
+
|
43
|
+
transport.listen
|
44
|
+
end
|
45
|
+
end
|
46
|
+
describe "#accept (2: accept a connection, returns a transport)" do
|
47
|
+
before(:each) do
|
48
|
+
transport.listen
|
49
|
+
end
|
50
|
+
it "should return a queue transport" do
|
51
|
+
transport.accept.should be_instance_of(Thrift::AMQP::Transport)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
describe "#close (3: closes the server)" do
|
55
|
+
before(:each) do
|
56
|
+
transport.listen
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not fail" do
|
60
|
+
transport.close
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Thrift::AMQP::Transport, 'when constructed with an exchange (server)' do
|
4
|
+
attr_reader :transport, :connection, :exchange, :queue
|
5
|
+
before(:each) do
|
6
|
+
@connection = flexmock(:connection)
|
7
|
+
@exchange = flexmock(:exchange)
|
8
|
+
@queue = flexmock(:queue)
|
9
|
+
|
10
|
+
# Stub an interface for the connection
|
11
|
+
set_defaults(connection,
|
12
|
+
:queue => queue
|
13
|
+
)
|
14
|
+
|
15
|
+
set_defaults(exchange,
|
16
|
+
:name => 'exchange'
|
17
|
+
)
|
18
|
+
|
19
|
+
# Stub an interface for the queue
|
20
|
+
set_defaults(queue,
|
21
|
+
:bind => nil,
|
22
|
+
:pop => :queue_empty
|
23
|
+
)
|
24
|
+
|
25
|
+
@transport = Thrift::AMQP::Transport.new(connection, exchange)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#read(sz)" do
|
29
|
+
it "should poll for a new message on the queue" do
|
30
|
+
queue.should_receive(:pop).and_return(:queue_empty,:queue_empty,'message')
|
31
|
+
|
32
|
+
transport.read(1).should == 'm'
|
33
|
+
end
|
34
|
+
it "should return sz bytes" do
|
35
|
+
queue.should_receive(:pop).and_return(' '*1000)
|
36
|
+
|
37
|
+
transport.read(999).size.should == 999
|
38
|
+
transport.read(10).size.should == 1
|
39
|
+
end
|
40
|
+
it "should return at most the whole message" do
|
41
|
+
queue.should_receive(:pop).and_return(' '*1000)
|
42
|
+
|
43
|
+
transport.read(2000).size.should == 1000
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe Thrift::AMQP::Transport, 'when using .connect (client)' do
|
49
|
+
attr_reader :bunny, :exchange
|
50
|
+
before(:each) do
|
51
|
+
@bunny = flexmock(:bunny)
|
52
|
+
@exchange = flexmock(:exchange)
|
53
|
+
|
54
|
+
set_defaults(bunny,
|
55
|
+
:start => nil,
|
56
|
+
:exchange => exchange)
|
57
|
+
|
58
|
+
set_defaults(exchange,
|
59
|
+
:name => 'exchange')
|
60
|
+
|
61
|
+
flexmock(Bunny).should_receive(:new).and_return bunny
|
62
|
+
end
|
63
|
+
describe ".connect(exchange_name)" do
|
64
|
+
it "should create a connection to the AMQP server" do
|
65
|
+
bunny.should_receive(:start).once
|
66
|
+
|
67
|
+
Thrift::AMQP::Transport.connect('exchange_name')
|
68
|
+
end
|
69
|
+
it "should access the exchange specified" do
|
70
|
+
bunny.should_receive(:exchange).with('exchange_name', Hash).once
|
71
|
+
|
72
|
+
Thrift::AMQP::Transport.connect('exchange_name')
|
73
|
+
end
|
74
|
+
it "should return a transport instance" do
|
75
|
+
transport = Thrift::AMQP::Transport.connect('exchange_name')
|
76
|
+
|
77
|
+
transport.should be_instance_of(Thrift::AMQP::Transport)
|
78
|
+
end
|
79
|
+
it "should raise a nice error when exchange can't be created" do
|
80
|
+
bunny.should_receive(:exchange).and_raise(Bunny::ProtocolError)
|
81
|
+
|
82
|
+
lambda {
|
83
|
+
transport = Thrift::AMQP::Transport.connect('exchange_name')
|
84
|
+
}.should raise_error()
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'connected' do
|
89
|
+
attr_reader :transport
|
90
|
+
before(:each) do
|
91
|
+
@transport = Thrift::AMQP::Transport.connect('exchange_name')
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "write(buffer)" do
|
95
|
+
it "should publish messages to the exchange" do
|
96
|
+
exchange.should_receive(:publish).with("some message (encoded by thrift)").once
|
97
|
+
|
98
|
+
transport.write("some message (encoded by thrift)")
|
99
|
+
transport.flush
|
100
|
+
end
|
101
|
+
it "should not publish on simple write" do
|
102
|
+
exchange.should_receive(:publish).never
|
103
|
+
|
104
|
+
transport.write("some message (encoded by thrift)")
|
105
|
+
end
|
106
|
+
it "should publish on #flush" do
|
107
|
+
exchange.should_receive(:publish).with("foobar").once
|
108
|
+
|
109
|
+
transport.write("foo")
|
110
|
+
transport.write("bar")
|
111
|
+
transport.flush
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
(in /Users/kaspar/git/own/thrift_amqp_transport)
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = %q{thrift_amqp_transport}
|
6
|
+
s.version = "0.1.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.authors = ["Kaspar Schiess"]
|
10
|
+
s.date = %q{2009-08-27}
|
11
|
+
s.description = %q{Transports thrift messages over a the advanced message queue protocol. (AMQP)
|
12
|
+
This is an early release that features only one-way communication.}
|
13
|
+
s.email = ["eule@space.ch"]
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
15
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/thrift_amqp/server_transport.rb", "lib/thrift_amqp/transport.rb", "lib/thrift_amqp_transport.rb", "spec/integration/test.thrift", "spec/integration/thrift_amqp_transport_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/unit/server_transport_spec.rb", "spec/unit/transport_spec.rb"]
|
16
|
+
s.rdoc_options = ["--main", "README.txt"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{thrift_amqp_transport}
|
19
|
+
s.rubygems_version = %q{1.3.5}
|
20
|
+
s.summary = %q{Transports thrift messages over a the advanced message queue protocol}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 3
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_development_dependency(%q<hoe>, [">= 2.3.2"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<hoe>, [">= 2.3.2"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<hoe>, [">= 2.3.2"])
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thrift_amqp_transport
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kaspar Schiess
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-31 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.3
|
24
|
+
version:
|
25
|
+
description: Transports thrift messages over a the advanced message queue protocol. (AMQP) Because of the unconnected broadcasting nature of the message queue, this transport supports only one-way communication. The usage scenario is that you would use this to broadcast information about services (1 producer, n consumers) and then create point to point connections from client to service using normal (TCP) thrift. You gain the advantage of using only one interface definition language (IDL).
|
26
|
+
email:
|
27
|
+
- eule@space.ch
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
files:
|
37
|
+
- History.txt
|
38
|
+
- Manifest.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- lib/thrift_amqp/server_transport.rb
|
42
|
+
- lib/thrift_amqp/transport.rb
|
43
|
+
- lib/thrift_amqp_transport.rb
|
44
|
+
- spec/integration/oneway_spec.rb
|
45
|
+
- spec/integration/test.thrift
|
46
|
+
- spec/spec.opts
|
47
|
+
- spec/spec_helper.rb
|
48
|
+
- spec/unit/server_transport_spec.rb
|
49
|
+
- spec/unit/transport_spec.rb
|
50
|
+
- thrift_amqp_transport.gemspec
|
51
|
+
has_rdoc: true
|
52
|
+
homepage:
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --main
|
56
|
+
- README.txt
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project: thrift_amqp_transport
|
74
|
+
rubygems_version: 1.3.1
|
75
|
+
signing_key:
|
76
|
+
specification_version: 2
|
77
|
+
summary: Transports thrift messages over a the advanced message queue protocol
|
78
|
+
test_files: []
|
79
|
+
|