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
|