Files
TheRock/rocm-libraries/shared/ctest/README.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

685 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ROCm Libraries CTest Integration Architecture
This directory contains the shared CTest integration files for organizing and executing tests across ROCm library projects using YAML-based test categorization.
## Directory Structure
```
shared/ctest/
├── README.md # This file - architecture documentation
├── TestCategories.cmake # CMake module for test category integration
└── parse_test_categories.py # Python parser for YAML to CMake conversion
```
**Files:**
- [TestCategories.cmake](./TestCategories.cmake) - CMake module with `apply_test_category_labels()` function
- [parse_test_categories.py](./parse_test_categories.py) - Python parser for YAML to CMake conversion
## Architecture Overview
The CTest integration provides a flexible, maintainable system for organizing tests into categories with support for platform-specific and GPU-specific test exclusions.
### **Core Components**
#### 1. **test_categories.yaml** (Project-specific)
Located in each project's test directory (e.g., `projects/miopen/test/gtest/test_categories.yaml`).
Defines test organization:
- Test categories with patterns and labels
- Test exclusions
- Timeout settings per category
#### 2. **parse_test_categories.py** (Shared)
Python script that:
- Parses YAML configuration files
- Detects runtime environment (OS, GPU architecture)
- Builds gtest filter strings with positive and negative patterns (default), or emits commands to run an **rtest** driver when **`--use-rtest-driver`** is passed
- Generates CMake test registration code with proper exclusion syntax
#### 3. **TestCategories.cmake** (Shared)
CMake module providing:
- `apply_test_category_labels()` function for projects
- Python interpreter detection
- Error handling and fallback mechanisms
## Execution Flow
```mermaid
flowchart TD
A[Project CMakeLists.txt] -->|include| B[TestCategories.cmake]
A -->|call| C[apply_test_category_labels<br/>target, yaml, workdir]
B -->|find_package| D[Python3]
C -->|execute_process| E[parse_test_categories.py]
E -->|read| F[test_categories.yaml]
E -->|detect| G[OS & GPU Architecture]
E -->|build| H[Filter Strings<br/>positive-negative]
E -->|generate| I[CMake Code]
I -->|write to| J[Generated CMake<br/>build/test_categories.cmake]
J -->|add_test| K[Test Registration]
J -->|set_tests_properties| L[Labels & Timeouts]
K --> M[CTest Execution]
L --> M
M -->|ctest -L category -LE ex_gpu| N[Run without gpu exclusions]
M -->|ctest -L category -L ex_gpu_gfx1150| O[Run on Specific GPU with exclusions]
style A fill:#e1f5ff,color:#000
style E fill:#fff4e1,color:#000
style J fill:#e8f5e9,color:#000
style M fill:#f3e5f5,color:#000
```
## YAML Configuration Format
### **Basic Structure**
```yaml
test_categories:
category_name:
description: "Human-readable description"
test_patterns:
- "*pattern1*"
- "*pattern2*"
exclude:
- "*pattern_to_exclude*"
exclude_windows:
- "*linux_only_tests*"
exclude_linux:
- "*windows_only_tests*"
labels:
- "quick"
- "label2"
exclude_gpu:
# Common pattern definitions using YAML anchors for reusability
common_patterns: &common_patterns
- "*pattern1*"
- "*pattern2*"
- "*pattern3*"
exclude_gpu_gfx11X:
test_patterns: *common_patterns # Reuse common patterns
labels:
- "quick"
- "standard"
- "comprehensive"
- "full"
- "ex_gpu_gfx11X"
exclude_gpu_gfx1150:
test_patterns:
- "*specific_pattern*"
labels:
- "quick"
- "ex_gpu_gfx1150"
execution_settings:
default_timeout: 300
timeout_multiplier: 1 # Multiplier for all timeouts (1, 1.5, 1.75, 2, etc.)
# environment: { VAR1: "val1", VAR2: "val2" } # optional; applied to all category tests
category_timeouts:
quick: 300
standard: 1800
```
**Timeout Configuration:**
- `default_timeout`: Base timeout for categories not explicitly listed (in seconds)
- `timeout_multiplier`: Global multiplier applied to all timeouts (default: 1)
- Use values like `1.5`, `1.75`, `2` to extend timeouts where needed
- `category_timeouts`: Timeouts for specific categories (before multiplier is applied)
**Environment (optional):** Under `execution_settings`, an `environment` map sets env vars for all category tests (e.g. `OPENBLAS_NUM_THREADS`, `OMP_NUM_THREADS`). Keys and values are strings; they are passed to CTest as `ENVIRONMENT "VAR1=val1;VAR2=val2"`.
**Test YAML (optional, per-category):** A category may set `test_yaml` to a basename (e.g. `rocblas_smoke.yaml`). For direct gtest invocations, the parser injects `--yaml <file>` **before** `--gtest_filter=...`. A category may define `test_yaml` only, `test_patterns` only, or both. When `--use-rtest-driver` is enabled, the project's rtest XML must still define matching `--yaml` / filter behavior for `ctest_<category>` suites.
**Extra arguments (optional, per-category):** A category may set `extra_args` to a list (or single string) of additional command-line arguments that the parser appends to the test command after `--gtest_filter=...` (or after `--yaml` when no filter is used). Useful for projects whose test binary accepts runtime flags beyond gtest filtering (for example, a flag to select a reduced subset of tests, or to scale a sampling/iteration parameter). Each entry is shell-quoted with `shlex.quote`, so values with spaces or shell metacharacters are preserved as a single argument by CTest.
```yaml
test_categories:
quick:
test_yaml: rocblas_smoke.yaml
test_patterns:
- "*quick*"
exclude:
- "*strided*"
extra_args: # appended after --gtest_filter (or after --yaml)
- "--quick-subset"
labels:
- "quick"
standard:
test_patterns:
- "*"
exclude:
- "*excluded_pattern*"
extra_args: # multi-token args are passed verbatim
- "--sample-probability"
- "0.02"
labels:
- "standard"
```
`extra_args` flow through identically to category tests and to GPU-exclusion test variants, in both the build-tree CTest definitions and the install-tree `CTestTestfile.cmake`.
### **Enhanced Structure (Optional Fields)**
All fields below are **optional** and can be added incrementally. Teams can use them for richer test documentation and enable future capabilities like AI-assisted test selection:
```yaml
test_categories:
category_name:
# Required fields (same as base)
description: "Human-readable description"
test_patterns:
- "*pattern1*"
- "*pattern2*"
labels:
- "label1"
- "label2"
# Optional enhancement fields - add only if useful for your project
notes: |
Human-readable context about when to run these tests.
Can include historical context, gotchas, or guidance for developers and AI tools.
source_coverage:
- "library/src/file.cpp"
- "library/src/module.cpp:function_name"
api_coverage:
- "apiFunction1"
- "apiFunction2"
feature_tags:
- "performance-critical"
- "numerical-stability"
dependencies:
- "other_category" # Metadata for related categories (not enforced by parser; for documentation/tooling)
# Standard fields (from base)
exclude:
- "*always_exclude*"
exclude_windows:
- "*linux_only*"
exclude_linux:
- "*windows_only*"
# Optional: Top-level context for AI/LLM tools
llm_context:
code_to_test_mapping_guidelines: |
Guidance for AI tools on how to map code changes to test categories.
Projects can use this for AI-assisted test selection.
execution_settings:
default_timeout: 300
category_timeouts:
category_name: 600
```
**Optional Field Descriptions:**
| Field | Purpose | Example Use |
|-------|---------|-------------|
| `notes` | Free-form text for context and documentation | "Run when epilogue changes. See bug #8765 for history" |
| `source_coverage` | Source files/functions tested by this category | `["library/src/gemm.cpp:matmul_kernel"]` |
| `api_coverage` | API functions tested by this category | `["hipblasLtMatmul", "hipblasLtMatmulAlgo"]` |
| `feature_tags` | Semantic tags for classification and filtering | `["performance-critical", "mixed-precision"]` |
| `dependencies` | Related test categories (documentation only) | `["auxiliary"]` - advisory metadata for downstream tooling |
| `llm_context` | Top-level guidance for AI-assisted workflows | Instructions for AI tools on test selection logic |
**Key Points:**
- All enhancement fields are **optional** - teams can ignore them entirely ✅
- Projects can adopt incrementally: start with just `notes`, add more later ✅
- **Parser does NOT process these fields** - they are for documentation and downstream tooling only ✅
- Parser gracefully ignores unknown fields - no code changes needed ✅
- Enables richer test documentation and future AI-assisted workflows ✅
### **GPU Exclusion with Hierarchical Matching**
GPU-specific exclusions use hierarchical pattern matching with wildcard 'X':
**Structure:**
- Each `exclude_gpu_gfx*` entry defines patterns to exclude for specific GPU architectures
- Patterns can be shared using YAML anchors (`&name`) and aliases (`*name`)
- Labels include both category labels and `ex_gpu_*` labels for filtering
**Hierarchical Matching:**
- Wildcard 'X' matches any remaining characters (e.g., `gfx11X` matches `gfx1100`, `gfx1150`, `gfx1151`)
- More specific GPUs inherit exclusions from general patterns:
- `gfx1150` matches both `exclude_gpu_gfx11X` and `exclude_gpu_gfx1150`
- `gfx1151` matches `exclude_gpu_gfx11X` (inherits from family pattern)
**Generated Tests:**
- For each GPU exclusion, separate tests are generated per applicable category
- Test name format: `{target}-{category}-{gpu_arch}-exclude`
- Uses gtest filter syntax: `{positive_patterns}-{category_excludes}:{gpu_exclusion_patterns}`
**Usage Examples:**
```bash
# On gfx1150 hardware (excludes gfx11X + gfx1150 patterns)
ctest -L quick -L ex_gpu_gfx1150
# On gfx950 hardware (excludes only gfx950 patterns)
ctest -L standard -L ex_gpu_gfx950
# On generic hardware (exclude all GPU-specific tests)
ctest -L quick -LE ex_gpu
```
### **Category-Level Exclusions**
Exclusions are applied using gtest's negative filter syntax (`positive_patterns-negative_patterns`):
**How it works:**
- All test patterns remain in the category definition
- Excluded patterns are added as negative filters after a single `-` separator
- Format: `pattern1:pattern2:pattern3-excluded1:excluded2:excluded3`
- Gtest runs tests matching positive patterns but excludes those matching negative patterns
**Exclusion order:**
1. **Base exclusions** (`exclude`) - Applied to that category
2. **OS-specific exclusions** (`exclude_windows`, `exclude_linux`) - Added based on detected OS at build time
3. **GPU exclusions** (`exclude_gpu`) - Appended for GPU-specific test variants
**Example filters:**
- **Category test**: `*Fusion*:*Conv*-*DeepBench*:*Slow*`
- **GPU exclusion test**: `*Fusion*:*Conv*-*DeepBench*:*Slow*:*gfx942*`
This approach maintains all patterns in the YAML configuration while letting gtest handle the filtering at runtime.
### **Implementation Details**
The `parse_test_categories.py` script builds filter strings using the following approach:
**1. Pattern String Storage**
For each category, the script stores:
```python
# Read timeout settings
base_timeout = timeouts.get(category_name, 300)
timeout = int(base_timeout * timeout_multiplier) # Apply global multiplier
category_data[category_name] = {
"positive_string": "pattern1:pattern2:pattern3", # All test patterns
"exclude_string": "neg1:neg2:neg3", # Category + OS exclusions
"labels": ["quick", "standard"],
"timeout": timeout # Final timeout after multiplier applied
}
```
**2. Category Test Generation**
```cmake
# Filter format: positive_string-exclude_string
add_test(
NAME miopen_gtest_standard_suite
COMMAND miopen_gtest --gtest_filter="*Fusion*:*Conv*-*DeepBench*:*Slow*"
)
```
**3. GPU Exclusion Test Generation**
```cmake
# Filter format: positive_string-exclude_string:gpu_exclude_string
add_test(
NAME miopen_gtest_standard_gfx1150_suite
COMMAND miopen_gtest --gtest_filter="*Fusion*:*Conv*-*DeepBench*:*Slow*:*gfx942*"
)
```
## Integration Guide
This guide walks through integrating the shared YAML-based test categorization into a GTest-based ROCm library project, using MIOpen as the reference implementation.
## Prerequisites
- A monolithic GTest binary (single executable containing all tests)
- Python 3 which is available in the build environment
- The `PyYAML` Python package installed
- `ROCM_LIBRARIES_ROOT` set to the repository root in your CMake
## Step 1: Create test_categories.yaml
Create a `test_categories.yaml` file in your project's test directory.
### Minimal Example
```yaml
test_categories:
quick:
description: "Fast sanity checks (target: < 5 min)"
test_patterns:
- "Smoke/*"
- "Unit/*"
labels:
- "quick"
- "pre-commit"
standard:
description: "Core functionality (target: < 30 min)"
test_patterns:
- "Smoke/*"
- "Unit/*"
- "*/GPU_Conv*"
- "*/GPU_BN*"
exclude:
- "*SlowTest*"
labels:
- "standard"
- "pr"
execution_settings:
timeout_multiplier: 1
category_timeouts:
quick: 300
standard: 1800
```
### Using YAML Anchors to Share Patterns
When multiple categories share the same base patterns, use YAML anchors (`&name`) and aliases (`*name`) to avoid duplication:
```yaml
# Define once at the top level
all_patterns: &all_patterns
- "*/GPU_Conv*"
- "*/GPU_BN*"
- "*/GPU_Reduce*"
test_categories:
standard:
test_patterns: *all_patterns
exclude:
- "*SlowTest*"
labels:
- "standard"
- "pr"
comprehensive:
test_patterns: *all_patterns
labels:
- "comprehensive"
- "nightly"
```
### Adding OS-Specific Exclusions
Exclude tests that only work on a specific OS:
```yaml
test_categories:
standard:
test_patterns:
- "*TestSuite*"
exclude:
- "*KnownBroken*"
exclude_windows:
- "*LinuxOnlyFeature*"
exclude_linux:
- "*WindowsOnlyFeature*"
labels:
- "standard"
```
### Adding GPU-Specific Exclusions
Define GPU exclusions with hierarchical matching using a naming convention for `exclude_gpu` keys. In this convention, an `X` suffix in the architecture portion of the key name (for example, `gfx11X`) stands for “all gfx11xx variants”; this is only a key-naming shorthand, not a glob or regex wildcard in `test_patterns`.
```yaml
# Shared patterns using YAML anchors
gpu_common_patterns: &gpu_common_patterns
- "*KnownGPUFailure*"
- "*UnsupportedOnGfx11*"
exclude_gpu:
exclude_gpu_gfx11X:
# Applies to all gfx11xx GPUs (gfx1100, gfx1150, gfx1151, etc.)
test_patterns: *gpu_common_patterns
labels:
- "quick" # Must list every category this exclusion applies to
- "standard"
- "comprehensive"
- "full"
- "ex_gpu_gfx11X" # Required: ex_gpu_<arch> label for CTest filtering
exclude_gpu_gfx1150:
# Additional exclusions specific to gfx1150 (on top of gfx11X)
test_patterns:
- "*Gfx1150SpecificFailure*"
labels:
- "quick"
- "ex_gpu_gfx1150"
exclude_gpu_gfx950:
test_patterns:
- "*Gfx950Issue*"
labels:
- "quick"
- "standard"
- "ex_gpu_gfx950"
```
**How hierarchical matching works for the above snippet:**
| GPU on machine | Exclusion configs applied |
| -------------- | -------------------------------------------- |
| gfx1100 | `exclude_gpu_gfx11X` |
| gfx1150 | `exclude_gpu_gfx11X` + `exclude_gpu_gfx1150` |
| gfx1151 | `exclude_gpu_gfx11X` |
| gfx950 | `exclude_gpu_gfx950` |
**Important:** The `labels` list in each `exclude_gpu` entry must include every test category that the exclusion applies to. The parser matches these labels against `category_data` keys to determine which categories receive the GPU-specific test variants.
## Step 2: Integrate in CMakeLists.txt
### Enable CTest
Ensure `enable_testing()` is called somewhere in your CMake hierarchy before `apply_test_category_labels()`. Without it, `add_test()` calls have no effect and CTest won't discover any tests. This is typically done in the project's test-level `CMakeLists.txt`:
```cmake
if(BUILD_TESTING)
enable_testing()
endif()
```
If your project already calls `enable_testing()` (or uses `include(CTest)`, which calls it internally), no additional change is needed.
### Integration with Install Support
For projects that distribute test binaries (for example, via TheRock), generate an install-time CTestTestfile.cmake, so that it can be installed wherever the final test binaries are present.
```cmake
set(ROCM_LIBRARIES_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
include(${ROCM_LIBRARIES_ROOT}/shared/ctest/TestCategories.cmake)
# Create install-time test file
set(INSTALL_TEST_FILE "${CMAKE_CURRENT_BINARY_DIR}/install_CTestTestfile.cmake")
file(WRITE "${INSTALL_TEST_FILE}"
[=[
# Generated test definitions for install-time execution.
# Tests use relative paths to the test binary.
]=]
)
# Apply categorization (4th argument enables install file generation)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_categories.yaml")
apply_test_category_labels(
my_project_gtest
"${CMAKE_CURRENT_SOURCE_DIR}/test_categories.yaml"
"${PROJECT_BINARY_DIR}"
"${INSTALL_TEST_FILE}"
)
endif()
# Install the generated CTestTestfile.cmake alongside the test binary
install(
FILES "${INSTALL_TEST_FILE}"
DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}"
COMPONENT tests
RENAME "CTestTestfile.cmake"
)
```
### Excluding Category Suites from `make check`
All YAML-generated tests are named with a `_suite` suffix. If your project has a `check` target that runs `ctest`, the newly generated tests can be excluded to avoid extended run times:
```cmake
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure --verbose -C ${CMAKE_CFG_INTDIR}
--exclude-regex ".*_suite"
)
```
## Step 3: Build and Run Tests
```bash
# Build with existing build commands for the project
cmake -DBUILD_TESTING=ON ..
cmake --build .
# List all registered tests
ctest -N
# Run a specific category (no GPU exclusions)
ctest -L quick -LE ex_gpu
# Run a specific category with GPU-specific exclusions
ctest -L quick -L ex_gpu_gfx1150
# Run with verbose output
ctest -L standard -L ex_gpu_gfx950 -V
```
## Generated Test Names
The framework generates tests with predictable naming:
| Type | Name Format | Example |
| -------------- | -------------------------------------- | -------------------------------------- |
| Category suite | `{target}_{category}_suite` | `my_project_gtest_quick_suite` |
| GPU exclusion | `{target}_{category}_{gpu_arch}_suite` | `my_project_gtest_quick_gfx1150_suite` |
## Generated Labels
Each test gets labels that enable flexible CTest filtering:
| Test Type | Labels |
| -------------- | ------------------------------------------------------------------- |
| Category suite | Category labels from YAML (for example, `quick`, `standard`) |
| GPU exclusion | Category labels + `ex_gpu_<arch>` (for example, `quick`, `ex_gpu_gfx1150`) |
## Function Reference
### `apply_test_category_labels(target_name yaml_file working_dir [install_test_file [resource_group [parser_extra]]])`
| Parameter | Required | Description |
| ------------------- | -------- | --------------------------------------------------------------------------------------------------- |
| `target_name` | Yes | Name of the GTest executable (must not be empty) |
| `yaml_file` | Yes | Absolute path to `test_categories.yaml` (must exist) |
| `working_dir` | Yes | Working directory for test execution (must be a valid directory) |
| `install_test_file` | No | Path to the generated install-time `CTestTestfile.cmake`. Not required for local builds, but |
| | | required for install/package workflows (for example, TheRock). |
| `resource_group` | No | CTest `RESOURCE_GROUPS` token; when set, suite names include `_<resource>` after the target name. |
| `parser_extra` | No | Extra argument(s) forwarded to `parse_test_categories.py` (for example `--use-rtest-driver`). |
**Validation:** The function validates all inputs before execution and emits `WARNING` messages if any check fails, returning early without generating tests.
### Optional rtest driver (`--use-rtest-driver`)
By default, generated CTest suites run the **gtest executable** with `--gtest_filter=...`. If the project passes **`--use-rtest-driver`** as the optional **`parser_extra`** argument to `apply_test_category_labels()`, the parser instead emits commands to run the **rtest** Python driver next to the binary. The driver basename is derived from the CTest name prefix (typically `mylib-test` → `mylib_rtest.py`). The driver is invoked as `<python> <stem>_rtest.py -t ctest_<category>` using a platform-appropriate interpreter on `PATH` at CTest run time (`python3` on Linux/macOS, `python` on Windows—not configure-time `Python3_EXECUTABLE`, which may be absent on CI test nodes). **`--cmake-python3`** may be passed explicitly to the parser to override the install-tree interpreter. PR-style labels are read at rtest run time from the **`GITHUB_PR_LABELS`** environment variable (semicolon-separated, same format as rtest’s `--ci_labels`) when that variable is set and `--ci_labels` was not passed on the command line. CTest **`LABELS`** on the suite are unchanged (for `ctest -L`). The project’s rtest XML must define matching `<test sets="ctest_<category>">` entries. GPU-specific exclusion suites still invoke the gtest binary directly. In **rocm-libraries**, only **rocBLAS** enables this via `USE_RTEST_DRIVER` in `projects/rocblas/clients/gtest/CMakeLists.txt`.
## YAML Reference
### `test_categories` (required)
```yaml
test_categories:
<category_name>:
description: "..." # Optional: human-readable description
test_patterns: # Required: gtest filter patterns (positive match)
- "..."
exclude: # Optional: patterns to exclude from this category
- "..."
exclude_windows: # Optional: additional exclusions on Windows
- "..."
exclude_linux: # Optional: additional exclusions on Linux
- "..."
labels: # Required: CTest labels for filtering
- "..."
```
### `exclude_gpu` (optional)
```yaml
exclude_gpu:
exclude_gpu_<arch>:
test_patterns: # Required: patterns to exclude on this GPU
- "..."
labels: # Required: must include applicable category names
- "<category_name>" # and an ex_gpu_<arch> label
- "ex_gpu_<arch>"
```
### `execution_settings` (optional)
```yaml
execution_settings:
timeout_multiplier: 1 # Global multiplier for all timeouts (default: 1)
category_timeouts:
<category_name>: <seconds> # Per-category timeout (default: 300)
```
## Checklist
- Created `test_categories.yaml` in your project's test directory
- At least one category has `test_patterns` and `labels` defined
- `ROCM_LIBRARIES_ROOT` is set correctly (points to the monorepo root)
- `include(${ROCM_LIBRARIES_ROOT}/shared/ctest/TestCategories.cmake)` added before calling the function
- `apply_test_category_labels()` called with the correct test executable name
- GPU exclusion `labels` lists include every applicable category name
- Each `exclude_gpu_<arch>` entry has an `ex_gpu_<arch>` label
- `ctest -N` shows the expected test suites after building
## Reference Implementation
See the MIOpen integration for a complete working example:
- **YAML config:** [projects/miopen/test/gtest/test_categories.yaml](../../projects/miopen/test/gtest/test_categories.yaml)
- **CMake integration:** [projects/miopen/test/gtest/CMakeLists.txt](../../projects/miopen/test/gtest/CMakeLists.txt)
- **Shared module:** [shared/ctest/TestCategories.cmake](./TestCategories.cmake)
- **Parser script:** [shared/ctest/parse_test_categories.py](./parse_test_categories.py)
### **Install-time CTestTestfile (TheRock / install tree)**
When tests are installed (e.g. into `/opt/rocm/bin/`), the **build-tree** test definitions are not installed. To run CTest from the **installed** location (e.g. on TheRock or any system that only has the install tree), projects can generate an **install-time CTestTestfile** that uses **relative paths** to the test executable.
**How it works:**
1. **Project enables it** by passing an optional **4th argument** to `apply_test_category_labels()`: a path to a file (e.g. `install_CTestTestfile.cmake`) that the parser will create or append to. The parser writes `add_test(...)` and `set_tests_properties(...)` lines into that file using a **relative** command (e.g. `"../my_project_gtest"`), so the test binary is found relative to the directory where the file will live after install.
2. **Project installs that file** to a fixed location under the install prefix, typically a **project-specific subdirectory** of the bin dir (e.g. `bin/my_project/`) and renames it to `CTestTestfile.cmake`. The test executable is installed in the parent `bin/` directory, so from `bin/my_project/` the path `../my_project_gtest` correctly points at the installed binary.
3. **TheRock (or any consumer)** runs CTest **from that installed directory** (e.g. `cd /opt/rocm/bin/my_project && ctest -L quick`). CTest reads the local `CTestTestfile.cmake`, runs the tests with the same labels and timeouts as in the build tree, and no build tree is required.
**Example (rocBLAS):**
- Build: parser writes tests into `install_CTestTestfile.cmake`; CMake installs it as `CTestTestfile.cmake` to `bin/rocblas/`.
- CMake: `ROCBLAS_ENABLE_CTEST` (in `projects/rocblas/cmake/build-options.cmake`) defaults to **ON** when `${ROCM_LIBRARIES_ROOT}/shared/ctest/TestCategories.cmake` exists; if **ON**, a missing YAML or shared module is a **configure error** (set to **OFF** to skip categorization).
- Install layout: `bin/rocblas-test` (executable) and `bin/rocblas/CTestTestfile.cmake` (test definitions).
- Run from install: `cd /opt/rocm/bin/rocblas && ctest -L quick -N` (list) or `ctest -L quick` (run).
Projects that use this pattern (e.g. MIOpen, rocBLAS) document it in their Integration entries below; the same approach applies to any project that needs install-tree CTest runs.
## Integrations
- **miopen** - [test_categories.yaml](../../projects/miopen/test/gtest/test_categories.yaml) | [CMakeLists.txt](../../projects/miopen/test/gtest/CMakeLists.txt)
- **rocblas** - [test_categories.yaml](../../projects/rocblas/clients/gtest/test_categories.yaml) | [CMakeLists.txt](../../projects/rocblas/clients/gtest/CMakeLists.txt)