Example #1
0
    def setUp(self):
        self.staging_order1 = StagingOrder(id=1,
                                           source='/test/this',
                                           staging_target='/foo',
                                           status=StagingStatus.pending)

        self.mock_general_project_repo = mock.MagicMock()

        stdout_mimicing_rsync = """
            Number of files: 1 (reg: 1)
            Number of created files: 0
            Number of deleted files: 0
            Number of regular files transferred: 1
            Total file size: 207,707,566 bytes
            Total transferred file size: 207,707,566 bytes
            Literal data: 207,707,566 bytes
            Matched data: 0 bytes
            File list size: 0
            File list generation time: 0.001 seconds
            File list transfer time: 0.000 seconds
            Total bytes sent: 207,758,378
            Total bytes received: 35

            sent 207,758,378 bytes  received 35 bytes  138,505,608.67 bytes/sec
            total size is 207,707,566  speedup is 1.00
        """

        mock_process = mock.MagicMock()
        mock_execution = Execution(pid=random.randint(1, 1000),
                                   process_obj=mock_process)

        self.mock_external_runner_service = mock.create_autospec(
            ExternalProgramService)
        self.mock_external_runner_service.run.return_value = mock_execution

        @coroutine
        def wait_as_coroutine(x):
            return ExecutionResult(stdout=stdout_mimicing_rsync,
                                   stderr="",
                                   status_code=0)

        self.mock_external_runner_service.wait_for_execution = wait_as_coroutine
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = self.staging_order1
        mock_staging_repo.create_staging_order.return_value = self.staging_order1

        self.mock_runfolder_repo = mock.MagicMock()

        mock_db_session_factory = mock.MagicMock()

        self.staging_service = StagingService(
            staging_dir="/tmp",
            external_program_service=self.mock_external_runner_service,
            staging_repo=mock_staging_repo,
            runfolder_repo=self.mock_runfolder_repo,
            session_factory=mock_db_session_factory,
            project_dir_repo=self.mock_general_project_repo)
        self.staging_service.io_loop_factory = MockIOLoop
        super(TestStagingService, self).setUp()
Example #2
0
    def setUp(self):
        self.staging_order1 = StagingOrder(id=1,
                                           source='/test/this',
                                           status=StagingStatus.pending)

        mock_external_runner_service = self.MockExternalRunnerService()
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = self.staging_order1
        mock_staging_repo.create_staging_order.return_value = self.staging_order1

        self.mock_runfolder_repo = mock.MagicMock()

        mock_db_session_factory = mock.MagicMock()

        self.staging_service = StagingService("/tmp",
                                              mock_external_runner_service,
                                              mock_staging_repo,
                                              self.mock_runfolder_repo,
                                              mock_db_session_factory)
Example #3
0
def compose_application(config):
    """
    Instantiates all service, repos, etc which are then used by the application.
    The resulting dictionary can then be passed on to routes which instantiates the
    http handlers.
    :param config: a configuration instance
    :return: a dictionary with references to any relevant resources
    """
    runfolder_repo = FileSystemBasedRunfolderRepository(
        config["monitored_directory"])
    external_program_service = ExternalProgramService()

    db_connection_string = config["db_connection_string"]
    engine = create_engine(db_connection_string, echo=False)

    create_and_migrate_db(engine, db_connection_string)

    session_factory = scoped_session(sessionmaker())
    session_factory.configure(bind=engine)

    staging_repo = DatabaseBasedStagingRepository(
        session_factory=session_factory)

    staging_service = StagingService(
        external_program_service=external_program_service,
        runfolder_repo=runfolder_repo,
        staging_repo=staging_repo,
        staging_dir=config["staging_directory"],
        session_factory=session_factory)

    delivery_repo = DatabaseBasedDeliveriesRepository(
        session_factory=session_factory)

    delivery_service = MoverDeliveryService(
        external_program_service=external_program_service,
        staging_service=staging_service,
        delivery_repo=delivery_repo)

    return dict(config=config,
                runfolder_repo=runfolder_repo,
                external_program_service=external_program_service,
                staging_service=staging_service,
                delivery_service=delivery_service)
