Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fd38d4e
Create L1_L2_CoverageReport
nhanasi Jul 15, 2026
e9d12a1
Rename L1_L2_CoverageReport to L1_L2_CoverageReport.yml
nhanasi Jul 15, 2026
f558f4e
Update L1_L2_CoverageReport.yml
nhanasi Jul 15, 2026
cd9e0b6
Update L1_L2_CoverageReport.yml
nhanasi Jul 16, 2026
dbfdc30
Update L1_L2_CoverageReport.yml
nhanasi Jul 16, 2026
82ddb48
Update L1_L2_CoverageReport.yml
nhanasi Jul 16, 2026
36c8812
Update L1_L2_CoverageReport.yml
nhanasi Jul 20, 2026
39d4401
Update L1_L2_CoverageReport.yml
nhanasi Jul 21, 2026
8af2bec
Update L1_L2_CoverageReport.yml
nhanasi Jul 21, 2026
701dbcc
Update L1_L2_CoverageReport.yml
nhanasi Jul 22, 2026
46c58f4
Update L1_L2_CoverageReport.yml
nhanasi Jul 22, 2026
56c3a98
Update L1_L2_CoverageReport.yml
nhanasi Jul 22, 2026
39479e3
Update L1_L2_CoverageReport.yml
nhanasi Jul 23, 2026
40ea4f4
Update L1_L2_CoverageReport.yml
nhanasi Jul 23, 2026
a2e91a9
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
3bd9a2c
Merge a2e91a9aa5f937292f5308bdbaf48a48c40c61cf into 3e333b86526c5d1e0…
nhanasi Jul 24, 2026
938bb05
docs(coverage): refresh L1/L2 coverage for PR #217
github-actions[bot] Jul 24, 2026
1d87c4c
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
6bcec06
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
118338c
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
4677e85
Update code-coverage.yml
nhanasi Jul 24, 2026
39e8b01
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
795d149
Create update_coverage_docs.py
nhanasi Jul 24, 2026
c05ed43
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
be19a2e
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
da55b5d
Update L1_L2_CoverageReport.yml
nhanasi Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 271 additions & 0 deletions .github/workflows/L1_L2_CoverageReport.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
name: L1 and L2 Coverage Report

on:
workflow_run:
workflows: ["Code Coverage"]
types: [completed]

permissions:
contents: write
pull-requests: write
Comment on lines +8 to +10
Comment on lines +8 to +10

jobs:
l2-coverage:
name: L2 functional coverage metrics
runs-on: ubuntu-latest

Comment on lines +13 to +16
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}

- name: Pull required docker images
run: |
docker pull ghcr.io/rdkcentral/docker-device-mgt-service-test/mockxconf:latest
docker pull ghcr.io/rdkcentral/docker-device-mgt-service-test/native-platform:latest

- name: Start mockxconf and native-platform containers
run: |
docker run -d --name mockxconf -p 50050:50050 -p 50051:50051 -p 50052:50052 -p 50054:50054 -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/mockxconf:latest
docker run -d --name native-platform --link mockxconf -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/native-platform:latest
Comment on lines +23 to +31

- name: Build and run L2 tests
run: |
docker exec -i native-platform /bin/bash -c "cd /mnt/L2_CONTAINER_SHARED_VOLUME && sh cov_build.sh && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/local/lib && sh run_l2.sh"

- name: Copy L2 reports to runner
run: |
docker cp native-platform:/tmp/rfc_test_report /tmp/L2_TEST_RESULTS
ls -l /tmp/L2_TEST_RESULTS

- name: Extract L2 metrics
shell: bash
run: |
set -euo pipefail

feature_files=$(find test/functional-tests/features -name '*.feature' | wc -l | tr -d ' ')
feature_scenarios=$(grep -R "^[[:space:]]*Scenario:" test/functional-tests/features/ | wc -l | tr -d ' ')
feature_scenarios_disabled=$(grep -R "^[[:space:]]*#[[:space:]]*Scenario:" test/functional-tests/features/ | wc -l | tr -d ' ' || true)

