예제 #1
0
 def test_1388055(self):
     """
     https://bugs.launchpad.net/plainbox/+bug/1388055
     """
     # This bug is about being able to resume a session despite job database
     # modification. Let's assume the following session first:
     # - desired job list: [a]
     # - run list [a_dep, a] (computed)
     # - job_repr: {a_dep: checksum}
     job_a = make_job(id='a', depends='a_dep')
     job_a_dep = make_job(id='a_dep')
     state = SessionState([job_a, job_a_dep])
     state.update_desired_job_list([job_a])
     self.assertEqual(state.run_list, [job_a_dep, job_a])
     self.assertEqual(state.desired_job_list, [job_a])
     helper = SessionSuspendHelper4()
     session_dir = None
     # Mock away the meta-data as we're not testing that
     with mock.patch.object(helper, '_repr_SessionMetaData') as m:
         m.return_value = 'mocked'
         actual = helper._repr_SessionState(state, session_dir)
     expected = {
         'jobs': {
             job_a_dep.id: job_a_dep.checksum,
             job_a.id: job_a.checksum,
         },
         'desired_job_list': [job_a.id],
         'mandatory_job_list': [],
         'results': {},
         'metadata': 'mocked'
     }
     self.assertEqual(expected, actual)
예제 #2
0
    def test_repr_SessionState_typical_session(self):
        """
        verify the representation of a SessionState with some unused jobs

        Unused jobs should just have no representation. Their checksum
        should not be mentioned. Their results (empty results) should be
        ignored.
        """
        used_job = JobDefinition({
            "plugin": "shell",
            "id": "used",
            "command": "echo 'hello world'",
        })
        unused_job = JobDefinition({
            "plugin": "shell",
            "id": "unused",
            "command": "echo 'hello world'",
        })
        used_result = MemoryJobResult({
            "io_log": [
                (0.0, "stdout", b'hello world\n'),
            ],
            'outcome':
            IJobResult.OUTCOME_PASS
        })
        session_state = SessionState([used_job, unused_job])
        session_state.update_desired_job_list([used_job])
        session_state.update_job_result(used_job, used_result)
        data = self.helper._repr_SessionState(session_state, self.session_dir)
        self.assertEqual(
            data, {
                'jobs': {
                    'used':
                    ('8c393c19fdfde1b6afc5b79d0a1617ecf7531cd832a16450dc'
                     '2f3f50d329d373')
                },
                'results': {
                    'used': [{
                        'comments': None,
                        'execution_duration': None,
                        'io_log': [[0.0, 'stdout', 'aGVsbG8gd29ybGQK']],
                        'outcome': 'pass',
                        'return_code': None
                    }]
                },
                'desired_job_list': ['used'],
                'mandatory_job_list': [],
                'metadata': {
                    'title': None,
                    'flags': [],
                    'running_job_name': None,
                    'app_blob': '',
                    'app_id': None,
                    'custom_joblist': False,
                    'rejected_jobs': []
                },
            })
