예제 #1
0
 def test_job_graph_disallows_multiple_jobs_with_same_name(self):
     graph = model.JobGraph()
     job1 = model.Job('job')
     job2 = model.Job('job')
     graph.addJob(job1)
     with testtools.ExpectedException(Exception, "Job job already added"):
         graph.addJob(job2)
예제 #2
0
    def test_node_request(self):
        # Test a simple node request

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller', 'foo'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        request = self.nodepool.requestNodes(None, job, 0)
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 1)
        self.assertEqual(request.state, 'fulfilled')

        # Accept the nodes
        self.nodepool.acceptNodes(request, request.id)
        nodeset = request.nodeset

        for node in nodeset.getNodes():
            self.assertIsNotNone(node.lock)
            self.assertEqual(node.state, 'ready')

        # Mark the nodes in use
        self.nodepool.useNodeSet(nodeset)
        for node in nodeset.getNodes():
            self.assertEqual(node.state, 'in-use')

        # Return the nodes
        self.nodepool.returnNodeSet(nodeset)
        for node in nodeset.getNodes():
            self.assertIsNone(node.lock)
            self.assertEqual(node.state, 'used')
예제 #3
0
 def job(self):
     job = model.Job('job')
     job.skip_if_matcher = cm.MatchAll([
         cm.ProjectMatcher('^project$'),
         cm.MatchAllFiles([cm.FileMatcher('^docs/.*$')]),
     ])
     return job
예제 #4
0
    def test_job_graph_allows_soft_dependencies(self):
        parent = model.Job('parent')
        child = model.Job('child')
        child.dependencies = frozenset(
            [model.JobDependency(parent.name, True)])

        # With the parent
        graph = model.JobGraph()
        graph.addJob(parent)
        graph.addJob(child)
        self.assertEqual(graph.getParentJobsRecursively(child.name), [parent])

        # Skip the parent
        graph = model.JobGraph()
        graph.addJob(child)
        self.assertEqual(graph.getParentJobsRecursively(child.name), [])
예제 #5
0
    def test_node_request(self):
        # Test a simple node request

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller'], 'fake-label'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        request = self.nodepool.requestNodes(None, job, 0)
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 1)
        self.assertEqual(request.state, model.STATE_FULFILLED)

        # Accept the nodes
        self.nodepool.acceptNodes(request, request.id)
        nodeset = request.nodeset

        for node in nodeset.getNodes():
            self.assertIsNotNone(node.lock)
            self.assertEqual(node.state, model.STATE_READY)

        # Mark the nodes in use
        self.nodepool.useNodeSet(nodeset)
        for node in nodeset.getNodes():
            self.assertEqual(node.state, model.STATE_IN_USE)

        # Return the nodes
        self.nodepool.returnNodeSet(nodeset)
        for node in nodeset.getNodes():
            self.assertIsNone(node.lock)
            self.assertEqual(node.state, model.STATE_USED)
예제 #6
0
    def test_job_variants(self):
        # This simulates freezing a job.

        secrets = ['foo']
        py27_pre = model.PlaybookContext(self.context, 'py27-pre', [], secrets)
        py27_run = model.PlaybookContext(self.context, 'py27-run', [], secrets)
        py27_post = model.PlaybookContext(self.context, 'py27-post', [],
                                          secrets)

        py27 = model.Job('py27')
        py27.timeout = 30
        py27.pre_run = [py27_pre]
        py27.run = [py27_run]
        py27.post_run = [py27_post]

        job = py27.copy()
        self.assertEqual(30, job.timeout)

        # Apply the diablo variant
        diablo = model.Job('py27')
        diablo.timeout = 40
        job.applyVariant(diablo, self.layout)

        self.assertEqual(40, job.timeout)
        self.assertEqual(['py27-pre'], [x.path for x in job.pre_run])
        self.assertEqual(['py27-run'], [x.path for x in job.run])
        self.assertEqual(['py27-post'], [x.path for x in job.post_run])
        self.assertEqual(secrets, job.pre_run[0].secrets)
        self.assertEqual(secrets, job.run[0].secrets)
        self.assertEqual(secrets, job.post_run[0].secrets)

        # Set the job to final for the following checks
        job.final = True
        self.assertTrue(job.voting)

        good_final = model.Job('py27')
        good_final.voting = False
        job.applyVariant(good_final, self.layout)
        self.assertFalse(job.voting)

        bad_final = model.Job('py27')
        bad_final.timeout = 600
        with testtools.ExpectedException(Exception,
                                         "Unable to modify final job"):
            job.applyVariant(bad_final, self.layout)
