We got nominated! Help us out and vote for GitHub as Best Bootstrapped Startup of 2008. (You can vote once a day.) [ hide ]

public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
passenger / test / message_channel_spec.rb
100644 172 lines (147 sloc) 4.586 kb
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
require 'socket'
require 'support/config'
require 'passenger/message_channel'
require 'passenger/utils'
include Passenger
 
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 "should be able to read a single written array message" do
      @writer.write("hello")
      @reader.read.should == ["hello"]
    end
    
    it "should be able to handle array messages that contain spaces" do
      @writer.write("hello world", "! ")
      @reader.read.should == ["hello world", "! "]
    end
    
    it "should be able to handle array messages that have only a single empty string" do
      @writer.write("")
      @reader.read.should == [""]
    end
    
    it "should be able to 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 "should properly detect end-of-file when reading an array message" do
      @writer.close
      @reader.read.should be_nil
    end
    
    it "should be able to read a single written scalar message" do
      @writer.write_scalar("hello world")
      @reader.read_scalar.should == "hello world"
    end
    
    it "should be able to handle empty scalar messages" do
      @writer.write_scalar("")
      @reader.read_scalar.should == ""
    end
    
    it "should properly detect end-of-file when reading a scalar message" do
      @writer.close
      @reader.read_scalar.should be_nil
    end
    
    it "should raise 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 should be able to 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 "should be able to 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 "should support 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 "should support 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 "should have 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