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

Run the test suite as a GitHub Action #208

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
41 changes: 39 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ on:
workflow_dispatch:

jobs:
Test:
PreCommit:
name: pre-commit
runs-on: ubuntu-latest
steps:
- name: 💾 Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: 🪝 Cache pre-commit hooks
uses: actions/cache@v3
Expand All @@ -29,6 +29,43 @@ jobs:
- name: 🔥 Test
run: pre-commit run --show-diff-on-failure --all-files

Test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- name: 💾 Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"

- name: Install OpenSCAD
run: |
sudo apt-get update
sudo apt-get install openscad
Copy link

@pimlie pimlie Aug 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This most likely installs the v2021 version, which is quite old. It might be beneficial to either install/use a nightly (appimage) version or even better use openscad's docker container for these tests.

Copy link
Collaborator

@Ruudjhuu Ruudjhuu Aug 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree it is very old but it is the latest stable afaik.

Maybe it is possible to use a fixed "nightly" version? I hate the ci/cd breaking due to the nightly being updated and unstable. I also don't like an openscad binary in this repo.


- name: OpenSCAD Build Information
run: openscad --info
continue-on-error: true

- name: Create Image Directories
run: mkdir -p base_hole_options baseplate hole_cutouts spiral_vase_base
working-directory: ./images

- name: Run Unit Tests (Headless)
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
with:
working-directory: ./tests
run: python3 -m unittest

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: images
path: images/**/*.png

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
34 changes: 25 additions & 9 deletions tests/openscad_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
from __future__ import annotations

import json
import logging
import subprocess
from dataclasses import dataclass, is_dataclass, asdict
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import NamedTuple, Optional

logger = logging.getLogger(__name__)

class DataClassJSONEncoder(json.JSONEncoder):
'''Allow json serialization'''
def default(self, o):
Expand Down Expand Up @@ -99,19 +102,22 @@ class CameraRotations:

class OpenScadRunner:
'''Helper to run the openscad binary'''
camera_arguments: CameraArguments
scad_file_path: Path
openscad_binary_path: Path
image_folder_base: Path
parameters: Optional[dict]
'''If set, a temporary parameter file is created, and used with these variables'''

WINDOWS_DEFAULT_PATH = 'C:\\Program Files\\OpenSCAD\\openscad.exe'
LINUX_DEFAULT_PATH = Path('/bin/openscad')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be just openscad, no need to add the /bin/ prefix as Linux resolves the path by whatever you put in env.PATH

Copy link
Collaborator Author

@EmperorArthur EmperorArthur Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it in cases where you're not running through a shell?

Edit: I also don't think the automatic expansion works when doing the exists() check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a fan of the absolute path as it won't depend on the users environment. If something is by default on Linux it does not mean we need to depend on it when it is not necessary. Defaults van change, users can do weird shit. We already have a big dependency on openscad. If they change the install location, it fails everywhere and we can change it.

WINDOWS_DEFAULT_PATH = Path('C:\\Program Files\\OpenSCAD\\openscad.exe')
TOP_ANGLE_CAMERA = CameraArguments(Vec3(0,0,0),Vec3(45,0,45),150)

common_arguments = [
#'--hardwarnings', // Does not work when setting variables by using functions
'--enable=fast-csg',
'--enable=predictible-output',
#'--hardwarnings', # Does not work when setting variables by using functions
#'--enable=fast-csg', # Requires Beta version of OpenSCAD
#'--enable=predictible-output', # Requires Beta version of OpenSCAD
#'--render=true' # Fully render geometry for images, instead of using fast preview mode.
'--imgsize=1280,720',
'--view=axes',
'--projection=ortho',
Expand All @@ -121,20 +127,30 @@ class OpenScadRunner:
set_variable_argument('$fa', 8) + set_variable_argument('$fs', 0.25)

def __init__(self, file_path: Path):
self.openscad_binary_path = self.WINDOWS_DEFAULT_PATH
self.openscad_binary_path = self.find_openscad_binary()
self.scad_file_path = file_path
self.image_folder_base = Path('.')
self.camera_arguments = None
self.parameters = None

@classmethod
Ruudjhuu marked this conversation as resolved.
Show resolved Hide resolved
def find_openscad_binary(cls) -> Path:
if cls.WINDOWS_DEFAULT_PATH.exists():
return cls.WINDOWS_DEFAULT_PATH
if cls.LINUX_DEFAULT_PATH.exists():
return cls.LINUX_DEFAULT_PATH
Ruudjhuu marked this conversation as resolved.
Show resolved Hide resolved
logger.warning("Could not find OpenSCAD binary, defaulting to 'openscad'")
return Path("openscad")

def create_image(self, args: [str], image_file_name: str):
"""
Run the code, to create an image.
@Important The only verification is that no errors occured.
There is no verification if the image was created, or the image contents.
"""
assert(self.scad_file_path.exists())
assert(self.image_folder_base.exists())
assert self.openscad_binary_path.exists(), f"OpenSCAD binary not found at '{self.openscad_binary_path}'"
assert self.scad_file_path.exists(), f"OpenSCAD file not found at '{self.scad_file_path}'"
assert self.image_folder_base.exists(), f"Image folder not found at '{self.image_folder_base}'"

image_path = self.image_folder_base.joinpath(image_file_name)
command_arguments = self.common_arguments + \
Expand All @@ -150,6 +166,6 @@ def create_image(self, args: [str], image_file_name: str):
json.dump(params, file, sort_keys=True, indent=2, cls=DataClassJSONEncoder)
file.close()
command_arguments += ["-p", file.name, "-P", "python_generated"]
return subprocess.run([self.openscad_binary_path]+command_arguments, check=True)
return subprocess.run([str(self.openscad_binary_path)] + command_arguments, check=True)
else:
return subprocess.run([self.openscad_binary_path]+command_arguments, check=True)
return subprocess.run([str(self.openscad_binary_path)] + command_arguments, check=True)
Loading