Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fs 4724 fix temp path #72

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"dockerComposeFile": [
"../docker-compose.yml",
"../compose.override.yml"
],
"service": "fab",
"shutdownAction": "none",
"workspaceFolder": "/fab",
"customizations": {
"vscode": {
"extensions": [
"ms-python.debugpy",
"ms-python.vscode-pylance",
"mikoz.black-py"
]
}
},
}
16 changes: 9 additions & 7 deletions app/blueprints/fund_builder/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,14 @@ def view_form_questions(round_id, form_id):
"view_questions.html", round=round, fund=fund, question_html=html, title=form.name_in_apply_json["en"]
)

def create_export_zip(directory_to_zip, zip_file_name) -> str:
# Output zip file path (temporary)
output_zip_path = Config.TEMP_FILE_PATH / zip_file_name
srh-sloan marked this conversation as resolved.
Show resolved Hide resolved

# Create a zip archive of the directory
shutil.make_archive(base_name=output_zip_path, format="zip", root_dir=directory_to_zip)
return f"{output_zip_path}.zip"


@build_fund_bp.route("/create_export_files/<round_id>", methods=["GET"])
def create_export_files(round_id):
Expand All @@ -530,13 +538,7 @@ def create_export_files(round_id):
generate_config_for_round(round_id)
round_short_name = get_round_by_id(round_id).short_name

# Directory to zip
directory_to_zip = f"app/export_config/output/{round_short_name}/"
# Output zip file path (temporary)
output_zip_path = f"app/export_config/output/{round_short_name}.zip"

# Create a zip archive of the directory
shutil.make_archive(output_zip_path.replace(".zip", ""), "zip", directory_to_zip)
output_zip_path = create_export_zip(directory_to_zip=Config.TEMP_FILE_PATH / round_short_name, zip_file_name=round_short_name)

# Ensure the file is removed after sending it
@after_this_request
Expand Down
17 changes: 9 additions & 8 deletions app/export_config/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,30 @@
from app.blueprints.self_serve.routes import human_to_kebab_case
from app.blueprints.self_serve.routes import human_to_snake_case
from app.shared.helpers import convert_to_dict
from config import Config


def write_config(config, filename, round_short_name, config_type):
# Get the directory of the current file
current_dir = os.path.dirname(__file__)


# Construct the path to the output directory relative to this file's location
base_output_dir = os.path.join(current_dir, f"output/{round_short_name}/")
base_output_dir = Config.TEMP_FILE_PATH / round_short_name

if config_type == "form_json":
output_dir = os.path.join(base_output_dir, "form_runner/")
output_dir = base_output_dir/ "form_runner"
content_to_write = config
file_path = os.path.join(output_dir, f"{human_to_kebab_case(filename)}.json")
file_path = output_dir/ f"{human_to_kebab_case(filename)}.json"
elif config_type == "python_file":
output_dir = os.path.join(base_output_dir, "fund_store/")
output_dir = base_output_dir/ "fund_store"
config_dict = convert_to_dict(config) # Convert config to dict for non-JSON types
content_to_write = "LOADER_CONFIG="
content_to_write += str(config_dict)
file_path = os.path.join(output_dir, f"{human_to_snake_case(filename)}.py")
file_path = output_dir/ f"{human_to_snake_case(filename)}.py"
elif config_type == "html":
output_dir = os.path.join(base_output_dir, "html/")
output_dir = base_output_dir/"html"
content_to_write = config
file_path = os.path.join(output_dir, f"{filename}_all_questions_en.html")
file_path = output_dir/f"{filename}_all_questions_en.html"

# Ensure the output directory exists
os.makedirs(output_dir, exist_ok=True)
Expand Down
3 changes: 3 additions & 0 deletions config/envs/default.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
from os import environ
from os import getenv
from pathlib import Path

from fsd_utils import CommonConfig
from fsd_utils import configclass
Expand All @@ -18,3 +19,5 @@ class DefaultConfig(object):
FORM_RUNNER_URL = getenv("FORM_RUNNER_INTERNAL_HOST", "http://form-runner:3009")
FORM_RUNNER_URL_REDIRECT = getenv("FORM_RUNNER_EXTERNAL_HOST", "http://localhost:3009")
SQLALCHEMY_DATABASE_URI = environ.get("DATABASE_URL")

TEMP_FILE_PATH=Path("/tmp")
2 changes: 2 additions & 0 deletions config/envs/development.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from os import getenv
from pathlib import Path

from fsd_utils import configclass

