Skip to content

Commit

Permalink
feat(kcov): add code coverage support for tests + fuzzers (#193)
Browse files Browse the repository at this point in the history
* adds support for kcov (can be used in both unit tests and fuzzing)
* adds new fuzz docs on how to use it in docs/fuzzing.md
* updates gossip fuzzing code to support fuzzing the gossipService in the same process (prev we would only support fuzzing across the network)
* see scripts/kcov_test.sh for how to run kcov on tests
  • Loading branch information
0xNineteen authored Jul 18, 2024
1 parent c921f04 commit e05ca73
Show file tree
Hide file tree
Showing 32 changed files with 1,451 additions and 417 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,44 @@ jobs:
- name: test
run: zig build test

kcov_test:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{matrix.os}}
steps:
- name: checkout
uses: actions/checkout@v2
with:
submodules: recursive

- name: setup-zig
uses: goto-bus-stop/setup-zig@v1
with:
version: 0.13.0

- name: Set up dependencies
run: sudo apt-get update

- name: Install kcov
run: |
sudo apt-get install -y binutils-dev libssl-dev libcurl4-openssl-dev zlib1g-dev libdw-dev libiberty-dev
git clone https://github.com/SimonKagstrom/kcov.git
cd kcov
mkdir build
cd build
cmake ..
make
sudo make install
- name: Run kcov
run: |
bash scripts/kcov_test.sh
- name: Print coverage report
run: |
python parse_kcov.py kcov-output/test/coverage.json
benchmarks:
strategy:
matrix:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ zig-out/
data/

index_storage/
kcov-output

/gossip-dumps

Expand Down
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug Tests",
"program": "${workspaceFolder}/zig-out/bin/test",
"args": [],
"cwd": "${workspaceFolder}",
"preLaunchTask": "zig build"
}
]
}
13 changes: 13 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "zig build",
"type": "shell",
"command": "zig",
"args": [
"build"
],
}
]
}
79 changes: 79 additions & 0 deletions docs/fuzzing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# fuzzing documentation

supported components:
- gossip
- accountsdb

main code paths:
- `fuzz.zig` <- main entrypoint
- `gossip/fuzz_table.zig`
- `gossip/fuzz_service.zig`
- `accountsdb/fuzz.zig`
- `scripts/` <- kcov + fuzz bash scripts

