Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/run-coverage/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "Run Coverage"
description: "Run code coverage collection and upload artifacts"
runs:
using: "composite"
steps:
- name: Install Task
shell: bash
run: |
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin

- name: Install reportgenerator
shell: bash
run: |
dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.4.12

- name: Build and run coverage
shell: bash
run: |
task coverage FRAMEWORK=net8.0
task coverage:summary >> $GITHUB_OUTPUT

- name: Upload coverage report artifact
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: reports/

- name: Upload coverage results artifact
uses: actions/upload-artifact@v4
with:
name: test-results
path: testresults/
6 changes: 4 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ on:
- main
- release-*
- v*
paths:
pull_request:
paths:
workflow_dispatch:
inputs:
full-matrix:
Expand Down Expand Up @@ -109,6 +107,10 @@ jobs:
redis-server --save "" --daemonize "yes"
./install_and_test.sh -no-tls -minimal -only-glide -data 1 -tasks 10 -csharp -dotnet-framework net${{ matrix.dotnet }}

- name: Run coverage
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs all tests second time. I propose to add a condition (like else) for test step (lines 97-99)

if: ${{ matrix.dotnet == '8.0' && contains(matrix.host.RUNNER, 'ubuntu') && matrix.host.ARCH == 'x64' && matrix.server.version == '8.1' }}
uses: ./.github/workflows/run-coverage

- name: Upload test reports
if: always()
continue-on-error: true
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ x64/
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# Code Coverage Reports
[Rr]eports/

*_i.c
*_p.c
*_i.h
Expand Down
237 changes: 237 additions & 0 deletions Taskfile.yml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update dev guide

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to have a discussion about taskfile usage as we have a lot of details in the developer guide that probably could move into the taskfile. Didn't want to do that until we discussed.

Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
version: "3"

vars:
TEST_RESULTS_DIR: testresults
REPORTS_DIR: reports
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider updating CI - it stores the report in the project root

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you want here. All reports are getting uploaded as artifacts correctly. I don't see anything to fix here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See CI job lines 97-99

COVERAGE_FILE: "{{.TEST_RESULTS_DIR}}/coverage.cobertura.xml"
UNIT_TEST_PROJECT: tests/Valkey.Glide.UnitTests/Valkey.Glide.UnitTests.csproj
INTEGRATION_TEST_PROJECT: tests/Valkey.Glide.IntegrationTests/Valkey.Glide.IntegrationTests.csproj
FRAMEWORK: '{{.FRAMEWORK | default "all"}}'
FRAMEWORK_FLAG: '{{if ne .FRAMEWORK "all"}}--framework {{.FRAMEWORK}}{{end}}'

tasks:
clean:
desc: Clean test results and reports directories
cmds:
- rm -rf {{.TEST_RESULTS_DIR}}
- rm -rf {{.REPORTS_DIR}}
- mkdir -p {{.TEST_RESULTS_DIR}}
- mkdir -p {{.REPORTS_DIR}}

install-tools:
desc: Install required tools for coverage reporting
cmds:
- dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.4.12
status:
- which reportgenerator

test:unit:
desc: Run unit tests only
deps: [clean]
cmds:
- dotnet test {{.UNIT_TEST_PROJECT}} --configuration Release --verbosity normal {{.FRAMEWORK_FLAG}}

test:integration:
desc: Run integration tests only
deps: [clean]
cmds:
- dotnet test {{.INTEGRATION_TEST_PROJECT}} --configuration Release --verbosity normal {{.FRAMEWORK_FLAG}}

test:coverage:unit:
desc: Run unit tests with coverage collection
deps: [clean]
cmds:
- dotnet test {{.UNIT_TEST_PROJECT}}
--configuration Release
--collect:"XPlat Code Coverage"
--results-directory {{.TEST_RESULTS_DIR}}
--logger trx
--logger "console;verbosity=detailed"
--logger "html;LogFileName=TestReport.html"
{{.FRAMEWORK_FLAG}}
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura

test:coverage:integration:
desc: Run integration tests with coverage collection
deps: [clean]
cmds:
- dotnet test {{.INTEGRATION_TEST_PROJECT}}
--configuration Release
--collect:"XPlat Code Coverage"
--results-directory {{.TEST_RESULTS_DIR}}
--logger trx
--logger "console;verbosity=detailed"
--logger "html;LogFileName=TestReport.html"
{{.FRAMEWORK_FLAG}}
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura

test:coverage:all:
desc: Run all tests with coverage collection
deps: [clean]
cmds:
- dotnet test
--configuration Release
--collect:"XPlat Code Coverage"
--results-directory {{.TEST_RESULTS_DIR}}
--logger trx
--logger "console;verbosity=detailed"
--logger "html;LogFileName=TestReport.html"
{{.FRAMEWORK_FLAG}}
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura

coverage:merge:
desc: Merge coverage files if multiple exist
cmds:
- |
COVERAGE_FILES=$(find {{.TEST_RESULTS_DIR}} -name "coverage.cobertura.xml" -type f)
if [ $(echo "$COVERAGE_FILES" | wc -l) -gt 1 ]; then
echo "Multiple coverage files found, merging..."
reportgenerator \
-reports:"{{.TEST_RESULTS_DIR}}/**/coverage.cobertura.xml" \
-targetdir:{{.TEST_RESULTS_DIR}} \
-reporttypes:Cobertura \
-assemblyfilters:"+Valkey.Glide*"
mv {{.TEST_RESULTS_DIR}}/Cobertura.xml {{.COVERAGE_FILE}}
else
echo "Single coverage file found, copying..."
cp $(echo "$COVERAGE_FILES" | head -1) {{.COVERAGE_FILE}}
fi