Expand All @@ -16,3 +17,4 @@ class DevelopmentConfig(Config):
"DATABASE_URL",
"postgresql://postgres:password@fab-db:5432/fab", # pragma: allowlist secret
)
TEMP_FILE_PATH=Path("app") / "export_config" / "output"
2 changes: 2 additions & 0 deletions config/envs/unit_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from os import getenv
from pathlib import Path

from fsd_utils import configclass

Expand All @@ -18,3 +19,4 @@ class UnitTestConfig(Config):
"DATABASE_URL_UNIT_TEST",
"postgresql://postgres:[email protected]:5432/fab_unit_test", # pragma: allowlist secret
)
TEMP_FILE_PATH=Path("app") / "export_config" / "output"
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@
from tests.helpers import create_test_fund
from tests.helpers import create_test_organisation
from tests.helpers import create_test_round
from config import Config
import shutil

pytest_plugins = ["fsd_test_utils.fixtures.db_fixtures"]


@pytest.fixture(scope="session")
def temp_output_dir():
temp_dir = Config.TEMP_FILE_PATH
yield temp_dir
if temp_dir.exists():
shutil.rmtree(temp_dir)

@pytest.fixture
def test_fund(flask_test_client, _db, clear_test_data):
"""
Expand Down
145 changes: 67 additions & 78 deletions tests/test_config_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pytest

from app.blueprints.fund_builder.routes import create_export_zip
from app.export_config.generate_fund_round_config import generate_config_for_round
from app.export_config.generate_fund_round_form_jsons import (
generate_form_jsons_for_round,
Expand All @@ -14,8 +15,6 @@
from app.export_config.generate_fund_round_html import generate_all_round_html
from app.export_config.helpers import validate_json

output_base_path = Path("app") / "export_config" / "output"


def read_data_from_output_file(file):
content = file.read()
Expand All @@ -26,7 +25,7 @@ def read_data_from_output_file(file):
return data


def test_generate_config_for_round_valid_input(seed_dynamic_data, monkeypatch):
def test_generate_config_for_round_valid_input(seed_dynamic_data, monkeypatch, temp_output_dir):
# Setup: Prepare valid input parameters
fund_short_name = seed_dynamic_data["funds"][0].short_name
round_id = seed_dynamic_data["rounds"][0].round_id
Expand All @@ -44,7 +43,7 @@ def test_generate_config_for_round_valid_input(seed_dynamic_data, monkeypatch):
# Assert: Check if the directory structure and files are created as expected
expected_files = [
{
"path": output_base_path / round_short_name / "fund_store" / "round_config.py",
"path": temp_output_dir / round_short_name / "fund_store" / "round_config.py",
"expected_output": {
"sections_config": [
{
Expand Down Expand Up @@ -96,49 +95,43 @@ def test_generate_config_for_round_valid_input(seed_dynamic_data, monkeypatch):
},
},
]
try:
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."

with open(expected_file["path"], "r") as file:
data = read_data_from_output_file(file=file)

if expected_file["expected_output"].get("fund_config", None):
# remove keys that can't be accurately compared
keys_to_remove = ["base_path"]
keys_to_remove_fund_config = ["id"]
keys_to_remove_round_config = [
"id",
"fund_id",
"reminder_date",
"assessment_start",
"assessment_deadline",
"deadline",
"opens",
]
keys_to_remove_section_config = ["tree_path"]
data = {k: v for k, v in data.items() if k not in keys_to_remove}
data["fund_config"] = {
k: v for k, v in data["fund_config"].items() if k not in keys_to_remove_fund_config
}
data["round_config"] = {
k: v for k, v in data["round_config"].items() if k not in keys_to_remove_round_config
}
data["sections_config"] = [
{k: v for k, v in section.items() if k not in keys_to_remove_section_config}
for section in data["sections_config"]
]
assert expected_file["expected_output"]["fund_config"] == data["fund_config"]
assert expected_file["expected_output"]["round_config"] == data["round_config"]
assert expected_file["expected_output"]["sections_config"] == data["sections_config"]
else:
assert data == expected_file["expected_output"]
finally:
# Cleanup step to remove the directory
directory_path = output_base_path / round_short_name
if directory_path.exists():
shutil.rmtree(directory_path)
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."

with open(expected_file["path"], "r") as file:
data = read_data_from_output_file(file=file)

if expected_file["expected_output"].get("fund_config", None):
# remove keys that can't be accurately compared
keys_to_remove = ["base_path"]
keys_to_remove_fund_config = ["id"]
keys_to_remove_round_config = [
"id",
"fund_id",
"reminder_date",
"assessment_start",
"assessment_deadline",
"deadline",
"opens",
]
keys_to_remove_section_config = ["tree_path"]
data = {k: v for k, v in data.items() if k not in keys_to_remove}
data["fund_config"] = {
k: v for k, v in data["fund_config"].items() if k not in keys_to_remove_fund_config
}
data["round_config"] = {
k: v for k, v in data["round_config"].items() if k not in keys_to_remove_round_config
}
data["sections_config"] = [
{k: v for k, v in section.items() if k not in keys_to_remove_section_config}
for section in data["sections_config"]
]
assert expected_file["expected_output"]["fund_config"] == data["fund_config"]
assert expected_file["expected_output"]["round_config"] == data["round_config"]
assert expected_file["expected_output"]["sections_config"] == data["sections_config"]
else:
assert data == expected_file["expected_output"]


def test_generate_config_for_round_invalid_input(seed_dynamic_data):
Expand All @@ -149,7 +142,7 @@ def test_generate_config_for_round_invalid_input(seed_dynamic_data):
generate_config_for_round(round_id)


def test_generate_form_jsons_for_round_valid_input(seed_dynamic_data):
def test_generate_form_jsons_for_round_valid_input(seed_dynamic_data,temp_output_dir):
# Setup: Prepare valid input parameters
round_id = seed_dynamic_data["rounds"][0].round_id
round_short_name = seed_dynamic_data["rounds"][0].short_name
Expand All @@ -160,7 +153,7 @@ def test_generate_form_jsons_for_round_valid_input(seed_dynamic_data):
# Assert: Check if the directory structure and files are created as expected
expected_files = [
{
"path": output_base_path / round_short_name / "form_runner" / f"{form_publish_name}.json",
"path": temp_output_dir / round_short_name / "form_runner" / f"{form_publish_name}.json",
"expected_output": {
"startPage": "/intro-about-your-organisation",
"pages": [
Expand Down Expand Up @@ -233,22 +226,16 @@ def test_generate_form_jsons_for_round_valid_input(seed_dynamic_data):
},
}
]
try:
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."

with open(expected_file["path"], "r") as file:
data = json.load(file)
for page in data["pages"]:
for component in page["components"]:
component.pop("metadata", None)
assert data == expected_file["expected_output"]
finally:
# Cleanup step to remove the directory
directory_path = output_base_path / round_short_name
if directory_path.exists():
shutil.rmtree(directory_path)
with open(expected_file["path"], "r") as file:
data = json.load(file)
for page in data["pages"]:
for component in page["components"]:
component.pop("metadata", None)
assert data == expected_file["expected_output"]


def test_generate_form_jsons_for_round_invalid_input(seed_dynamic_data):
Expand All @@ -259,7 +246,7 @@ def test_generate_form_jsons_for_round_invalid_input(seed_dynamic_data):
generate_form_jsons_for_round(round_id)


def test_generate_fund_round_html(seed_dynamic_data):
def test_generate_fund_round_html(seed_dynamic_data, temp_output_dir):

# Setup: Prepare valid input parameters
round_id = seed_dynamic_data["rounds"][0].round_id
Expand All @@ -270,7 +257,7 @@ def test_generate_fund_round_html(seed_dynamic_data):
# Assert: Check if the directory structure and files are created as expected
expected_files = [
{
"path": output_base_path
"path": temp_output_dir
/ round_short_name
/ "html"
/ f"{fund_short_name.casefold()}_{round_short_name.casefold()}_all_questions_en.html",
Expand All @@ -279,19 +266,13 @@ def test_generate_fund_round_html(seed_dynamic_data):
+ frontend_html_suffix,
}
]
try:
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."
for expected_file in expected_files:
path = expected_file["path"]
assert path.exists(), f"Expected file {path} does not exist."

with open(expected_file["path"], "r") as file:
data = file.read()
assert data == expected_file["expected_output"]
finally:
# Cleanup step to remove the directory
directory_path = output_base_path / round_short_name
if directory_path.exists():
shutil.rmtree(directory_path)
with open(expected_file["path"], "r") as file:
data = file.read()
assert data == expected_file["expected_output"]


def test_generate_fund_round_html_invalid_input(seed_dynamic_data):
Expand Down Expand Up @@ -330,3 +311,11 @@ def test_valid_data_validate_json():
def test_invalid_data_validate_json(data):
result = validate_json(data, test_json_schema)
assert not result, "The data should be invalid according to the schema"


def test_create_export_zip(temp_output_dir):
test_data_path = Path("tests") / "test_data"
output = create_export_zip(directory_to_zip=test_data_path, zip_file_name="test_zip")
assert output
output_path = Path(output)
assert output_path.exists()
Loading