kcov will give you coverage information on what was and was not fuzzed
- [https://github.com/SimonKagstrom/kcov](https://github.com/SimonKagstrom/kcov)

*note:* view the full script for helpful install instructions

![](imgs/2024-07-10-09-39-25.png)

![](imgs/2024-07-10-09-39-57.png)

## gossip

### service

gossip supports two types of fuzzing
- *option1*: sending fuzz packets to an arbitrary endpoint
- *option2*: sending fuzz packets directly to a sig client

![](imgs/2024-07-10-09-33-37.png)

example commands:
```bash
# <seed> <n_messages> <to_endpoint> (option1)
./zig-out/bin/fuzz gossip_service 10 4_000 127.0.0.1:8001

# <seed> <n_messages> (option2)
./zig-out/bin/fuzz gossip_service 10 4_000

# (run with random seed for inf)
./zig-out/bin/fuzz gossip_service
```

### table

you can also fuzz the `GossipTable` (see `src/gossip/table.zig`) for reads/writes/trims/remove-old-labels using the following:

example commands:
```bash
# <seed> <n_messages>
./zig-out/bin/fuzz gossip_table 10 4_000

# (run with random seed for inf)
./zig-out/bin/fuzz gossip_table
```

## accounts-db

the fuzzer does a few things
- runs the manager loop which flushes/cleans/shrinks/deletes account files in one thread
- another thread reads/writes accounts and verifies the data read is correct

the goal was to makes sure accounts-db was thread-safe for parallel access while also flushing/cleaning/purging

example command:
```bash
# <seed> <n_messages>
./zig-out/bin/fuzz accountsdb 10 4_000
# (run with random seed for inf)
./zig-out/bin/fuzz accountsdb
```

## running with kcov

commands to run:
- `bash scripts/kcov_fuzz_gossip_service.sh`
- `bash scripts/kcov_fuzz_gossip_table.sh`
- `bash scripts/kcov_fuzz_accountsdb.sh`
Binary file added docs/imgs/2024-07-10-09-33-37.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/imgs/2024-07-10-09-39-25.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/imgs/2024-07-10-09-39-57.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions parse_kcov.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json

# read path from cli
import sys
if len(sys.argv) != 2:
print("Usage: python parse_kcov.py <path_to_coverage.json>")
sys.exit(1)
coverage_path = sys.argv[1]

with open(coverage_path, "r") as f:
coverage = json.load(f)

max_path_length = max(len(file_info["file"]) for file_info in coverage["files"])

# order by coverage percentage
coverage["files"].sort(key=lambda x: float(x["percent_covered"]), reverse=False)

output = ""
for file_info in coverage["files"]:
path = file_info["file"]
path = path.split("sig/")[2]
file_coverage = float(file_info["percent_covered"])

# Determine the color based on the coverage percentage
if file_coverage < 50:
color = "\033[91m" # Red
elif file_coverage < 75:
color = "\033[93m" # Yellow
else:
color = "\033[92m" # Green

# Reset color
reset = "\033[0m"
output += f"{color}{path:<{max_path_length}} --- {file_coverage:>10}%{reset}\n"

print(output)
31 changes: 31 additions & 0 deletions scripts/kcov_fuzz_accountsdb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# to install kcov follow the instructions at:
# https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md
# to build on mac the following should work:
# ```
# cd /path/to/kcov/
# mkdir build
# cd build
# cmake ..
# make
# make install
# export PATH=$PATH:/path/to/kcov/build/src
# ```

echo "=> Clearing kcov-output directory"
rm -rf kcov-output
mkdir kcov-output

echo "=> Building Sig"
zig build

echo "=> Running kcov on accountsdb"
kcov \
--include-pattern=src/accountsdb/ \
# not sure why this is necessary with --include-pattern but it is
--exclude-pattern=$HOME/.cache \
kcov-output/ \
./zig-out/bin/fuzz accountsdb

# open report
echo "=> Opening kcov-output/index.html"
open kcov-output/index.html
30 changes: 30 additions & 0 deletions scripts/kcov_fuzz_gossip.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# to install kcov follow the instructions at:
# https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md
# to build on mac the following should work:
# ```
# cd /path/to/kcov/
# mkdir build
# cd build
# cmake ..
# make
# make install
# export PATH=$PATH:/path/to/kcov/build/src
# ```

echo "=> Clearing kcov-output directory"
rm -rf kcov-output
mkdir kcov-output

echo "=> Building Sig"
zig build

echo "=> Running kcov on gossip spy"
kcov \
--include-pattern=src/gossip/ \
--exclude-pattern=$HOME/.cache \
kcov-output/ \
./zig-out/bin/fuzz gossip_service 19 50_000

# open report
echo "=> Opening kcov-output/index.html"
open kcov-output/index.html
30 changes: 30 additions & 0 deletions scripts/kcov_fuzz_gossip_table.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# to install kcov follow the instructions at:
# https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md
# to build on mac the following should work:
# ```
# cd /path/to/kcov/
# mkdir build
# cd build
# cmake ..
# make
# make install
# export PATH=$PATH:/path/to/kcov/build/src
# ```

echo "=> Clearing kcov-output directory"
rm -rf kcov-output
mkdir kcov-output

echo "=> Building Sig"
zig build

echo "=> Running kcov on gossip spy"
kcov \
--include-pattern=src/gossip/ \
--exclude-pattern=$HOME/.cache \
kcov-output/ \
./zig-out/bin/fuzz gossip_table 19 50_000

# open report
echo "=> Opening kcov-output/index.html"
open kcov-output/index.html
29 changes: 29 additions & 0 deletions scripts/kcov_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# to install kcov follow the instructions at:
# https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md
# to build on mac the following should work:
# ```
# cd /path/to/kcov/
# mkdir build
# cd build
# cmake ..
# make
# make install
# export PATH=$PATH:/path/to/kcov/build/src
# ```

echo "=> Cleaning up"
rm -rf kcov-output
mkdir kcov-output

echo "=> Building Sig"
zig build

echo "=> Running kcov on tests"
kcov \
--include-pattern=src/ \
--exclude-pattern=$HOME/.cache \
kcov-output \
./zig-out/bin/test

echo "=> Opening kcov-output/index.html"
open kcov-output/index.html || echo "=> Failed to open kcov-output/index.html"
Loading

0 comments on commit e05ca73

Please sign in to comment.