class TestPropFuncs(unittest.TestCase):
    basedir = "test_misc_scheduler_propfuncs"

    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = mock.Mock()
        self.s.parent.db = self.dbc

        return self.dbc.addSchedulers([self.s])

    def tearDown(self):
        self.dbc.stop()
        shutil.rmtree(self.basedir)

    def test_buildIDSchedFunc(self):
        import time
        with mock.patch.object(time, 'time') as time_method:
            time_method.return_value = 10

            self.dbc.runInteractionNow(
                lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(
                state['last_buildid'],
                time.strftime("%Y%m%d%H%M%S", time.localtime(10)))

            # Running this again at the same time should increment our buildid by 1
            self.dbc.runInteractionNow(
                lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(
                state['last_buildid'],
                time.strftime("%Y%m%d%H%M%S", time.localtime(11)))

            # If time happens to go backwards, our buildid shouldn't
            time_method.return_value = 8
            self.dbc.runInteractionNow(
                lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(
                state['last_buildid'],
                time.strftime("%Y%m%d%H%M%S", time.localtime(12)))

    def test_buildUIDSchedFunc(self):
        import uuid
        with mock.patch.object(uuid, 'uuid4') as uuid4_method:
            uuid4_method.return_value.hex = '1234567890abcdef'
            props = self.dbc.runInteractionNow(
                lambda t: buildUIDSchedFunc(self.s, t, None))
            self.assertEquals(props['builduid'], '1234567890abcdef')
Example #2
0
    def test_many_changes(self):
        m, cm, sm = self.build_harness("db/scheduler/many_changes")
        s = Scheduler("one", branch=None, treeStableTimer=0.01,
                      builderNames=["builder-one"])
        d = sm.updateSchedulers([s])

        # add ten changes, then process them all at once. Sometimes the
        # database connector has problems with lots of queries happening
        # simultaneously.
        for i in range(10):
            c = Change(who="brian", files=["foo%d.txt" % i],
                       comments="change %d" % i,
                       revision="%d" % (i+10))
            d.addCallback(lambda ign, c=c: cm.addChange(c))
        d.addCallback(self.stall, 1.0)
        d.addCallback(lambda ign: s.run())
        def _build_not_sleep(res):
            # a BuildRequest should be pushed, and the Scheduler should go
            # back to sleep
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failUnlessEqual(len(pending), 1)
            changes = pending[0][1].changes
            self.failUnlessEqual(len(changes), 10)
        d.addCallback(_build_not_sleep)

        return d
Example #3
0
    def test_stabletimer(self):
        m, cm, sm = self.build_harness("db/scheduler/stabletimer")
        s = Scheduler("one", branch=None, treeStableTimer=30,
                      builderNames=["builder-one"])
        d = sm.updateSchedulers([s])

        # there are no changes in the database, so the scheduler should want
        # to keep sleeping.
        d.addCallback(lambda ign: s.run())
        def _sleep_forever_not_build(res):
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failIf(pending)
        d.addCallback(_sleep_forever_not_build)

        # now add one change. The scheduler should want to wait for the
        # tree-stable timer to fire.
        c1 = Change(who="brian", files=["foo.c"],
                    comments="first change",
                    revision="1234")
        d.addCallback(lambda ign: cm.addChange(c1))
        d.addCallback(lambda ign: s.run())
        def _sleep_not_build(res):
            # the scheduler should tell us that they want to be woken up in
            # 30 seconds. This test would be much too fragile if we actually
            # asserted anything about its value, though.
            self.failUnlessEqual(type(res), float)
            pending = self.get_buildrequests(m, cm)
            self.failIf(pending)
        d.addCallback(_sleep_not_build)

        # running it again should tell us roughly the same thing
        d.addCallback(lambda ign: s.run())
        d.addCallback(_sleep_not_build)
        def _reduce_timer(res):
            # artificially lower the tree-stable-timer value
            s.treeStableTimer = 0
        d.addCallback(_reduce_timer)
        d.addCallback(lambda ign: s.run())
        def _build_not_sleep(res):
            # a BuildRequest should be pushed, and the Scheduler should go
            # back to sleep
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failUnlessEqual(len(pending), 1)
            changes = pending[0][1].changes
            self.failUnlessEqual(len(changes), 1)
            self.failUnlessEqual(changes[0].revision, "1234")
            self.failUnlessEqual(changes[0].files, ["foo.c"])
        d.addCallback(_build_not_sleep)

        return d
class TestPropFuncs(unittest.TestCase):
    basedir = "test_misc_scheduler_propfuncs"
    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = mock.Mock()
        self.s.parent.db = self.dbc

        return self.dbc.addSchedulers([self.s])

    def tearDown(self):
        self.dbc.stop()
        shutil.rmtree(self.basedir)

    def test_buildIDSchedFunc(self):
        import time
        with mock.patch.object(time, 'time') as time_method:
            time_method.return_value = 10

            self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(10)))

            # Running this again at the same time should increment our buildid by 1
            self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(11)))

            # If time happens to go backwards, our buildid shouldn't
            time_method.return_value = 8
            self.dbc.runInteractionNow(lambda t: buildIDSchedFunc(self.s, t, None))
            state = self.dbc.runInteractionNow(lambda t: self.s.get_state(t))
            self.assertEquals(state['last_buildid'], time.strftime("%Y%m%d%H%M%S", time.localtime(12)))

    def test_buildUIDSchedFunc(self):
        import uuid
        with mock.patch.object(uuid, 'uuid4') as uuid4_method:
            uuid4_method.return_value.hex = '1234567890abcdef'
            props = self.dbc.runInteractionNow(lambda t: buildUIDSchedFunc(self.s, t, None))
            self.assertEquals(props['builduid'], '1234567890abcdef')
    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = mock.Mock()
        self.s.parent.db = self.dbc

        return self.dbc.addSchedulers([self.s])
    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = mock.Mock()
        self.s.parent.db = self.dbc

        return self.dbc.addSchedulers([self.s])
