Skip to content

Commit

Permalink
Add tests, Add workflow for testing and coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Jekannadar committed Nov 9, 2023
1 parent e3705bc commit 7ef628d
Show file tree
Hide file tree
Showing 12 changed files with 532 additions and 60 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/generate-latest-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,23 @@ jobs:
backend:
- 'applications/cls-cad-backend/**'
run-tests:
name: Run Tests
needs: changes
if: ${{ needs.changes.outputs.backend == 'true' }}
uses: tudo-seal/CLS-CAD/.github/workflows/build-publish-installer.yml@main
secrets: inherit

build-msi:
name: Build Installer Package
needs: changes
needs: [changes, run-tests]
if: ${{ needs.changes.outputs.plugin == 'true' }}
uses: tudo-seal/CLS-CAD/.github/workflows/build-publish-installer.yml@main
secrets: inherit

build-container:
name: Build Docker Container
needs: changes
needs: [changes, run-tests]
if: ${{ needs.changes.outputs.backend == 'true' }}
uses: tudo-seal/CLS-CAD/.github/workflows/build-publish-container.yml@main
permissions:
Expand All @@ -48,7 +55,7 @@ jobs:
pre-release:
permissions: write-all
name: Update Latest Release
needs: [build-msi, build-container, changes]
needs: [run-tests, build-msi, build-container, changes]
if: ${{ always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.changes.outputs.plugin == 'true' }}
runs-on: "ubuntu-latest"
steps:
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Build and Publish Installer
on:
workflow_call:
workflow_dispatch:

jobs:
run-tests:
runs-on: ubuntu-latest
name: Run Tests
defaults:
run:
working-directory: applications/cls-cad-backend
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
- name: Test with pytest
run: poetry run pytest --cov=. --cov-report=xml
34 changes: 25 additions & 9 deletions applications/cls-cad-backend/cls_cad_backend/database/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
from pymongo import MongoClient, errors
from pymongo.collection import Collection

database = None
parts: Collection = None
taxonomies: Collection = None
results: Collection = None
database: MontyClient | MongoClient
parts: Collection
taxonomies: Collection
results: Collection
storage_engine = "flatfile" if any(platform.win32_ver()) else "lightning"


def init_database():
def init_database() -> None:
global database, parts, taxonomies, results
if "__compiled__" in globals():
application_path = os.path.dirname(sys.argv[0])
Expand All @@ -32,7 +32,7 @@ def init_database():
"Connect to remote DB?",
"Do you want to connect to a hosted MongoDB instance?",
)
connection_url = ""
connection_url: str | None = ""
if is_remote:
connection_url = askstring(
"Remote URL",
Expand Down Expand Up @@ -98,17 +98,33 @@ def init_database():
results = database["results"]


def upsert_part(part: dict):
def switch_to_test_database() -> None:
global database, parts, taxonomies, results
application_path = os.path.dirname(__file__)
set_storage(
os.path.join(application_path, "test_db"),
storage=storage_engine,
use_bson=True,
map_size="1073741824",
)
database = MontyClient(os.path.join(application_path, "test_db"))
database = database["cls_cad_backend"]
parts = database["parts"]
taxonomies = database["taxonomies"]
results = database["results"]


def upsert_part(part: dict) -> None:
global parts
parts.replace_one({"_id": part["_id"]}, part, upsert=True)


def upsert_taxonomy(taxonomy: dict):
def upsert_taxonomy(taxonomy: dict) -> None:
global taxonomies
taxonomies.replace_one({"_id": taxonomy["_id"]}, taxonomy, upsert=True)


def upsert_result(result: dict):
def upsert_result(result: dict) -> None:
global results
results.replace_one({"_id": result["_id"]}, result, upsert=True)

Expand Down
20 changes: 10 additions & 10 deletions applications/cls-cad-backend/cls_cad_backend/repository_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ def __call__(self, *required_parts):
},
)

def __repr__(self):
def __repr__(self) -> str:
return self.__call__()

def __str__(self):
def __str__(self) -> str:
return ""

def __hash__(self):
return hash(json.dumps(self.info))

def __init__(self, info):
def __init__(self, info) -> None:
# Create combinator type here based on some JSON payload in future
self.info = info

