Merge remote-tracking branch 'ry/v0.10'
[platform/upstream/nodejs.git] / test / disabled / test-sendfd.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
23
24
25 // Test sending and receiving a file descriptor.
26 //
27 // This test is pretty complex. It ends up spawning test/fixtures/recvfd.js
28 // as a child to test desired behavior. What happens is
29 //
30 //  1. Create an in-memory pipe via pipe(2). These two file descriptors
31 //     are not visible to any other process, and so make a good test-case
32 //     for sharing.
33 //  2. Create a a UNIX socket at SOCK_PATH. When a client connects to this
34 //     path, they are sent the write end of the pipe from above.
35 //  3. The client is sent n JSON representations of the DATA variable, each
36 //     with a different ordinal. We send these delimited by '\n' strings
37 //     so that the receiving end can avoid any coalescing that happens
38 //     due to the stream nature of the socket (e.g. '{}{}' is not a valid
39 //     JSON string).
40 //  4. The child process receives file descriptors and JSON blobs and,
41 //     whenever it has at least one of each, writes a modified JSON blob
42 //     to the FD. The blob is modified to include the child's process ID.
43 //  5. Once the child process has sent n responses, it closes the write end
44 //     of the pipe, which signals to the parent that there is no more data
45 //     coming.
46 //  6. The parent listens to the read end of the pipe, accumulating JSON
47 //     blobs (again, delimited by '\n') and verifying that a) the 'pid'
48 //     attribute belongs to the child and b) the 'ord' field has not been
49 //     seen in a response yet. This is intended to ensure that all blobs
50 //     sent out have been relayed back to us.
51
52 var common = require('../common');
53 var assert = require('assert');
54
55 var buffer = require('buffer');
56 var child_process = require('child_process');
57 var fs = require('fs');
58 var net = require('net');
59 var netBinding = process.binding('net');
60 var path = require('path');
61
62 var DATA = {
63   'ppid' : process.pid,
64   'ord' : 0
65 };
66
67 var SOCK_PATH = path.join(__dirname,
68                           '..',
69                           path.basename(__filename, '.js') + '.sock');
70
71 var logChild = function(d) {
72   if (typeof d == 'object') {
73     d = d.toString();
74   }
75
76   d.split('\n').forEach(function(l) {
77     if (l.length > 0) {
78       common.debug('CHILD: ' + l);
79     }
80   });
81 };
82
83 // Create a pipe
84 //
85 // We establish a listener on the read end of the pipe so that we can
86 // validate any data sent back by the child. We send the write end of the
87 // pipe to the child and close it off in our process.
88 var pipeFDs = netBinding.pipe();
89 assert.equal(pipeFDs.length, 2);
90
91 var seenOrdinals = [];
92
93 var pipeReadStream = new net.Stream();
94 pipeReadStream.on('data', function(data) {
95   data.toString('utf8').trim().split('\n').forEach(function(d) {
96     var rd = JSON.parse(d);
97
98     assert.equal(rd.pid, cpp);
99     assert.equal(seenOrdinals.indexOf(rd.ord), -1);
100
101     seenOrdinals.unshift(rd.ord);
102   });
103 });
104 pipeReadStream.open(pipeFDs[0]);
105 pipeReadStream.resume();
106
107 // Create a UNIX socket at SOCK_PATH and send DATA and the write end
108 // of the pipe to whoever connects.
109 //
110 // We send two messages here, both with the same pipe FD: one string, and
111 // one buffer. We want to make sure that both datatypes are handled
112 // correctly.
113 var srv = net.createServer(function(s) {
114   var str = JSON.stringify(DATA) + '\n';
115
116   DATA.ord = DATA.ord + 1;
117   var buf = new buffer.Buffer(str.length);
118   buf.write(JSON.stringify(DATA) + '\n', 'utf8');
119
120   s.write(str, 'utf8', pipeFDs[1]);
121   if (s.write(buf, pipeFDs[1])) {
122     netBinding.close(pipeFDs[1]);
123   } else {
124     s.on('drain', function() {
125       netBinding.close(pipeFDs[1]);
126     });
127   }
128 });
129 srv.listen(SOCK_PATH);
130
131 // Spawn a child running test/fixtures/recvfd.js
132 var cp = child_process.spawn(process.argv[0],
133                              [path.join(common.fixturesDir, 'recvfd.js'),
134                               SOCK_PATH]);
135
136 cp.stdout.on('data', logChild);
137 cp.stderr.on('data', logChild);
138
139 // When the child exits, clean up and validate its exit status
140 var cpp = cp.pid;
141 cp.on('exit', function(code, signal) {
142   srv.close();
143   // fs.unlinkSync(SOCK_PATH);
144
145   assert.equal(code, 0);
146   assert.equal(seenOrdinals.length, 2);
147 });
148
149 // vim:ts=2 sw=2 et