def test_scan_skipped_if_builderfactory_stale(self):
        # singleCycle does nothing if the BuilderFactory's update
        # timestamp is older than the end of the previous scan. This
        # prevents eg. a scan after a dispatch from failing to notice
        # that a build has been dispatched.
        pbf = PrefetchedBuilderFactory()
        pbf.update()
        scanner = self._getScanner(builder_factory=pbf)
        fake_scan = FakeMethod()

        def _fake_scan():
            fake_scan()
            return defer.succeed(None)
        scanner.scan = _fake_scan
        self.assertEqual(0, fake_scan.call_count)

        # An initial cycle triggers a scan.
        yield scanner.singleCycle()
        self.assertEqual(1, fake_scan.call_count)

        # But a subsequent cycle without updating BuilderFactory's data
        # is a no-op.
        yield scanner.singleCycle()
        self.assertEqual(1, fake_scan.call_count)

        # Updating the BuilderFactory causes scans to resume.
        pbf.update()
        yield scanner.singleCycle()
        self.assertEqual(2, fake_scan.call_count)
 def test_update(self):
     # update grabs all of the Builders and their BuildQueues in a
     # single query.
     builders = [self.factory.makeBuilder() for i in range(5)]
     for i in range(3):
         bq = self.factory.makeBinaryPackageBuild().queueBuild()
         bq.markAsBuilding(builders[i])
     pbf = PrefetchedBuilderFactory()
     transaction.commit()
     pbf.update()
     with StormStatementRecorder() as recorder:
         pbf.update()
     self.assertThat(recorder, HasQueryCount(Equals(1)))
    def test_scan_skipped_if_builderfactory_stale(self):
        # singleCycle does nothing if the BuilderFactory's update
        # timestamp is older than the end of the previous scan. This
        # prevents eg. a scan after a dispatch from failing to notice
        # that a build has been dispatched.
        pbf = PrefetchedBuilderFactory()
        pbf.update()
        scanner = self._getScanner(builder_factory=pbf)
        fake_scan = FakeMethod()

        def _fake_scan():
            fake_scan()
            return defer.succeed(None)

        scanner.scan = _fake_scan
        self.assertEqual(0, fake_scan.call_count)

        # An initial cycle triggers a scan.
        yield scanner.singleCycle()
        self.assertEqual(1, fake_scan.call_count)

        # But a subsequent cycle without updating BuilderFactory's data
        # is a no-op.
        yield scanner.singleCycle()
        self.assertEqual(1, fake_scan.call_count)

        # Updating the BuilderFactory causes scans to resume.
        pbf.update()
        yield scanner.singleCycle()
        self.assertEqual(2, fake_scan.call_count)
    def test_iterVitals(self):
        # PrefetchedBuilderFactory.iterVitals looks up the details from
        # the local cached map, without hitting the DB.

        # Construct 5 new builders, 3 with builds. This is in addition
        # to the 2 in sampledata, 1 with a build.
        builders = [self.factory.makeBuilder() for i in range(5)]
        for i in range(3):
            bq = self.factory.makeBinaryPackageBuild().queueBuild()
            bq.markAsBuilding(builders[i])
        transaction.commit()
        pbf = PrefetchedBuilderFactory()
        pbf.update()

        with StormStatementRecorder() as recorder:
            all_vitals = list(pbf.iterVitals())
        self.assertThat(recorder, HasQueryCount(Equals(0)))
        # Compare the counts with what we expect, and the full result
        # with the non-prefetching BuilderFactory.
        self.assertEqual(7, len(all_vitals))
        self.assertEqual(
            4, len([v for v in all_vitals if v.build_queue is not None]))
        self.assertContentEqual(BuilderFactory().iterVitals(), all_vitals)
    def test_iterVitals(self):
        # PrefetchedBuilderFactory.iterVitals looks up the details from
        # the local cached map, without hitting the DB.

        # Construct 5 new builders, 3 with builds. This is in addition
        # to the 2 in sampledata, 1 with a build.
        builders = [self.factory.makeBuilder() for i in range(5)]
        for i in range(3):
            bq = self.factory.makeBinaryPackageBuild().queueBuild()
            bq.markAsBuilding(builders[i])
        transaction.commit()
        pbf = PrefetchedBuilderFactory()
        pbf.update()

        with StormStatementRecorder() as recorder:
            all_vitals = list(pbf.iterVitals())
        self.assertThat(recorder, HasQueryCount(Equals(0)))
        # Compare the counts with what we expect, and the full result
        # with the non-prefetching BuilderFactory.
        self.assertEqual(7, len(all_vitals))
        self.assertEqual(
            4, len([v for v in all_vitals if v.build_queue is not None]))
        self.assertContentEqual(BuilderFactory().iterVitals(), all_vitals)
    def test_getVitals(self):
        # PrefetchedBuilderFactory.getVitals looks up the BuilderVitals
        # in a local cached map, without hitting the DB.
        builder = self.factory.makeBuilder()
        bq = self.factory.makeBinaryPackageBuild().queueBuild()
        bq.markAsBuilding(builder)
        transaction.commit()
        name = builder.name
        pbf = PrefetchedBuilderFactory()
        pbf.update()

        def assertQuerylessVitals(comparator):
            expected_vitals = extract_vitals_from_db(builder)
            transaction.commit()
            with StormStatementRecorder() as recorder:
                got_vitals = pbf.getVitals(name)
                comparator(expected_vitals, got_vitals)
                comparator(expected_vitals.build_queue, got_vitals.build_queue)
            self.assertThat(recorder, HasQueryCount(Equals(0)))
            return got_vitals

        # We can get the vitals of a builder from the factory without
        # any DB queries.
        vitals = assertQuerylessVitals(self.assertEqual)
        self.assertIsNot(None, vitals.build_queue)

        # If we cancel the BuildQueue to unassign it, the factory
        # doesn't notice immediately.
        bq.cancel()
        vitals = assertQuerylessVitals(self.assertNotEqual)
        self.assertIsNot(None, vitals.build_queue)

        # But the vitals will show the builder as idle if we ask the
        # factory to refetch.
        pbf.update()
        vitals = assertQuerylessVitals(self.assertEqual)
        self.assertIs(None, vitals.build_queue)
 def test_update(self):
     # update grabs all of the Builders and their BuildQueues in a
     # single query.
     builders = [self.factory.makeBuilder() for i in range(5)]
     for i in range(3):
         bq = self.factory.makeBinaryPackageBuild().queueBuild()
         bq.markAsBuilding(builders[i])
     pbf = PrefetchedBuilderFactory()
     transaction.commit()
     pbf.update()
     with StormStatementRecorder() as recorder:
         pbf.update()
     self.assertThat(recorder, HasQueryCount(Equals(1)))
    def test_getVitals(self):
        # PrefetchedBuilderFactory.getVitals looks up the BuilderVitals
        # in a local cached map, without hitting the DB.
        builder = self.factory.makeBuilder()
        bq = self.factory.makeBinaryPackageBuild().queueBuild()
        bq.markAsBuilding(builder)
        transaction.commit()
        name = builder.name
        pbf = PrefetchedBuilderFactory()
        pbf.update()

        def assertQuerylessVitals(comparator):
            expected_vitals = extract_vitals_from_db(builder)
            transaction.commit()
            with StormStatementRecorder() as recorder:
                got_vitals = pbf.getVitals(name)
                comparator(expected_vitals, got_vitals)
                comparator(expected_vitals.build_queue, got_vitals.build_queue)
            self.assertThat(recorder, HasQueryCount(Equals(0)))
            return got_vitals

        # We can get the vitals of a builder from the factory without
        # any DB queries.
        vitals = assertQuerylessVitals(self.assertEqual)
        self.assertIsNot(None, vitals.build_queue)

        # If we cancel the BuildQueue to unassign it, the factory
        # doesn't notice immediately.
        bq.cancel()
        vitals = assertQuerylessVitals(self.assertNotEqual)
        self.assertIsNot(None, vitals.build_queue)

        # But the vitals will show the builder as idle if we ask the
        # factory to refetch.
        pbf.update()
        vitals = assertQuerylessVitals(self.assertEqual)
        self.assertIs(None, vitals.build_queue)
 def test_get(self):
     # PrefetchedBuilderFactory.__getitem__ is unoptimised, just
     # querying and returning the named builder.
     builder = self.factory.makeBuilder()
     pbf = PrefetchedBuilderFactory()
     self.assertEqual(builder, pbf[builder.name])