def test_scan_aborts_lost_slave_with_job(self):
        # SlaveScanner.scan uses BuilderInteractor.rescueIfLost to abort
        # slaves that don't have the expected job.
        slave = BuildingSlave('nontrivial')
        bq = FakeBuildQueue()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner(
            'mock', MockBuilderFactory(MockBuilder(), bq), BufferLogger(),
            interactor_factory=FakeMethod(interactor),
            slave_factory=FakeMethod(slave),
            behavior_factory=FakeMethod(TrivialBehavior()))
        # XXX: checkCancellation needs more than a FakeBuildQueue.
        scanner.checkCancellation = FakeMethod(defer.succeed(False))

        # A single scan will call status(), notice that the slave is
        # lost, abort() the slave, then reset() the job without calling
        # updateBuild().
        yield scanner.scan()
        self.assertEqual(['status', 'abort'], slave.call_log)
        self.assertEqual(0, interactor.updateBuild.call_count)
        self.assertEqual(1, bq.reset.call_count)
    def test_scan_aborts_lost_slave_with_job(self):
        # SlaveScanner.scan uses BuilderInteractor.rescueIfLost to abort
        # slaves that don't have the expected job.
        slave = BuildingSlave('nontrivial')
        bq = FakeBuildQueue()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner('mock',
                               MockBuilderFactory(MockBuilder(), bq),
                               BufferLogger(),
                               interactor_factory=FakeMethod(interactor),
                               slave_factory=FakeMethod(slave),
                               behavior_factory=FakeMethod(TrivialBehavior()))
        # XXX: checkCancellation needs more than a FakeBuildQueue.
        scanner.checkCancellation = FakeMethod(defer.succeed(False))

        # A single scan will call status(), notice that the slave is
        # lost, abort() the slave, then reset() the job without calling
        # updateBuild().
        yield scanner.scan()
        self.assertEqual(['status', 'abort'], slave.call_log)
        self.assertEqual(0, interactor.updateBuild.call_count)
        self.assertEqual(1, bq.reset.call_count)
 def _getScanner(self, clock=None):
     scanner = SlaveScanner(None,
                            BuilderFactory(),
                            BufferLogger(),
                            clock=clock)
     scanner.logger.name = 'slave-scanner'
     return scanner
    def test_scan_aborts_lost_slave_when_idle(self):
        # SlaveScanner.scan uses BuilderInteractor.rescueIfLost to abort
        # slaves that aren't meant to have a job.
        slave = BuildingSlave()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner(
            'mock', MockBuilderFactory(MockBuilder(), None), BufferLogger(),
            interactor_factory=FakeMethod(interactor),
            slave_factory=FakeMethod(slave),
            behavior_factory=FakeMethod(None))

        # A single scan will call status(), notice that the slave is
        # lost, abort() the slave, then reset() the job without calling
        # updateBuild().
        yield scanner.scan()
        self.assertEqual(['status', 'abort'], slave.call_log)
        self.assertEqual(0, interactor.updateBuild.call_count)
    def test_scan_with_job(self):
        # SlaveScanner.scan calls updateBuild() when a job is building.
        slave = BuildingSlave('trivial')
        bq = FakeBuildQueue()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner(
            'mock', MockBuilderFactory(MockBuilder(), bq), BufferLogger(),
            interactor_factory=FakeMethod(interactor),
            slave_factory=FakeMethod(slave),
            behavior_factory=FakeMethod(TrivialBehavior()))
        # XXX: checkCancellation needs more than a FakeBuildQueue.
        scanner.checkCancellation = FakeMethod(defer.succeed(False))

        yield scanner.scan()
        self.assertEqual(['status'], slave.call_log)
        self.assertEqual(1, interactor.updateBuild.call_count)
        self.assertEqual(0, bq.reset.call_count)
    def test_scan_aborts_lost_slave_when_idle(self):
        # SlaveScanner.scan uses BuilderInteractor.rescueIfLost to abort
        # slaves that aren't meant to have a job.
        slave = BuildingSlave()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner('mock',
                               MockBuilderFactory(MockBuilder(), None),
                               BufferLogger(),
                               interactor_factory=FakeMethod(interactor),
                               slave_factory=FakeMethod(slave),
                               behavior_factory=FakeMethod(None))

        # A single scan will call status(), notice that the slave is
        # lost, abort() the slave, then reset() the job without calling
        # updateBuild().
        yield scanner.scan()
        self.assertEqual(['status', 'abort'], slave.call_log)
        self.assertEqual(0, interactor.updateBuild.call_count)
    def test_scan_with_job(self):
        # SlaveScanner.scan calls updateBuild() when a job is building.
        slave = BuildingSlave('trivial')
        bq = FakeBuildQueue()

        # Instrument updateBuild.
        interactor = BuilderInteractor()
        interactor.updateBuild = FakeMethod()

        scanner = SlaveScanner('mock',
                               MockBuilderFactory(MockBuilder(), bq),
                               BufferLogger(),
                               interactor_factory=FakeMethod(interactor),
                               slave_factory=FakeMethod(slave),
                               behavior_factory=FakeMethod(TrivialBehavior()))
        # XXX: checkCancellation needs more than a FakeBuildQueue.
        scanner.checkCancellation = FakeMethod(defer.succeed(False))

        yield scanner.scan()
        self.assertEqual(['status'], slave.call_log)
        self.assertEqual(1, interactor.updateBuild.call_count)
        self.assertEqual(0, bq.reset.call_count)
    def test_getExpectedCookie_caches(self):
        bf = MockBuilderFactory(MockBuilder(), FakeBuildQueue())
        scanner = SlaveScanner(
            'mock', bf, BufferLogger(), interactor_factory=FakeMethod(None),
            slave_factory=FakeMethod(None),
            behavior_factory=FakeMethod(TrivialBehavior()))

        def assertCounts(expected):
            self.assertEqual(
                expected,
                (scanner.interactor_factory.call_count,
                 scanner.behavior_factory.call_count,
                 scanner.builder_factory.get_call_count))

        # The first call will get a Builder and a BuildFarmJobBehavior.
        assertCounts((0, 0, 0))
        cookie1 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual('trivial', cookie1)
        assertCounts((0, 1, 1))

        # A second call with the same BuildQueue will not reretrieve them.
        cookie2 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual(cookie1, cookie2)
        assertCounts((0, 1, 1))

        # But a call with a new BuildQueue will regrab.
        bf.updateTestData(bf._builder, FakeBuildQueue())
        cookie3 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual(cookie1, cookie3)
        assertCounts((0, 2, 2))

        # And unsetting the BuildQueue returns None again.
        bf.updateTestData(bf._builder, None)
        cookie4 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertIs(None, cookie4)
        assertCounts((0, 2, 2))
    def _getScanner(self, builder_name=None, clock=None, builder_factory=None):
        """Instantiate a SlaveScanner object.

        Replace its default logging handler by a testing version.
        """
        if builder_name is None:
            builder_name = BOB_THE_BUILDER_NAME
        if builder_factory is None:
            builder_factory = BuilderFactory()
        scanner = SlaveScanner(builder_name,
                               builder_factory,
                               BufferLogger(),
                               clock=clock)
        scanner.logger.name = 'slave-scanner'

        return scanner
    def test_getExpectedCookie_caches(self):
        bf = MockBuilderFactory(MockBuilder(), FakeBuildQueue())
        scanner = SlaveScanner('mock',
                               bf,
                               BufferLogger(),
                               interactor_factory=FakeMethod(None),
                               slave_factory=FakeMethod(None),
                               behavior_factory=FakeMethod(TrivialBehavior()))

        def assertCounts(expected):
            self.assertEqual(expected,
                             (scanner.interactor_factory.call_count,
                              scanner.behavior_factory.call_count,
                              scanner.builder_factory.get_call_count))

        # The first call will get a Builder and a BuildFarmJobBehavior.
        assertCounts((0, 0, 0))
        cookie1 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual('trivial', cookie1)
        assertCounts((0, 1, 1))

        # A second call with the same BuildQueue will not reretrieve them.
        cookie2 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual(cookie1, cookie2)
        assertCounts((0, 1, 1))

        # But a call with a new BuildQueue will regrab.
        bf.updateTestData(bf._builder, FakeBuildQueue())
        cookie3 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertEqual(cookie1, cookie3)
        assertCounts((0, 2, 2))

        # And unsetting the BuildQueue returns None again.
        bf.updateTestData(bf._builder, None)
        cookie4 = scanner.getExpectedCookie(bf.getVitals('foo'))
        self.assertIs(None, cookie4)
        assertCounts((0, 2, 2))