blob: 773fc0394b5818953eca5ec7575d259f08c76a1d [file] [log] [blame]
Kevin Clarke0fddde2008-06-18 01:16:02 +00001require File.dirname(__FILE__) + '/spec_helper'
2require 'thrift/server/nonblockingserver'
3$:.unshift File.dirname(__FILE__) + '/gen-rb'
4require 'NonblockingService'
5
6class ThriftNonblockingServerSpec < Spec::ExampleGroup
7 include Thrift
8 include SpecNamespace
9
10 class Handler
11 def initialize
12 @queue = Queue.new
13 end
14
15 attr_accessor :server
16
17 def greeting(english)
18 if english
19 SpecNamespace::Hello.new
20 else
21 SpecNamespace::Hello.new(:greeting => "Aloha!")
22 end
23 end
24
25 def block
26 @queue.pop
27 end
28
29 def unblock
30 @queue.num_waiting.times { @queue.push true }
31 end
32
33 def sleep(time)
34 Kernel.sleep time
35 end
36
37 def shutdown
38 @server.shutdown
39 end
40 end
41
42 before(:each) do
43 @port = 43251
44 handler = Handler.new
45 processor = NonblockingService::Processor.new(handler)
46 @transport = ServerSocket.new('localhost', @port)
47 transportFactory = FramedTransportFactory.new
48 @server = NonblockingServer.new(processor, @transport, transportFactory, nil, 5)
49 handler.server = @server
50 @server_thread = Thread.new do
51 begin
52 @server.serve
53 rescue => e
54 p e
55 puts e.backtrace * "\n"
56 raise e
57 end
58 end
59 Thread.pass
60
61 @clients = []
62 end
63
64 after(:each) do
65 @clients.each { |client, trans| trans.close }
66 @server_thread.kill
67 @transport.close
68 end
69
70 def setup_client
71 transport = FramedTransport.new(Socket.new('localhost', @port))
72 protocol = BinaryProtocol.new(transport)
73 client = NonblockingService::Client.new(protocol)
74 transport.open
75 @clients << [client, transport]
76 client
77 end
78
79 def setup_client_thread(result)
80 queue = Queue.new
81 Thread.new do
82 client = setup_client
83 while (msg = queue.pop)
84 case msg
85 when :block
86 result << client.block
87 when :unblock
88 client.unblock
89 when :hello
90 result << client.greeting(true) # ignore result
91 when :sleep
92 client.sleep(0.5)
93 result << :slept
94 when :shutdown
95 client.shutdown
96 when :exit
97 result << :done
98 break
99 end
100 end
101 @clients.each { |c,t| t.close and break if c == client } #close the transport
102 end
103 queue
104 end
105
106 it "should handle basic message passing" do
107 client = setup_client
108 client.greeting(true).should == Hello.new
109 client.greeting(false).should == Hello.new(:greeting => 'Aloha!')
110 end
111
112 it "should handle concurrent clients" do
113 queue = Queue.new
114 4.times { Thread.new { queue.push setup_client.block } }
115 setup_client.unblock
116 4.times { queue.pop.should be_true }
117 end
118
119 it "should handle messages from more than 5 long-lived connections" do
120 queues = []
121 result = Queue.new
122 7.times do |i|
123 queues << setup_client_thread(result)
124 Thread.pass if i == 4 # give the server time to accept connections
125 end
126 client = setup_client
127 # block 4 connections
128 4.times { |i| queues[i] << :block }
129 queues[4] << :hello
130 queues[5] << :hello
131 queues[6] << :hello
132 3.times { result.pop.should == Hello.new }
133 client.greeting(true).should == Hello.new
134 queues[5] << :unblock
135 4.times { result.pop.should be_true }
136 queues[2] << :hello
137 result.pop.should == Hello.new
138 client.greeting(false).should == Hello.new(:greeting => 'Aloha!')
139 7.times { queues.shift << :exit }
140 client.greeting(true).should == Hello.new
141 end
142
143 it "should shut down when asked" do
144 @server.shutdown
145 @server_thread.join(2).should be_an_instance_of(Thread)
146 end
147
148 it "should continue processing active messages when shutting down" do
149 result = Queue.new
150 client = setup_client_thread(result)
151 client << :sleep
152 sleep 0.1 # give the server time to start processing the client's message
153 @server.shutdown
154 @server_thread.join(2).should be_an_instance_of(Thread)
155 result.pop.should == :slept
156 end
157
158 it "should kill active messages when they don't expire while shutting down" do
159 result = Queue.new
160 client = setup_client_thread(result)
161 client << :block
162 sleep 0.1 # start processing the client's message
163 @server.shutdown(1, true)
164 @server_thread.join(3).should_not be_nil
165 end
Kevin Clark15350782008-06-18 01:16:27 +0000166
167 it "should allow shutting down in response to a message" do
168 client = setup_client
169 client.greeting(true).should == Hello.new
170 client.shutdown
171 @server_thread.join(2).should_not be_nil
172 end
Kevin Clarke0fddde2008-06-18 01:16:02 +0000173end