Example #4
0
def compose_application(config):
    """
    Instantiates all service, repos, etc which are then used by the application.
    The resulting dictionary can then be passed on to routes which instantiates the
    http handlers.
    :param config: a configuration instance
    :return: a dictionary with references to any relevant resources
    """
    def _assert_is_dir(directory):
        if not FileSystemService.isdir(directory):
            raise AssertionError("{} is not a directory".format(
                os.path.abspath(directory)))

    staging_dir = config['staging_directory']
    _assert_is_dir(staging_dir)

    runfolder_dir = config["runfolder_directory"]
    _assert_is_dir(runfolder_dir)

    project_links_directory = config["project_links_directory"]
    _assert_is_dir(project_links_directory)

    runfolder_repo = FileSystemBasedRunfolderRepository(runfolder_dir)
    project_repository = UnorganisedRunfolderProjectRepository(
        sample_repository=RunfolderProjectBasedSampleRepository())
    unorganised_runfolder_repo = FileSystemBasedUnorganisedRunfolderRepository(
        runfolder_dir, project_repository=project_repository)

    general_project_dir = config['general_project_directory']
    _assert_is_dir(general_project_dir)

    general_project_repo = GeneralProjectRepository(
        root_directory=general_project_dir)
    external_program_service = ExternalProgramService()

    db_connection_string = config["db_connection_string"]
    engine = create_engine(db_connection_string, echo=False)

    alembic_path = config["alembic_path"]
    create_and_migrate_db(engine, alembic_path, db_connection_string)

    session_factory = scoped_session(sessionmaker())
    session_factory.configure(bind=engine)

    staging_repo = DatabaseBasedStagingRepository(
        session_factory=session_factory)

    staging_service = StagingService(
        external_program_service=external_program_service,
        runfolder_repo=runfolder_repo,
        project_dir_repo=general_project_repo,
        staging_repo=staging_repo,
        staging_dir=staging_dir,
        project_links_directory=project_links_directory,
        session_factory=session_factory)

    delivery_repo = DatabaseBasedDeliveriesRepository(
        session_factory=session_factory)

    path_to_mover = config['path_to_mover']
    mover_delivery_service = MoverDeliveryService(
        external_program_service=external_program_service,
        staging_service=staging_service,
        delivery_repo=delivery_repo,
        session_factory=session_factory,
        path_to_mover=path_to_mover)

    dds_conf = config['dds_conf']
    dds_project_repo = DDSProjectRepository(session_factory=session_factory)
    dds_service = DDSService(external_program_service=external_program_service,
                             staging_service=staging_service,
                             staging_dir=staging_dir,
                             delivery_repo=delivery_repo,
                             dds_project_repo=dds_project_repo,
                             session_factory=session_factory,
                             dds_conf=dds_conf)

    delivery_sources_repo = DatabaseBasedDeliverySourcesRepository(
        session_factory=session_factory)
    runfolder_service = RunfolderService(runfolder_repo)

    delivery_service = DeliveryService(
        mover_service=mover_delivery_service,
        staging_service=staging_service,
        delivery_sources_repo=delivery_sources_repo,
        general_project_repo=general_project_repo,
        runfolder_service=runfolder_service,
        project_links_directory=project_links_directory)

    best_practice_analysis_service = BestPracticeAnalysisService(
        general_project_repo)

    organise_service = OrganiseService(
        runfolder_service=RunfolderService(unorganised_runfolder_repo))

    return dict(config=config,
                runfolder_repo=runfolder_repo,
                external_program_service=external_program_service,
                staging_service=staging_service,
                mover_delivery_service=mover_delivery_service,
                dds_service=dds_service,
                delivery_service=delivery_service,
                general_project_repo=general_project_repo,
                best_practice_analysis_service=best_practice_analysis_service,
                organise_service=organise_service)
