def test_change_owner() -> None: uuid = str(uuid4()) alice = User(id=1) bob = User(id=2) repository = Mock() user_service = Mock() service = StorageService( study_service=Mock(), importer_service=Mock(), exporter_service=Mock(), user_service=user_service, repository=repository, event_bus=Mock(), ) repository.get.return_value = Study(id=uuid, owner=alice) user_service.get_user.return_value = bob service.change_owner( uuid, 2, RequestParameters(JWTUser(id=1, impersonator=1, type="users"))) user_service.get_user.assert_called_once_with( 2, RequestParameters(JWTUser(id=1, impersonator=1, type="users"))) repository.save.assert_called_once_with(Study(id=uuid, owner=bob)) with pytest.raises(UserHasNotPermissionError): service.change_owner( uuid, 1, RequestParameters(JWTUser(id=1, impersonator=1, type="users")), )
def test_server_with_parameters() -> None: mock_storage_service = Mock() mock_storage_service.get.return_value = {} app = Flask(__name__) build_storage( app, storage_service=mock_storage_service, session=Mock(), config=CONFIG, user_service=Mock(), ) client = app.test_client() result = client.get("/studies/study1?depth=4") parameters = RequestParameters(user=ADMIN) assert result.status_code == 200 mock_storage_service.get.assert_called_once_with("study1", 4, parameters) result = client.get("/studies/study2?depth=WRONG_TYPE") excepted_parameters = RequestParameters(user=ADMIN) assert result.status_code == 200 mock_storage_service.get.assert_called_with("study2", 3, excepted_parameters)
def test_set_public_mode() -> None: uuid = str(uuid4()) group_admin = JWTGroup(id="admin", name="admin", role=RoleType.ADMIN) repository = Mock() user_service = Mock() service = StorageService( study_service=Mock(), importer_service=Mock(), exporter_service=Mock(), user_service=user_service, repository=repository, event_bus=Mock(), ) repository.get.return_value = Study(id=uuid) with pytest.raises(UserHasNotPermissionError): service.set_public_mode( uuid, PublicMode.FULL, RequestParameters(JWTUser(id=1, impersonator=1, type="users")), ) service.set_public_mode( uuid, PublicMode.FULL, RequestParameters( JWTUser(id=1, impersonator=1, type="users", groups=[group_admin])), ) repository.save.assert_called_once_with( Study(id=uuid, public_mode=PublicMode.FULL))
def test_sta_mini_import_output(tmp_path: Path, storage_service) -> None: params = RequestParameters(user=ADMIN) path_study_output = (storage_service.get_study_path("STA-mini", params) / "output" / "20201014-1422eco-hello") sta_mini_output_zip_filepath = shutil.make_archive(tmp_path, "zip", path_study_output) shutil.rmtree(path_study_output) sta_mini_output_zip_path = Path(sta_mini_output_zip_filepath) app = Flask(__name__) build_storage( app, storage_service=storage_service, session=Mock(), user_service=Mock(), config=storage_service.study_service.config, ) client = app.test_client() study_output_data = io.BytesIO(sta_mini_output_zip_path.read_bytes()) result = client.post( "/studies/STA-mini/output", data={"output": (study_output_data, "output.zip")}, ) assert result.status_code == HTTPStatus.ACCEPTED.value
def get_all_bots() -> Any: params = RequestParameters(user=Auth.get_current_user()) owner = request.args.get("owner", default=None, type=int) bots = (service.get_all_bots_by_owner(owner, params) if owner else service.get_all_bots(params)) return jsonify([b.to_dict() for b in bots]), 200
def groups_get_id(id: str) -> Any: params = RequestParameters(user=Auth.get_current_user()) group = service.get_group(id, params) if group: return jsonify(group.to_dict()) else: return f"Group {id} not found", 404
def users_get_id(id: int) -> Any: params = RequestParameters(user=Auth.get_current_user()) u = service.get_user(id, params) if u: return jsonify(u.to_dict()) else: return "", 404
def get_file(path: str) -> Any: """ Get file --- responses: '200': content: application/octet-stream: {} description: Successful operation '404': description: File not found parameters: - in: path name: path required: true schema: type: string tags: - Manage Matrix """ try: params = RequestParameters(user=Auth.get_current_user()) return storage_service.get_matrix(path, params) except FileNotFoundError: return f"{path} not found", HTTPStatus.NOT_FOUND.value
def change_owner(uuid: str, user_id: int) -> Any: """ Change study owner --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid used by server schema: type: string - in: path name: user_id required: true description: id of the new owner schema: type: number tags: - Manage Permissions """ uuid_sanitized = sanitize_uuid(uuid) params = RequestParameters(user=Auth.get_current_user()) storage_service.change_owner(uuid_sanitized, user_id, params) return "", HTTPStatus.OK
def set_public_mode(uuid: str, mode: str) -> Any: """ Set study public mode --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid used by server schema: type: string - in: path name: mode required: true description: public mode schema: type: string enum: [NONE,READ,EXECUTE,EDIT,FULL] tags: - Manage Permissions """ uuid_sanitized = sanitize_uuid(uuid) params = RequestParameters(user=Auth.get_current_user()) public_mode = PublicMode(mode) storage_service.set_public_mode(uuid_sanitized, public_mode, params) return "", HTTPStatus.OK
def delete_study(uuid: str) -> Any: """ Delete study --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid used by server schema: type: string tags: - Manage Studies """ uuid_sanitized = sanitize_uuid(uuid) params = RequestParameters(user=Auth.get_current_user()) storage_service.delete_study(uuid_sanitized, params) content = "" code = HTTPStatus.NO_CONTENT.value return content, code
def edit_study(path: str) -> Any: """ Update data --- responses: '200': description: Successful operation content: application/json: {} '404': description: File not found parameters: - in: path name: uuid required: true schema: type: string - in: path name: path schema: type: string required: true tags: - Manage Data inside Study """ new = json.loads(request.data) if not new: raise BadRequest("empty body not authorized") params = RequestParameters(user=Auth.get_current_user()) storage_service.edit_study(path, new, params) content = "" code = HTTPStatus.NO_CONTENT.value return content, code
def post_file(path: str) -> Any: """ Post file --- parameters: - in: path name: path required: true schema: type: string responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request tags: - Manage Matrix """ data = request.files["matrix"].read() params = RequestParameters(user=Auth.get_current_user()) storage_service.upload_matrix(path, data, params) output = b"" code = HTTPStatus.NO_CONTENT.value return output, code
def get_study(path: str) -> Any: """ Read data --- responses: '200': description: Successful operation content: application/json: {} '404': description: File not found parameters: - in: path name: uuid required: true schema: type: string - in: path name: path schema: type: string required: true - in: query name: depth schema: type: string tags: - Manage Data inside Study """ parameters = RequestParameters(user=Auth.get_current_user()) depth = request.args.get("depth", 3, type=int) output = storage_service.get(path, depth, parameters) return jsonify(output), 200
def copy_study(uuid: str) -> Any: """ Copy study --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid stored in server schema: type: string - in: query name: dest required: true description: new study name schema: type: string - in: query name: groups required: false description: list of group id assignment separated by comma schema: type: string tags: - Manage Studies """ source_uuid = uuid destination_study_name = request.args.get("dest") groups_arg = request.args.get("groups") group_ids = groups_arg.split(",") if groups_arg is not None else [] if destination_study_name is None: content = "Copy operation need a dest query parameter." code = HTTPStatus.BAD_REQUEST.value return content, code source_uuid_sanitized = sanitize_uuid(source_uuid) destination_name_sanitized = sanitize_study_name( destination_study_name) params = RequestParameters(user=Auth.get_current_user()) destination_uuid = storage_service.copy_study( src_uuid=source_uuid_sanitized, dest_study_name=destination_name_sanitized, group_ids=group_ids, params=params, ) code = HTTPStatus.CREATED.value return destination_uuid, code
def run(study_id: str) -> Any: """ Run study --- responses: '200': content: application/json: schema: $ref: '#/definitions/RunInfo' description: Successful operation '400': description: Invalid request '401': description: Unauthenticated User '403': description: Unauthorized parameters: - in: path name: study_id required: true description: study id schema: type: string definitions: - schema: id: RunInfo properties: job_id: type: string tags: - Run Studies """ params = RequestParameters(user=Auth.get_current_user()) return jsonify({"job_id": service.run_study(study_id, params)})
def test_get_studies_uuid() -> None: bob = User(id=1, name="bob") alice = User(id=2, name="alice") a = Study(id="A", owner=bob) b = Study(id="B", owner=alice) c = Study(id="C", owner=bob) # Mock repository = Mock() repository.get_all.return_value = [a, b, c] study_service = Mock() service = StorageService( study_service=study_service, importer_service=Mock(), exporter_service=Mock(), user_service=Mock(), repository=repository, event_bus=Mock(), ) studies = service._get_study_metadatas( RequestParameters(user=JWTUser(id=1, impersonator=1, type="users"))) assert [a, c] == studies
def remove_group(uuid: str, group_id: str) -> Any: """ Remove a group association --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid used by server schema: type: string - in: path name: group_id required: true description: id of the group to remove schema: type: string tags: - Manage Permissions """ uuid_sanitized = sanitize_uuid(uuid) params = RequestParameters(user=Auth.get_current_user()) storage_service.remove_group(uuid_sanitized, group_id, params) return "", HTTPStatus.OK
def users_update(id: int) -> Any: params = RequestParameters(user=Auth.get_current_user()) u = User.from_dict(json.loads(request.data)) if id != u.id: return "Id in path must be same id in body", 400 return jsonify(service.save_user(u, params).to_dict())
def assert_with_errors(storage_service: StorageService, url: str, new: SUB_JSON) -> None: url = url[len("/studies/"):] print(url) params = RequestParameters(user=ADMIN) res = storage_service.edit_study(route=url, new=new, params=params) assert res == new res = storage_service.get(route=url, depth=-1, params=params) assert res == new
def test_run() -> None: job = uuid4() study = "my-study" service = Mock() service.run_study.return_value = job app = create_app(service) client = app.test_client() res = client.post(f"/launcher/run/{study}") assert res.status_code == 200 assert res.json == {"job_id": str(job)} service.run_study.assert_called_once_with(study, RequestParameters(ADMIN))
def get_studies() -> Any: """ Get Studies --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request tags: - Manage Studies """ params = RequestParameters(user=Auth.get_current_user()) available_studies = storage_service.get_studies_information(params) return jsonify(available_studies), HTTPStatus.OK.value
def test_sta_mini_copy(storage_service) -> None: source_study_name = "STA-mini" destination_study_name = "copy-STA-mini" app = Flask(__name__) build_storage( app, session=Mock(), user_service=Mock(), storage_service=storage_service, config=storage_service.study_service.config, ) client = app.test_client() result = client.post( f"/studies/{source_study_name}/copy?dest={destination_study_name}") assert result.status_code == HTTPStatus.CREATED.value uuid = result.data.decode("utf-8") parameters = RequestParameters(user=ADMIN) data_source = storage_service.get(source_study_name, -1, parameters) data_destination = storage_service.get(uuid, -1, parameters) link_url_source = data_source["input"]["links"]["de"]["fr"] assert link_url_source == input_link link_url_destination = data_destination["input"]["links"]["de"]["fr"] assert link_url_destination == input_link def replace_study_name(data: JSON) -> None: if isinstance(data, dict): for key, value in data.items(): if isinstance(value, str) and value.startswith("file/"): data[key] = value.replace(uuid, source_study_name) else: replace_study_name(value) replace_study_name(data_destination) del data_source["output"] data_source["study"] = {} data_destination["study"] = {} assert data_source == data_destination
def export_study(uuid: str) -> Any: """ Export Study --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid stored in server schema: type: string - in: query name: no-output required: false example: false description: specify schema: type: boolean tags: - Manage Studies """ uuid_sanitized = sanitize_uuid(uuid) outputs: bool = ("no-output" not in request.args or request.args["no-output"] == "false") params = RequestParameters(user=Auth.get_current_user()) content = storage_service.export_study(uuid_sanitized, params, outputs) return send_file( content, mimetype="application/zip", as_attachment=True, attachment_filename=f"{uuid_sanitized}.zip", )
def test_sta_mini_import(tmp_path: Path, storage_service) -> None: params = RequestParameters(user=ADMIN) path_study = storage_service.get_study_path("STA-mini", params) sta_mini_zip_filepath = shutil.make_archive(tmp_path, "zip", path_study) sta_mini_zip_path = Path(sta_mini_zip_filepath) app = Flask(__name__) build_storage( app, storage_service=storage_service, session=Mock(), user_service=Mock(), config=storage_service.study_service.config, ) client = app.test_client() study_data = io.BytesIO(sta_mini_zip_path.read_bytes()) result = client.post("/studies", data={"study": (study_data, "study.zip")}) assert result.status_code == HTTPStatus.CREATED.value
def create_study(name: str) -> Any: """ Create study name --- description: Create an empty study responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: name required: true description: study name asked schema: type: string - in: query name: groups required: false description: list of group id assignment separated by comma schema: type: string tags: - Manage Studies """ name_sanitized = sanitize_study_name(name) groups_arg = request.args.get("groups") group_ids = groups_arg.split(",") if groups_arg is not None else [] params = RequestParameters(user=Auth.get_current_user()) uuid = storage_service.create_study(name_sanitized, group_ids, params) content = "/studies/" + uuid code = HTTPStatus.CREATED.value return jsonify(content), code
def import_study() -> Any: """ Import Study --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: query name: groups required: false description: list of group id assignment separated by comma schema: type: string tags: - Manage Studies """ if "study" not in request.files: content = "No data provided." code = HTTPStatus.BAD_REQUEST.value return content, code zip_binary = io.BytesIO(request.files["study"].read()) params = RequestParameters(user=Auth.get_current_user()) groups_arg = request.args.get("groups") group_ids = groups_arg.split(",") if groups_arg is not None else [] uuid = storage_service.import_study(zip_binary, group_ids, params) content = "/studies/" + uuid code = HTTPStatus.CREATED.value return jsonify(content), code
def bots_delete(id: int) -> Any: """ Revoke bot --- responses: '200': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: id required: true description: bot id schema: type: int tags: - Bot """ params = RequestParameters(user=Auth.get_current_user()) service.delete_bot(id, params) return jsonify(id), 200
def import_output(uuid: str) -> Any: """ Import Output --- responses: '202': content: application/json: {} description: Successful operation '400': description: Invalid request parameters: - in: path name: uuid required: true description: study uuid used by server schema: type: string tags: - Manage Outputs """ uuid_sanitized = sanitize_uuid(uuid) if "output" not in request.files: content = "No data provided." code = HTTPStatus.BAD_REQUEST.value return content, code zip_binary = io.BytesIO(request.files["output"].read()) params = RequestParameters(user=Auth.get_current_user()) content = str( storage_service.import_output(uuid_sanitized, zip_binary, params)) code = HTTPStatus.ACCEPTED.value return jsonify(content), code
def assert_with_errors(storage_service: StorageService, url: str, expected_output: dict) -> None: url = url[len("/studies/"):] params = RequestParameters(user=ADMIN) assert (storage_service.get(route=url, depth=3, params=params) == expected_output)