Skip to content

Commit

Permalink
test: add unit tests and add code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
pratikjagrut committed Oct 4, 2023
1 parent f8a98bf commit a85a8e4
Show file tree
Hide file tree
Showing 28 changed files with 1,035 additions and 122 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ jobs:
with:
args: -v --config=.golangci.yml

unit-test:
runs-on: ubuntu-latest
env:
GOPATH: ${{ github.workspace }}/../go
HOME: ${{ github.workspace }}/..
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: "stable"
- name: Install dependencies
run: make ebpf generate
- name: Run unit tests
run: make unit-test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
verbose: true # optional (default = false)

test-k8s:
runs-on: ubuntu-latest
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
/pkg/**/capture_exec.bpf.o
/pkg/tarianpb/api.pb.go
/pkg/tarianpb/types.pb.go
coverage.xml
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,17 @@ push-local-images:
docker push localhost:5000/tarian-node-agent

unit-test:
CGO_CFLAGS=$(CGO_CFLAGS_STATIC) CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) go test -v -race -count=1 ./pkg/...
CGO_CFLAGS=$(CGO_CFLAGS_STATIC) CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) go test -v -race -coverprofile=coverage.xml -covermode=atomic ./pkg/... ./cmd/...

e2e-test:
CGO_CFLAGS=$(CGO_CFLAGS_STATIC) CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) go test -v -race -count=1 ./test/e2e/...

k8s-test:
./test/k8s/test.sh

coverage: unit-test
go tool cover -html=coverage.xml

manifests: bin/controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) webhook paths="./pkg/clusteragent/..." output:webhook:artifacts:config=dev/config/webhook

Expand Down
232 changes: 232 additions & 0 deletions cmd/tarianctl/cmd/add/action_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package add

import (
"net"
"strings"
"testing"

"github.com/kube-tarian/tarian/cmd/tarianctl/cmd/flags"
ugrpc "github.com/kube-tarian/tarian/cmd/tarianctl/util/grpc"
"github.com/kube-tarian/tarian/pkg/log"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
)

func TestActionCommand_Run(t *testing.T) {
// t.Parallel()
tests := []struct {
name string
expectedErr string
expectedLog string

grpcClient ugrpc.Client
dryRun bool
onViolatedFile bool
onViolatedProcess bool
matchLabels []string
action string
onFalcoAlert string
}{
{
name: "Add Action Successfully",
grpcClient: ugrpc.NewFakeGrpcClient(),
action: "delete-pod",
expectedLog: "Action was added successfully",
},
{
name: "Add Action with Dry Run",
grpcClient: ugrpc.NewFakeGrpcClient(),
dryRun: true,
action: "delete-pod",
matchLabels: []string{
"key1=val1",
"key2=val2",
},
expectedLog: `kind: Action
namespace: test-namespace
name: test-action
selector:
matchlabels:
- key: key1
value: val1
- key: key2
value: val2
onviolatedprocess: false
onviolatedfile: false
onfalcoalert: false
falcopriority: 0
action: delete-pod
`,
},
{
name: "Add Action with Dry Run and On Falco Alert",
grpcClient: ugrpc.NewFakeGrpcClient(),
dryRun: true,
action: "delete-pod",
onFalcoAlert: "alert",
expectedLog: `kind: Action
namespace: test-namespace
name: test-action
selector:
matchlabels: []
onviolatedprocess: false
onviolatedfile: false
onfalcoalert: true
falcopriority: 1
action: delete-pod
`,
},
{
name: "Add Action with Invalid Falco Alert",
grpcClient: ugrpc.NewFakeGrpcClient(),
action: "delete-pod",
onFalcoAlert: "invalid",
expectedErr: "add action: invalid falco alert: invalid",
},
{
name: "Add Action on Violated Process and violated file",
grpcClient: ugrpc.NewFakeGrpcClient(),
dryRun: true,
action: "delete-pod",
onViolatedFile: true,
onViolatedProcess: true,
expectedLog: `kind: Action
namespace: test-namespace
name: test-action
selector:
matchlabels: []
onviolatedprocess: true
onviolatedfile: true
onfalcoalert: false
falcopriority: 0
action: delete-pod
`,
},
{
name: "Add Action with Invalid Action",
grpcClient: ugrpc.NewFakeGrpcClient(),
action: "invalid",
expectedErr: "invalid action: invalid",
},
{
name: "Use real gRPC client",
action: "delete-pod",
expectedErr: "rpc error: code = Unimplemented desc = unknown service tarianpb.api.Config",
},
}

serverAddr := "localhost:50051"
go startFakeServer(t, serverAddr)

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create the action command with the test configuration
cmd := &actionCommand{
globalFlags: &flags.GlobalFlags{
ServerAddr: serverAddr,
},
logger: log.GetLogger(),
grpcClient: tt.grpcClient,
dryRun: tt.dryRun,
onFalcoAlert: tt.onFalcoAlert,
onViolatedProcess: tt.onViolatedProcess,
onViolatedFile: tt.onViolatedFile,
action: tt.action,
name: "test-action",
namespace: "test-namespace",
matchLabels: tt.matchLabels,
}

// Capture log output
logOutput := []byte{}
cmd.logger.Out = &logOutputWriter{&logOutput}

// Call the run function
err := cmd.run(nil, nil)

// Assert expected error, if any
if tt.expectedErr != "" {
assert.Contains(t, err.Error(), tt.expectedErr)
} else {
if !assert.NoError(t, err) {
assert.FailNow(t, "error not expected")
}
}

// Assert expected log output
if tt.expectedLog != "" {
assert.Equal(t, strings.TrimSpace(cleanLog(string(logOutput))), strings.TrimSpace(tt.expectedLog))
}
})
}
}

