File: abstract_server_collection_spec.rb

package info (click to toggle)
passenger 2.2.11debian-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 11,576 kB
  • ctags: 28,138
  • sloc: cpp: 66,323; ruby: 9,646; ansic: 2,425; python: 141; sh: 56; makefile: 29
file content (246 lines) | stat: -rw-r--r-- 6,509 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
require 'support/config'
require 'support/test_helper'
require 'phusion_passenger/abstract_server'
require 'phusion_passenger/abstract_server_collection'

include PhusionPassenger

describe AbstractServerCollection do
	before :each do
		@collection = AbstractServerCollection.new
	end
	
	after :each do
		@collection.cleanup
	end
	
	specify "#lookup_or_add adds the server returned by its block" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') do
				AbstractServer.new
			end
			@collection.should have_key('foo')
		end
	end
	
	specify "#lookup_or_add does not execute the block if the key exists" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') do
				AbstractServer.new
			end
			@collection.lookup_or_add('foo') do
				violated
			end
		end
	end
	
	specify "#lookup_or_add returns the found server" do
		@collection.synchronize do
			server = AbstractServer.new
			@collection.lookup_or_add('foo') { server }
			result = @collection.lookup_or_add('foo') { AbstractServer.new }
			result.should == server
		end
	end
	
	specify "#lookup_or_add returns the value of the block if server is not already in the collection" do
		@collection.synchronize do
			server = AbstractServer.new
			result = @collection.lookup_or_add('foo') do
				server
			end
			result.should == server
		end
	end
	
	specify "#delete deletes the server with the given key" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') do
				AbstractServer.new
			end
			@collection.delete('foo')
			@collection.should_not have_key('foo')
		end
	end
	
	specify "#delete stops the server if it's started" do
		@collection.synchronize do
			server = AbstractServer.new
			@collection.lookup_or_add('foo') do
				server.start
				server
			end
			@collection.delete('foo')
			server.should_not be_started
		end
	end
	
	specify "#clear deletes everything" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') do
				AbstractServer.new
			end
			@collection.lookup_or_add('bar') do
				AbstractServer.new
			end
			@collection.clear
			@collection.should_not have_key('foo')
			@collection.should_not have_key('bar')
		end
	end
	
	specify "#cleanup deletes everything" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') do
				AbstractServer.new
			end
			@collection.lookup_or_add('bar') do
				AbstractServer.new
			end
		end
		@collection.cleanup
		@collection.synchronize do
			@collection.should_not have_key('foo')
			@collection.should_not have_key('bar')
		end
	end
	
	specify "#cleanup stops all servers" do
		servers = []
		3.times do
			server = AbstractServer.new
			server.start
			servers << server
		end
		@collection.synchronize do
			@collection.lookup_or_add('foo') { servers[0] }
			@collection.lookup_or_add('bar') { servers[1] }
			@collection.lookup_or_add('baz') { servers[2] }
		end
		@collection.cleanup
		servers.each do |server|
			server.should_not be_started
		end
	end
	
	specify "idle servers are cleaned up periodically" do
		foo = AbstractServer.new
		foo.max_idle_time = 0.05
		bar = AbstractServer.new
		bar.max_idle_time = 2
		
		@collection.synchronize do
			@collection.lookup_or_add('foo') { foo }
			@collection.lookup_or_add('bar') { bar }
		end
		sleep 0.3
		@collection.synchronize do
			@collection.should_not have_key('foo')
			@collection.should have_key('bar')
		end
	end
	
	specify "servers with max_idle_time of 0 are never cleaned up" do
		@collection.synchronize do
			@collection.lookup_or_add('foo') { AbstractServer.new }
		end
		original_cleaning_time = @collection.next_cleaning_time
		@collection.check_idle_servers!
		
		# Wait until the cleaner thread has run.
		while original_cleaning_time == @collection.next_cleaning_time
			sleep 0.01
		end
		
		@collection.synchronize do
			@collection.should have_key('foo')
		end
	end
	
	specify "upon adding a new server to an empty collection, the next cleaning will " <<
	        "be scheduled at that server's next cleaning time" do
		server = AbstractServer.new
		server.max_idle_time = 10
		@collection.synchronize do
			@collection.lookup_or_add('foo') { server }
		end
		@collection.next_cleaning_time.should == server.next_cleaning_time
	end
	
	specify "upon adding a new server to a nonempty collection, and that server's next cleaning " <<
	        "time is not the smallest of all servers' cleaning times, then the next cleaning schedule " <<
	        "will not change" do
		server1 = AbstractServer.new
		server1.max_idle_time = 10
		@collection.synchronize do
			@collection.lookup_or_add('foo') { server1 }
		end
		
		server2 = AbstractServer.new
		server2.max_idle_time = 11
		@collection.synchronize do
			@collection.lookup_or_add('bar') { server2 }
		end
		
		@collection.next_cleaning_time.should == server1.next_cleaning_time
	end
	
	specify "upon deleting server from a nonempty collection, and the deleted server's next cleaning " <<
	        "time IS the smallest of all servers' cleaning times, then the next cleaning schedule " <<
	        "will be changed to the smallest cleaning time of all servers" do
		server1 = AbstractServer.new
		server1.max_idle_time = 10
		@collection.synchronize do
			@collection.lookup_or_add('foo') { server1 }
		end
		
		server2 = AbstractServer.new
		server2.max_idle_time = 11
		@collection.synchronize do
			@collection.lookup_or_add('bar') { server2 }
		end
		
		@collection.synchronize do
			@collection.delete('foo')
		end
		
		@collection.next_cleaning_time.should == server2.next_cleaning_time
	end
	
	specify "upon deleting server from a nonempty collection, and the deleted server's next cleaning " <<
	        "time IS NOT the smallest of all servers' cleaning times, then the next cleaning schedule " <<
	        "will not change" do
		server1 = AbstractServer.new
		server1.max_idle_time = 10
		@collection.synchronize do
			@collection.lookup_or_add('foo') { server1 }
		end
		
		server2 = AbstractServer.new
		server2.max_idle_time = 11
		@collection.synchronize do
			@collection.lookup_or_add('bar') { server2 }
		end
		
		@collection.synchronize do
			@collection.delete('bar')
		end
		
		@collection.next_cleaning_time.should == server1.next_cleaning_time
	end
	
	specify "bug check" do
		block = lambda do
			@collection.synchronize do
				@collection.clear
				@collection.lookup_or_add('foo') do
					s = AbstractServer.new
					s.max_idle_time = 0.05
					s
				end
				@collection.lookup_or_add('bar') { AbstractServer.new }
			end
		end
		block.should_not raise_error
	end
end