Skip to content

Commit 4618141

Browse files
[Nexthop] Add CMake test infrastructure for FBOSS Image Builder
Integrate distro_cli Python unit tests into the FBOSS CMake build system to enable automated testing in CI/CD pipelines. - Add FbossImageDistroCliTests.cmake to discover and register Python unit tests - Configure test discovery for distro_cli modules (builder, cmds, lib, tools) - Update root CMakeLists.txt to include distro_cli test suite - Enable distro_cli tests in GitHub Actions workflow - Update distro_cli README with build and test instructions The CMake configuration automatically discovers all *_test.py files and registers them as CTest targets, allowing tests to run via 'ctest' or 'make test'.
1 parent 7a99879 commit 4618141

File tree

8 files changed

+193
-4
lines changed

8 files changed

+193
-4
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,3 +1154,6 @@ if (GITHUB_ACTIONS_BUILD)
11541154
fsdb_all_services
11551155
)
11561156
endif()
1157+
1158+
# FBOSS Image Builder distro_cli tests
1159+
include(cmake/FbossImageDistroCliTests.cmake)

build/fbcode_builder/CMake/FBPythonBinary.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ function(add_fb_python_executable TARGET)
158158
# CMake doesn't really seem to like having a directory specified as an
159159
# output; specify the __main__.py file as the output instead.
160160
set(zipapp_output_file "${zipapp_output}/__main__.py")
161+
# Update output_file to match zipapp_output_file for dir type
162+
set(output_file "${zipapp_output_file}")
161163
list(APPEND
162164
extra_cmd_params
163165
COMMAND "${CMAKE_COMMAND}" -E remove_directory "${zipapp_output}"
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# CMake to build and test fboss-image/distro_cli
2+
3+
# In general, libraries and binaries in fboss/foo/bar are built by
4+
# cmake/FooBar.cmake
5+
6+
# distro_cli requires Python 3.10+ with widespread use of union type syntax
7+
# Save and temporarily override Python3_EXECUTABLE
8+
if(DEFINED Python3_EXECUTABLE)
9+
set(SAVED_Python3_EXECUTABLE "${Python3_EXECUTABLE}")
10+
endif()
11+
12+
# Find the highest available Python version >= 3.10
13+
find_package(Python3 3.10 COMPONENTS Interpreter REQUIRED)
14+
message(STATUS "Using Python ${Python3_VERSION} (${Python3_EXECUTABLE}) for distro_cli tests")
15+
16+
include(FBPythonBinary)
17+
18+
file(GLOB DISTRO_CLI_TEST_SOURCES
19+
"fboss-image/distro_cli/tests/*_test.py"
20+
)
21+
22+
# Exclude image_builder_test.py - requires source tree access for templates
23+
# which isn't available in CMake build directory
24+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "image_builder_test\\.py$")
25+
26+
# Exclude: manual e2e tests
27+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "kernel_build_test\\.py$")
28+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "sai_build_test\\.py$")
29+
30+
# Exclude: Docker not available
31+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "build_entrypoint_test\\.py$")
32+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "build_test\\.py$")
33+
list(FILTER DISTRO_CLI_TEST_SOURCES EXCLUDE REGEX "docker_test\\.py$")
34+
35+
file(GLOB DISTRO_CLI_TEST_HELPERS
36+
"fboss-image/distro_cli/tests/test_helpers.py"
37+
)
38+
39+
file(GLOB_RECURSE DISTRO_CLI_LIB_SOURCES
40+
"fboss-image/distro_cli/builder/*.py"
41+
"fboss-image/distro_cli/cmds/*.py"
42+
"fboss-image/distro_cli/lib/*.py"
43+
"fboss-image/distro_cli/tools/*.py"
44+
)
45+
46+
# Create Python unittest executable with test data files
47+
# Use TYPE "dir" to create a directory-based executable instead of zipapp.
48+
# This allows tests to access data files via Path(__file__).parent, which
49+
# doesn't work inside zip archives.
50+
#
51+
# Note: Only include .py files in SOURCES. Non-Python data files would be
52+
# treated as Python modules during test discovery, causing import errors.
53+
# Data files are copied via add_custom_command below after the build
54+
# generates the directory structure.
55+
add_fb_python_unittest(
56+
distro_cli_tests
57+
BASE_DIR "fboss-image"
58+
TYPE "dir"
59+
SOURCES
60+
${DISTRO_CLI_TEST_SOURCES}
61+
${DISTRO_CLI_TEST_HELPERS}
62+
${DISTRO_CLI_LIB_SOURCES}
63+
ENV
64+
"PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/fboss-image"
65+
)
66+
67+
# Copy test data files AFTER the build generates the directory structure
68+
# Tests access these via Path(__file__).parent / "data" / "filename"
69+
# With TYPE "dir", the executable is created at distro_cli_tests/ so data
70+
# files need to be inside that directory structure.
71+
#
72+
# We use add_custom_command to copy AFTER the .GEN_PY_EXE target runs,
73+
# because that target creates/recreates the distro_cli_tests/ directory.
74+
set(DATA_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/distro_cli_tests/distro_cli/tests")
75+
set(DATA_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fboss-image/distro_cli/tests/data")
76+
77+
add_custom_command(
78+
TARGET distro_cli_tests.GEN_PY_EXE
79+
POST_BUILD
80+
COMMAND ${CMAKE_COMMAND} -E copy_directory
81+
"${DATA_SOURCE_DIR}"
82+
"${DATA_DEST_DIR}/data"
83+
COMMENT "Copying test data files for distro_cli_tests"
84+
)
85+
86+
install_fb_python_executable(distro_cli_tests)
87+
88+
# Restore the original Python3_EXECUTABLE if it was set
89+
if(DEFINED SAVED_Python3_EXECUTABLE)
90+
set(Python3_EXECUTABLE "${SAVED_Python3_EXECUTABLE}")
91+
unset(SAVED_Python3_EXECUTABLE)
92+
endif()

fboss-image/distro_cli/README.md

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,56 @@ Components are built in the following order:
110110

111111
### Running Tests
112112

113+
#### With Bazel (Recommended)
114+
113115
```bash
114116
# Run all tests
115-
cd fboss-image/distro_cli
116-
python3 -m unittest discover -s tests -p '*_test.py'
117+
bazel test //fboss/fboss-image/distro_cli:all
117118

118119
# Run specific test
119-
python3 -m unittest tests.cli_test
120+
bazel test //fboss/fboss-image/distro_cli:cli_test
121+
122+
# Run with detailed output
123+
bazel test //fboss/fboss-image/distro_cli:all --test_output=all
124+
```
125+
126+
#### With pytest
127+
128+
```bash
129+
# Run all tests (from fboss-image directory)
130+
cd fboss-image
131+
PYTHONPATH=. python3 -m pytest distro_cli/tests/ -v
132+
133+
# Run specific test file
134+
PYTHONPATH=. python3 -m pytest distro_cli/tests/cli_test.py -v
135+
136+
# Run specific test class or method
137+
PYTHONPATH=. python3 -m pytest distro_cli/tests/cli_test.py::CLITest::test_cli_creation -v
138+
```
139+
140+
#### With unittest
141+
142+
```bash
143+
# Run all tests (from fboss-image directory)
144+
cd fboss-image
145+
PYTHONPATH=. python3 -m unittest discover -s distro_cli/tests -p '*_test.py'
146+
147+
# Run specific test module
148+
PYTHONPATH=. python3 -m unittest distro_cli.tests.cli_test
149+
150+
# Run specific test class
151+
PYTHONPATH=. python3 -m unittest distro_cli.tests.cli_test.CLITest
120152
```
121153

122154
### Linting
123155

124156
```bash
157+
# With ruff (from distro_cli directory)
125158
cd fboss-image/distro_cli
126159
python3 -m ruff check .
160+
161+
# With bazel (from repository root)
162+
bazel test //private-fboss/fboss-image/distro_cli:lint_check
127163
```
128164

129165
### Project Structure
@@ -152,7 +188,7 @@ fboss-image/distro_cli/
152188
The CLI uses a custom OOP wrapper around argparse (stdlib only, no external dependencies):
153189

154190
```python
155-
from lib.cli import CLI
191+
from distro_cli.lib.cli import CLI
156192

157193
# Create CLI
158194
cli = CLI(description='My CLI')
@@ -171,3 +207,27 @@ device.add_command('ssh', ssh_func, help_text='SSH to device')
171207
# Run
172208
cli.run(setup_logging_func=setup_logging)
173209
```
210+
211+
## Running Tests
212+
213+
### Quick Tests (Default)
214+
Run all fast unit tests (excludes long-running E2E tests):
215+
```bash
216+
python3 -m pytest distro_cli/tests/ -v
217+
# or explicitly exclude e2e tests:
218+
python3 -m pytest distro_cli/tests/ -m "not e2e" -v
219+
```
220+
221+
### E2E Tests Only
222+
Run only the end-to-end tests (kernel build, SAI build):
223+
```bash
224+
python3 -m pytest distro_cli/tests/ -m e2e -v -s
225+
```
226+
227+
### All Tests (Including E2E)
228+
Run everything:
229+
```bash
230+
python3 -m pytest distro_cli/tests/ -v -s
231+
```
232+
233+
**Note:** E2E tests can take 10-60 minutes and require actual source files (kernel sources, SAI SDK, etc.).

fboss-image/distro_cli/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2004-present, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
"""FBOSS Distribution CLI package."""
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2004-present, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
"""FBOSS Distribution CLI commands package."""
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2004-present, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
"""FBOSS Distribution CLI library package."""
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2004-present, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
"""FBOSS Distribution CLI tests package."""

0 commit comments

Comments
 (0)