class FilesHelperTest(TransactionalTestCase): """ This class contains tests for the tvb.core.entities.file.fileshelper module. """ PROJECT_NAME = "test_proj" def setUp(self): """ Set up the context needed by the tests. """ # self.clean_database() self.files_helper = FilesHelper() self.test_user = TestFactory.create_user() self.test_project = TestFactory.create_project(self.test_user, self.PROJECT_NAME) def tearDown(self): """ Remove generated project during tests. """ self.delete_project_folders() def test_check_created(self): """ Test standard flows for check created. """ self.files_helper.check_created() self.assertTrue(os.path.exists(root_storage), "Storage not created!") self.files_helper.check_created(os.path.join(root_storage, "test")) self.assertTrue(os.path.exists(root_storage), "Storage not created!") self.assertTrue(os.path.exists(os.path.join(root_storage, "test")), "Test directory not created!") def test_get_project_folder(self): """ Test the get_project_folder method which should create a folder in case it doesn't already exist. """ project_path = self.files_helper.get_project_folder(self.test_project) self.assertTrue(os.path.exists(project_path), "Folder doesn't exist") folder_path = self.files_helper.get_project_folder(self.test_project, "43") self.assertTrue(os.path.exists(project_path), "Folder doesn't exist") self.assertTrue(os.path.exists(folder_path), "Folder doesn't exist") def test_rename_project_structure(self): """ Try to rename the folder structure of a project. Standard flow. """ self.files_helper.get_project_folder(self.test_project) path, name = self.files_helper.rename_project_structure(self.test_project.name, "new_name") self.assertNotEqual(path, name, "Rename didn't take effect.") def test_rename_structure_same_name(self): """ Try to rename the folder structure of a project. Same name. """ self.files_helper.get_project_folder(self.test_project) self.assertRaises(FileStructureException, self.files_helper.rename_project_structure, self.test_project.name, self.PROJECT_NAME) def test_remove_project_structure(self): """ Check that remove project structure deletes the corresponding folder. Standard flow. """ full_path = self.files_helper.get_project_folder(self.test_project) self.assertTrue(os.path.exists(full_path), "Folder was not created.") self.files_helper.remove_project_structure(self.test_project.name) self.assertFalse(os.path.exists(full_path), "Project folder not deleted.") def test_write_project_metadata(self): """ Write XML for test-project. """ self.files_helper.write_project_metadata(self.test_project) expected_file = self.files_helper.get_project_meta_file_path(self.PROJECT_NAME) self.assertTrue(os.path.exists(expected_file)) project_meta = XMLReader(expected_file).read_metadata() loaded_project = model.Project(None, None) loaded_project.from_dict(project_meta, self.test_user.id) self.assertEqual(self.test_project.name, loaded_project.name) self.assertEqual(self.test_project.description, loaded_project.description) self.assertEqual(self.test_project.gid, loaded_project.gid) expected_dict = self.test_project.to_dict()[1] del expected_dict['last_updated'] found_dict = loaded_project.to_dict()[1] del found_dict['last_updated'] self.assertEqual(expected_dict, found_dict) def test_write_operation_metadata(self): """ Test that a correct XML is created for an operation. """ operation = TestFactory.create_operation(test_user=self.test_user, test_project=self.test_project) expected_file = self.files_helper.get_operation_meta_file_path(self.PROJECT_NAME, operation.id) self.assertFalse(os.path.exists(expected_file)) self.files_helper.write_operation_metadata(operation) self.assertTrue(os.path.exists(expected_file)) operation_meta = XMLReader(expected_file).read_metadata() loaded_operation = model.Operation(None, None, None, None) loaded_operation.from_dict(operation_meta, dao) expected_dict = operation.to_dict()[1] found_dict = loaded_operation.to_dict()[1] for key, value in expected_dict.iteritems(): self.assertEqual(str(value), str(found_dict[key])) # Now validate that operation metaData can be also updated self.assertNotEqual("new_group_name", found_dict['user_group']) self.files_helper.update_operation_metadata(self.PROJECT_NAME, "new_group_name", operation.id) found_dict = XMLReader(expected_file).read_metadata() self.assertEqual("new_group_name", found_dict['user_group']) def test_remove_dt_happy_flow(self): """ Happy flow for removing a file related to a DataType. """ folder_path = self.files_helper.get_project_folder(self.test_project, "42") datatype = MappedType() datatype.storage_path = folder_path open(datatype.get_storage_file_path(), 'w') self.assertTrue(os.path.exists(datatype.get_storage_file_path()), "Test file was not created!") self.files_helper.remove_datatype(datatype) self.assertFalse(os.path.exists(datatype.get_storage_file_path()), "Test file was not deleted!") def test_remove_dt_non_existent(self): """ Try to call remove on a dataType with no H5 file. Should throw an exception. """ folder_path = self.files_helper.get_project_folder(self.test_project, "42") datatype = MappedType() datatype.storage_path = folder_path self.assertFalse(os.path.exists(datatype.get_storage_file_path())) self.assertRaises(FileStructureException, self.files_helper.remove_datatype, datatype) def test_move_datatype(self): """ Make sure associated H5 file is moved to a correct new location. """ folder_path = self.files_helper.get_project_folder(self.test_project, "42") datatype = MappedType() datatype.storage_path = folder_path open(datatype.get_storage_file_path(), 'w') self.assertTrue(os.path.exists(datatype.get_storage_file_path()), "Test file was not created!") self.files_helper.move_datatype(datatype, self.PROJECT_NAME + '11', "43") self.assertFalse(os.path.exists(datatype.get_storage_file_path()), "Test file was not moved!") datatype.storage_path = self.files_helper.get_project_folder(self.PROJECT_NAME + '11', "43") self.assertTrue(os.path.exists(datatype.get_storage_file_path()), "Test file was not created!") def test_find_relative_path(self): rel_path = self.files_helper.find_relative_path("/root/up/to/here/test/it/now", "/root/up/to/here") self.assertEqual(rel_path, os.sep.join(["test", "it", "now"]), "Did not extract relative path as expected.") def test_remove_files_valid(self): """ Pass a valid list of files and check they are all removed. """ file_list = ["test1", "test2", "test3"] for file_n in file_list: fp = open(file_n, 'w') fp.write('test') fp.close() for file_n in file_list: self.assertTrue(os.path.isfile(file_n)) self.files_helper.remove_files(file_list) for file_n in file_list: self.assertFalse(os.path.isfile(file_n)) def test_remove_folder(self): """ Pass an open file pointer, but ignore exceptions. """ folder_name = "test_folder" os.mkdir(folder_name) self.assertTrue(os.path.isdir(folder_name), "Folder should be created.") self.files_helper.remove_folder(folder_name) self.assertFalse(os.path.isdir(folder_name), "Folder should be deleted.") def test_remove_folder_non_existing_ignore_exc(self): """ Pass an open file pointer, but ignore exceptions. """ folder_name = "test_folder" self.assertFalse(os.path.isdir(folder_name), "Folder should not exist before call.") self.files_helper.remove_folder(folder_name, ignore_errors=True) def test_remove_folder_non_existing(self): """ Pass an open file pointer, but ignore exceptions. """ folder_name = "test_folder" self.assertFalse(os.path.isdir(folder_name), "Folder should not exist before call.") self.assertRaises(FileStructureException, self.files_helper.remove_folder, folder_name, False)
class FigureService: """ Service layer for Figure entities. """ def __init__(self): self.logger = get_logger(self.__class__.__module__) self.file_helper = FilesHelper() def store_result_figure(self, project, user, img_type, operation_id, export_data): """ Store into a file, Result Image and reference in DB. """ session_name = "Default" file_name = "snapshot." + img_type # Generate path where to store image store_path = self.file_helper.get_images_folder(project.name, operation_id) store_path = utils.get_unique_file_name(store_path, file_name)[0] file_name = os.path.split(store_path)[1] if img_type == "jpg": # JPG file from canvas # Store image img_data = base64.b64decode(export_data) dest = open(store_path, 'wb') dest.write(img_data) dest.close() elif img_type == 'svg': # SVG file from svg viewer # Generate path where to store image dest = open(store_path, 'w') dest.write(export_data) dest.close() # Store entity into DB entity = model.ResultFigure(operation_id, user.id, project.id, session_name, "Snapshot-" + operation_id, file_name) entity = dao.store_entity(entity) # Load instance from DB to have lazy fields loaded figure = dao.load_figure(entity.id) # Write image meta data to disk self.file_helper.write_image_metadata(figure) # Force writing operation meta data on disk. # This is important later for operation import operation = dao.get_operation_by_id(operation_id) self.file_helper.write_operation_metadata(operation) def retrieve_result_figures(self, project, user, selected_session_name='all_sessions'): """ Retrieve from DB all the stored Displayer previews that belongs to the specified session. The previews are for current user and project; grouped by session. """ result, previews_info = dao.get_previews(project.id, user.id, selected_session_name) for name in result: for figure in result[name]: figures_folder = self.file_helper.get_images_folder(project.name, figure.operation.id) figure_full_path = os.path.join(figures_folder, figure.file_path) # Compute the path figure.file_path = utils.path2url_part(figure_full_path) return result, previews_info @staticmethod def load_figure(figure_id): """ Loads a stored figure by its id. """ return dao.load_figure(figure_id) def edit_result_figure(self, figure_id, **data): """ Retrieve and edit a previously stored figure. """ figure = dao.load_figure(figure_id) figure.session_name = data['session_name'] figure.name = data['name'] dao.store_entity(figure) # Load instance from DB to have lazy fields loaded. figure = dao.load_figure(figure_id) # Store figure meta data in an XML attached to the image. self.file_helper.write_image_metadata(figure) def remove_result_figure(self, figure_id): """ Remove figure from DB and file storage. """ figure = dao.load_figure(figure_id) # Delete all figure related files from disk. figures_folder = self.file_helper.get_images_folder(figure.project.name, figure.operation.id) path2figure = os.path.join(figures_folder, figure.file_path) if os.path.exists(path2figure): os.remove(path2figure) self.file_helper.remove_image_metadata(figure) # Remove figure reference from DB. result = dao.remove_entity(model.ResultFigure, figure_id) return result