Example #1
0
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 test_create_study(tmp_path: str, storage_service_builder,
                      project_path) -> None:

    path_studies = Path(tmp_path)
    path_study = path_studies / "study1"
    path_study.mkdir()
    (path_study / "study.antares").touch()

    storage_service = Mock()
    storage_service.create_study.return_value = "my-uuid"

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    result_right = client.post("/studies/study2")

    assert result_right.status_code == HTTPStatus.CREATED.value
    assert json.loads(result_right.data) == "/studies/my-uuid"
    storage_service.create_study.assert_called_once_with("study2", [], PARAMS)
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_export_params() -> None:

    mock_storage_service = Mock()
    mock_storage_service.export_study.return_value = BytesIO(b"Hello")

    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/name/export")

    assert result.data == b"Hello"

    client.get("/studies/name/export?no-output")
    client.get("/studies/name/export?no-output=true")
    client.get("/studies/name/export?no-output=false")
    mock_storage_service.export_study.assert_has_calls([
        call(Markup("name"), PARAMS, True),
        call(Markup("name"), PARAMS, False),
        call(Markup("name"), PARAMS, False),
    ])
def test_list_studies(tmp_path: str, storage_service_builder) -> None:

    studies = {
        "study1": {
            "antares": {
                "caption": ""
            }
        },
        "study2": {
            "antares": {
                "caption": ""
            }
        },
    }

    storage_service = Mock()
    storage_service.get_studies_information.return_value = studies

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    result = client.get("/studies")

    assert json.loads(result.data) == studies
def assert_url_content(storage_service: StorageService, url: str) -> bytes:
    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()
    res = client.get(url)
    return res.data
def test_server_health() -> None:
    app = Flask(__name__)
    build_storage(
        app,
        storage_service=Mock(),
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    result = client.get("/health")
    assert result.data == b'{"status":"available"}\n'
Example #8
0
def assert_url_content(storage_service: StorageService, url: str,
                       expected_output: str) -> None:
    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()
    res = client.get(url)
    assert json.loads(res.data) == expected_output
def test_study_permission_management(tmp_path: Path,
                                     storage_service_builder) -> None:
    storage_service = Mock()

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=storage_service,
        session=Mock(),
        user_service=Mock(),
        config=CONFIG,
    )
    client = app.test_client()

    result = client.put("/studies/existing-study/owner/2")
    storage_service.change_owner.assert_called_with(
        "existing-study",
        2,
        PARAMS,
    )
    assert result.status_code == HTTPStatus.OK.value

    result = client.put("/studies/existing-study/groups/group-a")
    storage_service.add_group.assert_called_with(
        "existing-study",
        "group-a",
        PARAMS,
    )
    assert result.status_code == HTTPStatus.OK.value

    result = client.delete("/studies/existing-study/groups/group-b")
    storage_service.remove_group.assert_called_with(
        "existing-study",
        "group-b",
        PARAMS,
    )
    assert result.status_code == HTTPStatus.OK.value

    result = client.put("/studies/existing-study/public_mode/FULL")
    storage_service.set_public_mode.assert_called_with(
        "existing-study",
        PublicMode.FULL,
        PARAMS,
    )
    assert result.status_code == HTTPStatus.OK.value

    result = client.put("/studies/existing-study/public_mode/UNKNOWN")
    assert result.status_code == HTTPStatus.INTERNAL_SERVER_ERROR.value
def test_exporter_file(tmp_path: Path, sta_mini_zip_path: Path):

    path_studies = tmp_path / "studies"

    with ZipFile(sta_mini_zip_path) as zip_output:
        zip_output.extractall(path=path_studies)

    config = Config(
        resources_path=Path(),
        security=SecurityConfig(disabled=True),
        storage=StorageConfig(
            workspaces={
                DEFAULT_WORKSPACE_NAME: WorkspaceConfig(path=path_studies)
            }
        ),
    )

    md = RawStudy(
        id="STA-mini",
        workspace=DEFAULT_WORKSPACE_NAME,
        path=str(path_studies / "STA-mini"),
    )
    repo = Mock()
    repo.get.return_value = md

    service = build_storage(
        application=Mock(),
        config=config,
        session=Mock(),
        user_service=Mock(),
        metadata_repository=repo,
    )

    data = assert_url_content(service, url="/studies/STA-mini/export")
    assert_data(data)