test_files=$(find test/functional-tests/tests -maxdepth 1 -name 'test_*.py' | wc -l | tr -d ' ')
test_functions=$(grep -R "^def test_" test/functional-tests/tests/ | wc -l | tr -d ' ')
test_functions_disabled=$(grep -R "^[[:space:]]*#[[:space:]]*def test_" test/functional-tests/tests/ | wc -l | tr -d ' ' || true)

src_functions=$(grep -R "^[A-Za-z_][A-Za-z0-9_[:space:]\*]*([^;]*)[[:space:]]*{" rfcMgr/ rfcapi/ tr181api/ utils/ --include='*.cpp' --include='*.c' | wc -l | tr -d ' ')

# Parse L2 JSON results first so pass count can drive coverage formula
python3 - <<'PY' > /tmp/l2_runtime.env
import glob
import json

totals = {"collected": 0, "passed": 0, "failed": 0, "skipped": 0}
for path in glob.glob("/tmp/L2_TEST_RESULTS/*.json"):
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
s = data.get("summary", {})
totals["collected"] += int(s.get("collected", s.get("total", 0) or 0))
totals["passed"] += int(s.get("passed", 0) or 0)
totals["failed"] += int(s.get("failed", 0) or 0)
totals["skipped"] += int(s.get("skipped", 0) or 0)
except Exception:
continue

print(f"L2_COLLECTED={totals['collected']}")
print(f"L2_PASSED={totals['passed']}")
print(f"L2_FAILED={totals['failed']}")
print(f"L2_SKIPPED={totals['skipped']}")
PY

# Source the results so L2_PASSED is available for the coverage formula
# shellcheck source=/dev/null
source /tmp/l2_runtime.env

# Coverage = tests that actually passed / total feature scenarios
# (not 100% just because every scenario has a test function)
functional_coverage_pct=$(awk -v passed="$L2_PASSED" -v total="$feature_scenarios" 'BEGIN { if (total > 0) printf "%.2f", (passed/total)*100; else print "0.00" }')
gap_to_100_pct=$(awk -v cov="$functional_coverage_pct" 'BEGIN { printf "%.2f", 100-cov }')

{
echo "FEATURE_FILES=$feature_files"
echo "FEATURE_SCENARIOS=$feature_scenarios"
echo "FEATURE_SCENARIOS_DISABLED=$feature_scenarios_disabled"
echo "TEST_FILES=$test_files"
echo "TEST_FUNCTIONS=$test_functions"
echo "TEST_FUNCTIONS_DISABLED=$test_functions_disabled"
echo "SRC_FUNCTIONS_APPROX=$src_functions"
echo "FUNCTIONAL_COVERAGE_PCT=$functional_coverage_pct"
echo "GAP_TO_100_PCT=$gap_to_100_pct"
cat /tmp/l2_runtime.env
} > l2_metrics.env

