Esempio n. 1
0
class TestStart(unittest.TestCase):
    """Test various starting scenarios."""

    layer = ConfigLayer

    def setUp(self):
        self.command = Start()
        self.command.parser = FakeParser()
        self.args = FakeArgs()
        self.args.config = make_config()

    def tearDown(self):
        try:
            with open(config.PID_FILE) as fp:
                master_pid = int(fp.read())
        except OSError as error:
            if error.errno != errno.ENOENT:
                raise
            # There is no master, so just ignore this.
            return
        kill_watcher(signal.SIGTERM)
        os.waitpid(master_pid, 0)

    def test_force_stale_lock(self):
        # Fake an acquisition of the master lock by another process, which
        # subsequently goes stale.  Start by finding a free process id.  Yes,
        # this could race, but given that we're starting with our own PID and
        # searching downward, it's less likely.
        fake_pid = os.getpid() - 1
        while fake_pid > 1:
            try:
                os.kill(fake_pid, 0)
            except OSError as error:
                if error.errno == errno.ESRCH:
                    break
            fake_pid -= 1
        else:
            raise RuntimeError('Cannot find free PID')
        # Lock acquisition logic taken from flufl.lock.
        claim_file = SEP.join((
            config.LOCK_FILE,
            socket.getfqdn(),
            str(fake_pid),
            '0'))
        with open(config.LOCK_FILE, 'w') as fp:
            fp.write(claim_file)
        os.link(config.LOCK_FILE, claim_file)
        expiration_date = datetime.now() - timedelta(minutes=2)
        t = time.mktime(expiration_date.timetuple())
        os.utime(claim_file, (t, t))
        # Start without --force; no master will be running.
        with suppress(SystemExit):
            self.command.process(self.args)
        self.assertIsNone(find_master())
        self.assertIn('--force', self.command.parser.message)
        # Start again, this time with --force.
        self.args.force = True
        self.command.process(self.args)
        pid = find_master()
        self.assertIsNotNone(pid)
Esempio n. 2
0
class TestStart(unittest.TestCase):
    """Test various starting scenarios."""

    layer = ConfigLayer

    def setUp(self):
        self.command = Start()
        self.command.parser = FakeParser()
        self.args = FakeArgs()
        self.args.config = make_config()

    def tearDown(self):
        try:
            with open(config.PID_FILE) as fp:
                master_pid = int(fp.read())
        except OSError as error:
            if error.errno != errno.ENOENT:
                raise
            # There is no master, so just ignore this.
            return
        kill_watcher(signal.SIGTERM)
        os.waitpid(master_pid, 0)

    def test_force_stale_lock(self):
        # Fake an acquisition of the master lock by another process, which
        # subsequently goes stale.  Start by finding a free process id.  Yes,
        # this could race, but given that we're starting with our own PID and
        # searching downward, it's less likely.
        fake_pid = os.getpid() - 1
        while fake_pid > 1:
            try:
                os.kill(fake_pid, 0)
            except OSError as error:
                if error.errno == errno.ESRCH:
                    break
            fake_pid -= 1
        else:
            raise RuntimeError('Cannot find free PID')
        # Lock acquisition logic taken from flufl.lock.
        claim_file = SEP.join(
            (config.LOCK_FILE, socket.getfqdn(), str(fake_pid), '0'))
        with open(config.LOCK_FILE, 'w') as fp:
            fp.write(claim_file)
        os.link(config.LOCK_FILE, claim_file)
        expiration_date = datetime.now() - timedelta(minutes=2)
        t = time.mktime(expiration_date.timetuple())
        os.utime(claim_file, (t, t))
        # Start without --force; no master will be running.
        try:
            self.command.process(self.args)
        except SystemExit:
            pass
        self.assertEqual(find_master(), None)
        self.assertTrue('--force' in self.command.parser.message)
        # Start again, this time with --force.
        self.args.force = True
        self.command.process(self.args)
        pid = find_master()
        self.assertNotEqual(pid, None)
