def setup_workbook_with_project_worksheets(self,
                                            worksheet_importer_constructor):
     self.template_mgr.get_concrete_type = MagicMock(return_value='project')
     worksheet_importer = WorkbookImporter(self.template_mgr)
     worksheet_importer_constructor.return_value = worksheet_importer
     no_errors = []
     # and:
     project = MetadataEntity(domain_type='project',
                              concrete_type='project',
                              content={'description': 'test project'})
     jsmith = MetadataEntity(domain_type='project',
                             concrete_type='contact',
                             content={
                                 'contributors': {
                                     'name': 'John',
                                     'email': '*****@*****.**'
                                 }
                             })
     ppan = MetadataEntity(domain_type='project',
                           concrete_type='contact',
                           content={
                               'contributors': {
                                   'name': 'Peter',
                                   'email': '*****@*****.**'
                               }
                           })
     worksheet_importer.do_import = MagicMock(
         side_effect=[([project], no_errors), ([jsmith, ppan], no_errors)])
     # and:
     workbook = create_test_workbook('Project', 'Project - Contributors')
     ingest_workbook = IngestWorkbook(workbook)
     return ingest_workbook
    def test_do_import_no_project(self, worksheet_importer_constructor):
        # given:
        template_mgr = MagicMock(name='template_manager')
        worksheet_importer = WorksheetImporter(template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        expected_error = {
            'location': 'File',
            'type': 'NoProjectFound',
            'detail': 'The spreadsheet should be associated to a project.'
        }

        # and:
        item = MetadataEntity(concrete_type='product',
                              domain_type='product',
                              object_id=910)
        worksheet_importer.do_import = MagicMock(side_effect=[([item],
                                                               no_errors)])

        # and:
        workbook = create_test_workbook('Item')
        workbook_importer = WorkbookImporter(template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(
            IngestWorkbook(workbook), is_update=False)

        # then:
        self.assertIn(
            expected_error, errors,
            f'Errors expected to contain {NoProjectFound.__name__}.')
    def test_do_import_project_worksheet(self, worksheet_importer_constructor):
        # given:
        ingest_workbook = self.setup_workbook_with_project_worksheets(
            worksheet_importer_constructor)
        workbook_importer = WorkbookImporter(self.template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(ingest_workbook,
                                                               is_update=False)

        # then:
        project_map = spreadsheet_json.get('project')
        self.assertEqual(1, len(project_map))
        project_content = list(project_map.values())[0].get('content')
        self.assertEqual('test project', project_content.get('description'))
        self.assertEqual(errors, [])

        # and:
        contributors = project_content.get('contributors')
        self.assertEqual(2, len(contributors))
        self.assertIn({
            'name': 'John',
            'email': '*****@*****.**'
        }, contributors)
        self.assertIn({
            'name': 'Peter',
            'email': '*****@*****.**'
        }, contributors)
 def setUp(self, worksheet_importer_constructor) -> None:
     self.template_mgr = MagicMock(name='template_manager')
     self.template_mgr.template.json_schemas = self.mock_json_schemas
     self.concrete_type_map = {'Project': 'project', 'Users': 'users'}
     self.template_mgr.get_concrete_type = lambda key: self.concrete_type_map.get(
         key)
     self.worksheet_importer = WorksheetImporter(self.template_mgr)
     worksheet_importer_constructor.return_value = self.worksheet_importer
     self.workbook_importer = WorkbookImporter(self.template_mgr)
     self.workbook = create_test_workbook('Project', 'Users')
     self.ingest_workbook = IngestWorkbook(self.workbook)
    def test_do_import_multiple_projects(self, worksheet_importer_constructor):
        # given:
        template_mgr = MagicMock(name='template_manager')
        template_mgr.template.json_schemas = self.mock_json_schemas
        template_mgr.get_concrete_type = MagicMock(return_value='project')

        worksheet_importer = WorksheetImporter(template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        expected_error = {
            'location':
            'sheet=Project',
            'type':
            'MultipleProjectsFound',
            'detail':
            'The spreadsheet should only be associated to a single project.'
        }

        # and:
        project_1 = MetadataEntity(concrete_type='project',
                                   domain_type='project',
                                   object_id=1)
        project_2 = MetadataEntity(concrete_type='project',
                                   domain_type='project',
                                   object_id=2)
        worksheet_importer.do_import = MagicMock(
            side_effect=[([project_1, project_2], no_errors)])

        # and:
        workbook = create_test_workbook('Project')
        workbook_importer = WorkbookImporter(template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(
            IngestWorkbook(workbook), is_update=False)

        # then:
        self.assertIn(
            expected_error, errors,
            f'Errors expected to contain {MultipleProjectsFound.__name__}.')
Exemple #6
0
    def test_do_import(self, worksheet_importer_constructor):
        # given: set up template manager
        key_label_map = {
            'Project': 'project',
            'Cell Suspension': 'cell_suspension'
        }

        domain_entity_map = {
            'project': 'project',
            'cell_suspension': 'biomaterial'
        }

        mock_template_manager = MagicMock()
        mock_template_manager.get_concrete_entity_of_tab = lambda key: key_label_map.get(key)
        mock_template_manager.get_domain_entity = lambda key: domain_entity_map.get(key)

        # and: set up worksheet importer
        worksheet_importer = IdentifiableWorksheetImporter()
        expected_json = self._fake_worksheet_import(worksheet_importer, mock_template_manager)

        # and: set up workbook
        workbook = Workbook()
        ingest_workbook = IngestWorkbook(workbook)
        schema_list = self._mock_get_schemas(ingest_workbook)
        self._mock_importable_worksheets(ingest_workbook, workbook)

        # and: mock WorksheetImporter constructor
        worksheet_importer_constructor.return_value = worksheet_importer
        workbook_importer = WorkbookImporter(mock_template_manager)
        workbook_importer.import_or_reference_project = MagicMock()

        # when:
        workbook_output = workbook_importer.do_import(ingest_workbook)

        # then:
        self.assertEqual(2, len(list(workbook_output.keys())))
        self.assertEqual(['project', 'biomaterial'], list(workbook_output.keys()))
        self.assertEqual(2, len(list(workbook_output['project'].keys())))
        self.assertEqual(expected_json['project'], workbook_output['project'])
        self.assertEqual(expected_json['biomaterial'], workbook_output['biomaterial'])
class WorkbookImporterTest(TestCase):
    mock_json_schemas = [{
        'name': 'project',
        'properties': ['contributors']
    }, {
        'name': 'users',
        'properties': ['sn_profiles']
    }]

    @patch('ingest.importer.importer.WorksheetImporter')
    def setUp(self, worksheet_importer_constructor) -> None:
        self.template_mgr = MagicMock(name='template_manager')
        self.template_mgr.template.json_schemas = self.mock_json_schemas
        self.concrete_type_map = {'Project': 'project', 'Users': 'users'}
        self.template_mgr.get_concrete_type = lambda key: self.concrete_type_map.get(
            key)
        self.worksheet_importer = WorksheetImporter(self.template_mgr)
        worksheet_importer_constructor.return_value = self.worksheet_importer
        self.workbook_importer = WorkbookImporter(self.template_mgr)
        self.workbook = create_test_workbook('Project', 'Users')
        self.ingest_workbook = IngestWorkbook(self.workbook)

    def test_do_import(self, ):
        # given:
        project = MetadataEntity(concrete_type='project',
                                 domain_type='project')
        jdelacruz = MetadataEntity(concrete_type='user',
                                   domain_type='user',
                                   object_id=1,
                                   content={'user_name': 'jdelacruz'})
        setsuna_f_seiei = MetadataEntity(concrete_type='user',
                                         domain_type='user',
                                         object_id=96,
                                         content={'user_name': 'sayyeah'})
        no_errors = []
        self.worksheet_importer.do_import = MagicMock(
            side_effect=[([project],
                          no_errors), ([jdelacruz, setsuna_f_seiei],
                                       no_errors)])

        # when:
        workbook_json, errors = self.workbook_importer.do_import(
            self.ingest_workbook, is_update=False)

        # then:
        self.assertIsNotNone(workbook_json)
        self.assertEqual(errors, [])

        # and:
        user_map = workbook_json.get('user')
        self.assertIsNotNone(user_map)
        self.assertEqual(2, len(user_map))
        self.assertEqual([jdelacruz.object_id, setsuna_f_seiei.object_id],
                         list(user_map.keys()))

        # and:
        self.assertEqual({'user_name': 'jdelacruz'},
                         user_map.get(1)['content'])
        self.assertEqual({'user_name': 'sayyeah'}, user_map.get(96)['content'])

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_with_module_tab(self, worksheet_importer_constructor):
        # given:
        concrete_type_map = {
            'Project': 'project',
            'User': '******',
            'User - SN Profiles': 'users'
        }
        self.template_mgr.get_concrete_type = lambda key: concrete_type_map.get(
            key)

        project = MetadataEntity(concrete_type='Project',
                                 domain_type='Project')
        user = MetadataEntity(concrete_type='user',
                              domain_type='user',
                              object_id=773,
                              content={'user_name': 'janedoe'})
        fb_profile = MetadataEntity(concrete_type='sn_profile',
                                    domain_type='user',
                                    object_id=773,
                                    content={
                                        'sn_profiles': {
                                            'name': 'facebook',
                                            'id': '392'
                                        },
                                        'description': 'extra fb field'
                                    })
        ig_profile = MetadataEntity(concrete_type='sn_profile',
                                    domain_type='user',
                                    object_id=773,
                                    content={
                                        'sn_profiles': {
                                            'name': 'instagram',
                                            'id': 'a92'
                                        },
                                        'description': 'extra ig field'
                                    })

        no_errors = []
        self.worksheet_importer.do_import = MagicMock(side_effect=[(
            [project],
            no_errors), ([user],
                         no_errors), ([fb_profile, ig_profile], no_errors)])

        self.workbook = create_test_workbook('Project', 'User',
                                             'User - SN Profiles')
        self.ingest_workbook = IngestWorkbook(self.workbook)

        # when:
        spreadsheet_json, errors = self.workbook_importer.do_import(
            self.ingest_workbook, is_update=False)

        # then:
        expected_errors = [{
            'key': 'description',
            'value': 'extra fb field'
        }, {
            'key': 'description',
            'value': 'extra ig field'
        }]

        self.assertIsNotNone(spreadsheet_json)
        self.assertEqual(
            errors,
            self.workbook_importer.list_data_removal_errors(
                'User - SN Profiles', expected_errors))
        self.assertEqual(2, len(spreadsheet_json))

        # and:
        user_map = spreadsheet_json.get('user')
        self.assertIsNotNone(user_map)

        # and:
        janedoe = user_map.get(773)
        self.assertIsNotNone(janedoe)
        content = janedoe.get('content')
        self.assertEqual('janedoe', content.get('user_name'))
        self.assertEqual(['user_name', 'sn_profiles'], list(content.keys()))

        # and:
        sn_profiles = content.get('sn_profiles')
        self.assertIsNotNone(sn_profiles)
        self.assertEqual(2, len(sn_profiles))

        # and:
        self.assertEqual({'name': 'facebook', 'id': '392'}, sn_profiles[0])
        self.assertEqual({'name': 'instagram', 'id': 'a92'}, sn_profiles[1])

    # NOTE: this is added because the team chose not to define an identity label for Project schema
    # This breaks the schema agnosticism of the importer framework.
    # The assumption is that there's only one Project per submission
    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_project_worksheet(self, worksheet_importer_constructor):
        # given:
        ingest_workbook = self.setup_workbook_with_project_worksheets(
            worksheet_importer_constructor)
        workbook_importer = WorkbookImporter(self.template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(ingest_workbook,
                                                               is_update=False)

        # then:
        project_map = spreadsheet_json.get('project')
        self.assertEqual(1, len(project_map))
        project_content = list(project_map.values())[0].get('content')
        self.assertEqual('test project', project_content.get('description'))
        self.assertEqual(errors, [])

        # and:
        contributors = project_content.get('contributors')
        self.assertEqual(2, len(contributors))
        self.assertIn({
            'name': 'John',
            'email': '*****@*****.**'
        }, contributors)
        self.assertIn({
            'name': 'Peter',
            'email': '*****@*****.**'
        }, contributors)

    def setup_workbook_with_project_worksheets(self,
                                               worksheet_importer_constructor):
        self.template_mgr.get_concrete_type = MagicMock(return_value='project')
        worksheet_importer = WorkbookImporter(self.template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        # and:
        project = MetadataEntity(domain_type='project',
                                 concrete_type='project',
                                 content={'description': 'test project'})
        jsmith = MetadataEntity(domain_type='project',
                                concrete_type='contact',
                                content={
                                    'contributors': {
                                        'name': 'John',
                                        'email': '*****@*****.**'
                                    }
                                })
        ppan = MetadataEntity(domain_type='project',
                              concrete_type='contact',
                              content={
                                  'contributors': {
                                      'name': 'Peter',
                                      'email': '*****@*****.**'
                                  }
                              })
        worksheet_importer.do_import = MagicMock(
            side_effect=[([project], no_errors), ([jsmith, ppan], no_errors)])
        # and:
        workbook = create_test_workbook('Project', 'Project - Contributors')
        ingest_workbook = IngestWorkbook(workbook)
        return ingest_workbook

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_multiple_projects(self, worksheet_importer_constructor):
        # given:
        template_mgr = MagicMock(name='template_manager')
        template_mgr.template.json_schemas = self.mock_json_schemas
        template_mgr.get_concrete_type = MagicMock(return_value='project')

        worksheet_importer = WorksheetImporter(template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        expected_error = {
            'location':
            'sheet=Project',
            'type':
            'MultipleProjectsFound',
            'detail':
            'The spreadsheet should only be associated to a single project.'
        }

        # and:
        project_1 = MetadataEntity(concrete_type='project',
                                   domain_type='project',
                                   object_id=1)
        project_2 = MetadataEntity(concrete_type='project',
                                   domain_type='project',
                                   object_id=2)
        worksheet_importer.do_import = MagicMock(
            side_effect=[([project_1, project_2], no_errors)])

        # and:
        workbook = create_test_workbook('Project')
        workbook_importer = WorkbookImporter(template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(
            IngestWorkbook(workbook), is_update=False)

        # then:
        self.assertIn(
            expected_error, errors,
            f'Errors expected to contain {MultipleProjectsFound.__name__}.')

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_no_project(self, worksheet_importer_constructor):
        # given:
        template_mgr = MagicMock(name='template_manager')
        worksheet_importer = WorksheetImporter(template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        expected_error = {
            'location': 'File',
            'type': 'NoProjectFound',
            'detail': 'The spreadsheet should be associated to a project.'
        }

        # and:
        item = MetadataEntity(concrete_type='product',
                              domain_type='product',
                              object_id=910)
        worksheet_importer.do_import = MagicMock(side_effect=[([item],
                                                               no_errors)])

        # and:
        workbook = create_test_workbook('Item')
        workbook_importer = WorkbookImporter(template_mgr)

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(
            IngestWorkbook(workbook), is_update=False)

        # then:
        self.assertIn(
            expected_error, errors,
            f'Errors expected to contain {NoProjectFound.__name__}.')

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_with_create_spreadsheet(self,
                                               worksheet_importer_constructor):
        # given:
        template_mgr = MagicMock(name='template_manager')
        template_mgr.template.json_schemas = self.mock_json_schemas
        concrete_type_map = {'project': 'project', 'users': 'users'}
        template_mgr.get_concrete_type = lambda key: concrete_type_map.get(key)
        sheet_names = ['project', 'users']

        workbook = create_ingest_workbook(sheet_names, ['name', 'address'])
        workbook_importer = WorkbookImporter(template_mgr)

        # and
        worksheet_importer = WorksheetImporter(template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []
        expected_errors = []
        for sheet_name in sheet_names:
            expected_errors.append({
                'location':
                f'sheet={sheet_name}',
                'type':
                'MissingEntityUUIDFound',
                'detail':
                f'The {sheet_name} entities in the spreadsheet should have UUIDs.'
            })

        # and:
        item = MetadataEntity(concrete_type='product',
                              domain_type='product',
                              object_id=910)
        worksheet_importer.do_import = MagicMock(side_effect=[([item],
                                                               no_errors)])

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(workbook,
                                                               is_update=True)

        # then:
        self.assertTrue(
            all(elem in errors for elem in expected_errors),
            f'Errors expected to contain {MissingEntityUUIDFound.__name__}.')

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_with_update_spreadsheet(self,
                                               worksheet_importer_constructor):
        # given:
        concrete_type_map = {'project': 'project', 'users': 'users'}
        self.template_mgr.get_concrete_type = lambda key: concrete_type_map.get(
            key)
        sheet_names = ['project', 'users']

        workbook = create_ingest_workbook(sheet_names, ['uuid', 'description'])
        workbook_importer = WorkbookImporter(self.template_mgr)

        # and
        worksheet_importer = WorksheetImporter(self.template_mgr)
        worksheet_importer_constructor.return_value = worksheet_importer
        no_errors = []

        expected_errors = []
        for sheet_name in sheet_names:
            expected_errors.append({
                'location':
                f'sheet={sheet_name}',
                'type':
                'UnexpectedEntityUUIDFound',
                'detail':
                f'The {sheet_name} entities in the spreadsheet shouldn’t have UUIDs.'
            })

        # and:
        project = MetadataEntity(domain_type='project',
                                 concrete_type='project',
                                 object_id=910)
        user1 = MetadataEntity(concrete_type='user',
                               domain_type='user',
                               object_id=1,
                               content={'user_name': 'jdelacruz'})

        worksheet_importer.do_import = \
            MagicMock(side_effect=[([project], no_errors), ([user1], no_errors)])

        # when:
        spreadsheet_json, errors = workbook_importer.do_import(workbook,
                                                               is_update=False)

        # then:
        self.assertTrue(
            all(elem in errors for elem in expected_errors),
            f'Errors expected to contain {UnexpectedEntityUUIDFound.__name__}.'
        )

    def test_do_import_update_project_but_no_project_worksheet(self):
        # given:
        workbook = create_test_workbook('Users')

        # when:
        spreadsheet_json, errors = self.workbook_importer.do_import(
            IngestWorkbook(workbook),
            project_uuid='project-uuid',
            update_project=True,
            is_update=False)

        # then:
        self.assertEqual(len(errors), 1)
        self.assertEqual('NoProjectWorksheet', errors[0].get('type'))

    def test_do_import_do_not_update_project_and_no_project_worksheet(self):
        # given:
        workbook = create_test_workbook('Users')

        # when:
        spreadsheet_json, errors = self.workbook_importer.do_import(
            IngestWorkbook(workbook),
            project_uuid='project-uuid',
            update_project=False,
            is_update=False)

        # then:
        self.assertEqual(len(errors), 0)
        self.assertEqual(len(spreadsheet_json.get('project', {}).keys()), 1)
        self.assertFalse(
            spreadsheet_json['project']['project-uuid']['is_reference'])
        self.assertTrue(spreadsheet_json['project']['project-uuid']
                        ['is_linking_reference'])

    @patch('ingest.importer.importer.WorksheetImporter')
    def test_do_import_do_not_update_project_but_has_project_worksheets(
            self, worksheet_importer_constructor):
        # given:
        ingest_workbook = self.setup_workbook_with_project_worksheets(
            worksheet_importer_constructor)

        # when:
        spreadsheet_json, errors = self.workbook_importer.do_import(
            ingest_workbook,
            project_uuid='project-uuid',
            update_project=False,
            is_update=False)

        # then:
        self.assertEqual([], errors)
        self.assertEqual(len(spreadsheet_json.get('project', {}).keys()), 1)
        self.assertTrue(spreadsheet_json['project']['project-uuid']
                        ['is_linking_reference'])