Example #7
0
def Update(_config, active_master, c):
  factory_obj = annotator_factory.AnnotatorFactory(
      active_master=active_master)

  builders = [
      Builder(factory_obj, 'x86-generic'),
      Builder(factory_obj, 'amd64-generic'),
  ]

  c['schedulers'] += [
      Scheduler(name='chromium_src_asan',
                branch='master',
                treeStableTimer=60,
                builderNames=[b['name'] for b in builders],
      ),
  ]
  c['builders'] += builders
Example #8
0
  def Update(self, c):
    global_schedulers = dict((s.name, s) for s in c['schedulers']
                             if s.name.startswith('global_'))
    assert not (set(global_schedulers) & set(self._schedulers))

    for builder in self._builders:
      # Update the schedulers with the builder.
      schedulers = builder['schedulers']
      if schedulers:
        for scheduler in schedulers:
          if scheduler in global_schedulers:
            global_schedulers[scheduler].builderNames.append(builder['name'])
          else:
            self._schedulers[scheduler]['builders'].append(builder['name'])

      # Construct the category.
      categories = []
      if builder.get('category', None):
        categories.append(builder['category'])
      if builder.get('gatekeeper', None):
        categories.extend(builder['gatekeeper'].split('|'))
      category = '|'.join(categories)

      # Append the builder to the list.
      new_builder = {'name': builder['name'],
                     'factory': self._factories[builder['factory']],
                     'category': category,
                     'auto_reboot': builder['auto_reboot']}
      if builder['builddir']:
        new_builder['builddir'] = builder['builddir']
      if builder['slavebuilddir']:
        new_builder['slavebuilddir'] = builder['slavebuilddir']
      c['builders'].append(new_builder)

    # Process the main schedulers.
    for s_name in self._schedulers:
      scheduler = self._schedulers[s_name]
      if scheduler['type'] == 'Scheduler':
        instance = Scheduler(name=s_name,
                             branch=scheduler['branch'],
                             treeStableTimer=scheduler['treeStableTimer'],
                             builderNames=scheduler['builders'],
                             categories=scheduler['categories'])
        scheduler['instance'] = instance
        c['schedulers'].append(instance)
      elif scheduler['type'] == 'URLScheduler':
        ident = str(uuid.uuid4())
        c['change_source'].append(
          URLPoller(changeurl=scheduler['url'],
                    pollInterval=scheduler['pollInterval'],
                    category=ident,
                    include_revision=scheduler['include_revision']))
        instance = Scheduler(name=s_name,
                             change_filter=ChangeFilter(category=ident),
                             builderNames=scheduler['builders'])
        scheduler['instance'] = instance
        c['schedulers'].append(instance)

    # Process the dependent schedulers.
    for s_name in self._schedulers:
      scheduler = self._schedulers[s_name]
      if scheduler['type'] == 'Dependent':
        c['schedulers'].append(
            Dependent(s_name,
                      self._schedulers[scheduler['parent']]['instance'],
                      scheduler['builders']))

    # Process the triggerable schedulers.
    for s_name in self._schedulers:
      scheduler = self._schedulers[s_name]
      if scheduler['type'] == 'Triggerable':
        c['schedulers'].append(Triggerable(s_name,
                                           scheduler['builders']))

    # Process the periodic schedulers.
    for s_name in self._schedulers:
      scheduler = self._schedulers[s_name]
      if scheduler['type'] == 'Periodic':
        c['schedulers'].append(
            Periodic(s_name,
                     periodicBuildTimer=scheduler['periodicBuildTimer'],
                     builderNames=scheduler['builders']))

    # Process the nightly schedulers.
    for s_name in self._schedulers:
      scheduler = self._schedulers[s_name]
      if scheduler['type'] == 'Nightly':
        c['schedulers'].append(Nightly(s_name,
                                       branch=scheduler['branch'],
                                       hour=scheduler['hour'],
                                       builderNames=scheduler['builders']))