Example #5
0
class TestStagingService(unittest.TestCase):
    class MockExternalRunnerService():
        def __init__(self, return_status=0, throw=False):
            self.return_status = return_status
            self.throw = throw

        def run(self, cmd):
            if self.throw:
                raise Exception("Test the exception handling...")
            mock_process = mock.MagicMock()
            execution = Execution(pid=random.randint(1, 1000),
                                  process_obj=mock_process)
            return execution

        def wait_for_execution(self, execution):
            time.sleep(0.1)
            return ExecutionResult(status_code=self.return_status,
                                   stderr="stderr",
                                   stdout="stdout")

    def setUp(self):
        self.staging_order1 = StagingOrder(id=1,
                                           source='/test/this',
                                           status=StagingStatus.pending)

        mock_external_runner_service = self.MockExternalRunnerService()
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = self.staging_order1
        mock_staging_repo.create_staging_order.return_value = self.staging_order1

        self.mock_runfolder_repo = mock.MagicMock()

        mock_db_session_factory = mock.MagicMock()

        self.staging_service = StagingService("/tmp",
                                              mock_external_runner_service,
                                              mock_staging_repo,
                                              self.mock_runfolder_repo,
                                              mock_db_session_factory)

    # A StagingService should be able to:
    # - Stage a staging order
    def test_stage_order(self):
        self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        assert_eventually_equals(self, 1, _get_stating_status,
                                 StagingStatus.staging_successful)

    # - Set status to failed if rsyncing is not successful
    def test_unsuccessful_staging_order(self):
        mock_external_runner_service = self.MockExternalRunnerService(
            return_status=1)
        self.staging_service.external_program_service = mock_external_runner_service

        self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        assert_eventually_equals(self, 1, _get_stating_status,
                                 StagingStatus.staging_failed)

    # - Set status to failed if there is an exception is not successful
    def test_exception_in_staging_order(self):
        mock_external_runner_service = self.MockExternalRunnerService(
            throw=True)
        self.staging_service.external_program_service = mock_external_runner_service

        self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        assert_eventually_equals(self, 1, _get_stating_status,
                                 StagingStatus.staging_failed)

    # - Reject staging order if it has invalid state
    def test_stage_order_non_valid_state(self):
        with self.assertRaises(InvalidStatusException):

            staging_order_in_progress = StagingOrder(
                source='/test/this', status=StagingStatus.staging_in_progress)

            self.staging_service.stage_order(
                stage_order=staging_order_in_progress)

    # - Be able to stage a existing runfolder
    def test_stage_runfolder(self):
        class MockStagingRepo:

            orders_state = []

            def get_staging_order_by_id(self, identifier, custom_session=None):
                return filter(lambda x: x.id == identifier,
                              self.orders_state)[0]

            def create_staging_order(self, source, status, staging_target_dir):

                order = StagingOrder(id=len(self.orders_state) + 1,
                                     source=source,
                                     status=status,
                                     staging_target=staging_target_dir)
                self.orders_state.append(order)
                return order

        runfolder1 = FAKE_RUNFOLDERS[0]

        self.mock_runfolder_repo.get_runfolder.return_value = runfolder1
        mock_staging_repo = MockStagingRepo()

        self.staging_service.staging_repo = mock_staging_repo

        result = self.staging_service.stage_runfolder(
            runfolder_id=runfolder1.name, projects_to_stage=[])
        self.assertEqual(result,
                         map(lambda x: x.id, mock_staging_repo.orders_state))

    # - Reject staging a runfolder which does not exist runfolder
    def test_stage_runfolder_does_not_exist(self):
        with self.assertRaises(RunfolderNotFoundException):

            self.mock_runfolder_repo.get_runfolder.return_value = None
            self.staging_service.stage_runfolder(runfolder_id='foo_runfolder',
                                                 projects_to_stage=[])

    # - Be able to get the status of a stage order
    def test_get_status_or_stage_order(self):
        # Returns correctly for existing order
        actual = self.staging_service.get_status_of_stage_order(
            self.staging_order1.id)
        self.assertEqual(actual, self.staging_order1.status)

        # Returns None for none existent order
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = None
        self.staging_service.staging_repo = mock_staging_repo
        actual_not_there = self.staging_service.get_status_of_stage_order(1337)
        self.assertIsNone(actual_not_there)

    # - Be able to kill a ongoing staging process
    @mock.patch('delivery.services.staging_service.os')
    def test_kill_stage_order(self, mock_os):

        # If the status is in progress it should be possible to kill it.
        self.staging_order1.status = StagingStatus.staging_in_progress
        self.staging_order1.pid = 1337
        actual = self.staging_service.kill_process_of_staging_order(
            self.staging_order1.id)
        mock_os.kill.assert_called_with(self.staging_order1.pid,
                                        signal.SIGTERM)
        self.assertTrue(actual)

        # It should handle if kill raises a OSError gracefully
        self.staging_order1.status = StagingStatus.staging_in_progress
        self.staging_order1.pid = 1337
        mock_os.kill.side_effect = OSError
        actual = self.staging_service.kill_process_of_staging_order(
            self.staging_order1.id)
        mock_os.kill.assert_called_with(self.staging_order1.pid,
                                        signal.SIGTERM)
        self.assertFalse(actual)

        # If the status is not in progress it should not be possible to kill it.
        self.staging_order1.status = StagingStatus.staging_successful
        actual = self.staging_service.kill_process_of_staging_order(
            self.staging_order1.id)
        mock_os.kill.assert_not_called()
        self.assertFalse(actual)
