Skip to content

Commit

Permalink
tests(integration): add integration tests and test them with a pipeli…
Browse files Browse the repository at this point in the history
…ne (#34)

* tests(integration): add integration tests and test them with a dedicated pipeline

---------

Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
Co-authored-by: ccoVeille <3875889+ccoVeille@users.noreply.github.com>
  • Loading branch information
alegrey91 and ccoVeille committed Aug 12, 2024
1 parent 02cd5fd commit ea08fde
Show file tree
Hide file tree
Showing 25 changed files with 757 additions and 35 deletions.
129 changes: 129 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: tests

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
unit-test:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'

- name: Install Dependencies
run: |
sudo apt update
sudo apt install -y clang
sudo apt install -y libbpf-dev
sudo apt install -y libseccomp-dev
- name: Build coverage-instrumented binary
run: |
make build-static-libbpfgo
make build-bpf
- name: Run Unit-Test
run: |
mkdir /tmp/unit/
# test packages excluding the ones with libbpfgo
go test \
-cover \
-v \
$(go list ./... | grep -v "github.com/alegrey91/harpoon$" | grep -v ebpf | grep -v cmd) \
-skip TestHarpoon \
-args -test.gocoverdir=/tmp/unit/
- name: Upload cover profiles
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
with:
name: unit-test
path: /tmp/unit/

integration-test:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'

- name: Install Dependencies
run: |
sudo apt update
sudo apt install -y clang
sudo apt install -y libbpf-dev
sudo apt install -y libseccomp-dev
- name: Build coverage-instrumented binary
run: |
make build-static-libbpfgo
make build-bpf
make build-go-cover && sudo make -B install
- name: Run integration test
run: |
mkdir -p /tmp/integration
# we have to run integration tests one-by-one
# otherwhise they will run in parallel.
# since harpoon apply network forwards, these could
# interact with each other and make the test fail.
go test \
-exec sudo \
-cover \
-v main_test.go \
-args -test.gocoverdir=/tmp/integration/
- name: Upload cover profiles
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
with:
name: integration-test
path: /tmp/integration/

code-coverage:

runs-on: ubuntu-latest
needs: [unit-test,integration-test]
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3

- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3
with:
name: unit-test
path: /tmp/unit-test

- uses: actions/download-artifact@v3
with:
name: integration-test
path: /tmp/integration-test

- name: list files
run: |
ls -lah /tmp/unit-test
ls -lah /tmp/integration-test
- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'

- name: Calculate total coverage
run: |
go tool \
covdata \
textfmt \
-i=/tmp/unit-test,/tmp/integration-test \
-o code-coverage
go tool \
cover \
-func code-coverage
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ build-go: create-bin-dir
-o ${BINARY_DIR}/${BINARY_NAME} \
.

build-go-cover: create-bin-dir
go mod download
export CURRENT_DIR=$(shell pwd); \
CC=gcc \
CGO_CFLAGS="-I $$CURRENT_DIR/libbpfgo/output" \
CGO_LDFLAGS="-lelf -lz $$CURRENT_DIR/libbpfgo/output/libbpf/libbpf.a" \
go build \
-tags core,ebpf \
-v \
-cover \
-o ${BINARY_DIR}/${BINARY_NAME} \
.

build: create-bin-dir vmlinux.h build-static-libbpfgo build-bpf
go mod download
export CURRENT_DIR=$(shell pwd); \
Expand Down Expand Up @@ -60,6 +73,9 @@ create-bin-dir:
create-output-dir:
mkdir -p ${OUTPUT_DIR}

install:
cp ${BINARY_DIR}/${BINARY_NAME} /usr/local/bin/

clean:
rm -rf ${OUTPUT_DIR}
rm -rf ${BINARY_DIR}
Expand Down
33 changes: 20 additions & 13 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ import (
"github.com/spf13/cobra"
)

var excludedPaths []string
var exclude string
var saveAnalysis bool
var (
excludedPaths []string
exclude string
saveAnalysis bool
)

// analyzeCmd represents the create args
var analyzeCmd = &cobra.Command{
Use: "analyze",
Short: "Analyze infers the symbols of functions that are tested by unit-tests",
Long: `
`,
Example: " harpoon analyze --exclude vendor/ /path/to/repo/",
Example: " harpoon analyze --exclude vendor/ -s",
RunE: func(cmd *cobra.Command, args []string) error {
if exclude != "" {
excludedPaths = strings.Split(exclude, ",")
Expand Down Expand Up @@ -85,12 +87,12 @@ var analyzeCmd = &cobra.Command{
pkgPath := getPackagePath(path)
testFile := filepath.Base(path)
testFile = strings.ReplaceAll(testFile, "_test.go", ".test")
_, err = executor.Build(pkgPath, ".harpoon/"+testFile)
_, err = executor.Build(pkgPath, filepath.Join(".harpoon", testFile))
if err != nil {
return fmt.Errorf("failed to build test file: %v", err)
}

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

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

// store to file
file, err = os.Create(".harpoon.yml")
if err != nil {
return fmt.Errorf("failed to create symbols list file: %w", err)
if saveAnalysis {
file, err = os.Create("harpoon-report.yml")
if err != nil {
return fmt.Errorf("failed to create symbols list file: %w", err)
}
mw := io.Writer(file)
fmt.Fprintln(mw, symbolsList.String())
fmt.Println("file harpoon-report.yml is ready")
} else {
fmt.Println(symbolsList.String())
}
mw := io.Writer(file)
fmt.Fprintln(mw, symbolsList.String())
fmt.Println("file .harpoon.yml is ready")
return nil
},
}
Expand All @@ -140,7 +146,7 @@ func init() {
rootCmd.AddCommand(analyzeCmd)

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

func shouldSkipPath(path string) bool {
Expand Down Expand Up @@ -171,6 +177,7 @@ func getPackagePath(inputPath string) string {
// Adjust this according to your specific requirements
dirPath = strings.TrimPrefix(dirPath, "../")
dirPath = strings.TrimPrefix(dirPath, "./")
//dirPath = strings.TrimPrefix(inputPath, rootPath)

// Add "./" at the start again if necessary
dirPath = "./" + dirPath
Expand Down
6 changes: 3 additions & 3 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ var buildCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(buildCmd)

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

buildCmd.Flags().BoolVarP(&saveProfile, "save-profile", "s", false, "Save profile to a file")
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Save profile to a file")
buildCmd.Flags().BoolVarP(&saveProfile, "save", "S", false, "Save profile to a file")
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Specify a name for the seccomp profile")
}
2 changes: 1 addition & 1 deletion cmd/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"fmt"
"strings"

"github.com/alegrey91/harpoon/internal/captor"
"github.com/alegrey91/harpoon/internal/ebpf/probesfacade/captor"
"github.com/alegrey91/harpoon/internal/writer"
"github.com/spf13/cobra"
)
Expand Down
6 changes: 3 additions & 3 deletions cmd/hunt.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"io"
"os"

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

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

huntCmd.Flags().BoolVarP(&commandOutput, "include-cmd-output", "c", false, "Include the executed command output")
Expand Down
14 changes: 7 additions & 7 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ Harpoon has several commands that you can use.

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

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

* [`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.
* [`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.

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

## Analyze

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

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

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.
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.

Run it on your project folder:

```sh
sudo harpoon analyze --exclude .git/ .
sudo harpoon analyze --exclude .git/
```

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

```sh
harpoon hunt --file .harpoon.yml -S
harpoon hunt --file harpoon-report.yml -S
```

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.
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.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ require (
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/tools v0.1.12 // indirect
)

require (
github.com/rogpeppe/go-internal v1.12.0
github.com/spf13/cobra v1.8.0
golang.org/x/sys v0.16.0 // indirect
gopkg.in/yaml.v2 v2.4.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
Expand All @@ -22,6 +24,8 @@ golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"sync"
"unsafe"

probes "github.com/alegrey91/harpoon/internal/ebpf/probesfacade"
embedded "github.com/alegrey91/harpoon/internal/embeddable"
"github.com/alegrey91/harpoon/internal/executor"
probes "github.com/alegrey91/harpoon/internal/probesfacade"
bpf "github.com/aquasecurity/libbpfgo"
)

Expand Down
Loading

0 comments on commit ea08fde

Please sign in to comment.