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