Example #11
0
    def build_storage_service(
            study_factory=Mock(),
            exporter=Mock(),
            session=Mock(),
            path_studies=Path(),
            path_resources=Path(),
            user_service=Mock(),
    ) -> StorageService:

        config = Config(
            resources_path=path_resources,
            security=SecurityConfig(disabled=True),
            storage=StorageConfig(
                workspaces={
                    DEFAULT_WORKSPACE_NAME: WorkspaceConfig(path=path_studies)
                }),
        )

        return build_storage(
            application=Mock(),
            config=config,
            session=session,
            user_service=user_service,
            study_factory=study_factory,
            exporter=exporter,
        )
def test_delete_study() -> None:

    mock_storage_service = Mock()

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    client.delete("/studies/name")

    mock_storage_service.delete_study.assert_called_once_with("name", PARAMS)
def test_server() -> None:
    mock_service = Mock()
    mock_service.get.return_value = {}

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    client.get("/studies/study1/settings/general/params")

    mock_service.get.assert_called_once_with("study1/settings/general/params",
                                             3, PARAMS)
def test_404() -> None:
    mock_storage_service = Mock()
    mock_storage_service.get.side_effect = UrlNotMatchJsonDataError("Test")

    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/settings/general/params")
    assert result.status_code == 404

    result = client.get("/studies/WRONG_STUDY")
    assert result.status_code == 404
Example #15
0
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 test_export_files() -> None:

    mock_storage_service = Mock()
    mock_storage_service.export_study.return_value = BytesIO(b"Hello")

    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/name/export")

    assert result.data == b"Hello"
    mock_storage_service.export_study.assert_called_once_with(
        "name", PARAMS, True)
def test_edit_study() -> None:
    mock_storage_service = Mock()
    mock_storage_service.edit_study.return_value = {}

    data = json.dumps({"Hello": "World"})

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    client.post("/studies/my-uuid/url/to/change", data=data)

    mock_storage_service.edit_study.assert_called_once_with(
        "my-uuid/url/to/change", {"Hello": "World"}, PARAMS)
def test_edit_study_fail() -> None:
    mock_storage_service = Mock()

    data = json.dumps({})

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()
    res = client.post("/studies/my-uuid/url/to/change", data=data)

    assert res.status_code == 400

    mock_storage_service.edit_study.assert_not_called()
def test_get_matrix() -> None:

    mock_storage_service = Mock()
    mock_storage_service.get_matrix.return_value = b"Hello World"

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    path = "/file/my-study/matrix.txt"
    result = client.get(path)

    assert result.status_code == HTTPStatus.OK.value
    assert result.data == b"Hello World"
def test_version() -> None:

    mock_storage_service = Mock()
    mock_storage_service.study_service.path_resources = Path("/")

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=Config(),
        user_service=Mock(),
    )
    client = app.test_client()

    path = "/version"
    result = client.get(path)

    assert result.status_code == HTTPStatus.OK.value
    assert json.loads(result.data)["version"] == __version__
Example #21
0
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 test_import_matrix() -> None:
    mock_storage_service = Mock()

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    data = io.BytesIO(b"hello")
    path = "path/to/matrix.txt"
    result = client.post("/file/" + path,
                         data={"matrix": (data, "matrix.txt")})

    mock_storage_service.upload_matrix.assert_called_once_with(
        path, b"hello", PARAMS)
    assert result.status_code == HTTPStatus.NO_CONTENT.value
def test_import_matrix_with_wrong_path() -> None:

    mock_storage_service = Mock()
    mock_storage_service.upload_matrix = Mock(
        side_effect=IncorrectPathError(""))

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    data = io.BytesIO(b"hello")
    path = "path/to/matrix.txt"
    result = client.post("/file/" + path,
                         data={"matrix": (data, "matrix.txt")})

    assert result.status_code == HTTPStatus.NOT_FOUND.value
def test_import_study_zipped(tmp_path: Path, storage_service_builder,
                             project_path) -> None:

    tmp_path /= "tmp"
    tmp_path.mkdir()
    study_name = "study1"
    path_study = tmp_path / study_name
    path_study.mkdir()
    path_file = path_study / "study.antares"
    path_file.write_text("[antares]")

    shutil.make_archive(path_study, "zip", path_study)
    path_zip = tmp_path / "study1.zip"

    mock_storage_service = Mock()
    mock_storage_service.import_study.return_value = study_name

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=mock_storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    result = client.post("/studies")

    assert result.status_code == HTTPStatus.BAD_REQUEST.value

    study_data = io.BytesIO(path_zip.read_bytes())
    result = client.post("/studies", data={"study": (study_data, "study.zip")})

    print(result.data)
    assert json.loads(result.data) == "/studies/" + study_name
    assert result.status_code == HTTPStatus.CREATED.value
    mock_storage_service.import_study.assert_called_once()