// Helper struct to capture log output
type logOutputWriter struct {
output *[]byte
}

func (w *logOutputWriter) Write(p []byte) (n int, err error) {
*w.output = append(*w.output, p...)
return len(p), nil
}

func startFakeServer(t *testing.T, serverAddr string) {
lis, err := net.Listen("tcp", serverAddr)
if err != nil {
assert.NoError(t, err)
}

srv := grpc.NewServer()

if err := srv.Serve(lis); err != nil {
assert.NoError(t, err)
}
}

func cleanLog(logLine string) string {
index := strings.Index(logLine, "]")
return logLine[index+2:]
}

func TestNewAddActionCommand(t *testing.T) {
// Create a mock globalFlags instance
mockGlobalFlags := &flags.GlobalFlags{
ServerAddr: "mock-server-address",
// Add other fields as needed
}

// Call the function to be tested
cmd := newAddActionCommand(mockGlobalFlags)

// Check if the returned value is of type *cobra.Command
assert.IsType(t, &cobra.Command{}, cmd)

// Check if specific flags are correctly added
namespaceFlag := cmd.Flags().Lookup("namespace")
assert.NotNil(t, namespaceFlag)
assert.Equal(t, "default", namespaceFlag.DefValue) // Check default value

nameFlag := cmd.Flags().Lookup("name")
assert.NotNil(t, nameFlag)

matchLabelsFlag := cmd.Flags().Lookup("match-labels")
assert.NotNil(t, matchLabelsFlag)

actionFlag := cmd.Flags().Lookup("action")
assert.NotNil(t, actionFlag)

dryRunFlag := cmd.Flags().Lookup("dry-run")
assert.NotNil(t, dryRunFlag)

onViolatedProcessFlag := cmd.Flags().Lookup("on-violated-process")
assert.NotNil(t, onViolatedProcessFlag)

onViolatedFileFlag := cmd.Flags().Lookup("on-violated-file")
assert.NotNil(t, onViolatedFileFlag)

onFalcoAlertFlag := cmd.Flags().Lookup("on-falco-alert")
assert.NotNil(t, onFalcoAlertFlag)
}
40 changes: 32 additions & 8 deletions cmd/tarianctl/cmd/add/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ import (

"github.com/kube-tarian/tarian/cmd/tarianctl/cmd/flags"
"github.com/kube-tarian/tarian/cmd/tarianctl/util"
ugrpc "github.com/kube-tarian/tarian/cmd/tarianctl/util/grpc"
"google.golang.org/grpc"

"github.com/kube-tarian/tarian/pkg/log"
"github.com/kube-tarian/tarian/pkg/tarianctl/client"
"github.com/kube-tarian/tarian/pkg/tarianpb"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

type actionCommand struct {
globalFlags *flags.GlobalFlags
logger *logrus.Logger

grpcClient ugrpc.Client

name string
namespace string
matchLabels []string
Expand Down Expand Up @@ -58,15 +62,26 @@ func newAddActionCommand(globalFlags *flags.GlobalFlags) *cobra.Command {
}

func (c *actionCommand) run(_ *cobra.Command, args []string) error {
opts, err := util.ClientOptionsFromCliContext(c.logger, c.globalFlags)
if err != nil {
return fmt.Errorf("add action: %w", err)
// TODO: Remove this check when we support more actions
if c.action != "delete-pod" {
c.logger.Errorf("invalid action: %s", c.action)
return fmt.Errorf("add action: invalid action: %s", c.action)
}

configClient, err := client.NewConfigClient(c.globalFlags.ServerAddr, opts...)
if err != nil {
return fmt.Errorf("add action: failed to create config client: %w", err)
if c.grpcClient == nil {
opts, err := util.ClientOptionsFromCliContext(c.logger, c.globalFlags)
if err != nil {
return fmt.Errorf("add constraints: %w", err)
}

grpcConn, err := grpc.Dial(c.globalFlags.ServerAddr, opts...)
if err != nil {
return fmt.Errorf("add constraints: failed to connect to server: %w", err)
}
defer grpcConn.Close()
c.grpcClient = ugrpc.NewGRPCClient(grpcConn)
}
configClient := c.grpcClient.NewConfigClient()

req := &tarianpb.AddActionRequest{
Action: &tarianpb.Action{
Expand All @@ -84,6 +99,15 @@ func (c *actionCommand) run(_ *cobra.Command, args []string) error {

if c.onFalcoAlert != "" {
req.Action.OnFalcoAlert = true
falcoAlert := map[string]bool{
"alert": true,
"critical": true,
"emergency": true,
}
if !falcoAlert[c.onFalcoAlert] {
c.logger.Errorf("invalid falco alert: %s", c.onFalcoAlert)
return fmt.Errorf("add action: invalid falco alert: %s", c.onFalcoAlert)
}
req.Action.FalcoPriority = tarianpb.FalcoPriorityFromString(c.onFalcoAlert)
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/tarianctl/cmd/add/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func NewAddCommand(globalFlags *flags.GlobalFlags) *cobra.Command {
Short: "Add resources to the Tarian Server.",
Long: "Add resources to the Tarian Server.",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := errors.New("no resource specified, use `tarianctl add --help` for command usage")
if len(args) != 1 {
err := errors.New(`tarianctl needs exactly one argument, use "tarianctl add --help" for command usage`)
return fmt.Errorf("add: %w", err)
}
return nil
Expand Down
Loading

0 comments on commit a85a8e4

Please sign in to comment.