Expand Down Expand Up @@ -99,7 +99,7 @@ def collect_part_count(


def get_joint_origin_type(
uuid: str, part: dict, role: Role, prefix=""
uuid: str, part: dict, role: Role, prefix: str = ""
) -> list[Constructor]:
return [Constructor(f"{prefix}{tpe}") for tpe in part["jointOrigins"][uuid][role]]

Expand Down Expand Up @@ -145,7 +145,7 @@ def wrapped_counted_types(types: list[Type]) -> Type:


def types_from_uuids(
uuids: list, part: dict, prefix=""
uuids: list, part: dict, prefix: str = ""
) -> OrderedDict[str, list[Constructor]]:
return OrderedDict(
zip(
Expand All @@ -172,7 +172,7 @@ def counting_multiarrow_from_uuid(uuid_list, count_type: str):
)


def multiarrow_to_self(tpe, length):
def multiarrow_to_self(tpe, length: int):
return multiarrow_from_types([tpe] * length)


Expand All @@ -182,11 +182,11 @@ def add_part_to_repository(
part: dict,
repository: dict,
*,
part_counts: list[str, int] = None,
part_counts: list[tuple[str, int, str]] | None = None,
blacklist=None,
connect_uuid=None,
taxonomy: Subtypes = None,
):
) -> None:
"""
Adds a part to a repository to be used for synthesis. Adds necessary Constructors for the parts configurations,
unless the configuration provides a blacklisted type. The blacklist is intended to be used for synthesising
Expand Down Expand Up @@ -340,12 +340,12 @@ def add_part_to_repository(
def add_all_to_repository(
project_id: str,
*,
part_counts: list[[str, int]] = None,
part_counts: list[tuple[str, int, str]] | None = None,
blacklist=None,
connect_uuid=None,
taxonomy=None,
):
repository = {}
repository: dict = {}
for part in get_all_parts_for_project(project_id):
RepositoryBuilder.add_part_to_repository(
part,
Expand Down
23 changes: 15 additions & 8 deletions applications/cls-cad-backend/cls_cad_backend/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,17 @@
@app.post("/submit/part")
async def save_part(
payload: PartInf,
):
upsert_part(payload.dict(by_alias=True))
) -> str:
upsert_part(payload.model_dump(by_alias=True))
return "OK"


@app.post("/submit/taxonomy")
async def save_taxonomy(
payload: TaxonomyInf,
):
upsert_taxonomy(payload.dict(by_alias=True))
) -> str:
upsert_taxonomy(payload.model_dump(by_alias=True))
return "OK"


# @app.post("/request/assembly/optimization")
Expand Down Expand Up @@ -205,7 +206,13 @@ async def synthesize_assembly(
},
)
print(f"Took: {timer() - take_time}")
return str(request_id)
return {
"_id": request_id,
"forgeProjectId": payload.forgeProjectId,
"name": payload.name,
"timestamp": datetime.today().strftime("%Y-%m-%d %H:%M:%S"),
"count": len(interpreted_terms),
}


@app.get("/data/taxonomy/{project_id}", response_class=FastResponse)
Expand All @@ -219,7 +226,7 @@ async def list_result_ids():


@app.get("/results/{project_id}", response_class=FastResponse)
async def list_result_ids(project_id: str):
async def list_project_ids(project_id: str):
return [dict(x, id=x["_id"]) for x in get_all_result_ids_for_project(project_id)]


Expand All @@ -231,7 +238,7 @@ async def maximum_counts_for_id(
if request_id not in cache:
cache[request_id] = get_result_for_id(request_id)["interpretedTerms"]
results = cache[request_id]
part_counts = defaultdict(int)
part_counts: defaultdict[int] = defaultdict(int)
for result in results:
for document_id, data in result["quantities"].items():
part_counts[document_id] = (
Expand Down Expand Up @@ -271,7 +278,7 @@ async def results_for_id(


@app.get("/results/{project_id}/{request_id}/{result_id}", response_class=FastResponse)
async def results_for_id(project_id: str, request_id: str, result_id: int):
async def results_for_result_id(project_id: str, request_id: str, result_id: int):
if request_id not in cache:
cache[request_id] = get_result_for_id(request_id)["interpretedTerms"]
results = cache[request_id]
Expand Down
10 changes: 6 additions & 4 deletions applications/cls-cad-backend/cls_cad_backend/util/hrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

__all__ = ["generate_id"]

system_random = random.SystemRandom()
system_random: random.Random | random.SystemRandom = random.SystemRandom()


def generate_id(separator="-", seed: Hashable = None, word_count=6) -> str:
def generate_id(
separator: str = "-", seed: Hashable = None, word_count: int = 6
) -> str:
"""
Generate a human readable ID
:param separator: The string to use to separate words
Expand All @@ -29,11 +31,11 @@ def generate_id(separator="-", seed: Hashable = None, word_count=6) -> str:
for _ in range(3, word_count):
parts[random_obj.choice(list(parts.keys()))] += 1

parts = itertools.chain.from_iterable(
populated_parts = itertools.chain.from_iterable(
random_obj.sample(part, count) for part, count in parts.items()
)

return separator.join(parts)
return separator.join(populated_parts)


nouns = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from cls_cad_backend.util.hrid import generate_id


def postprocess(data: dict):
def postprocess(data: dict | Part):
data = data() if isinstance(data, Part) else data
name = re.sub("v[0-9]+$", "", data["name"])
data = {"connections": {"origin": data}, "name": "origin", "count": 1}
Expand Down Expand Up @@ -54,8 +54,8 @@ def resolve_multiplicity(data: dict):
return data


def compute_insertions_and_totals(data: dict):
part_counts = defaultdict(lambda: {"count": 0, "name": "", "cost": 0})
def compute_insertions_and_totals(data: dict) -> tuple:
part_counts: defaultdict = defaultdict(lambda: {"count": 0, "name": "", "cost": 0})
total_count, total_cost = 0, 0
to_traverse = deque(data["connections"])
while to_traverse:
Expand Down
22 changes: 0 additions & 22 deletions applications/cls-cad-backend/cls_cad_backend/util/set_json.py

This file was deleted.

Loading

0 comments on commit 7ef628d

Please sign in to comment.