coverage:report:
desc: Generate HTML coverage report from collected data
deps: [install-tools, coverage:merge]
cmds:
- reportgenerator
-reports:{{.COVERAGE_FILE}}
-targetdir:{{.REPORTS_DIR}}
-reporttypes:"Html;JsonSummary"
-assemblyfilters:"+Valkey.Glide*"
-classfilters:"-*.Tests*"
- echo "Coverage report generated in {{.REPORTS_DIR}}/index.html"

coverage:summary:
desc: Display coverage summary from the report
cmds:
- |
if [ -f "{{.REPORTS_DIR}}/Summary.json" ]; then
echo "=== Coverage Summary ==="
LINE_COVERAGE=$(cat {{.REPORTS_DIR}}/Summary.json | jq -r '.summary.linecoverage')
BRANCH_COVERAGE=$(cat {{.REPORTS_DIR}}/Summary.json | jq -r '.summary.branchcoverage')
echo "Line Coverage: ${LINE_COVERAGE}%"
echo "Branch Coverage: ${BRANCH_COVERAGE}%"
else
echo "No coverage summary found. Run 'task coverage:report' first."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo "No coverage summary found. Run 'task coverage:report' first."
echo "No coverage summary found. Run 'task coverage:report' first."
exit 1

fi

coverage:
desc: Run all tests with coverage and generate HTML report
cmds:
- task: test:coverage:all
- task: coverage:report
- task: coverage:summary

coverage:unit:
desc: Run unit tests with coverage and generate HTML report
cmds:
- task: test:coverage:unit
- task: coverage:report
- task: coverage:summary

coverage:integration:
desc: Run integration tests with coverage and generate HTML report
cmds:
- task: test:coverage:integration
- task: coverage:report
- task: coverage:summary

benchmark:
desc: Run benchmarks with Redis server (FRAMEWORK must be net8.0 or net6.0)
dir: valkey-glide/benchmarks
cmds:
- redis-server --save "" --daemonize "yes"
- |
case "{{.FRAMEWORK}}" in
"net8.0"|"net6.0")
echo "Running benchmarks for {{.FRAMEWORK}}..."
./install_and_test.sh -no-tls -minimal -only-glide -data 1 -tasks 10 -csharp -dotnet-framework {{.FRAMEWORK}}

echo ""
echo "=== Benchmark Results ==="

# Find the most recent CSV results file
RESULTS_FILE=$(find results -name "*.csv" -type f -exec ls -t {} + | head -1)

if [ -f "$RESULTS_FILE" ]; then
echo "Results from: $RESULTS_FILE"
echo ""

# Parse and format CSV as 3 separate tables
echo "=== Table 1: Basic Performance Metrics ==="
awk -F',' '
BEGIN {
printf "%-10s %-8s %-10s %-8s %-12s\n", "Language", "Client", "Cluster", "Tasks", "TPS"
printf "%-10s %-8s %-10s %-8s %-12s\n", "--------", "------", "-------", "-----", "---"
}
NR > 1 && NF > 1 {
printf "%-10s %-8s %-10s %-8s %-12s\n", $1, $2, $3, $4, $7
}' "$RESULTS_FILE"

echo ""
echo "=== Table 2: GET (non-existing) Operation Metrics ==="
awk -F',' '
BEGIN {
printf "%-15s %-15s %-15s %-15s %-15s\n", "GET Avg (ms)", "GET Std Dev", "GET P50 (ms)", "GET P90 (ms)", "GET P99 (ms)"
printf "%-15s %-15s %-15s %-15s %-15s\n", "-----------", "-----------", "-----------", "-----------", "-----------"
}
NR > 1 && NF > 1 {
printf "%-15.3f %-15.6f %-15s %-15s %-15s\n", $11, $12, $8, $9, $10
}' "$RESULTS_FILE"

echo ""
echo "=== Table 3: GET (existing) Operation Metrics ==="
awk -F',' '
BEGIN {
printf "%-15s %-15s %-15s %-15s %-15s\n", "GET Avg (ms)", "GET Std Dev", "GET P50 (ms)", "GET P90 (ms)", "GET P99 (ms)"
printf "%-15s %-15s %-15s %-15s %-15s\n", "-----------", "-----------", "-----------", "-----------", "-----------"
}
NR > 1 && NF > 1 {
printf "%-15.3f %-15.6f %-15s %-15s %-15s\n", $16, $17, $13, $14, $15
}' "$RESULTS_FILE"

echo ""
echo "=== Table 4: SET Operation Metrics ==="
awk -F',' '
BEGIN {
printf "%-15s %-15s %-15s %-15s %-15s\n", "SET Avg (ms)", "SET Std Dev", "SET P50 (ms)", "SET P90 (ms)", "SET P99 (ms)"
printf "%-15s %-15s %-15s %-15s %-15s\n", "-----------", "-----------", "-----------", "-----------", "-----------"
}
NR > 1 && NF > 1 {
printf "%-15.3f %-15.6f %-15s %-15s %-15s\n", $21, $22, $18, $19, $20
}' "$RESULTS_FILE"
else
echo "No benchmark results found in results/ directory"
exit 1
fi
;;
*)
echo "Error: FRAMEWORK must be either 'net8.0' or 'net6.0', got '{{.FRAMEWORK}}'"
exit 1
;;
esac

build:
desc: Build the solution
cmds:
- dotnet build --configuration Release {{.FRAMEWORK_FLAG}}

test:
desc: Build and run all tests
deps: [build]
cmds:
- task: test:coverage:all

default:
desc: Default task - build and run coverage
cmds:
- task: build
- task: coverage
Loading