Esempio n. 3
0
class TestBinDir(unittest.TestCase):
    """Test issues related to bin_dir, e.g. issue #3"""

    layer = ConfigLayer

    def setUp(self):
        self.command = Start()
        self.command.parser = FakeParser()
        self.args = FakeArgs()
        self.args.config = make_config()

    def test_master_is_elsewhere(self):
        with ExitStack() as resources:
            # Patch os.fork() so that we can record the failing child process's
            # id.  We need to wait on the child exiting in either case, and
            # when it fails, no master.pid will be written.
            bin_dir = resources.enter_context(TemporaryDirectory())
            old_master = os.path.join(config.BIN_DIR, 'master')
            new_master = os.path.join(bin_dir, 'master')
            shutil.move(old_master, new_master)
            resources.callback(shutil.move, new_master, old_master)
            # Starting mailman should fail because 'master' can't be found.
            # XXX This will print Errno 2 on the console because we're not
            # silencing the child process's stderr.
            self.command.process(self.args)
            # There should be no pid file.
            args_config = Configuration()
            args_config.load(self.args.config)
            self.assertFalse(os.path.exists(args_config.PID_FILE))
            os.wait()

    def test_master_is_elsewhere_and_findable(self):
        with ExitStack() as resources:
            bin_dir = resources.enter_context(TemporaryDirectory())
            old_master = os.path.join(config.BIN_DIR, 'master')
            new_master = os.path.join(bin_dir, 'master')
            shutil.move(old_master, new_master)
            resources.enter_context(
                configuration('paths.testing', bin_dir=bin_dir))
            resources.callback(shutil.move, new_master, old_master)
            # Starting mailman should find master in the new bin_dir.
            self.command.process(self.args)
            # There should a pid file and the process it describes should be
            # killable.  We might have to wait until the process has started.
            master_pid = find_master()
            self.assertIsNotNone(master_pid, 'master did not start')
            os.kill(master_pid, signal.SIGTERM)
            os.waitpid(master_pid, 0)
Esempio n. 4
0
class TestBinDir(unittest.TestCase):
    """Test issues related to bin_dir, e.g. issue #3"""

    layer = ConfigLayer

    def setUp(self):
        self.command = Start()
        self.command.parser = FakeParser()
        self.args = FakeArgs()
        self.args.config = make_config()

    def test_master_is_elsewhere(self):
        with ExitStack() as resources:
            # Patch os.fork() so that we can record the failing child process's
            # id.  We need to wait on the child exiting in either case, and
            # when it fails, no master.pid will be written.
            bin_dir = resources.enter_context(TemporaryDirectory())
            old_master = os.path.join(config.BIN_DIR, 'master')
            new_master = os.path.join(bin_dir, 'master')
            shutil.move(old_master, new_master)
            resources.callback(shutil.move, new_master, old_master)
            # Starting mailman should fail because 'master' can't be found.
            # XXX This will print Errno 2 on the console because we're not
            # silencing the child process's stderr.
            self.command.process(self.args)
            # There should be no pid file.
            args_config = Configuration()
            args_config.load(self.args.config)
            self.assertFalse(os.path.exists(args_config.PID_FILE))
            os.wait()

    def test_master_is_elsewhere_and_findable(self):
        with ExitStack() as resources:
            bin_dir = resources.enter_context(TemporaryDirectory())
            old_master = os.path.join(config.BIN_DIR, 'master')
            new_master = os.path.join(bin_dir, 'master')
            shutil.move(old_master, new_master)
            resources.enter_context(
                configuration('paths.testing', bin_dir=bin_dir))
            resources.callback(shutil.move, new_master, old_master)
            # Starting mailman should find master in the new bin_dir.
            self.command.process(self.args)
            # There should a pid file and the process it describes should be
            # killable.  We might have to wait until the process has started.
            master_pid = find_master()
            self.assertIsNotNone(master_pid, 'master did not start')
            os.kill(master_pid, signal.SIGTERM)
            os.waitpid(master_pid, 0)
Esempio n. 5
0
 def setUp(self):
     self.command = Start()
     self.command.parser = FakeParser()
     self.args = FakeArgs()
     self.args.config = make_config()
Esempio n. 6
0
 def setUp(self):
     self.command = Start()
     self.command.parser = FakeParser()
     self.args = FakeArgs()
     self.args.config = make_config()