{
echo "## L2 Coverage Summary"
echo ""
echo "| Metric | Value |"
echo "|---|---:|"
echo "| Feature files | $feature_files |"
echo "| Feature scenarios | $feature_scenarios |"
echo "| Test files | $test_files |"
echo "| Test functions | $test_functions |"
echo "| L2 collected | $L2_COLLECTED |"
echo "| L2 passed | $L2_PASSED |"
echo "| L2 failed | $L2_FAILED |"
echo "| L2 skipped | $L2_SKIPPED |"
echo "| Estimated functional coverage | $functional_coverage_pct% |"
echo "| Gap to 100% functional coverage | $gap_to_100_pct% |"
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload L2 per-test JSON reports
uses: actions/upload-artifact@v4
with:
name: l2-test-reports
path: /tmp/L2_TEST_RESULTS
if-no-files-found: warn

- name: Upload L2 metrics
uses: actions/upload-artifact@v4
with:
name: l2-metrics
path: l2_metrics.env

update-docs:
name: Update L1/L2 coverage markdowns
runs-on: ubuntu-latest
needs: [l2-coverage]
# Only update docs when code-coverage.yml succeeded (l1-metrics exists)
if: ${{ github.event.workflow_run.conclusion == 'success' }}
Comment on lines +133 to +138

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0

- name: Download L1 metrics
Comment on lines +141 to +147
uses: actions/download-artifact@v4
with:
name: l1-metrics
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: ci-artifacts/l1

- name: Download L2 metrics
Comment on lines +147 to +155
uses: actions/download-artifact@v4
with:
name: l2-metrics
path: ci-artifacts/l2

- name: Download L2 per-test JSON reports
uses: actions/download-artifact@v4
with:
name: l2-test-reports
path: ci-artifacts/l2-reports

- name: Regenerate L1 and L2 markdown docs
shell: bash
run: |
set -euo pipefail
python3 test/scripts/update_coverage_docs.py \
--reports-dir ci-artifacts/l2-reports \
--l1-env ci-artifacts/l1/l1_metrics.env \
--l2-env ci-artifacts/l2/l2_metrics.env
Comment on lines +171 to +174

- name: Commit docs to PR branch (same-repo PRs only)
id: commit_docs
if: ${{ github.event.workflow_run.head_repository.full_name == github.repository }}
shell: bash
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

git add test/docs/L1_Analysis_Report.md test/docs/L2_Analysis_Report.md
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi

git commit -m "docs(coverage): refresh L1/L2 coverage for PR #${{ github.event.workflow_run.pull_requests[0].number }}"
git push origin HEAD:${{ github.event.workflow_run.head_branch }}
echo "changed=true" >> "$GITHUB_OUTPUT"

- name: Build PR comment body
shell: bash
run: |
set -euo pipefail
source ci-artifacts/l1/l1_metrics.env
source ci-artifacts/l2/l2_metrics.env
DOC_STATUS="updated in PR branch"
if [ "${{ github.event.workflow_run.head_repository.full_name }}" != "${{ github.repository }}" ]; then
DOC_STATUS="not auto-committed (fork PR)"
elif [ "${{ steps.commit_docs.outputs.changed || 'false' }}" = "false" ]; then
DOC_STATUS="no doc changes detected"
fi

# Extract the CI-generated component table from the updated doc
COMPONENT_TABLE=$(python3 - <<'PY'
import re, sys
with open("test/docs/L2_Analysis_Report.md", "r") as f:
content = f.read()
m = re.search(r"<!-- CI-GENERATED-START -->\n(.*?)\n<!-- CI-GENERATED-END -->", content, re.DOTALL)
print(m.group(1) if m else "_Component table not available_")
PY
)

{
printf '<!-- pr-coverage-report -->\n'
printf '## PR Coverage Summary\n\n'
printf '### L1 Code Coverage\n'
printf '| Metric | Value |\n'
printf '|---|---:|\n'
printf '| Line coverage | %s%%%% (%s / %s) |\n' "${LINE_PCT}" "${LINE_HIT}" "${LINE_TOTAL}"
printf '| Function coverage | %s%%%% (%s / %s) |\n' "${FUNC_PCT}" "${FUNC_HIT}" "${FUNC_TOTAL}"
printf '\n### L2 Functional Coverage by Component\n'
printf '%s\n' "${COMPONENT_TABLE}"
printf '\nCoverage docs status: **%s**\n' "${DOC_STATUS}"
printf 'Updated: `test/docs/L1_Analysis_Report.md` . `test/docs/L2_Analysis_Report.md`\n'
} > /tmp/pr_coverage_comment.md

cat /tmp/pr_coverage_comment.md >> "$GITHUB_STEP_SUMMARY"

- name: Upsert PR coverage comment
uses: actions/github-script@v7
env:
COMMENT_PATH: /tmp/pr_coverage_comment.md
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
with:
script: |
const fs = require('fs');
const body = fs.readFileSync(process.env.COMMENT_PATH, 'utf8');
const marker = '<!-- pr-coverage-report -->';
const issue_number = parseInt(process.env.PR_NUMBER);
if (!issue_number) { console.log('No PR number — skipping comment'); return; }

const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number
});