예제 #3
0
class GeneratedJobSuspendTests(TestCase):
    """
    Tests that check how SessionSuspendHelper behaves when faced with
    generated jobs. This tests sets up the following job hierarchy:

        __category__
           \-> generator
                \-> generated

    The "__category__" job is a typical "catter" job that cats an existing
    job from somewhere else in the filesystem. This type of generated job
    is used often for category assignment.

    The "generator" job is a typical non-catter job that actually creates
    new jobs in some way. In this test it generates a job called "generated".
    """

    def setUp(self):
        # Crete a "__category__" job
        self.category_job = JobDefinition({
            "plugin": "local",
            "id": "__category__"
        })
        # Create a "generator" job
        self.generator_job = JobDefinition({
            "plugin": "local",
            "id": "generator"
        })
        # Keep a variable for the (future) generated job
        self.generated_job = None
        # Create a result for the "__category__" job.
        # It must define a verbatim copy of the "generator" job
        self.category_result = MemoryJobResult({
            "io_log": [
                (0.0, "stdout", b'plugin:local\n'),
                (0.1, "stdout", b'id:generator\n'),
            ]
        })
        # Create a result for the "generator" job.
        # It will define the "generated" job
        self.generator_result = MemoryJobResult({
            "io_log": [(0.0, 'stdout', b'id:generated')]
        })
        # Create a session that knows about the two jobs that exist
        # directly as files (__category__ and generator)
        self.session_state = SessionState([
            self.category_job, self.generator_job])
        # Select both of them for execution.
        self.session_state.update_desired_job_list([
            self.category_job, self.generator_job])
        # "execute" the "__category__" job by showing the session the result
        self.session_state.update_job_result(
            self.category_job, self.category_result)
        # Ensure that the generator job gained the "via" attribute
        # This is how we know the code above has no typos or anything.
        self.assertEqual(
            self.generator_job.via, self.category_job.checksum)
        # "execute" the "generator" job by showing the session the result.
        # Connect the 'on_job_added' signal to a helper function that
        # extracts the "generated" job

        def job_added(self, job):
            self.generated_job = job
        # Use partial to supply 'self' from the class into the function above
        self.session_state.on_job_added.connect(partial(job_added, self))
        # Show the result of the "generator" job to the session,
        # this will define the "generated" job, fire the signal
        # and call our callback
        self.session_state.update_job_result(
            self.generator_job, self.generator_result)
        # Ensure that we got the generated_job variable assigned
        # (by the event/signal handled above)
        self.assertIsNot(self.generated_job, None)
        # Now the stage is set for testing. Let's create the suspend helper
        # and use the data we've defined so far to create JSON-friendly
        # description of the session state.
        self.helper = SessionSuspendHelper1()
        self.data = self.helper._repr_SessionState(self.session_state)

    def test_state_tracked_for_all_jobs(self):
        """
        verify that 'state' keeps track of all three jobs
        """
        self.assertIn(self.category_job.id, self.data['jobs'])
        self.assertIn(self.generator_job.id, self.data['jobs'])
        self.assertIn(self.generated_job.id, self.data['jobs'])

    def test_category_job_result_is_saved(self):
        """
        verify that the 'category' job result was saved
        """
        # This result is essential to re-create the association
        # with the 'generator' job. In theory we could get it from
        # the 'via' attribute but that is only true for category assignment
        # where the child job already exists and is defined on the
        # filesystem. This would not work in the case of truly generated jobs
        # so for consistency it is done the same way.
        self.assertEqual(
            self.data['results']['__category__'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': [
                    [0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                    [0.1, 'stdout', 'aWQ6Z2VuZXJhdG9yCg==']
                ]
            }]
        )

    def test_generator_job_result_is_saved(self):
        """
        verify that the 'generator' job result was saved
        """
        self.assertEqual(
            self.data['results']['generator'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': [
                    [0.0, 'stdout', 'aWQ6Z2VuZXJhdGVk'],
                ]
            }]
        )

    def test_generated_job_result_is_saved(self):
        """
        verify that the 'generated' job result was saved
        """
        # This is the implicit "empty" result that all jobs have
        self.assertEqual(
            self.data['results']['generated'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': []
            }]
        )

    def test_sanity_check(self):
        """
        verify that the whole suspend data looks right
        """
        # This test is pretty much a "eyeball" inspection test
        # where we can see everything at a glance and not have to
        # deduce how each part looks like from the tests above.
        #
        # All the data below is verbatim copy of the generated  suspend data
        # that was created when this test was written. The only modification
        # was wrapping of the checksums in ( ) to make them wrap correctly
        # so that the file can stay PEP-8 clean
        self.maxDiff = None
        self.assertEqual(self.data, {
            'jobs': {
                '__category__': (
                    'e2475434e4c0b2c825541430e526fe0565780dfeb67'
                    '050f3b7f3453aa3cc439b'),
                'generator': (
                    'b2aa7b7c4298678cebfdbe30f4aae5be97d320910a5'
                    'b4dd312606099f35c03b6'),
                'generated': (
                    '57b395e91bb4af94143eb19586bd18e4013efc5e60d'
                    '6050d9ec0bea15dd19489'),
            },
            'results': {
                '__category__': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [
                        [0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                        [0.1, 'stdout', 'aWQ6Z2VuZXJhdG9yCg==']],
                    'outcome': None,
                    'return_code': None,
                }],
                'generator': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [
                        [0.0, 'stdout', 'aWQ6Z2VuZXJhdGVk']],
                    'outcome': None,
                    'return_code': None,
                }],
                'generated': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [],
                    'outcome': None,
                    'return_code': None,
                }]
            },
            'desired_job_list': ['__category__', 'generator'],
            'metadata': {
                'flags': [],
                'running_job_name': None,
                'title': None
            },
        })
