diff --git a/README.md b/README.md index 8eaad38..0aebd17 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,19 @@ This project presents a Flask-based API for validating RO-Crates. +### Optional MinIO object storage + +The RO-Crate Validation Service can validate an RO-Crate's metadata directly from a JSON payload (the `POST v1/ro_crates/validate_metadata` endpoint) without storing anything. This is the default mode. + +Optionally, the service can read crates from — and write validation results +back to — a [MinIO](https://min.io/) object store. This is disabled by +default and controlled by the `MINIO_ENABLED` environment variable: + +- `MINIO_ENABLED=false` (default): only a stateless validation endpoint is available and nothing is stored. +- `MINIO_ENABLED=true`: the ID endpoints (`POST`/`GET v1/ro_crates/{crate_id}/validation`) are also registered, and a MinIO instance is required. With Docker Compose, start MinIO with its opt-in profile: `docker compose --profile minio up`. + +When MinIO is disabled the ID-based endpoints are not registered and return `404`. + ## API #### Request Validation of RO-Crate @@ -184,8 +197,14 @@ curl -X 'POST' \ ```bash docker compose up --build ``` + This runs in the default (metadata-only) mode. To enable the MinIO-backed + endpoints, set `MINIO_ENABLED=true` in your `.env` and start the `minio` + profile: + ```bash + docker compose --profile minio up --build + ``` -5. Set up the MinIO bucket +5. **(Only when `MINIO_ENABLED=true`)** Set up the MinIO bucket 1. Open the MinIO web interface at `http://localhost:9000`. 2. Log in with your MinIO credentials. 3. Create a new bucket named `ro-crates`. diff --git a/app/__init__.py b/app/__init__.py index 95a3d98..dc3d67b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,14 +4,22 @@ # License: MIT # Copyright (c) 2025 eScience Lab, The University of Manchester +import logging import os from apiflask import APIFlask -from app.ro_crates.routes import v1_post_bp, v1_get_bp -from app.utils.config import DevelopmentConfig, ProductionConfig, InvalidAPIUsage, make_celery +from app.ro_crates.routes import v1_post_bp, v1_minio_post_bp, v1_minio_get_bp +from app.utils.config import ( + DevelopmentConfig, + ProductionConfig, + InvalidAPIUsage, + make_celery, +) from flask import jsonify +logger = logging.getLogger(__name__) + def create_app() -> APIFlask: """ @@ -20,23 +28,36 @@ def create_app() -> APIFlask: :return: Flask: A configured Flask application instance. """ app = APIFlask(__name__) - app.register_blueprint(v1_post_bp, url_prefix="/v1/ro_crates") - app.register_blueprint(v1_get_bp, url_prefix="/v1/ro_crates") - @app.errorhandler(InvalidAPIUsage) - def invalid_api_usage(e): - return jsonify(e.to_dict()), e.status_code - - # Load configuration: + # Load config before registering blueprints, so MINIO_ENABLED can + # decide whether the backed endpoints are exposed. if os.getenv("FLASK_ENV") == "production": app.config.from_object(ProductionConfig) else: # Development environment: app.debug = True + app.config.from_object(DevelopmentConfig) + + # Always available: + app.register_blueprint(v1_post_bp, url_prefix="/v1/ro_crates") + + # MinIO is optional and disabled by default. Only register + # the MinIO ID routes when enabled: + if app.config.get("MINIO_ENABLED"): + app.register_blueprint(v1_minio_post_bp, url_prefix="/v1/ro_crates") + app.register_blueprint(v1_minio_get_bp, url_prefix="/v1/ro_crates") + logger.info("MinIO storage enabled: ID-based validation endpoints registered.") + else: + logger.info("MinIO storage disabled: only metadata validation is available.") + + if app.debug: print("URL Map:") for rule in app.url_map.iter_rules(): print(rule) - app.config.from_object(DevelopmentConfig) + + @app.errorhandler(InvalidAPIUsage) + def invalid_api_usage(e): + return jsonify(e.to_dict()), e.status_code # Integrate Celery make_celery(app) diff --git a/app/ro_crates/routes/__init__.py b/app/ro_crates/routes/__init__.py index da8a903..f4ae897 100644 --- a/app/ro_crates/routes/__init__.py +++ b/app/ro_crates/routes/__init__.py @@ -4,8 +4,12 @@ # License: MIT # Copyright (c) 2025 eScience Lab, The University of Manchester -from app.ro_crates.routes.post_routes import post_routes_bp +from app.ro_crates.routes.post_routes import post_routes_bp, minio_post_routes_bp from app.ro_crates.routes.get_routes import get_routes_bp +# Always registered: v1_post_bp = post_routes_bp -v1_get_bp = get_routes_bp + +# Registered only when MinIO is enabled: +v1_minio_post_bp = minio_post_routes_bp +v1_minio_get_bp = get_routes_bp diff --git a/app/ro_crates/routes/post_routes.py b/app/ro_crates/routes/post_routes.py index 4fcf4ab..5fb1fda 100644 --- a/app/ro_crates/routes/post_routes.py +++ b/app/ro_crates/routes/post_routes.py @@ -11,11 +11,16 @@ from app.services.validation_service import ( queue_ro_crate_validation_task, - queue_ro_crate_metadata_validation_task + queue_ro_crate_metadata_validation_task, ) +# Always-on blueprint: post_routes_bp = APIBlueprint("post_routes", __name__) +# MinIO blueprint. Only registered when MINIO_ENABLED is true +# (see app.create_app), so the ID-based routes are unreachable by default. +minio_post_routes_bp = APIBlueprint("minio_post_routes", __name__) + class MinioConfig(Schema): endpoint = String(required=True) @@ -37,8 +42,8 @@ class ValidateJSON(Schema): profile_name = String(required=False) -@post_routes_bp.post("/validation") -@post_routes_bp.input(ValidateCrate(partial=False), location='json') +@minio_post_routes_bp.post("/validation") +@minio_post_routes_bp.input(ValidateCrate(partial=False), location="json") def validate_ro_crate_via_id(json_data, crate_id) -> tuple[Response, int]: """ Endpoint to validate an RO-Crate using its ID from MinIO. @@ -52,7 +57,7 @@ def validate_ro_crate_via_id(json_data, crate_id) -> tuple[Response, int]: - **accesskey**: Access key / username - **secret**: Secret / password - **ssl**: Use SSL encryption? True/False - - **bucket**: The MinIO bucket to access + - **bucket**: The MinIO bucket to access - **root_path**: The root path containing the RO-Crate. _Optional_ - **profile_name**: The profile name for validation. _Optional_. - **webhook_url**: The webhook URL where validation results will be sent. _Optional_. @@ -83,12 +88,13 @@ def validate_ro_crate_via_id(json_data, crate_id) -> tuple[Response, int]: profiles_path = current_app.config["PROFILES_PATH"] - return queue_ro_crate_validation_task(minio_config, crate_id, root_path, profile_name, - webhook_url, profiles_path) + return queue_ro_crate_validation_task( + minio_config, crate_id, root_path, profile_name, webhook_url, profiles_path + ) @post_routes_bp.post("/validate_metadata") -@post_routes_bp.input(ValidateJSON(partial=False), location='json') # -> json_data +@post_routes_bp.input(ValidateJSON(partial=False), location="json") # -> json_data def validate_ro_crate_metadata(json_data) -> tuple[Response, int]: """ Endpoint to validate an RO-Crate JSON file uploaded to the Service. @@ -113,4 +119,6 @@ def validate_ro_crate_metadata(json_data) -> tuple[Response, int]: profiles_path = current_app.config["PROFILES_PATH"] - return queue_ro_crate_metadata_validation_task(crate_json, profile_name, profiles_path=profiles_path) + return queue_ro_crate_metadata_validation_task( + crate_json, profile_name, profiles_path=profiles_path + ) diff --git a/app/utils/config.py b/app/utils/config.py index 28e71ae..465ca60 100644 --- a/app/utils/config.py +++ b/app/utils/config.py @@ -17,6 +17,13 @@ def get_env(name: str, default=None, required=False): return value +def get_bool_env(name: str, default: bool = False) -> bool: + value = get_env(name) + if value is None: + return default + return value.strip().lower() in ("true", "1", "yes", "on") + + class Config: """Base configuration class for the Flask application.""" @@ -27,14 +34,20 @@ class Config: # rocrate validator configuration: PROFILES_PATH = get_env("PROFILES_PATH", required=False) + # Optional MinIO storage. Disabled by default - when False the + # ID validation endpoints are not registered: + MINIO_ENABLED = get_bool_env("MINIO_ENABLED", default=False) + class DevelopmentConfig(Config): """Development configuration class.""" + DEBUG = True class ProductionConfig(Config): """Production configuration class.""" + DEBUG = False @@ -50,7 +63,7 @@ def __init__(self, message, status_code=None, payload=None): def to_dict(self): rv = dict(self.payload or ()) - rv['message'] = self.message + rv["message"] = self.message return rv diff --git a/docker-compose-develop.yml b/docker-compose-develop.yml index a8d27c2..334b0d6 100644 --- a/docker-compose-develop.yml +++ b/docker-compose-develop.yml @@ -12,6 +12,9 @@ services: - FLASK_ENV=development - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 + # Optional object storage. Set MINIO_ENABLED=true and start the "minio" + # profile (docker compose --profile minio up) to use + - MINIO_ENABLED=${MINIO_ENABLED:-false} - MINIO_ENDPOINT=${MINIO_ENDPOINT} - MINIO_ROOT_USER=${MINIO_ROOT_USER} - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD} @@ -19,7 +22,6 @@ services: - PROFILES_PATH=/app/profiles depends_on: - redis - - minio celery_worker: build: @@ -29,9 +31,9 @@ services: environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 + - MINIO_ENABLED=${MINIO_ENABLED:-false} depends_on: - redis - - minio volumes: - ./tests/data/rocrate_validator_profiles:/app/profiles:ro @@ -42,6 +44,9 @@ services: minio: image: "minio/minio" + # Started with `docker compose --profile minio up`. + profiles: + - minio ports: - "9000:9000" - "9001:9001" diff --git a/docker-compose.yml b/docker-compose.yml index bd47218..2f0bb3b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,13 +11,15 @@ services: - FLASK_ENV=development - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 + # Optional object storage. Set MINIO_ENABLED=true and start the "minio" + # profile (docker compose --profile minio up) to use + - MINIO_ENABLED=${MINIO_ENABLED:-false} - MINIO_ENDPOINT=${MINIO_ENDPOINT} - MINIO_ROOT_USER=${MINIO_ROOT_USER} - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD} - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME} depends_on: - redis - - minio celery_worker: platform: linux/x86_64 @@ -26,9 +28,9 @@ services: environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 + - MINIO_ENABLED=${MINIO_ENABLED:-false} depends_on: - redis - - minio redis: image: "redis:alpine" @@ -37,6 +39,9 @@ services: minio: image: "minio/minio" + # Started with `docker compose --profile minio up`. + profiles: + - minio ports: - "9000:9000" - "9001:9001" diff --git a/example.env b/example.env index 31313ec..5235486 100644 --- a/example.env +++ b/example.env @@ -1,3 +1,8 @@ +# MinIO is off by default; only the stateless validation endpoint is exposed when +# disabled. The MINIO_* vars below and the "minio" docker-compose profile are +#only needed when this is true. +MINIO_ENABLED=false + MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=minioadmin MINIO_BUCKET_NAME=ro-crates diff --git a/tests/test_api_routes.py b/tests/test_api_routes.py index 486378b..2f1071b 100644 --- a/tests/test_api_routes.py +++ b/tests/test_api_routes.py @@ -6,6 +6,17 @@ @pytest.fixture def client(): + """Client with MinIO disabled (the default): only metadata validation is exposed.""" + app = create_app() + return app.test_client() + + +@pytest.fixture +def minio_client(monkeypatch): + """Client with MinIO enabled, so the ID-based validation endpoints are registered.""" + # MINIO_ENABLED is resolved on the Config class at import time, so override + # the class attribute before building the app rather than the env var. + monkeypatch.setattr("app.utils.config.DevelopmentConfig.MINIO_ENABLED", True) app = create_app() return app.test_client() @@ -94,12 +105,12 @@ def client(): "validate_with_missing_webhook_url", "validate_with_missing_root_path", "validate_with_missing_root_path_and_profile_name_and_webhook_url"] ) -def test_validate_by_id_success(client: FlaskClient, crate_id: str, payload: dict, +def test_validate_by_id_success(minio_client: FlaskClient, crate_id: str, payload: dict, profiles_path: str, status_code: int, response_json: dict): with patch("app.ro_crates.routes.post_routes.queue_ro_crate_validation_task") as mock_queue: mock_queue.return_value = (response_json, status_code) - response = client.post(f"/v1/ro_crates/{crate_id}/validation", json=payload) + response = minio_client.post(f"/v1/ro_crates/{crate_id}/validation", json=payload) minio_config = payload["minio_config"] if "minio_config" in payload else None root_path = payload["root_path"] if "root_path" in payload else None @@ -134,8 +145,8 @@ def test_validate_by_id_success(client: FlaskClient, crate_id: str, payload: dic "missing_minio_bucket_returns_422" ] ) -def test_validate_fails_missing_elements(client: FlaskClient, crate_id: str, payload: dict, status_code: int): - response = client.post(f"/v1/ro_crates/{crate_id}/validation", json=payload) +def test_validate_fails_missing_elements(minio_client: FlaskClient, crate_id: str, payload: dict, status_code: int): + response = minio_client.post(f"/v1/ro_crates/{crate_id}/validation", json=payload) assert response.status_code == status_code @@ -238,12 +249,12 @@ def test_validate_metadata_failure(client: FlaskClient, payload: dict, status_co ], ids=["failure_missing_crate_id", "failure_missing_minio_bucket"] ) -def test_get_validation_by_id_failures(client: FlaskClient, crate_id: str, payload: dict, status_code: int): - response = client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) +def test_get_validation_by_id_failures(minio_client: FlaskClient, crate_id: str, payload: dict, status_code: int): + response = minio_client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) assert response.status_code == status_code -def test_get_validation_by_id_success(client): +def test_get_validation_by_id_success(minio_client): crate_id = "crate-123" payload = { "minio_config": { @@ -259,14 +270,14 @@ def test_get_validation_by_id_success(client): with patch("app.ro_crates.routes.get_routes.get_ro_crate_validation_task") as mock_get: mock_get.return_value = ({"status": "valid"}, 200) - response = client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) + response = minio_client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) assert response.status_code == 200 assert response.json == {"status": "valid"} mock_get.assert_called_once_with(payload["minio_config"], "crate-123", "base_path") -def test_get_validation_by_id_missing_root_path(client): +def test_get_validation_by_id_missing_root_path(minio_client): crate_id = "crate-123" payload = { "minio_config": { @@ -281,8 +292,49 @@ def test_get_validation_by_id_missing_root_path(client): with patch("app.ro_crates.routes.get_routes.get_ro_crate_validation_task") as mock_get: mock_get.return_value = ({"status": "valid"}, 200) - response = client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) + response = minio_client.get(f"/v1/ro_crates/{crate_id}/validation", json=payload) assert response.status_code == 200 assert response.json == {"status": "valid"} mock_get.assert_called_once_with(payload["minio_config"], "crate-123", None) + + +# Test MinIO-backed endpoints are unavailable when MinIO is disabled (the default) + +def test_minio_post_route_not_registered_when_disabled(client: FlaskClient): + payload = { + "minio_config": { + "endpoint": "localhost:9000", + "accesskey": "admin", + "secret": "password123", + "ssl": False, + "bucket": "test_bucket" + } + } + response = client.post("/v1/ro_crates/crate-123/validation", json=payload) + assert response.status_code == 404 + + +def test_minio_get_route_not_registered_when_disabled(client: FlaskClient): + payload = { + "minio_config": { + "endpoint": "localhost:9000", + "accesskey": "admin", + "secret": "password123", + "ssl": False, + "bucket": "test_bucket" + } + } + response = client.get("/v1/ro_crates/crate-123/validation", json=payload) + assert response.status_code == 404 + + +def test_metadata_route_available_when_minio_disabled(client: FlaskClient): + payload = {"crate_json": '{"@context": "https://w3id.org/ro/crate/1.1/context"}'} + with patch("app.ro_crates.routes.post_routes.queue_ro_crate_metadata_validation_task") as mock_queue: + mock_queue.return_value = ({"status": "success"}, 200) + + response = client.post("/v1/ro_crates/validate_metadata", json=payload) + + assert response.status_code == 200 + mock_queue.assert_called_once() diff --git a/tests/test_integration.py b/tests/test_integration.py index 63941c4..0c3b5fe 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -21,9 +21,25 @@ def docker_compose(docker_client): PROJECT = f"test_{uuid.uuid4().hex}" + # Integration tests use the MinIO endpoints, so enable + # MinIO and start the opt-in "minio" compose profile. + compose_env = {**os.environ, "MINIO_ENABLED": "true"} + subprocess.run( - ["docker", "compose", "-f", "docker-compose-develop.yml", "-p", PROJECT, "up", "-d"], - check=True + [ + "docker", + "compose", + "-f", + "docker-compose-develop.yml", + "-p", + PROJECT, + "--profile", + "minio", + "up", + "-d", + ], + check=True, + env=compose_env, ) time.sleep(10) # Wait for services to start — adjust as needed @@ -39,7 +55,21 @@ def docker_compose(docker_client): print(logs) print("Stopping Docker Compose...") - subprocess.run(["docker", "compose", "-p", PROJECT, "down", "-v"], check=True) + subprocess.run( + [ + "docker", + "compose", + "-f", + "docker-compose-develop.yml", + "-p", + PROJECT, + "--profile", + "minio", + "down", + "-v", + ], + check=True, + ) def load_test_data_into_minio(): @@ -48,7 +78,7 @@ def load_test_data_into_minio(): endpoint="localhost:9000", access_key="minioadmin", secret_key="minioadmin", - secure=False + secure=False, ) bucket_name = "ro-crates" @@ -68,10 +98,7 @@ def load_test_data_into_minio(): def test_validate_metadata(): url = "http://localhost:5001/v1/ro_crates/validate_metadata" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # Load the JSON from file filepath = os.path.join("tests/data", "ro-crate-metadata.json") @@ -79,13 +106,11 @@ def test_validate_metadata(): crate_json_data = json.load(f) # The API expects the JSON to be passed as a string - payload = { - "crate_json": json.dumps(crate_json_data) - } + payload = {"crate_json": json.dumps(crate_json_data)} response = requests.post(url, json=payload, headers=headers) - response_result = json.loads(response.json()['result']) + response_result = json.loads(response.json()["result"]) # Print response for debugging print("Status Code:", response.status_code) @@ -93,16 +118,13 @@ def test_validate_metadata(): # Assertions — update based on expected API behavior assert response.status_code == 200 - assert response_result['passed'] is True + assert response_result["passed"] is True def test_no_rocrate_for_validation(): ro_crate = "ro_crate_10" url = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -111,7 +133,7 @@ def test_no_rocrate_for_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } @@ -125,16 +147,13 @@ def test_no_rocrate_for_validation(): # Assertions — update based on expected API behavior assert response.status_code == 400 - assert response_result['message'] == f"No RO-Crate with prefix: {ro_crate}" + assert response_result["message"] == f"No RO-Crate with prefix: {ro_crate}" def test_no_validation_result_for_missing_crate(): ro_crate = "ro_crate_10" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -143,7 +162,7 @@ def test_no_validation_result_for_missing_crate(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } @@ -157,16 +176,13 @@ def test_no_validation_result_for_missing_crate(): # Assertions assert response.status_code == 400 - assert response_result['message'] == f"No RO-Crate with prefix: {ro_crate}" + assert response_result["message"] == f"No RO-Crate with prefix: {ro_crate}" def test_get_existing_validation_result(): ro_crate = "ro_crate_3" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -175,7 +191,7 @@ def test_get_existing_validation_result(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } @@ -195,10 +211,7 @@ def test_get_existing_validation_result(): def test_rocrate_not_validated_yet(): ro_crate = "ro_crate_not_validated" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -207,7 +220,7 @@ def test_rocrate_not_validated_yet(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } @@ -221,17 +234,17 @@ def test_rocrate_not_validated_yet(): # Assertions assert response.status_code == 400 - assert response_result['message'] == f"No validation result yet for RO-Crate: {ro_crate}" + assert ( + response_result["message"] + == f"No validation result yet for RO-Crate: {ro_crate}" + ) def test_zipped_rocrate_validation(): ro_crate = "ro_crate_1" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -240,13 +253,13 @@ def test_zipped_rocrate_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } # POST action and tests response = requests.post(url_post, json=payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code) @@ -291,10 +304,7 @@ def test_directory_rocrate_validation(): ro_crate = "ro_crate_2" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -303,13 +313,13 @@ def test_directory_rocrate_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } # POST action and tests response = requests.post(url_post, json=payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code) @@ -355,10 +365,7 @@ def test_extra_profile_rocrate_validation(): profile_name = "alpha-crate-0.1" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string post_payload = { @@ -367,9 +374,9 @@ def test_extra_profile_rocrate_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", }, - "profile_name": profile_name + "profile_name": profile_name, } get_payload = { "minio_config": { @@ -377,13 +384,13 @@ def test_extra_profile_rocrate_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } # POST action and tests response = requests.post(url_post, json=post_payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code) @@ -427,10 +434,7 @@ def test_extra_profile_rocrate_validation(): def test_ignore_rocrates_not_on_basepath(): ro_crate = "ro_crate_4" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -439,13 +443,13 @@ def test_ignore_rocrates_not_on_basepath(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", } } # POST action and tests response = requests.post(url_post, json=payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code) @@ -461,10 +465,7 @@ def test_zipped_rocrate_in_subdirectory_validation(): subdir_path = "project_a" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -473,14 +474,14 @@ def test_zipped_rocrate_in_subdirectory_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", }, - "root_path" : subdir_path + "root_path": subdir_path, } # POST action and tests response = requests.post(url_post, json=payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code) @@ -526,10 +527,7 @@ def test_directory_rocrate_in_subdirectory_validation(): subdir_path = "project_a" url_post = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" url_get = f"http://localhost:5001/v1/ro_crates/{ro_crate}/validation" - headers = { - "accept": "application/json", - "Content-Type": "application/json" - } + headers = {"accept": "application/json", "Content-Type": "application/json"} # The API expects the JSON to be passed as a string payload = { @@ -538,14 +536,14 @@ def test_directory_rocrate_in_subdirectory_validation(): "accesskey": "minioadmin", "secret": "minioadmin", "ssl": False, - "bucket": "ro-crates" + "bucket": "ro-crates", }, - "root_path" : subdir_path + "root_path": subdir_path, } # POST action and tests response = requests.post(url_post, json=payload, headers=headers) - response_result = response.json()['message'] + response_result = response.json()["message"] # Print response for debugging print("Status Code:", response.status_code)