const existing = comments.find(c =>
c.user && c.user.type === 'Bot' && c.body && c.body.includes(marker)
);

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
body
});
}
30 changes: 30 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,36 @@ jobs:
run: |
sh run_ut.sh --enable-cov

- name: Parse coverage and upload l1-metrics
shell: bash
run: |
set -euo pipefail
COV_FILE="rfcMgr/gtest/coverage.info"
SUMMARY="$(lcov --summary "$COV_FILE" 2>&1)"

line_pct="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*lines\.*:[[:space:]]*\([0-9.]*\)%.*/\1/p' | head -n1)"
line_hit="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*lines\.*:[[:space:]]*[0-9.]*% (\([0-9]*\) of [0-9]*.*/\1/p' | head -n1)"
line_total="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*lines\.*:[[:space:]]*[0-9.]*% ([0-9]* of \([0-9]*\).*/\1/p' | head -n1)"
func_pct="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*functions\.*:[[:space:]]*\([0-9.]*\)%.*/\1/p' | head -n1)"
func_hit="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*functions\.*:[[:space:]]*[0-9.]*% (\([0-9]*\) of [0-9]*.*/\1/p' | head -n1)"
func_total="$(echo "$SUMMARY" | sed -n 's/^[[:space:]]*functions\.*:[[:space:]]*[0-9.]*% ([0-9]* of \([0-9]*\).*/\1/p' | head -n1)"

{
echo "LINE_PCT=$line_pct"
echo "LINE_HIT=$line_hit"
echo "LINE_TOTAL=$line_total"
echo "FUNC_PCT=$func_pct"
echo "FUNC_HIT=$func_hit"
echo "FUNC_TOTAL=$func_total"
} > l1_metrics.env

- name: Upload l1-metrics
uses: actions/upload-artifact@v4
with:
name: l1-metrics
path: l1_metrics.env
if-no-files-found: error

- name: Caculate the code coverage summary
run: |
cd ./rfcMgr/gtest
Expand Down
23 changes: 23 additions & 0 deletions test/docs/L1_Test_Coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# RFC L1 Coverage Report

**Generated:** 2026-07-24
**Component:** `rfc`
**Source:** PR pipeline coverage run

---

## Executive Summary

| Metric | Value |
|---|---:|
| Line coverage | 81.6% (1893 / 2320) |
| Function coverage | 93.2% (124 / 133) |
| Unit test framework | GoogleTest |

---

## Notes

- Coverage is generated by running `sh run_ut.sh --enable-cov`.
- Source artifact: `rfcMgr/gtest/coverage.info`.
- This file is updated automatically on pull requests.
Comment on lines +21 to +23
53 changes: 53 additions & 0 deletions test/docs/L2_Test_Coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# RFC L2 Test Coverage Report

**Generated:** 2026-07-24
**Component:** `rfc`
**Test Suite:** `test/functional-tests`

---

## Executive Summary

| Metric | Count |
|---|---:|
| Feature files | 19 |
| Feature scenarios | 35 |
| Disabled feature scenarios | 0 |
| Test files (pytest) | 19 |
| Test functions (`def test_*`) | 35 |
| Disabled test functions | 0 |
| Approx source functions | 232 |
| L2 collected tests | 30 |
| L2 passed tests | 22 |
| L2 failed tests | 8 |
| L2 skipped tests | 0 |
| Estimated functional coverage | 62.86% |
| Gap to 100% functional coverage | 37.14% |

---

## Gap Highlights

Coverage focus areas to improve:
- XConf communication error/retry flows
- mTLS certificate selection negative branches
- IARM bus startup and failure branches
- RFC parameter set/get edge cases

---

## Progress To 100% Functional Coverage

- Current estimated functional coverage: **62.86%**
- Remaining gap to target (100%): **37.14%**
- L2 failed tests: **8**

> Coverage estimate formula used by CI in this report:
> `(L2 Passed Tests / Feature Scenarios) * 100`

---

## Notes

- L2 results are generated by `run_l2.sh` in the PR workflow.
- This file is refreshed automatically on pull requests.
Comment on lines +52 to +53
Loading
Loading