'L{IProcessProtocol.processExited} is called when the child process
exits, even if file descriptors associated with the child are still
open.'

def test_processExited(self):

    exited = Deferred()
    allLost = Deferred()
    lost = []
    class Waiter(ProcessProtocol, ):
        def childDataReceived(self, fd, data):
            msg(('childDataReceived(%d,    %r)' % (fd, data)))
        def childConnectionLost(self, childFD):
            msg(('childConnectionLost(%d)' % (childFD,)))
            lost.append(childFD)
            if (len(lost) == 3):
                allLost.callback(None)
        def processExited(self, reason):
            msg(('processExited(%r)' % (reason,)))
            exited.callback([reason])
            self.transport.loseConnection()
    reactor = self.buildReactor()
    reactor.callWhenRunning(reactor.spawnProcess, Waiter(), pyExe, [pyExe, '-u', '-m', self.keepStdioOpenProgram, 'child', self.keepStdioOpenArg], env=properEnv, usePTY=self.usePTY)
    def cbExited(args):
        (failure,) = args
        failure.trap(ProcessDone)
        msg(('cbExited;    lost    =    %s' % (lost,)))
        self.assertEqual(lost, [])
        return allLost
    exited.addCallback(cbExited)
    def cbAllLost(ignored):
        self.assertEqual(set(lost), set([0, 1, 2]))
    exited.addCallback(cbAllLost)
    exited.addErrback(err)
    exited.addCallback((lambda ign: reactor.stop()))
    self.runReactor(reactor)