예제 #4
0
class GeneratedJobSuspendTests(TestCase):
    """
    Tests that check how SessionSuspendHelper behaves when faced with
    generated jobs. This tests sets up the following job hierarchy:

        __category__
           \-> generator
                \-> generated

    The "__category__" job is a typical "catter" job that cats an existing
    job from somewhere else in the filesystem. This type of generated job
    is used often for category assignment.

    The "generator" job is a typical non-catter job that actually creates
    new jobs in some way. In this test it generates a job called "generated".
    """

    def setUp(self):
        # Crete a "__category__" job
        self.category_job = JobDefinition({
            "plugin": "local",
            "name": "__category__"
        })
        # Create a "generator" job
        self.generator_job = JobDefinition({
            "plugin": "local",
            "name": "generator"
        })
        # Keep a variable for the (future) generated job
        self.generated_job = None
        # Create a result for the "__category__" job.
        # It must define a verbatim copy of the "generator" job
        self.category_result = MemoryJobResult({
            "io_log": [
                (0.0, "stdout", b'plugin:local\n'),
                (0.1, "stdout", b'name:generator\n'),
            ]
        })
        # Create a result for the "generator" job.
        # It will define the "generated" job
        self.generator_result = MemoryJobResult({
            "io_log": [(0.0, 'stdout', b'name:generated')]
        })
        # Create a session that knows about the two jobs that exist
        # directly as files (__category__ and generator)
        self.session_state = SessionState([
            self.category_job, self.generator_job])
        # Select both of them for execution.
        self.session_state.update_desired_job_list([
            self.category_job, self.generator_job])
        # "execute" the "__category__" job by showing the session the result
        self.session_state.update_job_result(
            self.category_job, self.category_result)
        # Ensure that the generator job gained the "via" attribute
        # This is how we know the code above has no typos or anything.
        self.assertEqual(
            self.generator_job.via, self.category_job.get_checksum())
        # "execute" the "generator" job by showing the session the result.
        # Connect the 'on_job_added' signal to a helper function that
        # extracts the "generated" job

        def job_added(self, job):
            self.generated_job = job
        # Use partial to supply 'self' from the class into the function above
        self.session_state.on_job_added.connect(partial(job_added, self))
        # Show the result of the "generator" job to the session,
        # this will define the "generated" job, fire the signal
        # and call our callback
        self.session_state.update_job_result(
            self.generator_job, self.generator_result)
        # Ensure that we got the generated_job variable assigned
        # (by the event/signal handled above)
        self.assertIsNot(self.generated_job, None)
        # Now the stage is set for testing. Let's create the suspend helper
        # and use the data we've defined so far to create JSON-friendly
        # description of the session state.
        self.helper = SessionSuspendHelper()
        self.data = self.helper._repr_SessionState(self.session_state)

    def test_state_tracked_for_all_jobs(self):
        """
        verify that 'state' keeps track of all three jobs
        """
        self.assertIn(self.category_job.name, self.data['jobs'])
        self.assertIn(self.generator_job.name, self.data['jobs'])
        self.assertIn(self.generated_job.name, self.data['jobs'])

    def test_category_job_result_is_saved(self):
        """
        verify that the 'category' job result was saved
        """
        # This result is essential to re-create the association
        # with the 'generator' job. In theory we could get it from
        # the 'via' attribute but that is only true for category assignment
        # where the child job already exists and is defined on the
        # filesystem. This would not work in the case of truly generated jobs
        # so for consistency it is done the same way.
        self.assertEqual(
            self.data['results']['__category__'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': [
                    [0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                    [0.1, 'stdout', 'bmFtZTpnZW5lcmF0b3IK']
                ]
            }]
        )

    def test_generator_job_result_is_saved(self):
        """
        verify that the 'generator' job result was saved
        """
        self.assertEqual(
            self.data['results']['generator'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': [
                    [0.0, 'stdout', 'bmFtZTpnZW5lcmF0ZWQ='],
                ]
            }]
        )

    def test_generated_job_result_is_saved(self):
        """
        verify that the 'generated' job result was saved
        """
        # This is the implicit "empty" result that all jobs have
        self.assertEqual(
            self.data['results']['generated'], [{
                'comments': None,
                'execution_duration': None,
                'outcome': None,
                'return_code': None,
                'io_log': []
            }]
        )

    def test_sanity_check(self):
        """
        verify that the whole suspend data looks right
        """
        # This test is pretty much a "eyeball" inspection test
        # where we can see everything at a glance and not have to
        # deduce how each part looks like from the tests above.
        #
        # All the data below is verbatim copy of the generated  suspend data
        # that was created when this test was written. The only modification
        # was wrapping of the checksums in ( ) to make them wrap correctly
        # so that the file can stay PEP-8 clean
        self.maxDiff = None
        self.assertEqual(self.data, {
            'jobs': {
                '__category__': (
                    '5267192a5eac9288d144242d800b981eeca476c17e0'
                    'dd32a09c4b3ea0a14f955'),
                'generator': (
                    '7e67e23b7e7a6a5803721a9f282c0e88c7f40bae470'
                    '950f880e419bb9c7665d8'),
                'generated': (
                    'bfee8c57b6adc9f0f281b59fe818de2ed98b6affb78'
                    '9cf4fbf282d89453190d3'),
            },
            'results': {
                '__category__': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [
                        [0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                        [0.1, 'stdout', 'bmFtZTpnZW5lcmF0b3IK']],
                    'outcome': None,
                    'return_code': None,
                }],
                'generator': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [
                        [0.0, 'stdout', 'bmFtZTpnZW5lcmF0ZWQ=']],
                    'outcome': None,
                    'return_code': None,
                }],
                'generated': [{
                    'comments': None,
                    'execution_duration': None,
                    'io_log': [],
                    'outcome': None,
                    'return_code': None,
                }]
            },
            'desired_job_list': ['__category__', 'generator'],
            'metadata': {
                'flags': [],
                'running_job_name': None,
                'title': None
            },
        })