Example #6
0
class TestStagingService(AsyncTestCase):

    class MockStagingRepo:

        def __init__(self):
            self.orders_state = []

        def get_staging_order_by_id(self, identifier, custom_session=None):
            return list(filter(lambda x: x.id == identifier, self.orders_state))[0]

        def create_staging_order(self, source, status, staging_target_dir):

            order = StagingOrder(id=len(self.orders_state) + 1,
                                 source=source,
                                 status=status,
                                 staging_target=staging_target_dir)
            self.orders_state.append(order)
            return order

    def setUp(self):
        self.staging_order1 = StagingOrder(id=1,
                                           source='/test/this',
                                           staging_target='/foo',
                                           status=StagingStatus.pending)

        self.mock_general_project_repo = mock.MagicMock()

        stdout_mimicing_rsync = """
            Number of files: 1 (reg: 1)
            Number of created files: 0
            Number of deleted files: 0
            Number of regular files transferred: 1
            Total file size: 207,707,566 bytes
            Total transferred file size: 207,707,566 bytes
            Literal data: 207,707,566 bytes
            Matched data: 0 bytes
            File list size: 0
            File list generation time: 0.001 seconds
            File list transfer time: 0.000 seconds
            Total bytes sent: 207,758,378
            Total bytes received: 35

            sent 207,758,378 bytes  received 35 bytes  138,505,608.67 bytes/sec
            total size is 207,707,566  speedup is 1.00
        """

        mock_process = mock.MagicMock()
        mock_execution = Execution(pid=random.randint(1, 1000), process_obj=mock_process)

        self.mock_external_runner_service = mock.create_autospec(ExternalProgramService)
        self.mock_external_runner_service.run.return_value = mock_execution

        self.mock_file_system_service = mock.create_autospec(FileSystemService)

        @coroutine
        def wait_as_coroutine(x):
            return ExecutionResult(stdout=stdout_mimicing_rsync, stderr="", status_code=0)

        self.mock_external_runner_service.wait_for_execution = wait_as_coroutine
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = self.staging_order1
        mock_staging_repo.create_staging_order.return_value = self.staging_order1

        self.mock_runfolder_repo = mock.MagicMock()

        mock_db_session_factory = mock.MagicMock()

        self.staging_service = StagingService(staging_dir="/tmp",
                                              project_links_directory="/tmp",
                                              external_program_service=self.mock_external_runner_service,
                                              staging_repo=mock_staging_repo,
                                              runfolder_repo=self.mock_runfolder_repo,
                                              session_factory=mock_db_session_factory,
                                              project_dir_repo=self.mock_general_project_repo,
                                              file_system_service=self.mock_file_system_service)
        self.staging_service.io_loop_factory = MockIOLoop
        super(TestStagingService, self).setUp()

    # A StagingService should be able to:
    # - Stage a staging order
    @tornado.testing.gen_test
    def test_stage_order(self):
        res = yield self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        def _get_staging_size():
            return self.staging_order1.size

        assert_eventually_equals(self, 1, _get_stating_status, StagingStatus.staging_successful)
        self.assertEqual(self.staging_order1.size, 207707566)

    # - Set status to failed if rsyncing is not successful
    @tornado.testing.gen_test
    def test_unsuccessful_staging_order(self):
        @coroutine
        def wait_as_coroutine(x):
            return ExecutionResult(stdout="", stderr="", status_code=1)

        self.mock_external_runner_service.wait_for_execution = wait_as_coroutine

        yield self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        assert_eventually_equals(self, 1, _get_stating_status, StagingStatus.staging_failed)

    # - Set status to failed if there is an exception is not successful
    def test_exception_in_staging_order(self):

        def raise_exception(x):
            raise Exception
        self.mock_external_runner_service.wait_for_execution = raise_exception
        self.staging_service.stage_order(stage_order=self.staging_order1)

        def _get_stating_status():
            return self.staging_order1.status

        assert_eventually_equals(self, 1, _get_stating_status, StagingStatus.staging_failed)

    # - Reject staging order if it has invalid state
    @tornado.testing.gen_test
    def test_stage_order_non_valid_state(self):
        with self.assertRaises(InvalidStatusException):

            staging_order_in_progress = StagingOrder(source='/test/this',
                                                     status=StagingStatus.staging_in_progress)

            res = yield self.staging_service.stage_order(stage_order=staging_order_in_progress)

    # - Be able to get the status of a stage order
    def test_get_status_or_stage_order(self):
        # Returns correctly for existing order
        actual = self.staging_service.get_status_of_stage_order(self.staging_order1.id)
        self.assertEqual(actual, self.staging_order1.status)

        # Returns None for none existent order
        mock_staging_repo = mock.MagicMock()
        mock_staging_repo.get_staging_order_by_id.return_value = None
        self.staging_service.staging_repo = mock_staging_repo
        actual_not_there = self.staging_service.get_status_of_stage_order(1337)
        self.assertIsNone(actual_not_there)

    # - Be able to kill a ongoing staging process
    @mock.patch('delivery.services.staging_service.os')
    def test_kill_stage_order(self, mock_os):

        # If the status is in progress it should be possible to kill it.
        self.staging_order1.status = StagingStatus.staging_in_progress
        self.staging_order1.pid = 1337
        actual = self.staging_service.kill_process_of_staging_order(self.staging_order1.id)
        mock_os.kill.assert_called_with(self.staging_order1.pid, signal.SIGTERM)
        self.assertTrue(actual)

        # It should handle if kill raises a OSError gracefully
        self.staging_order1.status = StagingStatus.staging_in_progress
        self.staging_order1.pid = 1337
        mock_os.kill.side_effect = OSError
        actual = self.staging_service.kill_process_of_staging_order(self.staging_order1.id)
        mock_os.kill.assert_called_with(self.staging_order1.pid, signal.SIGTERM)
        self.assertFalse(actual)

    @mock.patch('delivery.services.staging_service.os')
    def test_kill_stage_order_not_valid_state(self, mock_os):
        # If the status is not in progress it should not be possible to kill it.
        self.staging_order1.status = StagingStatus.staging_successful
        actual = self.staging_service.kill_process_of_staging_order(self.staging_order1.id)
        mock_os.kill.assert_not_called()
        self.assertFalse(actual)
