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

Gets Baseline Test Working With Current State of Codebase #91

Merged
merged 6 commits into from
Aug 22, 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
37 changes: 37 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Test

on: [push]

jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: "Check out the repo"
uses: actions/checkout@v3
with:
submodules: true

- name: Fix checkout ownership
run: |
# HACK Workaround for bug:
# https://github.com/actions/runner/issues/2033
mkdir -p /home/runner/work/_temp/_github_home
printf "[safe]\n\tdirectory = /github/workspace" \
> /home/runner/work/_temp/_github_home/.gitconfig

- uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Install system dependencies
run: |
sudo apt update && sudo apt install -y libgl1-mesa-glx

- name: Install nimble packages and dev tools
run: |
pip install .[dev]

- name: Run tests
run: |
pytest
14 changes: 11 additions & 3 deletions nimble_build_system/cad/device_placeholder.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""
This module provides a function to generate a placeholder object for a device. Given the dimensions
of a device, this function will create a placeholder object that can be used to represent the
device in an assembly. The function will also try to imprint the name of the device on the resulting
model.
"""
import cadquery as cq

def generate_placeholder(device_name, length, depth, height):
"""
Generates a generalized placeholder object for a device.
"""
print(length, depth, height)

# Save the smallest dimension for things like filleting and text
smallest_dim = min(length, depth, height)

Expand All @@ -15,6 +21,8 @@ def generate_placeholder(device_name, length, depth, height):
placeholder = placeholder.edges().fillet(smallest_dim * 0.3)

# Add the text of what the device is to the top
placeholder = placeholder.faces(">Z").workplane(centerOption="CenterOfBoundBox").text(device_name, fontsize=6, distance=-smallest_dim * 0.1)
placeholder = (placeholder.faces(">Z")
.workplane(centerOption="CenterOfBoundBox")
.text(device_name, fontsize=6, distance=-smallest_dim * 0.1))

return placeholder
return placeholder
68 changes: 56 additions & 12 deletions nimble_build_system/cad/shelf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
This module generates shelves for the nimble rack system. The shelves are matched with devices, and
the shelves are generated based on the device type. The shelves are generated using the
`ShelfBuilder` class from the `nimble_build_system.cad.shelf_builder` module.

Rendering and documentation generation is also supported for the shelves.
"""
import os
import posixpath
import warnings
Expand All @@ -21,7 +28,21 @@ def create_shelf_for(device_id: str,
color: str='dodgerblue1',
rack_params: RackParameters|None = None,
dummy_device_data:dict|None=None):

"""
Create a shelf for a device based on the device id. The shelf is generated based on the device
type and dimensions.

Parameters:
device_id (str): The id of the device that the shelf is for.
assembly_key (str): The key for the assembled shelf.
position (tuple[float, float, float]): The position of the shelf in the rack.
color (str): The color of the shelf, useful for rendering.
rack_params (RackParameters): The parameters for the rack that this shelf will be in.
dummy_device_data (dict): Data used if the device is a dummy device.

Returns:
Shelf: A shelf object for the device, instantiating the correct Class.
"""

