File: message_channel_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 (170 lines) | stat: -rw-r--r-- 4,425 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
require 'socket'
require 'support/config'
require 'phusion_passenger/message_channel'
include PhusionPassenger

describe MessageChannel do
	describe "scenarios with a single channel" do
		before :each do
			@reader_pipe, @writer_pipe = IO.pipe
			@reader = MessageChannel.new(@reader_pipe)
			@writer = MessageChannel.new(@writer_pipe)
		end
		
		after :each do
			@reader_pipe.close unless @reader_pipe.closed?
			@writer_pipe.close unless @writer_pipe.closed?
		end
		
		it "can read a single written array message" do
			@writer.write("hello")
			@reader.read.should == ["hello"]
		end
		
		it "can handle array messages that contain spaces" do
			@writer.write("hello world", "! ")
			@reader.read.should == ["hello world", "! "]
		end
		
		it "can handle array messages that have only a single empty string" do
			@writer.write("")
			@reader.read.should == [""]
		end
		
		it "can handle array messages with empty arguments" do
			@writer.write("hello", "", "world")
			@reader.read.should == ["hello", "", "world"]
			
			@writer.write("")
			@reader.read.should == [""]
			
			@writer.write(nil, "foo")
			@reader.read.should == ["", "foo"]
		end
		
		it "properly detects end-of-file when reading an array message" do
			@writer.close
			@reader.read.should be_nil
		end
		
		it "can read a single written scalar message" do
			@writer.write_scalar("hello world")
			@reader.read_scalar.should == "hello world"
		end
		
		it "can handle empty scalar messages" do
			@writer.write_scalar("")
			@reader.read_scalar.should == ""
		end
		
		it "properly detects end-of-file when reading a scalar message" do
			@writer.close
			@reader.read_scalar.should be_nil
		end
		
		it "raises SecurityError when a received scalar message's size is larger than a specified maximum" do
			@writer.write_scalar(" " * 100)
			lambda { @reader.read_scalar(99) }.should raise_error(SecurityError)
		end
	end
	
	describe "scenarios with 2 channels and 2 concurrent processes" do
		after :each do
			@parent_socket.close
			Process.waitpid(@pid) rescue nil
		end
		
		it "both processes can read and write a single array message" do
			spawn_process do
				x = @channel.read
				@channel.write("#{x}!")
			end
			@channel.write("hello")
			@channel.read.should == ["hello!"]
		end
		
		it "can handle scalar messages with arbitrary binary data" do
			garbage_files = ["garbage1.dat", "garbage2.dat", "garbage3.dat"]
			spawn_process do
				garbage_files.each do |name|
					data = File.read("stub/#{name}")
					@channel.write_scalar(data)
				end
			end
			
			garbage_files.each do |name|
				data = File.read("stub/#{name}")
				@channel.read_scalar.should == data
			end
		end
		
		it "supports IO object (file descriptor) passing" do
			spawn_process do
				writer = @channel.recv_io
				writer.write("it works")
				writer.close
			end
			reader, writer = IO.pipe
			@channel.send_io(writer)
			writer.close
			reader.read.should == "it works"
			reader.close
		end
		
		it "supports large amounts of data" do
			iterations = 1000
			blob = "123" * 1024
			spawn_process do
				iterations.times do |i|
					@channel.write(blob)
				end
			end
			iterations.times do
				@channel.read.should == [blob]
			end
		end
		
		it "has stream properties" do
			garbage = File.read("stub/garbage1.dat")
			spawn_process do
				@channel.write("hello", "world")
				@channel.write_scalar(garbage)
				@channel.send_io(STDIN)
				@channel.write_scalar(":-)")
				
				a = @channel.read_scalar
				b = @channel.read
				b << a
				@channel.write(*b)
			end
			@channel.read.should == ["hello", "world"]
			@channel.read_scalar.should == garbage
			@channel.recv_io.close
			@channel.read_scalar.should == ":-)"
			
			@channel.write_scalar("TASTE MY WRATH! ULTIMATE SWORD TECHNIQUE!! DRAGON'S BREATH SL--")
			@channel.write("Uhm, watch your step.", "WAAHH?!", "Calm down, Motoko!!")
			@channel.read.should == ["Uhm, watch your step.", "WAAHH?!", "Calm down, Motoko!!",
				"TASTE MY WRATH! ULTIMATE SWORD TECHNIQUE!! DRAGON'S BREATH SL--"]
		end
		
		def spawn_process
			@parent_socket, @child_socket = UNIXSocket.pair
			@pid = fork do
				@parent_socket.close
				@channel = MessageChannel.new(@child_socket)
				begin
					yield
				rescue Exception => e
					print_exception("child", e)
				ensure
					@child_socket.close
					exit!
				end
			end
			@child_socket.close
			@channel = MessageChannel.new(@parent_socket)
		end
	end
end