Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pkg/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type Processor struct {

func NewProcessor(sub substrate.Manager, cb Callback, state State) *Processor {
return &Processor{
update: make(chan substrate.Manager, 0),
update: make(chan substrate.Manager),
sub: sub,
cb: cb,
state: state,
Expand Down
19 changes: 15 additions & 4 deletions pkg/perf/cpubench/cpubench_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
"os/exec"

"github.com/threefoldtech/zosbase/pkg/perf"
execwrapper "github.com/threefoldtech/zosbase/pkg/perf/exec_wrapper"
"github.com/threefoldtech/zosbase/pkg/stubs"
)

// CPUBenchmarkTask defines CPU benchmark task.
type CPUBenchmarkTask struct{}
type CPUBenchmarkTask struct {
execWrapper execwrapper.ExecWrapper
}

// CPUBenchmarkResult holds CPU benchmark results with the workloads number during the benchmark.
type CPUBenchmarkResult struct {
Expand All @@ -25,7 +27,15 @@ var _ perf.Task = (*CPUBenchmarkTask)(nil)

// NewTask returns a new CPU benchmark task.
func NewTask() perf.Task {
return &CPUBenchmarkTask{}
return &CPUBenchmarkTask{
execWrapper: &execwrapper.RealExecWrapper{},
}
}

func NewTaskWithExecWrapper(execWrapper execwrapper.ExecWrapper) perf.Task {
return &CPUBenchmarkTask{
execWrapper: execWrapper,
}
}

// ID returns task ID.
Expand All @@ -50,7 +60,8 @@ func (c *CPUBenchmarkTask) Jitter() uint32 {

// Run executes the CPU benchmark.
func (c *CPUBenchmarkTask) Run(ctx context.Context) (interface{}, error) {
cpubenchOut, err := exec.CommandContext(ctx, "cpubench", "-j").CombinedOutput()
cmd := c.execWrapper.CommandContext(ctx, "cpubench", "-j")
cpubenchOut, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("failed to execute cpubench command: %w", err)
}
Expand Down
121 changes: 121 additions & 0 deletions pkg/perf/cpubench/cpubench_task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package cpubench

import (
"context"
"encoding/binary"
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/threefoldtech/zbus"
"github.com/threefoldtech/zosbase/pkg/mocks"
"github.com/threefoldtech/zosbase/pkg/perf"
execwrapper "github.com/threefoldtech/zosbase/pkg/perf/exec_wrapper"
"go.uber.org/mock/gomock"
)

func TestCPUBenchmarkTask(t *testing.T) {
t.Run("create new CPU benchmark task", func(t *testing.T) {
task := NewTask()

assert.NotNil(t, task)
assert.Equal(t, "cpu-benchmark", task.ID())
assert.Equal(t, "0 0 */6 * * *", task.Cron()) // Every 6 hours
assert.Contains(t, task.Description(), "CPU")
assert.Equal(t, uint32(0), task.Jitter())
})

t.Run("task implements perf.Task interface", func(t *testing.T) {
var _ perf.Task = NewTask()
})
}

func TestCPUBenchmarkTask_Run(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockExec := execwrapper.NewMockExecWrapper(ctrl)
mockCmd := execwrapper.NewMockExecCmd(ctrl)
task := NewTaskWithExecWrapper(mockExec).(*CPUBenchmarkTask)
ctx := context.Background()
mockZbus := mocks.NewMockClient(ctrl)
ctx = perf.WithZbusClient(ctx, mockZbus)

mockExec.EXPECT().CommandContext(ctx, "cpubench", "-j").Return(mockCmd).Times(4)
t.Run("successful benchmark execution", func(t *testing.T) {

// Mock successful cpubench execution
expectedOutput := `{
"single": 1542.67,
"multi": 6170.89,
"threads": 4
}`

data := make([]byte, 8)
binary.LittleEndian.PutUint64(data, 5)
response := &zbus.Response{
ID: "test-id",
Output: zbus.Output{
Data: data,
Error: nil,
},
}

mockZbus.EXPECT().
RequestContext(gomock.Any(), "provision", zbus.ObjectID{Name: "statistics", Version: "0.0.1"}, "Workloads").
Return(response, nil)

mockCmd.EXPECT().CombinedOutput().Return([]byte(expectedOutput), nil)

result, err := task.Run(ctx)
require.NoError(t, err)
assert.NotNil(t, result)

// Verify result structure
cpuResult, ok := result.(CPUBenchmarkResult)
require.True(t, ok, "Result should be of type CPUBenchmarkResult")

assert.Equal(t, 1542.67, cpuResult.SingleThreaded)
assert.Equal(t, 6170.89, cpuResult.MultiThreaded)
assert.Equal(t, 4, cpuResult.Threads)
assert.Equal(t, 5, cpuResult.Workloads)

})

t.Run("cpubench command fails", func(t *testing.T) {
// Mock command failure
mockCmd.EXPECT().CombinedOutput().Return([]byte{}, errors.New("command not found"))

result, err := task.Run(ctx)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "failed to execute cpubench command")
})

t.Run("invalid JSON output", func(t *testing.T) {

// Mock command with invalid JSON output
invalidJSON := `{invalid json output}`

mockCmd.EXPECT().CombinedOutput().Return([]byte(invalidJSON), nil)

result, err := task.Run(ctx)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "failed to parse cpubench output")
})

t.Run("failed to get workloads number", func(t *testing.T) {

mockCmd.EXPECT().CombinedOutput().Return([]byte(`{"single": 1000, "multi": 2000, "threads": 4}`), nil)
// Mock failure in getting workloads number
mockZbus.EXPECT().
RequestContext(gomock.Any(), "provision", zbus.ObjectID{Name: "statistics", Version: "0.0.1"}, "Workloads").
Return(nil, errors.New("failed to get workloads"))

assert.Panics(t, func() {
_, _ = task.Run(ctx)
})
})
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package iperf
package execwrapper

import (
"context"
Expand Down Expand Up @@ -38,6 +38,3 @@ type RealExecCmd struct {
func (r *RealExecCmd) CombinedOutput() ([]byte, error) {
return r.cmd.CombinedOutput()
}

// Global instance that can be overridden in tests
var execWrapper ExecWrapper = &RealExecWrapper{}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions pkg/perf/iperf/iperf_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/threefoldtech/zosbase/pkg/environment"
"github.com/threefoldtech/zosbase/pkg/network/iperf"
"github.com/threefoldtech/zosbase/pkg/perf"
"github.com/threefoldtech/zosbase/pkg/perf/exec_wrapper"
"github.com/threefoldtech/zosbase/pkg/perf/graphql"
)

Expand All @@ -32,7 +33,7 @@ const (
type IperfTest struct {
// Optional dependencies for testing
graphqlClient GraphQLClient
execWrapper ExecWrapper
execWrapper execwrapper.ExecWrapper
}

// IperfResult for iperf test results
Expand Down Expand Up @@ -170,7 +171,7 @@ func (t *IperfTest) runIperfTest(ctx context.Context, clientIP string, tcp bool)
opts = append(opts, "--length", "16B", "--udp")
}

execWrap := execWrapper
var execWrap execwrapper.ExecWrapper = &execwrapper.RealExecWrapper{}
if t.execWrapper != nil {
execWrap = t.execWrapper
}
Expand Down Expand Up @@ -221,7 +222,7 @@ func (t *IperfTest) runIperfTest(ctx context.Context, clientIP string, tcp bool)
return iperfResult
}

func runIperfCommand(ctx context.Context, opts []string, execWrap ExecWrapper) iperfCommandOutput {
func runIperfCommand(ctx context.Context, opts []string, execWrap execwrapper.ExecWrapper) iperfCommandOutput {
output, err := execWrap.CommandContext(ctx, "iperf", opts...).CombinedOutput()
exitErr := &exec.ExitError{}
if err != nil && !errors.As(err, &exitErr) {
Expand Down
9 changes: 5 additions & 4 deletions pkg/perf/iperf/iperf_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
execwrapper "github.com/threefoldtech/zosbase/pkg/perf/exec_wrapper"
"github.com/threefoldtech/zosbase/pkg/perf/graphql"
"go.uber.org/mock/gomock"
)
Expand All @@ -16,8 +17,8 @@ func TestIperfTest_Run_Success(t *testing.T) {
defer ctrl.Finish()

mockGraphQL := NewMockGraphQLClient(ctrl)
mockExec := NewMockExecWrapper(ctrl)
mockCmd := NewMockExecCmd(ctrl)
mockExec := execwrapper.NewMockExecWrapper(ctrl)
mockCmd := execwrapper.NewMockExecCmd(ctrl)

task := &IperfTest{
graphqlClient: mockGraphQL,
Expand Down Expand Up @@ -111,7 +112,7 @@ func TestIperfTest_Run_IperfNotFound(t *testing.T) {
defer ctrl.Finish()

mockGraphQL := NewMockGraphQLClient(ctrl)
mockExec := NewMockExecWrapper(ctrl)
mockExec := execwrapper.NewMockExecWrapper(ctrl)

task := &IperfTest{
graphqlClient: mockGraphQL,
Expand Down Expand Up @@ -142,7 +143,7 @@ func TestIperfTest_Run_InvalidIPAddress(t *testing.T) {
defer ctrl.Finish()

mockGraphQL := NewMockGraphQLClient(ctrl)
mockExec := NewMockExecWrapper(ctrl)
mockExec := execwrapper.NewMockExecWrapper(ctrl)

task := &IperfTest{
graphqlClient: mockGraphQL,
Expand Down
Loading