def test_setsid_helper(self):
        got = []
        def callback(pid, status):
            got.append((pid, status))

        spec1 = {"args": ["sh", "-c", "exit 42"],
                "fds": {0: sys.stdin, 1: sys.stdout, 2: sys.stderr}}
        spec2 = {"args": ["sh", "-c", "exit 24"],
                 "fds": {0: sys.stdin, 1: sys.stdout, 2: sys.stderr}}
        master_fd, slave_fd = terminal.openpty()
        helper_pid, pids = setsid_helper.run([spec1, spec2], slave_fd, callback)
        self.assertEquals(len(pids), 2)
        gobject.main_context_default().iteration(True)
        gobject.main_context_default().iteration(True)
        gobject.main_context_default().iteration(True)
        statuses = dict(got)
        self.assertEquals(set(statuses.keys()), set(pids))
        assert os.WIFEXITED(statuses[pids[0]])
        assert os.WIFEXITED(statuses[pids[1]])
        self.assertEquals(os.WEXITSTATUS(statuses[pids[0]]), 42)
        self.assertEquals(os.WEXITSTATUS(statuses[pids[1]]), 24)

        # Helper process should exit OK.
        pid2, status = os.waitpid(helper_pid, 0)
        assert os.WIFEXITED(status)
        self.assertEquals(os.WEXITSTATUS(status), 0)
 def start_job(self, job_procs, is_foreground, cmd_text):
     dispatcher_for_job = SessionHelperDispatcher()
     helper_pid, pids = setsid_helper.run(
         job_procs, self._tty_fd, dispatcher_for_job.handle_status)
     # Wait for helper process so that it doesn't become a zombie.
     self._dispatcher.add_handler(helper_pid, lambda status: None)
     # We must ensure that FDs are dropped before any waiting.
     job_procs[:] = []
     procs = [ChildProcess(dispatcher_for_job, proc) for proc in pids]
     pgid = pids[0]
     job = Job(procs, pgid, cmd_text, self._to_foreground)
     self._job_controller.add_job(job, is_foreground)