Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / python / test / test_sendmsg.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for L{twisted.python.sendmsg}.
6 """
7
8 import sys
9 import errno
10
11 from socket import SOL_SOCKET, AF_INET, AF_INET6, socket, error
12
13 try:
14     from socket import AF_UNIX, socketpair
15 except ImportError:
16     nonUNIXSkip = "Platform does not support AF_UNIX sockets"
17 else:
18     nonUNIXSkip = None
19
20 from struct import pack
21 from os import devnull, pipe, read, close, environ
22
23 from twisted.internet.defer import Deferred
24 from twisted.internet.error import ProcessDone
25 from twisted.trial.unittest import TestCase
26 from twisted.internet.defer import inlineCallbacks
27 from twisted.internet import reactor
28 from twisted.python.filepath import FilePath
29 from twisted.python.runtime import platform
30
31 from twisted.internet.protocol import ProcessProtocol
32
33 if platform.isLinux():
34     from socket import MSG_DONTWAIT
35     dontWaitSkip = None
36 else:
37     # It would be nice to be able to test flags on more platforms, but finding a
38     # flag that works *at all* is somewhat challenging.
39     dontWaitSkip = "MSG_DONTWAIT is only known to work as intended on Linux"
40
41 try:
42     from twisted.python.sendmsg import SCM_RIGHTS, send1msg, recv1msg, getsockfam
43 except ImportError:
44     importSkip = "Cannot import twisted.python.sendmsg"
45 else:
46     importSkip = None
47
48
49 class ExitedWithStderr(Exception):
50     """
51     A process exited with some stderr.
52     """
53
54     def __str__(self):
55         """
56         Dump the errors in a pretty way in the event of a subprocess traceback.
57         """
58         return '\n'.join([''] + list(self.args))
59
60
61 class StartStopProcessProtocol(ProcessProtocol):
62     """
63     An L{IProcessProtocol} with a Deferred for events where the subprocess
64     starts and stops.
65
66     @ivar started: A L{Deferred} which fires with this protocol's
67         L{IProcessTransport} provider when it is connected to one.
68
69     @ivar stopped: A L{Deferred} which fires with the process output or a
70         failure if the process produces output on standard error.
71
72     @ivar output: A C{str} used to accumulate standard output.
73
74     @ivar errors: A C{str} used to accumulate standard error.
75     """
76     def __init__(self):
77         self.started = Deferred()
78         self.stopped = Deferred()
79         self.output = ''
80         self.errors = ''
81
82
83     def connectionMade(self):
84         self.started.callback(self.transport)
85
86
87     def outReceived(self, data):
88         self.output += data
89
90
91     def errReceived(self, data):
92         self.errors += data
93
94
95     def processEnded(self, reason):
96         if reason.check(ProcessDone):
97             self.stopped.callback(self.output)
98         else:
99             self.stopped.errback(ExitedWithStderr(
100                     self.errors, self.output))
101
102
103
104 class BadList(list):
105     """
106     A list which cannot be iterated sometimes.
107
108     This is a C{list} subclass to get past the type check in L{send1msg}, not as
109     an example of how real programs might want to interact with L{send1msg} (or
110     anything else).  A custom C{list} subclass makes it easier to trigger
111     certain error cases in the implementation.
112
113     @ivar iterate: A flag which indicates whether an instance of L{BadList} will
114         allow iteration over itself or not.  If C{False}, an attempt to iterate
115         over the instance will raise an exception.
116     """
117     iterate = True
118
119     def __iter__(self):
120         """
121         Allow normal list iteration, or raise an exception.
122
123         If C{self.iterate} is C{True}, it will be flipped to C{False} and then
124         normal iteration will proceed.  If C{self.iterate} is C{False},
125         L{RuntimeError} is raised instead.
126         """
127         if self.iterate:
128             self.iterate = False
129             return super(BadList, self).__iter__()
130         raise RuntimeError("Something bad happened")
131
132
133
134 class WorseList(list):
135     """
136     A list which at first gives the appearance of being iterable, but then
137     raises an exception.
138
139     See L{BadList} for a warning about not writing code like this.
140     """
141     def __iter__(self):
142         """
143         Return an iterator which will raise an exception as soon as C{next} is
144         called on it.
145         """
146         class BadIterator(object):
147             def next(self):
148                 raise RuntimeError("This is a really bad case.")
149         return BadIterator()
150
151
152
153 class SendmsgTestCase(TestCase):
154     """
155     Tests for sendmsg extension module and associated file-descriptor sending
156     functionality.
157     """
158     if nonUNIXSkip is not None:
159         skip = nonUNIXSkip
160     elif importSkip is not None:
161         skip = importSkip
162
163     def setUp(self):
164         """
165         Create a pair of UNIX sockets.
166         """
167         self.input, self.output = socketpair(AF_UNIX)
168
169
170     def tearDown(self):
171         """
172         Close the sockets opened by setUp.
173         """
174         self.input.close()
175         self.output.close()
176
177
178     def test_sendmsgBadArguments(self):
179         """
180         The argument types accepted by L{send1msg} are:
181
182           1. C{int}
183           2. read-only character buffer
184           3. C{int}
185           4. sequence
186
187         The 3rd and 4th arguments are optional.  If fewer than two arguments or
188         more than four arguments are passed, or if any of the arguments passed
189         are not compatible with these types, L{TypeError} is raised.
190         """
191         # Exercise the wrong number of arguments cases
192         self.assertRaises(TypeError, send1msg)
193         self.assertRaises(TypeError, send1msg, 1)
194         self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [], object())
195
196         # Exercise the wrong type of arguments cases
197         self.assertRaises(TypeError, send1msg, object(), "hello world", 2, [])
198         self.assertRaises(TypeError, send1msg, 1, object(), 2, [])
199         self.assertRaises(TypeError, send1msg, 1, "hello world", object(), [])
200         self.assertRaises(TypeError, send1msg, 1, "hello world", 2, object())
201
202
203     def test_badAncillaryIter(self):
204         """
205         If iteration over the ancillary data list fails (at the point of the
206         C{__iter__} call), the exception with which it fails is propagated to
207         the caller of L{send1msg}.
208         """
209         badList = BadList()
210         badList.append((1, 2, "hello world"))
211         badList.iterate = False
212
213         self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList)
214
215         # Hit the second iteration
216         badList.iterate = True
217         self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList)
218
219
220     def test_badAncillaryNext(self):
221         """
222         If iteration over the ancillary data list fails (at the point of a
223         C{next} call), the exception with which it fails is propagated to the
224         caller of L{send1msg}.
225         """
226         worseList = WorseList()
227         self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, worseList)
228
229
230     def test_sendmsgBadAncillaryItem(self):
231         """
232         The ancillary data list contains three-tuples with element types of:
233
234           1. C{int}
235           2. C{int}
236           3. read-only character buffer
237
238         If a tuple in the ancillary data list does not elements of these types,
239         L{TypeError} is raised.
240         """
241         # Exercise the wrong number of arguments cases
242         self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [()])
243         self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1,)])
244         self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1, 2)])
245         self.assertRaises(
246             TypeError,
247             send1msg, 1, "hello world", 2, [(1, 2, "goodbye", object())])
248
249         # Exercise the wrong type of arguments cases
250         exc = self.assertRaises(
251             TypeError, send1msg, 1, "hello world", 2, [object()])
252         self.assertEqual(
253             "send1msg argument 3 expected list of tuple, "
254             "got list containing object",
255             str(exc))
256         self.assertRaises(
257             TypeError,
258             send1msg, 1, "hello world", 2, [(object(), 1, "goodbye")])
259         self.assertRaises(
260             TypeError,
261             send1msg, 1, "hello world", 2, [(1, object(), "goodbye")])
262         self.assertRaises(
263             TypeError,
264             send1msg, 1, "hello world", 2, [(1, 1, object())])
265
266
267     def test_syscallError(self):
268         """
269         If the underlying C{sendmsg} call fails, L{send1msg} raises
270         L{socket.error} with its errno set to the underlying errno value.
271         """
272         probe = file(devnull)
273         fd = probe.fileno()
274         probe.close()
275         exc = self.assertRaises(error, send1msg, fd, "hello, world")
276         self.assertEqual(exc.args[0], errno.EBADF)
277
278
279     def test_syscallErrorWithControlMessage(self):
280         """
281         The behavior when the underlying C{sendmsg} call fails is the same
282         whether L{send1msg} is passed ancillary data or not.
283         """
284         probe = file(devnull)
285         fd = probe.fileno()
286         probe.close()
287         exc = self.assertRaises(
288             error, send1msg, fd, "hello, world", 0, [(0, 0, "0123")])
289         self.assertEqual(exc.args[0], errno.EBADF)
290
291
292     def test_roundtrip(self):
293         """
294         L{recv1msg} will retrieve a message sent via L{send1msg}.
295         """
296         message = "hello, world!"
297         self.assertEqual(
298             len(message),
299             send1msg(self.input.fileno(), message, 0))
300
301         result = recv1msg(fd=self.output.fileno())
302         self.assertEquals(result, (message, 0, []))
303
304
305     def test_shortsend(self):
306         """
307         L{send1msg} returns the number of bytes which it was able to send.
308         """
309         message = "x" * 1024 * 1024
310         self.input.setblocking(False)
311         sent = send1msg(self.input.fileno(), message)
312         # Sanity check - make sure we did fill the send buffer and then some
313         self.assertTrue(sent < len(message))
314         received = recv1msg(self.output.fileno(), 0, len(message))
315         self.assertEqual(len(received[0]), sent)
316
317
318     def test_roundtripEmptyAncillary(self):
319         """
320         L{send1msg} treats an empty ancillary data list the same way it treats
321         receiving no argument for the ancillary parameter at all.
322         """
323         send1msg(self.input.fileno(), "hello, world!", 0, [])
324
325         result = recv1msg(fd=self.output.fileno())
326         self.assertEquals(result, ("hello, world!", 0, []))
327
328
329     def test_flags(self):
330         """
331         The C{flags} argument to L{send1msg} is passed on to the underlying
332         C{sendmsg} call, to affect it in whatever way is defined by those flags.
333         """
334         # Just exercise one flag with simple, well-known behavior.  MSG_DONTWAIT
335         # makes the send a non-blocking call, even if the socket is in blocking
336         # mode.  See also test_flags in RecvmsgTestCase
337         for i in range(1024):
338             try:
339                 send1msg(self.input.fileno(), "x" * 1024, MSG_DONTWAIT)
340             except error, e:
341                 self.assertEqual(e.args[0], errno.EAGAIN)
342                 break
343         else:
344             self.fail(
345                 "Failed to fill up the send buffer, "
346                 "or maybe send1msg blocked for a while")
347     if dontWaitSkip is not None:
348         test_flags.skip = dontWaitSkip
349
350
351     def test_wrongTypeAncillary(self):
352         """
353         L{send1msg} will show a helpful exception message when given the wrong
354         type of object for the 'ancillary' argument.
355         """
356         error = self.assertRaises(TypeError,
357                                   send1msg, self.input.fileno(),
358                                   "hello, world!", 0, 4321)
359         self.assertEquals(str(error),
360                           "send1msg argument 3 expected list, got int")
361
362
363     def spawn(self, script):
364         """
365         Start a script that is a peer of this test as a subprocess.
366
367         @param script: the module name of the script in this directory (no
368             package prefix, no '.py')
369         @type script: C{str}
370
371         @rtype: L{StartStopProcessProtocol}
372         """
373         sspp = StartStopProcessProtocol()
374         reactor.spawnProcess(
375             sspp, sys.executable, [
376                 sys.executable,
377                 FilePath(__file__).sibling(script + ".py").path,
378                 str(self.output.fileno()),
379             ],
380             environ,
381             childFDs={0: "w", 1: "r", 2: "r",
382                       self.output.fileno(): self.output.fileno()}
383         )
384         return sspp
385
386
387     @inlineCallbacks
388     def test_sendSubProcessFD(self):
389         """
390         Calling L{sendsmsg} with SOL_SOCKET, SCM_RIGHTS, and a platform-endian
391         packed file descriptor number should send that file descriptor to a
392         different process, where it can be retrieved by using L{recv1msg}.
393         """
394         sspp = self.spawn("pullpipe")
395         yield sspp.started
396         pipeOut, pipeIn = pipe()
397         self.addCleanup(close, pipeOut)
398
399         send1msg(
400             self.input.fileno(), "blonk", 0,
401             [(SOL_SOCKET, SCM_RIGHTS, pack("i", pipeIn))])
402
403         close(pipeIn)
404         yield sspp.stopped
405         self.assertEquals(read(pipeOut, 1024), "Test fixture data: blonk.\n")
406         # Make sure that the pipe is actually closed now.
407         self.assertEquals(read(pipeOut, 1024), "")
408
409
410
411 class RecvmsgTestCase(TestCase):
412     """
413     Tests for L{recv1msg} (primarily error handling cases).
414     """
415     if importSkip is not None:
416         skip = importSkip
417
418     def test_badArguments(self):
419         """
420         The argument types accepted by L{recv1msg} are:
421
422           1. C{int}
423           2. C{int}
424           3. C{int}
425           4. C{int}
426
427         The 2nd, 3rd, and 4th arguments are optional.  If fewer than one
428         argument or more than four arguments are passed, or if any of the
429         arguments passed are not compatible with these types, L{TypeError} is
430         raised.
431         """
432         # Exercise the wrong number of arguments cases
433         self.assertRaises(TypeError, recv1msg)
434         self.assertRaises(TypeError, recv1msg, 1, 2, 3, 4, object())
435
436         # Exercise the wrong type of arguments cases
437         self.assertRaises(TypeError, recv1msg, object(), 2, 3, 4)
438         self.assertRaises(TypeError, recv1msg, 1, object(), 3, 4)
439         self.assertRaises(TypeError, recv1msg, 1, 2, object(), 4)
440         self.assertRaises(TypeError, recv1msg, 1, 2, 3, object())
441
442
443     def test_cmsgSpaceOverflow(self):
444         """
445         L{recv1msg} raises L{OverflowError} if passed a value for the
446         C{cmsg_size} argument which exceeds C{SOCKLEN_MAX}.
447         """
448         self.assertRaises(OverflowError, recv1msg, 0, 0, 0, 0x7FFFFFFF)
449
450
451     def test_syscallError(self):
452         """
453         If the underlying C{recvmsg} call fails, L{recv1msg} raises
454         L{socket.error} with its errno set to the underlying errno value.
455         """
456         probe = file(devnull)
457         fd = probe.fileno()
458         probe.close()
459         exc = self.assertRaises(error, recv1msg, fd)
460         self.assertEqual(exc.args[0], errno.EBADF)
461
462
463     def test_flags(self):
464         """
465         The C{flags} argument to L{recv1msg} is passed on to the underlying
466         C{recvmsg} call, to affect it in whatever way is defined by those flags.
467         """
468         # See test_flags in SendmsgTestCase
469         reader, writer = socketpair(AF_UNIX)
470         exc = self.assertRaises(
471             error, recv1msg, reader.fileno(), MSG_DONTWAIT)
472         self.assertEqual(exc.args[0], errno.EAGAIN)
473     if dontWaitSkip is not None:
474         test_flags.skip = dontWaitSkip
475
476
477
478 class GetSocketFamilyTests(TestCase):
479     """
480     Tests for L{getsockfam}, a helper which reveals the address family of an
481     arbitrary socket.
482     """
483     if importSkip is not None:
484         skip = importSkip
485
486     def _socket(self, addressFamily):
487         """
488         Create a new socket using the given address family and return that
489         socket's file descriptor.  The socket will automatically be closed when
490         the test is torn down.
491         """
492         s = socket(addressFamily)
493         self.addCleanup(s.close)
494         return s.fileno()
495
496
497     def test_badArguments(self):
498         """
499         L{getsockfam} accepts a single C{int} argument.  If it is called in some
500         other way, L{TypeError} is raised.
501         """
502         self.assertRaises(TypeError, getsockfam)
503         self.assertRaises(TypeError, getsockfam, 1, 2)
504
505         self.assertRaises(TypeError, getsockfam, object())
506
507
508     def test_syscallError(self):
509         """
510         If the underlying C{getsockname} call fails, L{getsockfam} raises
511         L{socket.error} with its errno set to the underlying errno value.
512         """
513         probe = file(devnull)
514         fd = probe.fileno()
515         probe.close()
516         exc = self.assertRaises(error, getsockfam, fd)
517         self.assertEqual(errno.EBADF, exc.args[0])
518
519
520     def test_inet(self):
521         """
522         When passed the file descriptor of a socket created with the C{AF_INET}
523         address family, L{getsockfam} returns C{AF_INET}.
524         """
525         self.assertEqual(AF_INET, getsockfam(self._socket(AF_INET)))
526
527
528     def test_inet6(self):
529         """
530         When passed the file descriptor of a socket created with the C{AF_INET6}
531         address family, L{getsockfam} returns C{AF_INET6}.
532         """
533         self.assertEqual(AF_INET6, getsockfam(self._socket(AF_INET6)))
534
535
536     def test_unix(self):
537         """
538         When passed the file descriptor of a socket created with the C{AF_UNIX}
539         address family, L{getsockfam} returns C{AF_UNIX}.
540         """
541         self.assertEqual(AF_UNIX, getsockfam(self._socket(AF_UNIX)))
542     if nonUNIXSkip is not None:
543         test_unix.skip = nonUNIXSkip