예제 #5
0
class GeneratedJobSuspendTests(TestCase):
    """
    Tests that check how SessionSuspendHelper behaves when faced with
    generated jobs. This tests sets up the following job hierarchy:

        __category__
           \-> generator
                \-> generated

    The "__category__" job is a typical "catter" job that cats an existing
    job from somewhere else in the filesystem. This type of generated job
    is used often for category assignment.

    The "generator" job is a typical non-catter job that actually creates
    new jobs in some way. In this test it generates a job called "generated".
    """
    def setUp(self):
        # Crete a "__category__" job
        self.category_job = JobDefinition({
            "plugin": "local",
            "id": "__category__"
        })
        # Create a "generator" job
        self.generator_job = JobDefinition({
            "plugin": "local",
            "id": "generator"
        })
        # Keep a variable for the (future) generated job
        self.generated_job = None
        # Create a result for the "__category__" job.
        # It must define a verbatim copy of the "generator" job
        self.category_result = MemoryJobResult({
            "io_log": [
                (0.0, "stdout", b'plugin:local\n'),
                (0.1, "stdout", b'id:generator\n'),
            ]
        })
        # Create a result for the "generator" job.
        # It will define the "generated" job
        self.generator_result = MemoryJobResult(
            {"io_log": [(0.0, 'stdout', b'id:generated')]})
        # Create a session that knows about the two jobs that exist
        # directly as files (__category__ and generator)
        self.session_state = SessionState(
            [self.category_job, self.generator_job])
        # Select both of them for execution.
        self.session_state.update_desired_job_list(
            [self.category_job, self.generator_job])
        # "execute" the "__category__" job by showing the session the result
        self.session_state.update_job_result(self.category_job,
                                             self.category_result)
        # Ensure that the generator job gained the "via" attribute
        # This is how we know the code above has no typos or anything.
        self.assertEqual(self.generator_job.via, self.category_job.checksum)

        # "execute" the "generator" job by showing the session the result.
        # Connect the 'on_job_added' signal to a helper function that
        # extracts the "generated" job

        def job_added(self, job):
            self.generated_job = job

        # Use partial to supply 'self' from the class into the function above
        self.session_state.on_job_added.connect(partial(job_added, self))
        # Show the result of the "generator" job to the session,
        # this will define the "generated" job, fire the signal
        # and call our callback
        self.session_state.update_job_result(self.generator_job,
                                             self.generator_result)
        # Ensure that we got the generated_job variable assigned
        # (by the event/signal handled above)
        self.assertIsNot(self.generated_job, None)
        # Now the stage is set for testing. Let's create the suspend helper
        # and use the data we've defined so far to create JSON-friendly
        # description of the session state.
        self.helper = SessionSuspendHelper1()
        self.data = self.helper._repr_SessionState(self.session_state)

    def test_state_tracked_for_all_jobs(self):
        """
        verify that 'state' keeps track of all three jobs
        """
        self.assertIn(self.category_job.id, self.data['jobs'])
        self.assertIn(self.generator_job.id, self.data['jobs'])
        self.assertIn(self.generated_job.id, self.data['jobs'])

    def test_category_job_result_is_saved(self):
        """
        verify that the 'category' job result was saved
        """
        # This result is essential to re-create the association
        # with the 'generator' job. In theory we could get it from
        # the 'via' attribute but that is only true for category assignment
        # where the child job already exists and is defined on the
        # filesystem. This would not work in the case of truly generated jobs
        # so for consistency it is done the same way.
        self.assertEqual(self.data['results']['__category__'], [{
            'comments':
            None,
            'execution_duration':
            None,
            'outcome':
            None,
            'return_code':
            None,
            'io_log': [[0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                       [0.1, 'stdout', 'aWQ6Z2VuZXJhdG9yCg==']]
        }])

    def test_generator_job_result_is_saved(self):
        """
        verify that the 'generator' job result was saved
        """
        self.assertEqual(self.data['results']['generator'],
                         [{
                             'comments': None,
                             'execution_duration': None,
                             'outcome': None,
                             'return_code': None,
                             'io_log': [
                                 [0.0, 'stdout', 'aWQ6Z2VuZXJhdGVk'],
                             ]
                         }])

    def test_generated_job_result_is_saved(self):
        """
        verify that the 'generated' job result was saved
        """
        # This is the implicit "empty" result that all jobs have
        self.assertEqual(self.data['results']['generated'],
                         [{
                             'comments': None,
                             'execution_duration': None,
                             'outcome': None,
                             'return_code': None,
                             'io_log': []
                         }])

    def test_sanity_check(self):
        """
        verify that the whole suspend data looks right
        """
        # This test is pretty much a "eyeball" inspection test
        # where we can see everything at a glance and not have to
        # deduce how each part looks like from the tests above.
        #
        # All the data below is verbatim copy of the generated  suspend data
        # that was created when this test was written. The only modification
        # was wrapping of the checksums in ( ) to make them wrap correctly
        # so that the file can stay PEP-8 clean
        self.maxDiff = None
        self.assertEqual(
            self.data, {
                'jobs': {
                    '__category__':
                    ('e2475434e4c0b2c825541430e526fe0565780dfeb67'
                     '050f3b7f3453aa3cc439b'),
                    'generator': ('b2aa7b7c4298678cebfdbe30f4aae5be97d320910a5'
                                  'b4dd312606099f35c03b6'),
                    'generated': ('57b395e91bb4af94143eb19586bd18e4013efc5e60d'
                                  '6050d9ec0bea15dd19489'),
                },
                'results': {
                    '__category__': [{
                        'comments':
                        None,
                        'execution_duration':
                        None,
                        'io_log': [[0.0, 'stdout', 'cGx1Z2luOmxvY2FsCg=='],
                                   [0.1, 'stdout', 'aWQ6Z2VuZXJhdG9yCg==']],
                        'outcome':
                        None,
                        'return_code':
                        None,
                    }],
                    'generator': [
                        {
                            'comments': None,
                            'execution_duration': None,
                            'io_log': [[0.0, 'stdout', 'aWQ6Z2VuZXJhdGVk']],
                            'outcome': None,
                            'return_code': None,
                        }
                    ],
                    'generated': [{
                        'comments': None,
                        'execution_duration': None,
                        'io_log': [],
                        'outcome': None,
                        'return_code': None,
                    }]
                },
                'desired_job_list': ['__category__', 'generator'],
                'metadata': {
                    'flags': [],
                    'running_job_name': None,
                    'title': None
                },
            })