Skip to content

Commit ea08fde

Browse files
alegrey91ccoVeille
andauthored
tests(integration): add integration tests and test them with a pipeline (#34)
* tests(integration): add integration tests and test them with a dedicated pipeline --------- Signed-off-by: Alessio Greggi <[email protected]> Co-authored-by: ccoVeille <[email protected]>
1 parent 02cd5fd commit ea08fde

25 files changed

+757
-35
lines changed

.github/workflows/tests.yaml

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: tests
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
9+
jobs:
10+
unit-test:
11+
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
18+
with:
19+
go-version: '1.21'
20+
21+
- name: Install Dependencies
22+
run: |
23+
sudo apt update
24+
sudo apt install -y clang
25+
sudo apt install -y libbpf-dev
26+
sudo apt install -y libseccomp-dev
27+
28+
- name: Build coverage-instrumented binary
29+
run: |
30+
make build-static-libbpfgo
31+
make build-bpf
32+
33+
- name: Run Unit-Test
34+
run: |
35+
mkdir /tmp/unit/
36+
# test packages excluding the ones with libbpfgo
37+
go test \
38+
-cover \
39+
-v \
40+
$(go list ./... | grep -v "github.com/alegrey91/harpoon$" | grep -v ebpf | grep -v cmd) \
41+
-skip TestHarpoon \
42+
-args -test.gocoverdir=/tmp/unit/
43+
44+
- name: Upload cover profiles
45+
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
46+
with:
47+
name: unit-test
48+
path: /tmp/unit/
49+
50+
integration-test:
51+
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
55+
56+
- name: Set up Go
57+
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
58+
with:
59+
go-version: '1.21'
60+
61+
- name: Install Dependencies
62+
run: |
63+
sudo apt update
64+
sudo apt install -y clang
65+
sudo apt install -y libbpf-dev
66+
sudo apt install -y libseccomp-dev
67+
68+
- name: Build coverage-instrumented binary
69+
run: |
70+
make build-static-libbpfgo
71+
make build-bpf
72+
make build-go-cover && sudo make -B install
73+
74+
- name: Run integration test
75+
run: |
76+
mkdir -p /tmp/integration
77+
# we have to run integration tests one-by-one
78+
# otherwhise they will run in parallel.
79+
# since harpoon apply network forwards, these could
80+
# interact with each other and make the test fail.
81+
go test \
82+
-exec sudo \
83+
-cover \
84+
-v main_test.go \
85+
-args -test.gocoverdir=/tmp/integration/
86+
87+
- name: Upload cover profiles
88+
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
89+
with:
90+
name: integration-test
91+
path: /tmp/integration/
92+
93+
code-coverage:
94+
95+
runs-on: ubuntu-latest
96+
needs: [unit-test,integration-test]
97+
steps:
98+
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
99+
100+
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3
101+
with:
102+
name: unit-test
103+
path: /tmp/unit-test
104+
105+
- uses: actions/download-artifact@v3
106+
with:
107+
name: integration-test
108+
path: /tmp/integration-test
109+
110+
- name: list files
111+
run: |
112+
ls -lah /tmp/unit-test
113+
ls -lah /tmp/integration-test
114+
115+
- name: Set up Go
116+
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
117+
with:
118+
go-version: '1.21'
119+
120+
- name: Calculate total coverage
121+
run: |
122+
go tool \
123+
covdata \
124+
textfmt \
125+
-i=/tmp/unit-test,/tmp/integration-test \
126+
-o code-coverage
127+
go tool \
128+
cover \
129+
-func code-coverage

Makefile

+16
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ build-go: create-bin-dir
2626
-o ${BINARY_DIR}/${BINARY_NAME} \
2727
.
2828

29+
build-go-cover: create-bin-dir
30+
go mod download
31+
export CURRENT_DIR=$(shell pwd); \
32+
CC=gcc \
33+
CGO_CFLAGS="-I $$CURRENT_DIR/libbpfgo/output" \
34+
CGO_LDFLAGS="-lelf -lz $$CURRENT_DIR/libbpfgo/output/libbpf/libbpf.a" \
35+
go build \
36+
-tags core,ebpf \
37+
-v \
38+
-cover \
39+
-o ${BINARY_DIR}/${BINARY_NAME} \
40+
.
41+
2942
build: create-bin-dir vmlinux.h build-static-libbpfgo build-bpf
3043
go mod download
3144
export CURRENT_DIR=$(shell pwd); \
@@ -60,6 +73,9 @@ create-bin-dir:
6073
create-output-dir:
6174
mkdir -p ${OUTPUT_DIR}
6275

76+
install:
77+
cp ${BINARY_DIR}/${BINARY_NAME} /usr/local/bin/
78+
6379
clean:
6480
rm -rf ${OUTPUT_DIR}
6581
rm -rf ${BINARY_DIR}

cmd/analyze.go

+20-13
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,19 @@ import (
2828
"github.com/spf13/cobra"
2929
)
3030

31-
var excludedPaths []string
32-
var exclude string
33-
var saveAnalysis bool
31+
var (
32+
excludedPaths []string
33+
exclude string
34+
saveAnalysis bool
35+
)
3436

3537
// analyzeCmd represents the create args
3638
var analyzeCmd = &cobra.Command{
3739
Use: "analyze",
3840
Short: "Analyze infers the symbols of functions that are tested by unit-tests",
3941
Long: `
4042
`,
41-
Example: " harpoon analyze --exclude vendor/ /path/to/repo/",
43+
Example: " harpoon analyze --exclude vendor/ -s",
4244
RunE: func(cmd *cobra.Command, args []string) error {
4345
if exclude != "" {
4446
excludedPaths = strings.Split(exclude, ",")
@@ -85,12 +87,12 @@ var analyzeCmd = &cobra.Command{
8587
pkgPath := getPackagePath(path)
8688
testFile := filepath.Base(path)
8789
testFile = strings.ReplaceAll(testFile, "_test.go", ".test")
88-
_, err = executor.Build(pkgPath, ".harpoon/"+testFile)
90+
_, err = executor.Build(pkgPath, filepath.Join(".harpoon", testFile))
8991
if err != nil {
9092
return fmt.Errorf("failed to build test file: %v", err)
9193
}
9294

93-
symbolsOrig := metadata.NewSymbolsOrigin(".harpoon/" + testFile)
95+
symbolsOrig := metadata.NewSymbolsOrigin(filepath.Join(".harpoon", testFile))
9496

9597
fmt.Println("test: .harpoon/" + testFile)
9698
for _, symbol := range symbolNames {
@@ -125,13 +127,17 @@ var analyzeCmd = &cobra.Command{
125127
}
126128

127129
// store to file
128-
file, err = os.Create(".harpoon.yml")
129-
if err != nil {
130-
return fmt.Errorf("failed to create symbols list file: %w", err)
130+
if saveAnalysis {
131+
file, err = os.Create("harpoon-report.yml")
132+
if err != nil {
133+
return fmt.Errorf("failed to create symbols list file: %w", err)
134+
}
135+
mw := io.Writer(file)
136+
fmt.Fprintln(mw, symbolsList.String())
137+
fmt.Println("file harpoon-report.yml is ready")
138+
} else {
139+
fmt.Println(symbolsList.String())
131140
}
132-
mw := io.Writer(file)
133-
fmt.Fprintln(mw, symbolsList.String())
134-
fmt.Println("file .harpoon.yml is ready")
135141
return nil
136142
},
137143
}
@@ -140,7 +146,7 @@ func init() {
140146
rootCmd.AddCommand(analyzeCmd)
141147

142148
analyzeCmd.Flags().StringVarP(&exclude, "exclude", "e", "", "Skip directories specified in the comma separated list")
143-
analyzeCmd.Flags().BoolVarP(&saveAnalysis, "save", "s", false, "Save the result of analysis into a file")
149+
analyzeCmd.Flags().BoolVarP(&saveAnalysis, "save", "S", false, "Save the result of analysis into a file")
144150
}
145151

146152
func shouldSkipPath(path string) bool {
@@ -171,6 +177,7 @@ func getPackagePath(inputPath string) string {
171177
// Adjust this according to your specific requirements
172178
dirPath = strings.TrimPrefix(dirPath, "../")
173179
dirPath = strings.TrimPrefix(dirPath, "./")
180+
//dirPath = strings.TrimPrefix(inputPath, rootPath)
174181

175182
// Add "./" at the start again if necessary
176183
dirPath = "./" + dirPath

cmd/build.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ var buildCmd = &cobra.Command{
9696
func init() {
9797
rootCmd.AddCommand(buildCmd)
9898

99-
buildCmd.Flags().StringVarP(&inputDirectory, "directory", "D", "", "Directory containing harpoon's files")
99+
buildCmd.Flags().StringVarP(&inputDirectory, "directory", "D", "", "Directory containing harpoon's metadata files")
100100
buildCmd.MarkFlagRequired("directory")
101101

102-
buildCmd.Flags().BoolVarP(&saveProfile, "save-profile", "s", false, "Save profile to a file")
103-
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Save profile to a file")
102+
buildCmd.Flags().BoolVarP(&saveProfile, "save", "S", false, "Save profile to a file")
103+
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Specify a name for the seccomp profile")
104104
}

cmd/capture.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"fmt"
2020
"strings"
2121

22-
"github.com/alegrey91/harpoon/internal/captor"
22+
"github.com/alegrey91/harpoon/internal/ebpf/probesfacade/captor"
2323
"github.com/alegrey91/harpoon/internal/writer"
2424
"github.com/spf13/cobra"
2525
)

cmd/hunt.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"io"
2121
"os"
2222

23-
"github.com/alegrey91/harpoon/internal/captor"
23+
"github.com/alegrey91/harpoon/internal/ebpf/probesfacade/captor"
2424
meta "github.com/alegrey91/harpoon/internal/metadata"
2525
"github.com/alegrey91/harpoon/internal/writer"
2626
"github.com/spf13/cobra"
@@ -37,7 +37,7 @@ var huntCmd = &cobra.Command{
3737
Short: "Hunt is like capture but gets a list of functions to be traced",
3838
Long: `
3939
`,
40-
Example: " harpoon hunt --file .harpoon.yaml",
40+
Example: " harpoon hunt --file harpoon-report.yml",
4141
RunE: func(cmd *cobra.Command, args []string) error {
4242
file, err := os.Open(harpoonFile)
4343
if err != nil {
@@ -91,7 +91,7 @@ var huntCmd = &cobra.Command{
9191
func init() {
9292
rootCmd.AddCommand(huntCmd)
9393

94-
huntCmd.Flags().StringVarP(&harpoonFile, "file", "F", ".harpoon.yaml", "File with the result of analysis")
94+
huntCmd.Flags().StringVarP(&harpoonFile, "file", "F", "harpoon-report.yml", "File with the result of analysis")
9595
huntCmd.MarkFlagRequired("file")
9696

9797
huntCmd.Flags().BoolVarP(&commandOutput, "include-cmd-output", "c", false, "Include the executed command output")

docs/commands.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@ Harpoon has several commands that you can use.
44

55
The common way of using `harpoon` is to execute the available commands as follow:
66

7-
* [`harpoon analyze`](#analyze-) to analyze the project to infer symbols to be traced. This will create a `.harpoon.yml` file.
7+
* [`harpoon analyze`](#analyze) to infer symbols to be traced from the project root directory. This will create the `harpoon-report.yml` file.
88

9-
* [`harpoon hunt`](#hunt-) by passing the `.harpoon.yml` file to trace the functions and get their system calls. This will generate the `./harpoon/` directory with the metadata that contain the system calls traced.
9+
* [`harpoon hunt`](#hunt) by passing the `harpoon-report.yml` file to trace the functions and get their system calls. This will generate the `./harpoon/` directory with the metadata that contain the system calls traced.
1010

11-
* [`harpoon build`](#build-️) to read the metadata files and provide the **seccomp** profile.
11+
* [`harpoon build`](#build) to read the metadata files and provide the **seccomp** profile.
1212

1313
## Analyze
1414

1515
The `analyze` command is used to analyze the project's folder and get the list of function symbols you want to trace.
1616

1717
Additionally it automatically build the test binary and place them into the `harpoon/` directory.
1818

19-
The result of this command is the `.harpoon.yml` file with the list of test binaries followed by their function symbols that are currently tested.
19+
The result of this command is the `harpoon-report.yml` file with the list of test binaries followed by their function symbols that are currently tested.
2020

2121
Run it on your project folder:
2222

2323
```sh
24-
sudo harpoon analyze --exclude .git/ .
24+
sudo harpoon analyze --exclude .git/
2525
```
2626

2727
## Build
@@ -51,7 +51,7 @@ The command needs a file as input paramenter that is the result of the `analyze`
5151
This will loop over the entries of the file, capturing the system calls of each entry.
5252

5353
```sh
54-
harpoon hunt --file .harpoon.yml -S
54+
harpoon hunt --file harpoon-report.yml -S
5555
```
5656

57-
This will create the directory `harpoon/` with the list of system calls traced from the execution of the different test binaries present in the `.harpoon.yml` file.
57+
This will create the directory `harpoon/` with the list of system calls traced from the execution of the different test binaries present in the `harpoon-report.yml` file.

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ require (
1414
require (
1515
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1616
github.com/spf13/pflag v1.0.5 // indirect
17+
golang.org/x/tools v0.1.12 // indirect
1718
)
1819

1920
require (
21+
github.com/rogpeppe/go-internal v1.12.0
2022
github.com/spf13/cobra v1.8.0
2123
golang.org/x/sys v0.16.0 // indirect
2224
gopkg.in/yaml.v2 v2.4.0

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
99
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1010
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1111
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
12+
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
13+
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
1214
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
1315
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
1416
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
@@ -22,6 +24,8 @@ golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
2224
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
2325
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
2426
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
27+
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
28+
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
2529
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2630
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
2731
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

internal/captor/capture.go internal/ebpf/probesfacade/captor/capture.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import (
99
"sync"
1010
"unsafe"
1111

12+
probes "github.com/alegrey91/harpoon/internal/ebpf/probesfacade"
1213
embedded "github.com/alegrey91/harpoon/internal/embeddable"
1314
"github.com/alegrey91/harpoon/internal/executor"
14-
probes "github.com/alegrey91/harpoon/internal/probesfacade"
1515
bpf "github.com/aquasecurity/libbpfgo"
1616
)
1717

0 commit comments

Comments
 (0)