def test_copy_study(tmp_path: Path, storage_service_builder) -> None:
    storage_service = Mock()
    storage_service.copy_study.return_value = "/studies/study-copied"

    app = Flask(__name__)
    build_storage(
        app,
        storage_service=storage_service,
        session=Mock(),
        config=CONFIG,
        user_service=Mock(),
    )
    client = app.test_client()

    result = client.post("/studies/existing-study/copy?dest=study-copied")

    storage_service.copy_study.assert_called_with(
        src_uuid="existing-study",
        dest_study_name="study-copied",
        group_ids=[],
        params=PARAMS,
    )
    assert result.status_code == HTTPStatus.CREATED.value
Example #26
0
def storage_service(tmp_path: str, project_path: Path,
                    sta_mini_zip_path: Path) -> StorageService:

    path_studies = Path(tmp_path) / "studies"

    path_resources = project_path / "resources"

    with ZipFile(sta_mini_zip_path) as zip_output:
        zip_output.extractall(path=path_studies)

    md = RawStudy(
        id="STA-mini",
        workspace=DEFAULT_WORKSPACE_NAME,
        path=str(path_studies / "STA-mini"),
    )
    repo = Mock()
    repo.get.side_effect = lambda name: RawStudy(
        id=name,
        workspace=DEFAULT_WORKSPACE_NAME,
        path=str(path_studies / name),
    )
    repo.get_all.return_value = [md]

    config = Config(
        resources_path=path_resources,
        security=SecurityConfig(disabled=True),
        storage=StorageConfig(
            workspaces={
                DEFAULT_WORKSPACE_NAME: WorkspaceConfig(path=path_studies)
            }),
    )

    storage_service = build_storage(
        application=Mock(),
        session=Mock(),
        user_service=Mock(),
        config=config,
        metadata_repository=repo,
    )

    return storage_service
Example #27
0
def flask_app(config_file: Path,
              resource_path: Optional[Path] = None) -> Flask:
    res = resource_path or get_local_path() / "resources"
    config = Config.from_yaml_file(res=res, file=config_file)

    configure_logger(config)
    # Database
    engine = create_engine(config.db_url, echo=config.debug)
    Base.metadata.create_all(engine)
    db_session = scoped_session(
        sessionmaker(autocommit=False, autoflush=False, bind=engine))

    application = Flask(__name__,
                        static_url_path="/static",
                        static_folder=str(res / "webapp"))
    application.wsgi_app = ReverseProxyMiddleware(
        application.wsgi_app)  # type: ignore

    application.config["SECRET_KEY"] = config.security.jwt_key
    application.config["JWT_ACCESS_TOKEN_EXPIRES"] = Auth.ACCESS_TOKEN_DURATION
    application.config[
        "JWT_REFRESH_TOKEN_EXPIRES"] = Auth.REFRESH_TOKEN_DURATION
    application.config["JWT_TOKEN_LOCATION"] = ["headers", "cookies"]

    @application.route("/", methods=["GET"])
    def home() -> Any:
        """
        Home ui
        ---
        responses:
            '200':
              content:
                 application/html: {}
              description: html home page
        tags:
          - UI
        """
        return render_template("index.html")

    @application.teardown_appcontext
    def shutdown_session(exception: Any = None) -> None:
        Auth.invalidate()
        db_session.remove()

    @application.errorhandler(HTTPException)
    def handle_exception(e: Any) -> Tuple[Any, Number]:
        """Return JSON instead of HTML for HTTP errors."""
        # start with the correct headers and status code from the error
        response = e.get_response()
        # replace the body with JSON
        response.data = json.dumps({
            "name": e.name,
            "description": e.description,
        })
        response.content_type = "application/json"
        return response, e.code

    event_bus = build_eventbus(application, config)
    user_service = build_login(application,
                               config,
                               db_session,
                               event_bus=event_bus)
    storage = build_storage(
        application,
        config,
        db_session,
        user_service=user_service,
        event_bus=event_bus,
    )
    build_launcher(
        application,
        config,
        db_session,
        service_storage=storage,
        event_bus=event_bus,
    )
    build_swagger(application)

    return application