예제 #7
0
 def test_invalid_node_request(self):
     # Test requests with an invalid node type fail
     nodeset = model.NodeSet()
     nodeset.addNode(model.Node(['controller'], 'invalid-label'))
     job = model.Job('testjob')
     job.nodeset = nodeset
     request = self.nodepool.requestNodes(None, job, 0)
     self.waitForRequests()
     self.assertEqual(len(self.provisioned_requests), 1)
     self.assertEqual(request.state, model.STATE_FAILED)
예제 #8
0
    def test_job_graph_allows_soft_dependencies4(self):
        # A more complex scenario with multiple parents at each level
        parents = [model.Job('parent%i' % i) for i in range(6)]
        child = model.Job('child')
        child.dependencies = frozenset([
            model.JobDependency(parents[0].name, True),
            model.JobDependency(parents[1].name)
        ])
        parents[0].dependencies = frozenset([
            model.JobDependency(parents[2].name),
            model.JobDependency(parents[3].name, True)
        ])
        parents[1].dependencies = frozenset([
            model.JobDependency(parents[4].name),
            model.JobDependency(parents[5].name)
        ])
        # Run them all
        graph = model.JobGraph()
        for j in parents:
            graph.addJob(j)
        graph.addJob(child)
        self.assertEqual(set(graph.getParentJobsRecursively(child.name)),
                         set(parents))

        # Skip first parent, therefore its recursive dependencies don't appear
        graph = model.JobGraph()
        for j in parents:
            if j is not parents[0]:
                graph.addJob(j)
        graph.addJob(child)
        self.assertEqual(
            set(graph.getParentJobsRecursively(child.name)),
            set(parents) - set([parents[0], parents[2], parents[3]]))

        # Skip a leaf node
        graph = model.JobGraph()
        for j in parents:
            if j is not parents[3]:
                graph.addJob(j)
        graph.addJob(child)
        self.assertEqual(set(graph.getParentJobsRecursively(child.name)),
                         set(parents) - set([parents[3]]))
예제 #9
0
    def test_job_graph_disallows_circular_dependencies(self):
        graph = model.JobGraph()
        jobs = [model.Job('job%d' % i) for i in range(0, 10)]
        prevjob = None
        for j in jobs[:3]:
            if prevjob:
                j.dependencies = frozenset([model.JobDependency(prevjob.name)])
            graph.addJob(j)
            prevjob = j
        # 0 triggers 1 triggers 2 triggers 3...

        # Cannot depend on itself
        with testtools.ExpectedException(
                Exception, "Dependency cycle detected in job jobX"):
            j = model.Job('jobX')
            j.dependencies = frozenset([model.JobDependency(j.name)])
            graph.addJob(j)

        # Disallow circular dependencies
        with testtools.ExpectedException(
                Exception, "Dependency cycle detected in job job3"):
            jobs[4].dependencies = frozenset(
                [model.JobDependency(jobs[3].name)])
            graph.addJob(jobs[4])
            jobs[3].dependencies = frozenset(
                [model.JobDependency(jobs[4].name)])
            graph.addJob(jobs[3])

        jobs[5].dependencies = frozenset([model.JobDependency(jobs[4].name)])
        graph.addJob(jobs[5])

        with testtools.ExpectedException(
                Exception, "Dependency cycle detected in job job3"):
            jobs[3].dependencies = frozenset(
                [model.JobDependency(jobs[5].name)])
            graph.addJob(jobs[3])

        jobs[3].dependencies = frozenset([model.JobDependency(jobs[2].name)])
        graph.addJob(jobs[3])
        jobs[6].dependencies = frozenset([model.JobDependency(jobs[2].name)])
        graph.addJob(jobs[6])