Example #7
0
def compose_application(config):
    """
    Instantiates all service, repos, etc which are then used by the application.
    The resulting dictionary can then be passed on to routes which instantiates the
    http handlers.
    :param config: a configuration instance
    :return: a dictionary with references to any relevant resources
    """
    def _assert_is_dir(directory):
        if not FileSystemService.isdir(directory):
            raise AssertionError("{} is not a directory".format(directory))

    staging_dir = config['staging_directory']
    _assert_is_dir(staging_dir)

    runfolder_dir = config["runfolder_directory"]
    _assert_is_dir(runfolder_dir)

    runfolder_repo = FileSystemBasedRunfolderRepository(runfolder_dir)

    general_project_dir = config['general_project_directory']
    _assert_is_dir(general_project_dir)

    general_project_repo = GeneralProjectRepository(
        root_directory=general_project_dir)
    external_program_service = ExternalProgramService()

    db_connection_string = config["db_connection_string"]
    engine = create_engine(db_connection_string, echo=False)

    alembic_path = config["alembic_path"]
    create_and_migrate_db(engine, alembic_path, db_connection_string)

    session_factory = scoped_session(sessionmaker())
    session_factory.configure(bind=engine)

    staging_repo = DatabaseBasedStagingRepository(
        session_factory=session_factory)

    staging_service = StagingService(
        external_program_service=external_program_service,
        runfolder_repo=runfolder_repo,
        project_dir_repo=general_project_repo,
        staging_repo=staging_repo,
        staging_dir=staging_dir,
        session_factory=session_factory)

    delivery_repo = DatabaseBasedDeliveriesRepository(
        session_factory=session_factory)

    path_to_mover = config['path_to_mover']
    delivery_service = MoverDeliveryService(
        external_program_service=external_program_service,
        staging_service=staging_service,
        delivery_repo=delivery_repo,
        session_factory=session_factory,
        path_to_mover=path_to_mover)

    return dict(config=config,
                runfolder_repo=runfolder_repo,
                external_program_service=external_program_service,
                staging_service=staging_service,
                delivery_service=delivery_service)