Add bbsim-tests action
This is for the initial action. Workflow to follow.
Signed-off-by: Eric Ball <eball@linuxfoundation.org>
Change-Id: I70f46f6e8933a2a8a465c7b6b96767e8ee618c97
diff --git a/.github/actions/bbsim-tests/EXTERNAL-USAGE.md b/.github/actions/bbsim-tests/EXTERNAL-USAGE.md
new file mode 100644
index 0000000..e0ca577
--- /dev/null
+++ b/.github/actions/bbsim-tests/EXTERNAL-USAGE.md
@@ -0,0 +1,273 @@
+# Using BBSim Tests Action from External Repositories
+
+## Overview
+
+This action is specifically designed to be used as a **shared/reusable action** from external repositories. All implementation details are self-contained within the `action.yaml` file, with no dependencies on external script files that could cause path resolution issues.
+
+## Why This Matters
+
+When a GitHub Action is called from an external repository (e.g., `uses: opencord/shared-workflows/.github/actions/bbsim-tests@master`), the action runs in the context of the **calling repository**, not the action's repository. This means:
+
+- ❌ Relative paths like `./execute_test.sh` won't work
+- ❌ `${{ github.action_path }}/script.sh` may not be accessible
+- ✅ Inline scripts work perfectly
+- ✅ Scripts created at runtime in `/tmp` work perfectly
+
+## Implementation Approach
+
+### The Problem (Original Approach)
+
+```yaml
+# This DOES NOT work from external repositories
+- name: Execute test
+ shell: bash
+ run: |
+ bash ${{ github.action_path }}/execute_test.sh
+```
+
+When called from `opencord/bbsim` repository, `github.action_path` points to a directory that doesn't exist in the caller's context.
+
+### The Solution (Current Approach)
+
+```yaml
+# This WORKS from external repositories
+- name: Create test execution script
+ shell: bash
+ run: |
+ cat > /tmp/execute_test.sh <<'SCRIPT'
+ #!/bin/bash
+ # ... entire script embedded here ...
+ SCRIPT
+ chmod +x /tmp/execute_test.sh
+
+- name: Execute test
+ shell: bash
+ run: |
+ bash /tmp/execute_test.sh
+```
+
+The script is created dynamically at runtime, ensuring it's always available regardless of where the action is called from.
+
+## Usage Pattern
+
+### From External Repository (Standard Usage)
+
+```yaml
+name: BBSim Tests
+
+on:
+ push:
+ branches: [master]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+**No special steps required!** The action handles everything automatically.
+
+### Repository Setup Required
+
+The calling repository needs:
+- GitHub Actions enabled
+- Sufficient runner resources (minimum 8GB RAM, 2 CPUs)
+- Network access to pull Docker images and Helm charts
+
+The calling repository does **NOT** need:
+- The `shared-workflows` repository checked out locally
+- Any of the action's script files
+- Special permissions or configurations
+
+## What Gets Checked Out
+
+When the action runs, it automatically checks out these repositories into the runner's workspace:
+
+1. **voltha-system-tests** - Contains the Robot Framework test suites
+2. **voltha-helm-charts** - Contains Helm charts for deployment (if using patches or release branches)
+3. **gerrit-project** (optional) - If testing a specific component patch
+
+The calling repository is **not** automatically checked out. If you need files from your repository, add a checkout step:
+
+```yaml
+steps:
+ - name: Checkout calling repository
+ uses: actions/checkout@v4
+ with:
+ path: my-repo
+
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ test-targets: |
+ ...
+```
+
+## File System Layout
+
+When the action runs, the file system looks like this:
+
+```
+/home/runner/work/
+└── <calling-repo-name>/
+ ├── <calling-repo-name>/ (only if explicitly checked out)
+ ├── voltha-system-tests/ (checked out by action)
+ ├── voltha-helm-charts/ (checked out by action, if needed)
+ ├── <gerrit-project>/ (checked out by action, if specified)
+ ├── bin/ (created by action for tools)
+ ├── logs/ (created by action for test results)
+ └── tmp/
+ └── execute_test.sh (created by action at runtime)
+```
+
+## Environment Variables
+
+The action sets these environment variables automatically:
+
+- `GITHUB_WORKSPACE` - Base workspace directory
+- `KUBECONFIG` - Kubernetes configuration file location
+- `VOLTCONFIG` - VOLTHA CLI configuration location
+- `PATH` - Extended with tool directories
+- `DIAGS_PROFILE` - VOLTHA diagnostics profile
+- `SSHPASS` - ONOS SSH password
+
+All test-specific variables are passed to the execution script via environment.
+
+## Troubleshooting External Usage
+
+### Issue: Action not found
+
+**Error**: `Unable to resolve action 'opencord/shared-workflows/.github/actions/bbsim-tests@master'`
+
+**Solutions**:
+1. Verify the repository path is correct
+2. Check that the action exists at that path in the repository
+3. Ensure you have access to the repository (public or proper permissions)
+4. Try using a specific commit SHA instead of branch name
+
+### Issue: Permission denied errors
+
+**Error**: `Permission denied` when running tests
+
+**Solutions**:
+1. Ensure the runner has Docker access
+2. Check that the runner has sufficient permissions to create kind clusters
+3. Verify network access to required registries
+
+### Issue: Tests can't find voltha-system-tests
+
+**Error**: `No such file or directory: voltha-system-tests`
+
+**Solutions**:
+1. This should not happen - the action checks out the repository automatically
+2. If it does occur, check the action's checkout step logs
+3. Verify network connectivity to GitHub/Gerrit
+
+## Version Pinning
+
+For production use, always pin to a specific version:
+
+### Using Tags (Recommended)
+```yaml
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@v1.0.0
+```
+
+### Using Commit SHA (Most Secure)
+```yaml
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@abc123def456...
+```
+
+### Using Branch (Development Only)
+```yaml
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+```
+
+## Benefits of This Approach
+
+✅ **Portability**: Works from any repository without modifications
+✅ **Self-Contained**: No external dependencies to manage
+✅ **Maintainability**: Single file to update (action.yaml)
+✅ **Testability**: Easy to test from different repositories
+✅ **Security**: No risk of path traversal issues
+✅ **Transparency**: All logic visible in one place
+
+## Real-World Example
+
+See the actual usage in the BBSim repository:
+
+**Repository**: `opencord/bbsim`
+**Workflow File**: `.github/workflows/bbsim-basic-test.yaml`
+
+```yaml
+name: BBSim Tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+
+jobs:
+ bbsim-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+This works perfectly without any additional setup!
+
+## Developer Notes
+
+If you're modifying this action:
+
+1. **Never use relative paths** to script files - they won't work from external repos
+2. **Always test from an external repository** before considering the change complete
+3. **Keep all logic in action.yaml** or create files dynamically at runtime
+4. **Use absolute paths** when referring to files created by the action itself
+5. **Document any new inputs** thoroughly in README.md
+
+## Migration from Jenkins
+
+Unlike Jenkins shared libraries, GitHub Actions composite actions run in the caller's context. This means:
+
+| Jenkins | GitHub Actions |
+|---------|----------------|
+| Library code runs in shared space | Action code runs in caller's workspace |
+| Can reference shared files directly | Must inline or create files at runtime |
+| `@Library('shared')` imports | `uses: org/repo/.github/actions/name` |
+| Groovy functions | Composite action steps |
+
+The conversion required embedding all shell script logic directly into the action definition to ensure cross-repository compatibility.
+
+## Support
+
+If you encounter issues using this action from your repository:
+
+1. Check this document first
+2. Review the action's README.md
+3. Examine the workflow logs in GitHub Actions UI
+4. Verify your test-targets YAML syntax
+5. Ensure your runner has sufficient resources
+
+For bugs or feature requests, open an issue in the `shared-workflows` repository.
\ No newline at end of file
diff --git a/.github/actions/bbsim-tests/QUICKSTART.md b/.github/actions/bbsim-tests/QUICKSTART.md
new file mode 100644
index 0000000..1b0c7c0
--- /dev/null
+++ b/.github/actions/bbsim-tests/QUICKSTART.md
@@ -0,0 +1,341 @@
+# BBSim Tests - Quick Start Guide
+
+This guide will help you get started with the BBSim Tests GitHub Action in under 5 minutes.
+
+## Prerequisites
+
+- A GitHub repository with GitHub Actions enabled
+- Basic understanding of VOLTHA and BBSim
+- Sufficient runner resources (minimum 8GB RAM, 2 CPUs)
+
+## Minimal Example
+
+Create `.github/workflows/bbsim-test.yaml` in your repository:
+
+```yaml
+name: BBSim Tests
+
+on:
+ push:
+ branches: [master]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: master
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+That's it! Commit and push this file to trigger your first BBSim test.
+
+**Note**: This action is designed as a **shared/reusable action**. You don't need to check out the `shared-workflows` repository - just reference it directly with `uses:`. All dependencies and scripts are handled automatically.
+
+## What This Does
+
+1. **Installs dependencies**: kubectl, helm, kind, kail, voltctl
+2. **Creates a Kubernetes cluster**: 3-node kind cluster
+3. **Deploys VOLTHA**: Complete VOLTA stack with BBSim
+4. **Runs tests**: Executes the specified Robot Framework tests
+5. **Collects results**: Uploads logs and test reports as artifacts
+
+## Common Test Targets
+
+### DT Workflow
+```yaml
+- target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### ATT Workflow
+```yaml
+- target: functional-single-kind-att
+ workflow: att
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### TT Workflow
+```yaml
+- target: functional-single-kind-tt
+ workflow: tt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### Sanity Tests (Quick)
+```yaml
+- target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+## Running Multiple Tests
+
+Just add more entries to the `test-targets` list:
+
+```yaml
+test-targets: |
+ - target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+## Enabling Debug Logging
+
+Set `log-level` to `DEBUG`:
+
+```yaml
+- name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: master
+ log-level: DEBUG
+ test-targets: |
+ ...
+```
+
+## Enabling Monitoring
+
+Add `with-monitoring: true` to collect memory consumption metrics:
+
+```yaml
+- name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: master
+ with-monitoring: true
+ test-targets: |
+ ...
+```
+
+## Testing Multiple OLTs
+
+Set the `olts` parameter:
+
+```yaml
+- name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: master
+ olts: "2"
+ test-targets: |
+ ...
+```
+
+## Viewing Results
+
+After the workflow completes:
+
+1. Go to the **Actions** tab in your repository
+2. Click on the workflow run
+3. Scroll to the bottom to see **Artifacts**
+4. Download the test results artifact
+5. Open `report.html` in a browser to see the Robot Framework report
+
+## Manual Trigger
+
+Add `workflow_dispatch` to trigger tests manually:
+
+```yaml
+name: BBSim Tests
+
+on:
+ workflow_dispatch:
+ inputs:
+ branch:
+ description: 'Branch to test'
+ required: true
+ default: 'master'
+ log_level:
+ description: 'Log level'
+ required: false
+ default: 'WARN'
+ type: choice
+ options:
+ - DEBUG
+ - INFO
+ - WARN
+ - ERROR
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ inputs.branch }}
+ log-level: ${{ inputs.log_level }}
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+Now you can trigger tests from the GitHub UI!
+
+## Troubleshooting
+
+### Test Fails Immediately
+
+Check that your runner has enough resources:
+- Minimum: 8GB RAM, 2 CPUs
+- Recommended: 16GB RAM, 4 CPUs
+
+Free up disk space before running:
+```yaml
+- name: Free disk space
+ run: |
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+```
+
+### Cluster Creation Fails
+
+The kind cluster name might conflict. Try a unique name:
+```yaml
+with:
+ cluster-name: "my-test-cluster"
+```
+
+### Tests Time Out
+
+Increase the job timeout:
+```yaml
+jobs:
+ test:
+ timeout-minutes: 480 # 8 hours
+```
+
+### Need Help?
+
+1. Check the [README.md](README.md) for detailed documentation
+1. Look at [example-workflow.yaml](example-workflow.yaml) for complete examples
+1. Check GitHub Actions logs for specific error messages
+
+## Important Notes
+
+### External Usage
+This action is designed to be called from external repositories. You don't need to:
+- ❌ Check out the `shared-workflows` repository
+- ❌ Copy any script files
+- ❌ Install dependencies manually
+
+The action is **fully self-contained** and handles everything automatically.
+
+### Version Pinning
+For production use, pin to a specific version:
+```yaml
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@v1.0.0 # Recommended
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@abc123 # Most secure
+uses: opencord/shared-workflows/.github/actions/bbsim-tests@main # Development only
+```
+
+## Next Steps
+
+- **Customize**: Adjust parameters for your specific needs
+- **Schedule**: Add `schedule` triggers for nightly tests
+- **Integrate**: Add to PR workflows for automated testing
+- **Monitor**: Enable monitoring to track resource usage
+- **Optimize**: Adjust timeouts and resource limits
+- **Read**: Check [EXTERNAL-USAGE.md](EXTERNAL-USAGE.md) for detailed information
+
+## Full Example with All Options
+
+```yaml
+name: Complete BBSim Tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ schedule:
+ - cron: '0 2 * * *'
+ workflow_dispatch:
+
+jobs:
+ bbsim-tests:
+ runs-on: ubuntu-latest
+ timeout-minutes: 360
+
+ steps:
+ - name: Free up disk space
+ run: |
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: master
+ log-level: INFO
+ cluster-name: kind-ci
+ docker-registry: linuxfoundation.jfrog.io/voltha-docker
+ olts: "2"
+ with-monitoring: true
+ enable-mac-learning: false
+ extra-helm-flags: "--set global.some_option=value"
+ extra-robot-args: "-v some_var:some_value"
+ test-targets: |
+ - target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+```
+
+---
+
+**Happy Testing!** 🚀
diff --git a/.github/actions/bbsim-tests/README.md b/.github/actions/bbsim-tests/README.md
new file mode 100644
index 0000000..4731187
--- /dev/null
+++ b/.github/actions/bbsim-tests/README.md
@@ -0,0 +1,404 @@
+# BBSim Tests GitHub Action
+
+This action runs VOLTHA end-to-end tests using BBSim (Broadband Simulator) to simulate OLT/ONU devices. It's a conversion of the Jenkins pipeline from `ci-management/jjb/pipeline/voltha/bbsim-tests.groovy` to GitHub Actions.
+
+## Important Note
+
+This action is designed to be used as a **shared/reusable action** from external repositories. All test execution logic is embedded directly in the `action.yaml` file (no external script dependencies), making it compatible with GitHub Actions' composite action model when called from other repositories.
+
+## Overview
+
+The action performs the following steps:
+
+1. **Setup Environment**: Installs all required dependencies (kubectl, helm, kind, kail, voltctl)
+2. **Checkout Repositories**: Clones voltha-system-tests and voltha-helm-charts
+3. **Build Components**: Optionally builds VOLTHA components from Gerrit patches
+4. **Create Kubernetes Cluster**: Sets up a kind cluster for testing
+5. **Deploy Infrastructure**: Deploys VOLTHA, ONOS, and BBSim instances
+6. **Run Tests**: Executes Robot Framework test suites
+7. **Collect Artifacts**: Gathers logs, test results, and metrics
+
+## Inputs
+
+### Required Inputs
+
+- **`branch`**: Branch to test (e.g., `master`, `voltha-2.15`)
+- **`test-targets`**: YAML string defining test targets to run (see format below)
+
+### Optional Inputs
+
+- **`gerrit-project`**: Gerrit project name if building a patch (default: `""`)
+- **`gerrit-refspec`**: Gerrit refspec if building a patch (default: `""`)
+- **`voltha-system-tests-change`**: Gerrit change number for voltha-system-tests (default: `""`)
+- **`voltha-helm-charts-change`**: Gerrit change number for voltha-helm-charts (default: `""`)
+- **`extra-helm-flags`**: Additional Helm flags for deployment (default: `""`)
+- **`log-level`**: Log level for VOLTHA components: DEBUG, INFO, WARN, ERROR (default: `"WARN"`)
+- **`timeout`**: Timeout in minutes for the entire action (default: `"240"`)
+- **`cluster-name`**: Name of the kind cluster (default: `"kind-ci"`)
+- **`docker-registry`**: Docker registry to use (default: `"linuxfoundation.jfrog.io/voltha-docker"`)
+- **`olts`**: Number of OLTs to simulate (default: `"1"`)
+- **`with-monitoring`**: Enable monitoring with Prometheus (default: `false`)
+- **`enable-mac-learning`**: Enable MAC learning in VOLTHA (default: `false`)
+- **`extra-robot-args`**: Additional arguments for Robot Framework (default: `""`)
+
+## Outputs
+
+- **`test-results`**: Path to test results directory
+
+## Test Targets Format
+
+The `test-targets` input should be a YAML array with the following structure:
+
+```yaml
+- target: functional-single-kind-dt
+ workflow: dt
+ flags: "--set someFlag=value"
+ teardown: true
+ logging: true
+ vgcEnabled: false
+- target: functional-single-kind-att
+ workflow: att
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### Test Target Fields
+
+- **`target`**: Make target from voltha-system-tests (e.g., `functional-single-kind-dt`)
+- **`workflow`**: VOLTHA workflow type (e.g., `dt`, `att`, `tt`)
+- **`flags`**: Additional Helm flags specific to this test (optional)
+- **`teardown`**: Whether to tear down and redeploy VOLTHA (default: `true`)
+- **`logging`**: Enable test logging (default: `true`)
+- **`vgcEnabled`**: Enable VOLTHA Go Controller (default: `false`)
+
+## Usage Examples
+
+### Basic Usage (from External Repository)
+
+This is the most common usage pattern - calling the action from another repository:
+
+```yaml
+name: BBSim Tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+
+jobs:
+ bbsim-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+**Note**: Replace `@master` with a specific version tag or commit SHA for production use.
+
+### Usage from Local Repository
+
+If you're developing or testing the action within the `shared-workflows` repository itself:
+
+```yaml
+jobs:
+ bbsim-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### Advanced Usage with Multiple Tests
+
+```yaml
+name: BBSim Multi-Workflow Tests
+
+on:
+ schedule:
+ - cron: '0 2 * * *' # Run nightly
+
+jobs:
+ bbsim-tests:
+ runs-on: ubuntu-latest
+ timeout-minutes: 300
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Run BBSim Tests
+ uses: ./.github/actions/bbsim-tests
+ with:
+ branch: master
+ log-level: INFO
+ olts: "2"
+ with-monitoring: true
+ extra-helm-flags: "--set global.some_option=true"
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-att
+ workflow: att
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-tt
+ workflow: tt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Publish Test Results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-results
+ path: logs/
+```
+
+### Testing a Gerrit Patch
+
+```yaml
+name: Test Gerrit Patch
+
+on:
+ workflow_dispatch:
+ inputs:
+ gerrit_project:
+ description: 'Gerrit project name'
+ required: true
+ type: string
+ gerrit_refspec:
+ description: 'Gerrit refspec'
+ required: true
+ type: string
+
+jobs:
+ test-patch:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests with Patch
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ gerrit-project: ${{ inputs.gerrit_project }}
+ gerrit-refspec: ${{ inputs.gerrit_refspec }}
+ test-targets: |
+ - target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+### Testing with voltha-system-tests Changes
+
+```yaml
+name: Test System Tests Changes
+
+on:
+ pull_request:
+ paths:
+ - 'tests/**'
+
+jobs:
+ test-changes:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Run BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@master
+ with:
+ branch: master
+ voltha-system-tests-change: "refs/changes/12/34512/1"
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+```
+
+## How It Works
+
+This action is implemented as a **composite action** with all logic embedded directly in the `action.yaml` file. When called from an external repository:
+
+1. The test execution script is created dynamically at runtime in `/tmp/execute_test.sh`
+2. No local file paths or relative references are needed
+3. All dependencies are installed fresh in each run
+4. The action is fully self-contained and portable
+
+This design ensures the action works correctly whether called from:
+- External repositories (most common use case)
+- The shared-workflows repository itself (for development/testing)
+- Forked repositories
+
+## Dependencies
+
+This action automatically installs the following dependencies:
+
+- **kubectl**: Kubernetes CLI
+- **helm**: Kubernetes package manager
+- **kind**: Kubernetes in Docker (for local cluster)
+- **kail**: Kubernetes log viewer
+- **voltctl**: VOLTHA CLI tool
+- **Python 3**: For Robot Framework tests
+- **System packages**: curl, wget, git, make, jq, sshpass, rsync
+
+## Artifacts
+
+The action automatically uploads the following artifacts:
+
+- Robot Framework test reports (HTML)
+- Robot Framework test logs
+- Robot Framework output XML
+- VOLTHA pod logs
+- Kubernetes events and pod information
+- Memory consumption metrics (if monitoring enabled)
+- Combined startup logs (compressed)
+
+Artifacts are retained for 30 days and can be downloaded from the GitHub Actions UI.
+
+## Architecture
+
+### Components
+
+1. **BBSim**: Simulates OLT/ONU devices
+2. **VOLTHA**: Open source VOLT management system
+3. **ONOS**: SDN controller
+4. **Kafka**: Message broker for VOLTHA
+5. **ETCD**: Key-value store for VOLTHA
+6. **Robot Framework**: Test automation framework
+
+### Namespaces
+
+- **default**: Infrastructure components (optional monitoring)
+- **voltha**: VOLTHA stack and BBSim instances
+
+### Port Forwarding
+
+The action sets up the following port forwards:
+
+- **9092**: Kafka (voltha-infra-kafka)
+- **30115**: ONOS SSH
+- **30120**: ONOS REST API
+- **31301**: Prometheus (if monitoring enabled)
+- **50075+**: BBSim DMI ports (one per OLT instance)
+- **8181**: VOLTHA Go Controller (if VGC enabled)
+
+## Troubleshooting
+
+### Tests Fail to Start
+
+- Check that the cluster was created successfully
+- Verify that all pods are running: `kubectl get pods -A`
+- Check pod logs: `kubectl logs -n voltha <pod-name>`
+
+### Timeout Issues
+
+- Increase the `timeout` input value
+- Check resource constraints on the runner
+- Verify network connectivity
+
+### Image Pull Errors
+
+- Verify the `docker-registry` input is correct
+- Check if images exist for the specified branch
+- Ensure the runner has network access to the registry
+
+### Port Forward Issues
+
+Port forwards may fail if:
+- Ports are already in use
+- Pods are not ready
+- Network policies block access
+
+Check port-forward processes: `ps aux | grep port-forward`
+
+### Test Failures
+
+1. Check the Robot Framework logs in artifacts
+2. Review VOLTHA pod logs
+3. Check Kubernetes events
+4. Verify test configuration matches the workflow
+
+## Migration from Jenkins
+
+This action replaces the Jenkins pipeline `bbsim-tests.groovy`. Key differences:
+
+1. **No shared library**: All functionality is self-contained
+2. **Declarative syntax**: Uses GitHub Actions YAML instead of Groovy
+3. **Native artifact handling**: Uses GitHub Actions artifact upload
+4. **Simplified configuration**: Direct input parameters instead of Jenkins parameters
+5. **Better isolation**: Each run gets a fresh environment
+
+### Parameter Mapping
+
+| Jenkins Parameter | GitHub Action Input |
+|------------------|---------------------|
+| `branch` | `branch` |
+| `testTargets` | `test-targets` |
+| `gerritProject` | `gerrit-project` |
+| `gerritRefspec` | `gerrit-refspec` |
+| `volthaSystemTestsChange` | `voltha-system-tests-change` |
+| `volthaHelmChartsChange` | `voltha-helm-charts-change` |
+| `extraHelmFlags` | `extra-helm-flags` |
+| `logLevel` | `log-level` |
+| `timeout` | `timeout` |
+| `registry` | `docker-registry` |
+| `olts` | `olts` |
+| `withMonitoring` | `with-monitoring` |
+| `enableMacLearning` | `enable-mac-learning` |
+| `extraRobotArgs` | `extra-robot-args` |
+
+## Contributing
+
+When modifying this action:
+
+1. Test changes locally using [act](https://github.com/nektos/act)
+2. Update this README with any new inputs or behavior changes
+3. Follow the existing code structure and style
+4. Add comments for complex logic
+5. Update version numbers appropriately
+
+## License
+
+Copyright 2026 The Linux Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/.github/actions/bbsim-tests/action.yaml b/.github/actions/bbsim-tests/action.yaml
new file mode 100644
index 0000000..72803ac
--- /dev/null
+++ b/.github/actions/bbsim-tests/action.yaml
@@ -0,0 +1,734 @@
+---
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: 2026 Open Networking Foundation Contributors
+
+name: "bbsim-tests"
+description: "VOLTHA BBSim E2E Tests - Simulates OLT/ONUs using bbsim and runs robot framework tests"
+
+inputs:
+ branch:
+ description: "Branch to test (master, voltha-2.15, etc.)"
+ required: true
+ type: string
+ test-targets:
+ description: "YAML string defining test targets to run"
+ required: true
+ type: string
+ gerrit-project:
+ description: "Gerrit project name if building a patch"
+ required: false
+ type: string
+ default: ""
+ gerrit-refspec:
+ description: "Gerrit refspec if building a patch"
+ required: false
+ type: string
+ default: ""
+ voltha-system-tests-change:
+ description: "Gerrit change number for voltha-system-tests"
+ required: false
+ type: string
+ default: ""
+ voltha-helm-charts-change:
+ description: "Gerrit change number for voltha-helm-charts"
+ required: false
+ type: string
+ default: ""
+ extra-helm-flags:
+ description: "Additional Helm flags for deployment"
+ required: false
+ type: string
+ default: ""
+ log-level:
+ description: "Log level for VOLTHA components (DEBUG, INFO, WARN, ERROR)"
+ required: false
+ type: string
+ default: "WARN"
+ timeout:
+ description: "Timeout in minutes for the entire action"
+ required: false
+ type: string
+ default: "240"
+ cluster-name:
+ description: "Name of the kind cluster"
+ required: false
+ type: string
+ default: "kind-ci"
+ docker-registry:
+ description: "Docker registry to use"
+ required: false
+ type: string
+ default: "linuxfoundation.jfrog.io/voltha-docker"
+ olts:
+ description: "Number of OLTs to simulate"
+ required: false
+ type: string
+ default: "1"
+ with-monitoring:
+ description: "Enable monitoring with prometheus"
+ required: false
+ type: boolean
+ default: false
+ enable-mac-learning:
+ description: "Enable MAC learning in VOLTHA"
+ required: false
+ type: boolean
+ default: false
+ extra-robot-args:
+ description: "Additional arguments for Robot Framework"
+ required: false
+ type: string
+ default: ""
+
+outputs:
+ test-results:
+ description: "Path to test results"
+ value: ${{ steps.test-execution.outputs.results-path }}
+
+runs:
+ using: "composite"
+ steps:
+ # -----------------------------------------------------------------------
+ # Setup environment variables
+ # -----------------------------------------------------------------------
+ - name: Setup environment
+ shell: bash
+ run: |
+ echo "KUBECONFIG=$HOME/.kube/kind-${{ inputs.cluster-name }}" >> $GITHUB_ENV
+ echo "VOLTCONFIG=$HOME/.volt/config" >> $GITHUB_ENV
+ echo "PATH=$PATH:$GITHUB_WORKSPACE/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> $GITHUB_ENV
+ echo "DIAGS_PROFILE=VOLTHA_PROFILE" >> $GITHUB_ENV
+ echo "SSHPASS=karaf" >> $GITHUB_ENV
+ mkdir -p $GITHUB_WORKSPACE/bin
+
+ # -----------------------------------------------------------------------
+ # Install dependencies
+ # -----------------------------------------------------------------------
+ - name: Install system dependencies
+ shell: bash
+ run: |
+ echo "Installing system dependencies..."
+ sudo apt-get update
+ sudo apt-get install -y \
+ curl \
+ wget \
+ git \
+ make \
+ jq \
+ sshpass \
+ python3 \
+ python3-pip \
+ python3-venv \
+ rsync
+
+ # -----------------------------------------------------------------------
+ # Install kubectl
+ # -----------------------------------------------------------------------
+ - name: Install kubectl
+ shell: bash
+ run: |
+ echo "Installing kubectl..."
+ if [ ! -f "$GITHUB_WORKSPACE/bin/kubectl" ]; then
+ KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
+ curl -Lo "$GITHUB_WORKSPACE/bin/kubectl" \
+ "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
+ chmod +x "$GITHUB_WORKSPACE/bin/kubectl"
+ fi
+ kubectl version --client
+
+ # -----------------------------------------------------------------------
+ # Install Helm
+ # -----------------------------------------------------------------------
+ - name: Install Helm
+ shell: bash
+ run: |
+ echo "Installing Helm..."
+ if ! command -v helm &> /dev/null; then
+ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
+ fi
+ helm version
+
+ # -----------------------------------------------------------------------
+ # Install kind
+ # -----------------------------------------------------------------------
+ - name: Install kind
+ shell: bash
+ run: |
+ echo "Installing kind..."
+ if [ ! -f "$GITHUB_WORKSPACE/bin/kind" ]; then
+ KIND_VERSION="v0.20.0"
+ curl -Lo "$GITHUB_WORKSPACE/bin/kind" \
+ "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64"
+ chmod +x "$GITHUB_WORKSPACE/bin/kind"
+ fi
+ kind version
+
+ # -----------------------------------------------------------------------
+ # Install kail
+ # -----------------------------------------------------------------------
+ - name: Install kail
+ shell: bash
+ run: |
+ echo "Installing kail..."
+ if [ ! -f "$GITHUB_WORKSPACE/bin/kail" ]; then
+ KAIL_VERSION="v0.17.4"
+ wget -O /tmp/kail.tar.gz \
+ "https://github.com/boz/kail/releases/download/${KAIL_VERSION}/kail_${KAIL_VERSION}_linux_amd64.tar.gz"
+ tar -xzf /tmp/kail.tar.gz -C "$GITHUB_WORKSPACE/bin" kail
+ chmod +x "$GITHUB_WORKSPACE/bin/kail"
+ rm /tmp/kail.tar.gz
+ fi
+
+ # -----------------------------------------------------------------------
+ # Install voltctl
+ # -----------------------------------------------------------------------
+ - name: Install voltctl
+ shell: bash
+ run: |
+ echo "Installing voltctl..."
+ if [ "${{ inputs.gerrit-project }}" != "voltctl" ]; then
+ if [ ! -f "$GITHUB_WORKSPACE/bin/voltctl" ]; then
+ VOLTCTL_VERSION="1.8.45"
+ curl -Lo "$GITHUB_WORKSPACE/bin/voltctl" \
+ "https://github.com/opencord/voltctl/releases/download/v${VOLTCTL_VERSION}/voltctl-${VOLTCTL_VERSION}-linux-amd64"
+ chmod +x "$GITHUB_WORKSPACE/bin/voltctl"
+ fi
+ fi
+
+ # -----------------------------------------------------------------------
+ # Checkout VOLTHA repositories
+ # -----------------------------------------------------------------------
+ - name: Checkout voltha-system-tests
+ uses: actions/checkout@v4
+ with:
+ repository: opencord/voltha-system-tests
+ ref: ${{ inputs.branch }}
+ path: voltha-system-tests
+
+ - name: Apply voltha-system-tests patch
+ if: inputs.voltha-system-tests-change != ''
+ shell: bash
+ working-directory: voltha-system-tests
+ run: |
+ echo "Applying voltha-system-tests change ${{ inputs.voltha-system-tests-change }}"
+ git fetch https://gerrit.lfbroadband.org/voltha-system-tests \
+ refs/changes/${{ inputs.voltha-system-tests-change }}
+ git checkout FETCH_HEAD
+
+ - name: Checkout voltha-helm-charts
+ uses: actions/checkout@v4
+ with:
+ repository: opencord/voltha-helm-charts
+ ref: ${{ inputs.branch }}
+ path: voltha-helm-charts
+
+ - name: Apply voltha-helm-charts patch
+ if: inputs.voltha-helm-charts-change != ''
+ shell: bash
+ working-directory: voltha-helm-charts
+ run: |
+ echo "Applying voltha-helm-charts change ${{ inputs.voltha-helm-charts-change }}"
+ git fetch https://gerrit.lfbroadband.org/voltha-helm-charts \
+ refs/changes/${{ inputs.voltha-helm-charts-change }}
+ git checkout FETCH_HEAD
+
+ # -----------------------------------------------------------------------
+ # Checkout and build gerrit project if specified
+ # -----------------------------------------------------------------------
+ - name: Checkout gerrit project
+ if: inputs.gerrit-project != ''
+ uses: actions/checkout@v4
+ with:
+ repository: opencord/${{ inputs.gerrit-project }}
+ ref: ${{ inputs.gerrit-refspec }}
+ path: ${{ inputs.gerrit-project }}
+
+ - name: Build gerrit project
+ if: inputs.gerrit-project != ''
+ shell: bash
+ working-directory: ${{ inputs.gerrit-project }}
+ run: |
+ echo "Building ${{ inputs.gerrit-project }}..."
+ if [ -f "Makefile" ]; then
+ make docker-build
+ fi
+
+ - name: Build and install voltctl from source
+ if: inputs.gerrit-project == 'voltctl'
+ shell: bash
+ working-directory: voltctl
+ run: |
+ echo "Building voltctl from source..."
+ make build
+ cp voltctl "$GITHUB_WORKSPACE/bin/"
+ chmod +x "$GITHUB_WORKSPACE/bin/voltctl"
+
+ # -----------------------------------------------------------------------
+ # Create kind cluster
+ # -----------------------------------------------------------------------
+ - name: Check if kind cluster exists
+ id: cluster-check
+ shell: bash
+ run: |
+ if kind get clusters | grep -q "^${{ inputs.cluster-name }}$"; then
+ echo "exists=true" >> $GITHUB_OUTPUT
+ else
+ echo "exists=false" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Create kind cluster
+ if: steps.cluster-check.outputs.exists == 'false'
+ shell: bash
+ run: |
+ echo "Creating kind cluster ${{ inputs.cluster-name }}..."
+ cat <<EOF > /tmp/kind-config.yaml
+ kind: Cluster
+ apiVersion: kind.x-k8s.io/v1alpha4
+ nodes:
+ - role: control-plane
+ - role: worker
+ - role: worker
+ EOF
+
+ kind create cluster --name ${{ inputs.cluster-name }} --config /tmp/kind-config.yaml
+
+ # Configure kubeconfig
+ mkdir -p $HOME/.kube
+ kind export kubeconfig --name ${{ inputs.cluster-name }} --kubeconfig $HOME/.kube/kind-${{ inputs.cluster-name }}
+
+ # Wait for cluster to be ready
+ kubectl wait --for=condition=Ready nodes --all --timeout=300s
+
+ # -----------------------------------------------------------------------
+ # Load images to kind if building a component
+ # -----------------------------------------------------------------------
+ - name: Load images to kind
+ if: inputs.gerrit-project != '' && inputs.gerrit-project != 'voltctl'
+ shell: bash
+ run: |
+ echo "Loading images to kind cluster..."
+ PROJECT="${{ inputs.gerrit-project }}"
+ IMAGE_NAME="${PROJECT//-/_}"
+
+ # Find the built image
+ IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "voltha/${PROJECT}|opencord/${PROJECT}" | head -1)
+
+ if [ -n "$IMAGE" ]; then
+ echo "Loading image: $IMAGE"
+ kind load docker-image "$IMAGE" --name ${{ inputs.cluster-name }}
+ else
+ echo "Warning: No image found for project $PROJECT"
+ fi
+
+ # -----------------------------------------------------------------------
+ # Setup Helm repositories
+ # -----------------------------------------------------------------------
+ - name: Setup Helm repositories
+ shell: bash
+ run: |
+ echo "Adding Helm repositories..."
+ helm repo add onf https://charts.lfbroadband.org
+ helm repo add cord https://charts.lfbroadband.org
+ helm repo update
+
+ # -----------------------------------------------------------------------
+ # Run tests
+ # -----------------------------------------------------------------------
+ - name: Install PyYAML for test parsing
+ shell: bash
+ run: |
+ pip3 install pyyaml
+
+ - name: Create test execution script
+ shell: bash
+ run: |
+ # Create the test execution script inline
+ cat > /tmp/execute_test.sh <<'EXECUTE_TEST_SCRIPT'
+ #!/bin/bash
+ set -euo pipefail
+
+ # Get environment variables
+ TEST_TARGET="${TEST_TARGET:-functional-single-kind-dt}"
+ WORKFLOW="${WORKFLOW:-dt}"
+ TEST_FLAGS="${TEST_FLAGS:-}"
+ TEARDOWN="${TEARDOWN:-true}"
+ TEST_LOGGING="${TEST_LOGGING:-True}"
+ VGC_ENABLED="${VGC_ENABLED:-false}"
+ INFRA_NAMESPACE="${INFRA_NAMESPACE:-default}"
+ VOLTHA_NAMESPACE="${VOLTHA_NAMESPACE:-voltha}"
+ LOGS_DIR="${LOGS_DIR:-$GITHUB_WORKSPACE/logs}"
+ EXTRA_HELM_FLAGS="${EXTRA_HELM_FLAGS:-}"
+ LOG_LEVEL="${LOG_LEVEL:-WARN}"
+ DOCKER_REGISTRY="${DOCKER_REGISTRY:-linuxfoundation.jfrog.io/voltha-docker}"
+ OLTS="${OLTS:-1}"
+ WITH_MONITORING="${WITH_MONITORING:-false}"
+ ENABLE_MAC_LEARNING="${ENABLE_MAC_LEARNING:-false}"
+ EXTRA_ROBOT_ARGS="${EXTRA_ROBOT_ARGS:-}"
+ BRANCH="${BRANCH:-master}"
+ GERRIT_PROJECT="${GERRIT_PROJECT:-}"
+
+ # Helper functions
+ banner() {
+ echo ""
+ echo "** -----------------------------------------------------------------------"
+ echo "** $1"
+ echo "** -----------------------------------------------------------------------"
+ echo ""
+ }
+
+ cleanup_port_forward() {
+ echo "Cleaning up port-forward processes..."
+ pkill -f "kubectl.*port-forward" || true
+ }
+
+ get_pods_info() {
+ local logs_dir=$1
+ mkdir -p "$logs_dir"
+ kubectl get pods --all-namespaces -o wide > "$logs_dir/pods.txt" || true
+ kubectl get nodes -o wide > "$logs_dir/nodes.txt" || true
+ kubectl describe pods -n "$VOLTHA_NAMESPACE" > "$logs_dir/voltha-pods-describe.txt" || true
+ kubectl describe pods -n "$INFRA_NAMESPACE" > "$logs_dir/infra-pods-describe.txt" || true
+ }
+
+ # Stage: Cleanup (if teardown enabled)
+ if [ "$TEARDOWN" = "true" ]; then
+ banner "Cleanup - Helm Teardown"
+ cleanup_port_forward
+ for namespace in default "$INFRA_NAMESPACE" "$VOLTHA_NAMESPACE"; do
+ echo "Cleaning up Helm releases in namespace: $namespace"
+ helm list -n "$namespace" -q | xargs -r helm uninstall -n "$namespace" || true
+ done
+ echo "Waiting for pods to terminate..."
+ kubectl wait --for=delete pods --all -n "$VOLTHA_NAMESPACE" --timeout=120s || true
+ kubectl wait --for=delete pods --all -n "$INFRA_NAMESPACE" --timeout=120s || true
+ fi
+
+ # Stage: Deploy Common Infrastructure
+ banner "Deploying Common Infrastructure"
+ if [ "$WITH_MONITORING" = "true" ]; then
+ echo "Deploying monitoring stack..."
+ helm install nem-monitoring onf/nem-monitoring \
+ --set prometheus.alertmanager.enabled=false \
+ --set prometheus.pushgateway.enabled=false \
+ --set kpi_exporter.enabled=false \
+ --set dashboards.xos=false \
+ --set dashboards.onos=false \
+ --set dashboards.aaa=false \
+ --set dashboards.voltha=false \
+ --wait || true
+ fi
+
+ # Stage: Deploy VOLTHA
+ if [ "$TEARDOWN" = "true" ]; then
+ banner "Deploying VOLTHA"
+ ONOS_LOG="${LOGS_DIR}/onos-voltha-startup-combined.log"
+ mkdir -p "$LOGS_DIR"
+ touch "$ONOS_LOG"
+ _TAG=kail-startup kail -n "${INFRA_NAMESPACE}" -n "${VOLTHA_NAMESPACE}" > "$ONOS_LOG" &
+ KAIL_PID=$!
+
+ LOCAL_CHARTS="false"
+ if [ -d "$GITHUB_WORKSPACE/voltha-helm-charts" ]; then
+ LOCAL_CHARTS="true"
+ fi
+
+ HELM_FLAGS="--set global.log_level=${LOG_LEVEL^^}"
+ if [ "$VGC_ENABLED" != "true" ]; then
+ HELM_FLAGS="$HELM_FLAGS --set onos-classic.onosSshPort=30115"
+ HELM_FLAGS="$HELM_FLAGS --set onos-classic.onosApiPort=30120"
+ HELM_FLAGS="$HELM_FLAGS --set onos-classic.onosOfPort=31653"
+ HELM_FLAGS="$HELM_FLAGS --set onos-classic.individualOpenFlowNodePorts=true"
+ fi
+ if [ -n "$EXTRA_HELM_FLAGS" ]; then
+ HELM_FLAGS="$HELM_FLAGS $EXTRA_HELM_FLAGS"
+ fi
+ if [ -n "$TEST_FLAGS" ]; then
+ HELM_FLAGS="$HELM_FLAGS $TEST_FLAGS"
+ fi
+
+ if [ -n "$GERRIT_PROJECT" ] && [ "$GERRIT_PROJECT" != "voltctl" ]; then
+ IMAGE_TAG="citest"
+ case "$GERRIT_PROJECT" in
+ voltha-go)
+ HELM_FLAGS="$HELM_FLAGS --set voltha.image.tag=$IMAGE_TAG"
+ ;;
+ voltha-openolt-adapter)
+ HELM_FLAGS="$HELM_FLAGS --set voltha-adapter-openolt.image.tag=$IMAGE_TAG"
+ ;;
+ voltha-openonu-adapter-go)
+ HELM_FLAGS="$HELM_FLAGS --set voltha-adapter-openonu.image.tag=$IMAGE_TAG"
+ ;;
+ ofagent-go)
+ HELM_FLAGS="$HELM_FLAGS --set voltha.ofagent.image.tag=$IMAGE_TAG"
+ ;;
+ bbsim)
+ HELM_FLAGS="$HELM_FLAGS --set bbsim.image.tag=$IMAGE_TAG"
+ ;;
+ esac
+ fi
+
+ echo "Deploying VOLTHA with workflow: $WORKFLOW"
+ echo "Helm flags: $HELM_FLAGS"
+
+ if [ "$LOCAL_CHARTS" = "true" ]; then
+ echo "Using local charts from $GITHUB_WORKSPACE/voltha-helm-charts"
+ helm dependency update "$GITHUB_WORKSPACE/voltha-helm-charts/voltha-infra" || true
+ helm dependency update "$GITHUB_WORKSPACE/voltha-helm-charts/voltha-stack" || true
+ helm install voltha-infra "$GITHUB_WORKSPACE/voltha-helm-charts/voltha-infra" \
+ -n "$INFRA_NAMESPACE" --create-namespace --wait --timeout 120m
+ helm install voltha "$GITHUB_WORKSPACE/voltha-helm-charts/voltha-stack" \
+ -n "$VOLTHA_NAMESPACE" --create-namespace \
+ --set global.stack_name=voltha \
+ --set global.voltha_infra_name=voltha-infra \
+ --set global.voltha_infra_namespace="$INFRA_NAMESPACE" \
+ $(echo "$HELM_FLAGS") --wait --timeout 120m
+ else
+ echo "Using charts from Helm repository"
+ helm install voltha-infra onf/voltha-infra \
+ -n "$INFRA_NAMESPACE" --create-namespace --wait --timeout 120m
+ helm install voltha onf/voltha-stack \
+ -n "$VOLTHA_NAMESPACE" --create-namespace \
+ --set global.stack_name=voltha \
+ --set global.voltha_infra_name=voltha-infra \
+ --set global.voltha_infra_namespace="$INFRA_NAMESPACE" \
+ $(echo "$HELM_FLAGS") --wait --timeout 120m
+ fi
+
+ for i in $(seq 0 $((OLTS - 1))); do
+ echo "Deploying bbsim${i}..."
+ if [ "$LOCAL_CHARTS" = "true" ]; then
+ helm install "bbsim${i}" "$GITHUB_WORKSPACE/voltha-helm-charts/bbsim" \
+ -n "$VOLTHA_NAMESPACE" --set olt_id="${i}" --wait || true
+ else
+ helm install "bbsim${i}" onf/bbsim \
+ -n "$VOLTHA_NAMESPACE" --set olt_id="${i}" --wait || true
+ fi
+ done
+
+ if [ -n "${KAIL_PID:-}" ]; then
+ kill "$KAIL_PID" || true
+ wait "$KAIL_PID" 2>/dev/null || true
+ fi
+ gzip -f "$ONOS_LOG" || true
+
+ echo "Setting up port forwarding..."
+ kubectl port-forward --address 0.0.0.0 -n "$INFRA_NAMESPACE" svc/voltha-infra-kafka 9092:9092 &
+ bbsim_dmi_port=50075
+ for i in $(seq 0 $((OLTS - 1))); do
+ kubectl port-forward --address 0.0.0.0 -n "$VOLTHA_NAMESPACE" "svc/bbsim${i}" "${bbsim_dmi_port}:50075" &
+ ((bbsim_dmi_port++))
+ done
+ if [ "$WITH_MONITORING" = "true" ]; then
+ kubectl port-forward --address 0.0.0.0 -n default svc/nem-monitoring-prometheus-server 31301:80 &
+ fi
+ if [ "$VGC_ENABLED" = "true" ]; then
+ kubectl port-forward --address 0.0.0.0 -n "$VOLTHA_NAMESPACE" svc/voltha-voltha-go-controller 8181:8181 &
+ fi
+ sleep 5
+ fi
+
+ # Stage: Run Tests
+ banner "Running test ${TEST_TARGET} on workflow ${WORKFLOW}"
+ if [ "$WITH_MONITORING" = "true" ]; then
+ echo "Collecting initial memory consumption..."
+ mkdir -p "$GITHUB_WORKSPACE/voltha-pods-mem-consumption-${WORKFLOW}"
+ cd "$GITHUB_WORKSPACE/voltha-system-tests"
+ if [ -f "requirements.txt" ]; then
+ python3 -m venv .venv || true
+ source .venv/bin/activate || true
+ pip install -r requirements.txt || true
+ if [ -f "scripts/mem_consumption.py" ]; then
+ python scripts/mem_consumption.py \
+ -o "$GITHUB_WORKSPACE/voltha-pods-mem-consumption-${WORKFLOW}" \
+ -a 0.0.0.0:31301 -n "$VOLTHA_NAMESPACE" || true
+ fi
+ fi
+ fi
+
+ echo "Running Robot Framework tests..."
+ mkdir -p "$LOGS_DIR"
+ export ROBOT_MISC_ARGS="-d ${LOGS_DIR} ${EXTRA_ROBOT_ARGS}"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v ONOS_SSH_PORT:30115"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v ONOS_REST_PORT:30120"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v NAMESPACE:${VOLTHA_NAMESPACE}"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v INFRA_NAMESPACE:${INFRA_NAMESPACE}"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v container_log_dir:${LOGS_DIR}"
+ ROBOT_MISC_ARGS="${ROBOT_MISC_ARGS} -v logging:${TEST_LOGGING}"
+ export ROBOT_MISC_ARGS
+ export KVSTOREPREFIX="voltha/voltha_voltha"
+ cd "$GITHUB_WORKSPACE/voltha-system-tests"
+ make "${TEST_TARGET}" || TEST_RESULT=$?
+
+ get_pods_info "$LOGS_DIR"
+
+ if [ "$WITH_MONITORING" = "true" ]; then
+ echo "Collecting final memory consumption..."
+ cd "$GITHUB_WORKSPACE/voltha-system-tests"
+ source .venv/bin/activate || true
+ if [ -f "scripts/mem_consumption.py" ]; then
+ python scripts/mem_consumption.py \
+ -o "$GITHUB_WORKSPACE/voltha-pods-mem-consumption-${WORKFLOW}" \
+ -a 0.0.0.0:31301 -n "$VOLTHA_NAMESPACE" || true
+ fi
+ fi
+
+ echo "Compressing logs..."
+ cd "$LOGS_DIR"
+ gzip *-combined.log 2>/dev/null || true
+ banner "Test execution completed"
+ exit ${TEST_RESULT:-0}
+ EXECUTE_TEST_SCRIPT
+
+ chmod +x /tmp/execute_test.sh
+
+ - name: Execute tests
+ id: test-execution
+ shell: bash
+ run: |
+ echo "Executing tests..."
+
+ # Create logs directory
+ mkdir -p $GITHUB_WORKSPACE/logs
+ echo "results-path=$GITHUB_WORKSPACE/logs" >> $GITHUB_OUTPUT
+
+ # Parse test targets from YAML
+ cat > /tmp/test-targets.yaml <<'EOF'
+ ${{ inputs.test-targets }}
+ EOF
+
+ # Run each test target
+ python3 - <<'PYTHON_SCRIPT'
+ import yaml
+ import subprocess
+ import os
+ import sys
+
+ with open('/tmp/test-targets.yaml', 'r') as f:
+ tests = yaml.safe_load(f)
+
+ if not tests:
+ print("No tests defined")
+ sys.exit(0)
+
+ workspace = os.environ['GITHUB_WORKSPACE']
+ test_failures = []
+
+ for idx, test in enumerate(tests):
+ target = test.get('target', '')
+ workflow = test.get('workflow', '')
+ flags = test.get('flags', '')
+ teardown = test.get('teardown', True)
+ logging = test.get('logging', True)
+ vgc_enabled = test.get('vgcEnabled', False)
+
+ print(f"\n** -----------------------------------------------------------------------")
+ print(f"** Executing test {target} on workflow {workflow}")
+ print(f"** -----------------------------------------------------------------------\n")
+
+ # Set environment variables
+ env = os.environ.copy()
+ env['TEST_TARGET'] = target
+ env['WORKFLOW'] = workflow
+ env['TEST_FLAGS'] = flags
+ env['TEARDOWN'] = str(teardown).lower()
+ env['TEST_LOGGING'] = 'True' if logging else 'False'
+ env['VGC_ENABLED'] = 'true' if vgc_enabled else 'false'
+ env['INFRA_NAMESPACE'] = 'default'
+ env['VOLTHA_NAMESPACE'] = 'voltha'
+ env['LOGS_DIR'] = f"{workspace}/logs/{target}"
+ env['EXTRA_HELM_FLAGS'] = "${{ inputs.extra-helm-flags }}"
+ env['LOG_LEVEL'] = "${{ inputs.log-level }}"
+ env['DOCKER_REGISTRY'] = "${{ inputs.docker-registry }}"
+ env['OLTS'] = "${{ inputs.olts }}"
+ env['WITH_MONITORING'] = "${{ inputs.with-monitoring }}"
+ env['ENABLE_MAC_LEARNING'] = "${{ inputs.enable-mac-learning }}"
+ env['EXTRA_ROBOT_ARGS'] = "${{ inputs.extra-robot-args }}"
+ env['BRANCH'] = "${{ inputs.branch }}"
+ env['GERRIT_PROJECT'] = "${{ inputs.gerrit-project }}"
+
+ # Create logs directory for this test
+ os.makedirs(env['LOGS_DIR'], exist_ok=True)
+
+ # Execute the test using the inline script
+ script_path = "/tmp/execute_test.sh"
+
+ print(f"Running test script: {script_path}")
+
+ try:
+ result = subprocess.run(
+ ['/bin/bash', script_path],
+ env=env,
+ check=True
+ )
+ print(f"\nTest {target} completed successfully\n")
+ except subprocess.CalledProcessError as e:
+ print(f"\nTest {target} failed with exit code {e.returncode}\n")
+ test_failures.append(target)
+ # Continue with other tests
+ continue
+ except Exception as e:
+ print(f"\nTest {target} failed with exception: {e}\n")
+ test_failures.append(target)
+ continue
+
+ if test_failures:
+ print(f"\n** Failed tests: {', '.join(test_failures)}")
+ sys.exit(1)
+ else:
+ print("\n** All tests passed successfully")
+
+ PYTHON_SCRIPT
+
+ # -----------------------------------------------------------------------
+ # Collect artifacts
+ # -----------------------------------------------------------------------
+ - name: Collect pod information
+ if: always()
+ shell: bash
+ run: |
+ echo "Collecting pod information..."
+ mkdir -p $GITHUB_WORKSPACE/logs/artifacts
+
+ kubectl get pods --all-namespaces -o wide > $GITHUB_WORKSPACE/logs/artifacts/pods.txt || true
+ kubectl get nodes -o wide > $GITHUB_WORKSPACE/logs/artifacts/nodes.txt || true
+ kubectl get events --all-namespaces --sort-by='.lastTimestamp' > $GITHUB_WORKSPACE/logs/artifacts/events.txt || true
+
+ - name: Collect VOLTHA logs
+ if: always()
+ shell: bash
+ run: |
+ echo "Collecting VOLTHA logs..."
+ kubectl logs -n voltha -l app.kubernetes.io/part-of=voltha \
+ > $GITHUB_WORKSPACE/logs/artifacts/voltha.log || true
+
+ - name: Cleanup port-forward processes
+ if: always()
+ shell: bash
+ run: |
+ echo "Cleaning up port-forward processes..."
+ pkill -f "kubectl.*port-forward" || true
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: bbsim-test-results-${{ github.run_id }}
+ path: |
+ ${{ github.workspace }}/logs/**/*.log
+ ${{ github.workspace }}/logs/**/*.gz
+ ${{ github.workspace }}/logs/**/*.txt
+ ${{ github.workspace }}/logs/**/*.html
+ ${{ github.workspace }}/logs/**/*.xml
+ ${{ github.workspace }}/logs/**/voltha-pods-mem-consumption-*/*
+ retention-days: 30
+ if-no-files-found: warn
+
+ # -----------------------------------------------------------------------
+ # Cleanup
+ # -----------------------------------------------------------------------
+ - name: Delete kind cluster
+ if: always()
+ shell: bash
+ run: |
+ # Note: Cluster deletion is optional and can be controlled by workflow
+ echo "To delete cluster manually, run: kind delete cluster --name ${{ inputs.cluster-name }}"
diff --git a/.github/actions/bbsim-tests/example-workflow.yaml b/.github/actions/bbsim-tests/example-workflow.yaml
new file mode 100644
index 0000000..3654bb6
--- /dev/null
+++ b/.github/actions/bbsim-tests/example-workflow.yaml
@@ -0,0 +1,362 @@
+---
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: 2025 Open Networking Foundation Contributors
+
+name: BBSim Tests Example
+
+on:
+ # Run on push to main branches
+ push:
+ branches:
+ - master
+ - "voltha-*"
+
+ # Run on pull requests
+ pull_request:
+ branches:
+ - master
+ - "voltha-*"
+
+ # Allow manual triggering with custom parameters
+ workflow_dispatch:
+ inputs:
+ branch:
+ description: "Branch to test"
+ required: true
+ default: "master"
+ type: choice
+ options:
+ - master
+ - voltha-2.15
+ workflow_type:
+ description: "Workflow to test"
+ required: true
+ default: "all"
+ type: choice
+ options:
+ - all
+ - dt
+ - att
+ - tt
+ log_level:
+ description: "Log level"
+ required: false
+ default: "WARN"
+ type: choice
+ options:
+ - DEBUG
+ - INFO
+ - WARN
+ - ERROR
+ with_monitoring:
+ description: "Enable monitoring"
+ required: false
+ default: false
+ type: boolean
+
+ # Run nightly
+ schedule:
+ - cron: "0 2 * * *" # 2 AM UTC daily
+
+jobs:
+ # -----------------------------------------------------------------------
+ # Job: DT Workflow Tests
+ # -----------------------------------------------------------------------
+ dt-tests:
+ name: DT Workflow Tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 240
+ if: |
+ github.event_name == 'schedule' ||
+ (github.event_name == 'workflow_dispatch' &&
+ (github.event.inputs.workflow_type == 'dt' || github.event.inputs.workflow_type == 'all')) ||
+ github.event_name == 'push' ||
+ github.event_name == 'pull_request'
+
+ steps:
+ - name: Free up disk space
+ run: |
+ echo "Disk space before cleanup:"
+ df -h
+
+ # Remove unnecessary software
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ echo "Disk space after cleanup:"
+ df -h
+
+ - name: Run DT BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ github.event.inputs.branch || 'master' }}
+ log-level: ${{ github.event.inputs.log_level || 'WARN' }}
+ with-monitoring: ${{ github.event.inputs.with_monitoring || false }}
+ test-targets: |
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: dt-test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+
+ # -----------------------------------------------------------------------
+ # Job: ATT Workflow Tests
+ # -----------------------------------------------------------------------
+ att-tests:
+ name: ATT Workflow Tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 240
+ if: |
+ github.event_name == 'schedule' ||
+ (github.event_name == 'workflow_dispatch' &&
+ (github.event.inputs.workflow_type == 'att' || github.event.inputs.workflow_type == 'all'))
+
+ steps:
+ - name: Free up disk space
+ run: |
+ echo "Disk space before cleanup:"
+ df -h
+
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ echo "Disk space after cleanup:"
+ df -h
+
+ - name: Run ATT BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ github.event.inputs.branch || 'master' }}
+ log-level: ${{ github.event.inputs.log_level || 'WARN' }}
+ with-monitoring: ${{ github.event.inputs.with_monitoring || false }}
+ test-targets: |
+ - target: functional-single-kind-att
+ workflow: att
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: att-test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+
+ # -----------------------------------------------------------------------
+ # Job: TT Workflow Tests
+ # -----------------------------------------------------------------------
+ tt-tests:
+ name: TT Workflow Tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 240
+ if: |
+ github.event_name == 'schedule' ||
+ (github.event_name == 'workflow_dispatch' &&
+ (github.event.inputs.workflow_type == 'tt' || github.event.inputs.workflow_type == 'all'))
+
+ steps:
+ - name: Free up disk space
+ run: |
+ echo "Disk space before cleanup:"
+ df -h
+
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ echo "Disk space after cleanup:"
+ df -h
+
+ - name: Run TT BBSim Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ github.event.inputs.branch || 'master' }}
+ log-level: ${{ github.event.inputs.log_level || 'WARN' }}
+ with-monitoring: ${{ github.event.inputs.with_monitoring || false }}
+ test-targets: |
+ - target: functional-single-kind-tt
+ workflow: tt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: tt-test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+
+ # -----------------------------------------------------------------------
+ # Job: Multi-workflow Tests (run multiple workflows in sequence)
+ # -----------------------------------------------------------------------
+ multi-workflow-tests:
+ name: Multi-Workflow Tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 480
+ if: github.event_name == 'workflow_dispatch' && github.event.inputs.workflow_type == 'all'
+
+ steps:
+ - name: Free up disk space
+ run: |
+ echo "Disk space before cleanup:"
+ df -h
+
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ echo "Disk space after cleanup:"
+ df -h
+
+ - name: Run All Workflow Tests
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ github.event.inputs.branch || 'master' }}
+ log-level: ${{ github.event.inputs.log_level || 'INFO' }}
+ with-monitoring: true
+ olts: "2"
+ test-targets: |
+ - target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-dt
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-att
+ workflow: att
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+ - target: functional-single-kind-tt
+ workflow: tt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: multi-workflow-test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+
+ # -----------------------------------------------------------------------
+ # Job: Test Gerrit Patch
+ # -----------------------------------------------------------------------
+ test-patch:
+ name: Test Gerrit Patch
+ runs-on: ubuntu-latest
+ timeout-minutes: 240
+ # Only run when triggered manually with patch information
+ if: |
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.gerrit_project != '' &&
+ github.event.inputs.gerrit_refspec != ''
+
+ steps:
+ - name: Free up disk space
+ run: |
+ sudo rm -rf /usr/share/dotnet
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/share/boost
+ sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+
+ - name: Test Patch with BBSim
+ uses: opencord/shared-workflows/.github/actions/bbsim-tests@main
+ with:
+ branch: ${{ github.event.inputs.branch || 'master' }}
+ gerrit-project: ${{ github.event.inputs.gerrit_project }}
+ gerrit-refspec: ${{ github.event.inputs.gerrit_refspec }}
+ log-level: DEBUG
+ test-targets: |
+ - target: sanity-single-kind
+ workflow: dt
+ flags: ""
+ teardown: true
+ logging: true
+ vgcEnabled: false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: patch-test-results-${{ github.run_id }}
+ path: logs/
+ retention-days: 30
+
+ # -----------------------------------------------------------------------
+ # Job: Report Results
+ # -----------------------------------------------------------------------
+ report:
+ name: Test Results Summary
+ runs-on: ubuntu-latest
+ needs: [dt-tests, att-tests, tt-tests]
+ if: always()
+
+ steps:
+ - name: Download all artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: all-results
+
+ - name: Generate summary report
+ run: |
+ echo "# BBSim Test Results Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "## Test Execution" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
+ echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
+ echo "| DT Tests | ${{ needs.dt-tests.result }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| ATT Tests | ${{ needs.att-tests.result }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| TT Tests | ${{ needs.tt-tests.result }} |" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ # List available artifacts
+ echo "## Artifacts" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [ -d "all-results" ]; then
+ find all-results -type f -name "*.html" | while read file; do
+ echo "- $(basename $file)" >> $GITHUB_STEP_SUMMARY
+ done
+ fi
+
+ - name: Check overall status
+ run: |
+ if [[ "${{ needs.dt-tests.result }}" != "success" ]] || \
+ [[ "${{ needs.att-tests.result }}" != "success" && "${{ needs.att-tests.result }}" != "skipped" ]] || \
+ [[ "${{ needs.tt-tests.result }}" != "success" && "${{ needs.tt-tests.result }}" != "skipped" ]]; then
+ echo "One or more test jobs failed"
+ exit 1
+ fi
+ echo "All executed tests passed successfully"