if not rack_params:
rack_params = RackParameters()
Expand Down Expand Up @@ -99,6 +120,9 @@ def __init__(self,

@property
def height_in_u(self):
"""
Return the height of the shelf in standard rack units/increments.
"""
return self._device.height_in_u

def _generate_assembled_shelf(self,
Expand Down Expand Up @@ -141,7 +165,7 @@ def name(self):
Return the name of the shelf. This is the same name as the
component.
"""
return self.assembled_shelf.name
return self._assembled_shelf.name


@property
Expand Down Expand Up @@ -178,6 +202,11 @@ def generate_device_model(self):
self._device.width,
self._device.depth,
self._device.height)

# Once the device model has been generated once, save it so that it can be reused in
# assemblies and such
self._device_model = device

return device


Expand Down Expand Up @@ -206,15 +235,13 @@ def generate_shelf_stl(self, shelf_model=None):

def generate_assembly_model(self,
shelf_model=None,
device_model=None,
with_fasteners=True,
exploded=False,
annotated=False):
device_model=None):
"""
Generates an CAD model of the shelf assembly showing assembly step between
a device and a shelf. This can be optionally be exploded.
It is generated solely based on the device ID.
"""
#pylint: disable=unused-argument
return NotImplemented


Expand All @@ -225,7 +252,7 @@ def get_render(self, assy, camera_pos, image_format="png"):

# TODO - Use the PNG functionality in CadQuery to generate a PNG render
# TODO - Maybe also need other formats such as glTF

#pylint: disable=unused-argument
return NotImplemented


Expand Down Expand Up @@ -258,6 +285,9 @@ def generate_docs(self):
return md

class StuffShelf(Shelf):
"""
A generic shelf for devices that do not have a specific shelf type.
"""
##TODO: Perhaps make a "dummy" device for "stuff"?
def __init__(self,
device: Device,
Expand All @@ -282,6 +312,9 @@ def generate_shelf_model(self) -> cadscript.Body:
return builder.get_body()

class NUCShelf(Shelf):
"""
Shelf class for an Intel NUC device.
"""
def generate_shelf_model(self) -> cadscript.Body:
"""
A shelf for an Intel NUC
Expand All @@ -296,6 +329,9 @@ def generate_shelf_model(self) -> cadscript.Body:
return builder.get_body()

class USWFlexShelf(Shelf):
"""
Shelf class for a Ubiquiti USW-Flex device.
"""
def generate_shelf_model(self) -> cadscript.Body:
"""
A shelf for a Ubiquiti USW-Flex
Expand All @@ -315,6 +351,9 @@ def generate_shelf_model(self) -> cadscript.Body:
return builder.get_body()

class USWFlexMiniShelf(Shelf):
"""
Shelf class for a Ubiquiti Flex Mini device.
"""
def generate_shelf_model(self) -> cadscript.Body:
"""
A shelf for a for Ubiquiti Flex Mini
Expand Down Expand Up @@ -342,7 +381,9 @@ def generate_shelf_model(self) -> cadscript.Body:
return builder.get_body()

class AnkerShelf(Shelf):

"""
Shelf class for an Anker PowerPort 5, Anker 360 Charger 60W (a2123), etc
"""
def __init__(self,
device: Device,
assembly_key: str,
Expand Down Expand Up @@ -374,6 +415,9 @@ def generate_shelf_model(self) -> cadscript.Body:
)

class HDD35Shelf(Shelf):
"""
Shelf class for a 3.5" hard drive device.
"""
def generate_shelf_model(self) -> cadscript.Body:
"""
A shelf for an 3.5" HDD
Expand Down Expand Up @@ -410,6 +454,9 @@ def generate_shelf_model(self) -> cadscript.Body:
return builder.get_body()

class DualSSDShelf(Shelf):
"""
Shelf class for two 2.5" solid state drive devices.
"""
def generate_shelf_model(self) -> cadscript.Body:
"""
A shelf for two 2.5" SSDs
Expand Down Expand Up @@ -494,10 +541,7 @@ def generate_shelf_model(self):

def generate_assembly_model(self,
shelf_model=None,
device_model=None,
with_fasteners=True,
exploded=False,
annotated=False):
device_model=None):
"""
Generates an assembly showing the assembly step between a device
and a shelf, optionally with fasteners.
Expand Down
3 changes: 1 addition & 2 deletions py.pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,7 @@ timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.

# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
XXX

# Regular expression of note tags to take in consideration.
notes-rgx=
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
extras_require={
'dev': [
'pylint',
'colorama'
'colorama',
'pytest'
]
},
entry_points={'console_scripts': ['gen_nimble_conf_options = nimble_build_system.utils.gen_nimble_conf_options:main']}
Expand Down
119 changes: 112 additions & 7 deletions tests/test_cad.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,129 @@
from nimble_build_system.cad.shelf import Shelf, RaspberryPiShelf
from nimble_build_system.orchestration.configuration import NimbleConfiguration

def test_generating_raspberry_pi_shelf():
def test_shelf_generation():
"""
Tests whether or not the functionality for a Raspberry Pi shelf is working as expected.
This tests all of the CAD related functionality related to the Raspberry Pi shelf.
"""

# This is a list of the shelf models that have potential red flags.
# In the cases where the depth seems small compared to the device, it
# seems to be related to the generic/zip-tie shelf. This needs more
# investigation.
broken_shelves = []
broken_shelves.append("mANTBox_2_12s") # Shelf depth seems very small compared to the device
broken_shelves.append("mANTBox_ax_15s") # Missing height in units
broken_shelves.append("NetBox_5_ax") # Missing height in units
broken_shelves.append("OmniTIK_5") # Shelf depth seems very small compared to the device
broken_shelves.append("OmniTIK_5_ac") # Shelf depth seems very small compared to the device
broken_shelves.append("OmniTIK_5_PoE_ac") # Shelf depth seems very small compared to the device
broken_shelves.append("AC_Lite") # Missing device dimensions
broken_shelves.append("AC_Mesh_Pro") # Shelf depth seems very small compared to the device
broken_shelves.append("AC_Pro") # Missing device dimensions
broken_shelves.append("U6_Lite") # Missing device dimensions
broken_shelves.append("U6_Long_Range") # Missing device dimensions
broken_shelves.append("U6_Mesh") # Missing device dimensions
broken_shelves.append("U6_Pro") # Missing device dimensions
broken_shelves.append("U6+") # Missing device dimensions
broken_shelves.append("UniFi_AC_Mesh") # Shelf depth seems very small compared to the device
broken_shelves.append("hAP_ac") # Shelf depth seems smaller than the device
broken_shelves.append("hAP_lite") # Missing device dimensions
broken_shelves.append("RB951Ui-2HnD") # Shelf depth seems smaller than the device
broken_shelves.append("Hex_PoE") # Shelf depth seems smaller than the device
broken_shelves.append("L009UiGS-RM") # Missing height in units
broken_shelves.append("RB4011iGS+RM") # Shelf depth seems smaller than the device
broken_shelves.append("RB5009UG+S+IN") # Missing height in units
broken_shelves.append("RB5009UPr+S+IN") # Missing height in units
broken_shelves.append("EQ12_N100") # Missing height in units
broken_shelves.append("SEi10_1035G7") # Shelf depth seems smaller than the device
broken_shelves.append("SEi12_i7-12650H") # Missing height in units
broken_shelves.append("SER5_PRO_5700U") # Missing height in units
broken_shelves.append("Gigabyte_Brix_GB-BEi5-1240_(rev._1.0)") # Shelf depth seems smaller than the device
broken_shelves.append("Gigabyte_Brix_GB-BRi5-10210(E)") # Shelf depth seems smaller than the device
broken_shelves.append("Gigabyte_Brix_GB-BRi5H-10210(E)") # Shelf depth seems smaller than the device
broken_shelves.append("Gigabyte_Brix_GB-BRi5HS-1335") # Shelf depth seems smaller than the device
broken_shelves.append("Gigabyte_Brix_GB-BSi5-1135G7_(rev._1.0)") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCenter_M700") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCentre_M70q") # Missing height in units
broken_shelves.append("ThinkCentre_M70s") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCentre_M75s") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCentre_M80s") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCentre_M90q") # Shelf depth seems smaller than the device
broken_shelves.append("ThinkCentre_M90s") # Shelf depth seems smaller than the device
broken_shelves.append("CRS106-1C-5S") # Shelf depth seems smaller than the device
broken_shelves.append("CRS112-8G-4S-IN") # Shelf depth seems smaller than the device
broken_shelves.append("CRS112-8P-4S-IN") # Shelf depth seems smaller than the device
broken_shelves.append("CRS305-1G-4S+IN") # Shelf depth is the same as the device depth, which seems too tight
broken_shelves.append("CRS310-1G-5S-4S+IN") # Shelf depth seems smaller than the device
broken_shelves.append("CRS310-8G+2S+IN") # Shelf depth seems smaller than the device
broken_shelves.append("CSS610-8G-2S+IN") # Shelf depth seems smaller than the device
broken_shelves.append("RB260GS") # Shelf depth seems smaller than the device
broken_shelves.append("RB260GSP") # Shelf depth seems smaller than the device
broken_shelves.append("Enterprise_8_PoE") # Shelf depth seems smaller than the device
broken_shelves.append("Lite_16_PoE") # Shelf depth seems smaller than the device
broken_shelves.append("Pro_8_PoE") # Shelf depth seems smaller than the device

# The configuration of hardware/shelves that we want to test against
test_config = ["Raspberry_Pi_4B"]
test_config = ["Raspberry_Pi_4B",
"Raspberry_Pi_5",
"hAP",
"hAP_ac_lite",
"UniFi_Express",
"Beryl_AX",
"Beryl",
"Slate_Plus",
"Hex",
"hEX_PoE_lite",
"hEX_S",
"LtAP_mini",
"LtAP_mini_LTE_kit",
"Gateway_Lite",
"MINI_S12_Pro",
"SEi12_i5-12450H",
"SER5_MAX_5800H",
"NUC10FNK_",
"NUC10i5FNH",
"NUC8I5BEH",
"NUC8i5BEK",
"UniFi_8_PoE_(Gen1)",
"Unifi_Flex_Mini",
"Unifi_Switch_Flex"
]

# Load the needed information to generate a Shelf object
config = NimbleConfiguration(test_config)

# Make sure that each shelf can generate the proper files
for i, shelf in enumerate(config.shelves):
# Find the matching device for the shelf
device = config.devices[i]
device = shelf.device

# Instantiate the shelf object and check to make sure it has a valid name
shelf = RaspberryPiShelf(device,
assembly_key=f"shelf_{i}",
position=(1.0, 0.0, 12.0),
color='deepskyblue1',
rack_params=config._rack_params)
assert shelf.name.lower().startswith(test_config[i].lower().split("_")[0])

# Check that the device model was generated with the proper dimensions per the configuration
device_model = shelf.generate_device_model()
x_size = device_model.val().BoundingBox().xmax - device_model.val().BoundingBox().xmin
y_size = device_model.val().BoundingBox().ymax - device_model.val().BoundingBox().ymin
z_size = device_model.val().BoundingBox().zmax - device_model.val().BoundingBox().zmin
assert x_size == pytest.approx(config.devices[i].width, 0.001)
assert y_size == pytest.approx(config.devices[i].depth, 0.001)
assert z_size == pytest.approx(config.devices[i].height, 0.001)

# Generate the right type of shelf based on the name
if "raspberry" in shelf.name.lower():
shelf = RaspberryPiShelf(shelf, device)
assert shelf.name == "Raspberry Pi 4B shelf"
# Make sure the shelf model is valid and has generally the correct dimensions
shelf_model = shelf.generate_shelf_model().cq()
x_size = shelf_model.val().BoundingBox().xmax - shelf_model.val().BoundingBox().xmin
y_size = shelf_model.val().BoundingBox().ymax - shelf_model.val().BoundingBox().ymin
z_size = shelf_model.val().BoundingBox().zmax - shelf_model.val().BoundingBox().zmin
print(x_size, y_size, z_size)
print(config.devices[i].width, config.devices[i].depth, config.devices[i].height)
assert shelf_model.val().isValid()
assert x_size > config.devices[i].width
assert y_size > config.devices[i].depth
assert z_size > config.devices[i].height
Loading