Example #9
0
class TestTestOrder(unittest.TestCase):
    """Tests that tests are run according to their corresponding build's start
    time"""

    basedir = "test_test_order"

    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        parent = mock.Mock()
        parent.db = self.dbc

        change_manager = ChangeManager()
        change_manager.parent = parent

        parent.change_svc = change_manager

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = parent


        return self.dbc.addSchedulers([self.s])

    def makeBuilder(self, klass):
        dummy_factory = klass([Dummy()])
        builder = {
                'name': 'b1',
                'slavenames': ['s1'],
                'builddir': 'b1',
                'slavebuilddir': 'b1',
                'factory': dummy_factory,
                }
        builder_status = mock.Mock()

        builder = Builder(builder, builder_status)
        builder.running = True
        builder.db = self.dbc
        builder.master_name = 'test_master'
        builder.master_incarnation = '12345'
        builder.botmaster = mock.Mock()
        builder.botmaster.shouldMergeRequests.return_value = True
        return builder

    def tearDown(self):
        self.dbc.stop()
        shutil.rmtree(self.basedir)

    def test_singleRequest(self):
        # Easy peasy
        c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000001'})
        self.dbc.addChangeToDatabase(c1)

        builder = self.makeBuilder(BuildFactory)

        # Run the scheduler
        d = self.s.run()

        # Check that we have a build request
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 1)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 1)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, '1')

            changes = build.source.changes
            self.assertEquals(changes[0].revision, '1')
            return
        d.addCallback(startBuild)

        return d

    def test_threeRequests(self):
        # Three changes, r1, r2, r3
        # They start in order, and finish in reverse order
        # We want the to be testing r3 in the end
        c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000003'}, when=4)
        c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000002'}, when=5)
        c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000001'}, when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r3')

            changes = build.source.changes
            # The last revision should be r3, since it started latest
            self.assertEquals(changes[0].revision, 'r1')
            self.assertEquals(changes[1].revision, 'r2')
            self.assertEquals(changes[2].revision, 'r3')
            return
        d.addCallback(startBuild)
        return d

    def test_threeRequestsUnsorted(self):
        # Three changes, r1, r2, r3
        # They start in order, and finish in reverse order
        # We want the to be testing r3 in the end
        c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000003'}, when=4)
        c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000002'}, when=5)
        c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000001'}, when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(BuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was submitted latest
            self.assertEquals(changes[0].revision, 'r3')
            self.assertEquals(changes[1].revision, 'r2')
            self.assertEquals(changes[2].revision, 'r1')
            return
        d.addCallback(startBuild)
        return d

    def test_threeRequestsManual(self):
        # Three changes, r1, r2, r3
        # r2, and r3 have buildids
        # r1 is manually triggered, and is submitted later
        # we want to be testing r1 in the end
        c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000003'}, when=4)
        c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000002'}, when=5)
        c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'],
                comments='really important', when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was manually triggered later
            self.assertEquals(changes[0].revision, 'r2')
            self.assertEquals(changes[1].revision, 'r3')
            self.assertEquals(changes[2].revision, 'r1')
            return
        d.addCallback(startBuild)
        return d

    def test_Rebuilds(self):
        # Two changes, r2, r3
        # They start in order, and finish in reverse order
        # We also have a pending request to re-build r1 that happens after r2, r3 have started
        # We want to end up re-building r1
        c1 = Change(who='me!', branch='b1', revision='r3', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000003'}, when=4)
        c2 = Change(who='me!', branch='b1', revision='r2', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000002'}, when=5)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)

        # Run the scheduler
        d = self.s.run()

        # Rebuild r1
        def addRebuild(t):
            c3 = Change(who='me!', branch='b1', revision='r1', files=['http://path/to/build'],
                    comments='really important', properties={'buildid': '20110214000001'}, when=6)
            self.dbc.addChangeToDatabase(c3)
            ss = SourceStamp(branch='b1', changes=[c3], revision='r1')
            ss1 = ss.getAbsoluteSourceStamp('r1')
            ssid = self.dbc.get_sourcestampid(ss, t)
            bsid = self.dbc.create_buildset(ssid, "rebuild", Properties(), ["b1"], t)

        d.addCallback(lambda ign: self.dbc.runInteractionNow(addRebuild))

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was manually triggered later
            self.assertEquals(changes[0].revision, 'r2')
            self.assertEquals(changes[1].revision, 'r3')
            self.assertEquals(changes[2].revision, 'r1')
            return
        d.addCallback(startBuild)
        return d

    def test_brokenRequest(self):
        c1 = Change(who='me!', branch='b1', revision='1', files=['http://path/to/build'],
                comments='really important', properties={'buildid': '20110214000001'})
        self.dbc.addChangeToDatabase(c1)

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Run the scheduler
        d = self.s.run()

        # Check that we have a build request
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 1)
        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d
        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            # Hack the request to break the sorting
            requests[0].submittedAt = "asdf"
            requests[0].reason = "rebuild"

            self.assertEquals(len(requests), 1)

            build = builder.buildFactory.newBuild(requests)
            # This should have generated an error
            self.failUnless(len(self.flushLoggedErrors()) == 1)
            self.assertEquals(build.source.revision, '1')

            changes = build.source.changes
            self.assertEquals(changes[0].revision, '1')
            return
        d.addCallback(startBuild)

        return d
Example #10
0
    def test_immediate(self):
        m, cm, sm = self.build_harness("db/scheduler/immediate")
        def fileIsImportant(c):
            for fn in c.files:
                if not fn.endswith(".txt"):
                    return True
            return False
        # we set the treeStableTimer to something tiny, since "None" has a
        # special meaning ("do not merge Changes")
        s = Scheduler("one", branch=None, treeStableTimer=0.01,
                      builderNames=["builder-one"],
                      fileIsImportant=fileIsImportant)
        d = sm.updateSchedulers([s])

        # there are no changes in the database, so the scheduler should want
        # to keep sleeping.
        d.addCallback(lambda ign: s.run())
        def _sleep_forever_not_build(res):
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failIf(pending)
        d.addCallback(_sleep_forever_not_build)

        # now add one change. The change is "unimportant", so no build will
        # be run.
        c1 = Change(who="brian", files=["docs.txt"],
                    comments="doc change",
                    revision="1234")
        d.addCallback(lambda ign: cm.addChange(c1))
        d.addCallback(lambda ign: s.run())
        d.addCallback(_sleep_forever_not_build)
        # running it again should tell us the same thing
        d.addCallback(lambda ign: s.run())
        d.addCallback(_sleep_forever_not_build)

        # now add a second change which evaluates as "important", which
        # should trigger a build with both changes after the treeStableTimer
        # has passed, which should be quickly
        c2 = Change(who="brian", files=["foo.c", "subdir/bar.c"],
                    comments="second change",
                    revision="1235")
        d.addCallback(lambda ign: cm.addChange(c2))
        # stall here to let the treeStableTimer expire
        d.addCallback(self.stall, 1.0)
        d.addCallback(lambda ign: s.run())
        def _build_not_sleep(res):
            # a BuildRequest should be pushed, and the Scheduler should go
            # back to sleep
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failUnlessEqual(len(pending), 1)
            changes = pending[0][1].changes
            self.failUnlessEqual(len(changes), 2)
            self.failUnlessEqual(changes[0].revision, "1234")
            self.failUnlessEqual(changes[0].files, ["docs.txt"])
            self.failUnlessEqual(changes[1].revision, "1235")
            self.failUnlessIn("foo.c", changes[1].files)
            self.failUnlessIn("subdir/bar.c", changes[1].files)
        d.addCallback(_build_not_sleep)
        # running it again should not do anything
        d.addCallback(lambda ign: s.run())
        def _build_and_sleep(res):
            self.failUnlessEqual(res, None)
            pending = self.get_buildrequests(m, cm)
            self.failUnlessEqual(len(pending), 1)
        d.addCallback(_build_and_sleep)

        return d
Example #11
0
class TestTestOrder(unittest.TestCase):
    """Tests that tests are run according to their corresponding build's start
    time"""

    basedir = "test_test_order"

    def setUp(self):
        if os.path.exists(self.basedir):
            shutil.rmtree(self.basedir)
        os.makedirs(self.basedir)
        spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", self.basedir)
        manager = DBSchemaManager(spec, self.basedir)
        manager.upgrade()

        self.dbc = connector.DBConnector(spec)
        self.dbc.start()

        parent = mock.Mock()
        parent.db = self.dbc

        change_manager = ChangeManager()
        change_manager.parent = parent

        parent.change_svc = change_manager

        self.s = Scheduler(name="s", builderNames=["b1"])
        self.s.parent = parent

        return self.dbc.addSchedulers([self.s])

    def makeBuilder(self, klass):
        dummy_factory = klass([Dummy()])
        builder = {
            'name': 'b1',
            'slavenames': ['s1'],
            'builddir': 'b1',
            'slavebuilddir': 'b1',
            'factory': dummy_factory,
        }
        builder_status = mock.Mock()

        builder = Builder(builder, builder_status)
        builder.running = True
        builder.db = self.dbc
        builder.master_name = 'test_master'
        builder.master_incarnation = '12345'
        builder.botmaster = mock.Mock()
        builder.botmaster.shouldMergeRequests.return_value = True
        return builder

    def tearDown(self):
        self.dbc.stop()
        shutil.rmtree(self.basedir)

    def test_singleRequest(self):
        # Easy peasy
        c1 = Change(who='me!',
                    branch='b1',
                    revision='1',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000001'})
        self.dbc.addChangeToDatabase(c1)

        builder = self.makeBuilder(BuildFactory)

        # Run the scheduler
        d = self.s.run()

        # Check that we have a build request
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 1)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 1)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, '1')

            changes = build.source.changes
            self.assertEquals(changes[0].revision, '1')
            return

        d.addCallback(startBuild)

        return d

    def test_threeRequests(self):
        # Three changes, r1, r2, r3
        # They start in order, and finish in reverse order
        # We want the to be testing r3 in the end
        c1 = Change(who='me!',
                    branch='b1',
                    revision='r3',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000003'},
                    when=4)
        c2 = Change(who='me!',
                    branch='b1',
                    revision='r2',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000002'},
                    when=5)
        c3 = Change(who='me!',
                    branch='b1',
                    revision='r1',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000001'},
                    when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r3')

            changes = build.source.changes
            # The last revision should be r3, since it started latest
            self.assertEquals(changes[0].revision, 'r1')
            self.assertEquals(changes[1].revision, 'r2')
            self.assertEquals(changes[2].revision, 'r3')
            return

        d.addCallback(startBuild)
        return d

    def test_threeRequestsUnsorted(self):
        # Three changes, r1, r2, r3
        # They start in order, and finish in reverse order
        # We want the to be testing r3 in the end
        c1 = Change(who='me!',
                    branch='b1',
                    revision='r3',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000003'},
                    when=4)
        c2 = Change(who='me!',
                    branch='b1',
                    revision='r2',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000002'},
                    when=5)
        c3 = Change(who='me!',
                    branch='b1',
                    revision='r1',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000001'},
                    when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(BuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was submitted latest
            self.assertEquals(changes[0].revision, 'r3')
            self.assertEquals(changes[1].revision, 'r2')
            self.assertEquals(changes[2].revision, 'r1')
            return

        d.addCallback(startBuild)
        return d

    def test_threeRequestsManual(self):
        # Three changes, r1, r2, r3
        # r2, and r3 have buildids
        # r1 is manually triggered, and is submitted later
        # we want to be testing r1 in the end
        c1 = Change(who='me!',
                    branch='b1',
                    revision='r3',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000003'},
                    when=4)
        c2 = Change(who='me!',
                    branch='b1',
                    revision='r2',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000002'},
                    when=5)
        c3 = Change(who='me!',
                    branch='b1',
                    revision='r1',
                    files=['http://path/to/build'],
                    comments='really important',
                    when=6)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)
        self.dbc.addChangeToDatabase(c3)

        # Run the scheduler
        d = self.s.run()

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was manually triggered
            # later
            self.assertEquals(changes[0].revision, 'r2')
            self.assertEquals(changes[1].revision, 'r3')
            self.assertEquals(changes[2].revision, 'r1')
            return

        d.addCallback(startBuild)
        return d

    def test_Rebuilds(self):
        # Two changes, r2, r3
        # They start in order, and finish in reverse order
        # We also have a pending request to re-build r1 that happens after r2, r3 have started
        # We want to end up re-building r1
        c1 = Change(who='me!',
                    branch='b1',
                    revision='r3',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000003'},
                    when=4)
        c2 = Change(who='me!',
                    branch='b1',
                    revision='r2',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000002'},
                    when=5)
        self.dbc.addChangeToDatabase(c1)
        self.dbc.addChangeToDatabase(c2)

        # Run the scheduler
        d = self.s.run()

        # Rebuild r1
        def addRebuild(t):
            c3 = Change(who='me!',
                        branch='b1',
                        revision='r1',
                        files=['http://path/to/build'],
                        comments='really important',
                        properties={'buildid': '20110214000001'},
                        when=6)
            self.dbc.addChangeToDatabase(c3)
            ss = SourceStamp(branch='b1', changes=[c3], revision='r1')
            ssid = self.dbc.get_sourcestampid(ss, t)
            self.dbc.create_buildset(ssid, "rebuild", Properties(), ["b1"], t)

        d.addCallback(lambda ign: self.dbc.runInteractionNow(addRebuild))

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Check that we have three build requests
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 3)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            self.assertEquals(len(requests), 3)

            build = builder.buildFactory.newBuild(requests)
            self.assertEquals(build.source.revision, 'r1')

            changes = build.source.changes
            # The last revision should be r1, since it was manually triggered
            # later
            self.assertEquals(changes[0].revision, 'r2')
            self.assertEquals(changes[1].revision, 'r3')
            self.assertEquals(changes[2].revision, 'r1')
            return

        d.addCallback(startBuild)
        return d

    def test_brokenRequest(self):
        c1 = Change(who='me!',
                    branch='b1',
                    revision='1',
                    files=['http://path/to/build'],
                    comments='really important',
                    properties={'buildid': '20110214000001'})
        self.dbc.addChangeToDatabase(c1)

        builder = self.makeBuilder(RequestSortingBuildFactory)

        # Run the scheduler
        d = self.s.run()

        # Check that we have a build request
        def checkRequests(ign):
            req = self.dbc.runQueryNow("select count(*) from buildrequests")
            self.assertEquals(req[0][0], 1)

        d.addCallback(checkRequests)

        # Claim the request
        def claimRequest(ign):
            d = self.dbc.runInteraction(builder._claim_buildreqs, ["slave!"])
            return d

        d.addCallback(claimRequest)

        # Start the build!
        def startBuild(assignments):
            self.assertEquals(len(assignments.keys()), 1)
            requests = assignments.values()[0]
            # Hack the request to break the sorting
            requests[0].submittedAt = "asdf"
            requests[0].reason = "rebuild"

            self.assertEquals(len(requests), 1)

            build = builder.buildFactory.newBuild(requests)
            # This should have generated an error
            self.failUnless(len(self.flushLoggedErrors()) == 1)
            self.assertEquals(build.source.revision, '1')

            changes = build.source.changes
            self.assertEquals(changes[0].revision, '1')
            return

        d.addCallback(startBuild)

        return d