예제 #10
0
    def test_node_request_canceled(self):
        # Test that node requests can be canceled

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        self.fake_nodepool.pause()
        request = self.nodepool.requestNodes(None, job, 0)
        self.nodepool.cancelRequest(request)

        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 0)
예제 #11
0
    def test_node_request_disconnect(self):
        # Test that node requests are re-submitted after disconnect

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        self.fake_nodepool.pause()
        request = self.nodepool.requestNodes(None, job, 0)
        self.zk.client.stop()
        self.zk.client.start()
        self.fake_nodepool.unpause()
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 1)
        self.assertEqual(request.state, 'fulfilled')
예제 #12
0
    def test_node_request_priority(self):
        # Test that requests are satisfied in priority order

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller', 'foo'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        self.fake_nodepool.pause()
        request1 = self.nodepool.requestNodes(None, job, 1)
        request2 = self.nodepool.requestNodes(None, job, 0)
        self.fake_nodepool.unpause()
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 2)
        self.assertEqual(request1.state, 'fulfilled')
        self.assertEqual(request2.state, 'fulfilled')
        self.assertTrue(request2.state_time < request1.state_time)
예제 #13
0
    def test_accept_nodes_resubmitted(self):
        # Test that a resubmitted request would not lock nodes

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        request = self.nodepool.requestNodes(None, job, 0)
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 1)
        self.assertEqual(request.state, 'fulfilled')

        # Accept the nodes, passing a different ID
        self.nodepool.acceptNodes(request, "invalid")
        nodeset = request.nodeset

        for node in nodeset.getNodes():
            self.assertIsNone(node.lock)
            self.assertEqual(node.state, 'ready')
예제 #14
0
    def test_accept_nodes_lost_request(self):
        # Test that a lost request would not lock nodes

        nodeset = model.NodeSet()
        nodeset.addNode(model.Node(['controller'], 'ubuntu-xenial'))
        nodeset.addNode(model.Node(['compute'], 'ubuntu-xenial'))
        job = model.Job('testjob')
        job.nodeset = nodeset
        request = self.nodepool.requestNodes(None, job, 0)
        self.waitForRequests()
        self.assertEqual(len(self.provisioned_requests), 1)
        self.assertEqual(request.state, 'fulfilled')

        self.zk.deleteNodeRequest(request)

        # Accept the nodes
        self.nodepool.acceptNodes(request, request.id)
        nodeset = request.nodeset

        for node in nodeset.getNodes():
            self.assertIsNone(node.lock)
            self.assertEqual(node.state, 'ready')
예제 #15
0
 def test_job_sets_defaults_for_boolean_attributes(self):
     job = model.Job('job')
     self._assert_job_booleans_are_not_none(job)
예제 #16
0
 def test_copy_retains_skip_if(self):
     job = model.Job('job')
     job.copy(self.job)
     self.assertTrue(job.skip_if_matcher)
예제 #17
0
 def test_metajob_does_not_set_defaults_for_boolean_attributes(self):
     job = model.Job('^job')
     self.assertIsNone(job.voting)
     self.assertIsNone(job.hold_following_changes)
예제 #18
0
 def test_metajob_copy_does_not_set_undefined_boolean_attributes(self):
     job = model.Job('job')
     metajob = model.Job('^job')
     job.copy(metajob)
     self._assert_job_booleans_are_not_none(job)