From ec2bc04a1ff0b98df22479fb92fd92560d861330 Mon Sep 17 00:00:00 2001 From: siyul-park Date: Sat, 21 Dec 2024 21:22:51 +0900 Subject: [PATCH] fix: move agent and debug package to runtime --- cmd/pkg/cli/debug.go | 43 ++-- cmd/pkg/cli/debug_test.go | 69 +++--- cmd/pkg/cli/start.go | 3 +- ext/pkg/language/cel/adapter.go | 4 +- ext/pkg/language/cel/error.go | 40 ++- ext/pkg/language/cel/error_test.go | 68 ++--- ext/pkg/system/builder.go | 29 ++- pkg/chart/chart.go | 2 +- pkg/chart/chart_test.go | 287 +++++++++++++--------- pkg/node/proxy_test.go | 28 ++- pkg/process/process.go | 64 ++--- pkg/{agent => runtime}/agent.go | 6 +- pkg/{agent => runtime}/agent_test.go | 12 +- pkg/{debug => runtime}/breakpoint.go | 39 ++- pkg/{debug => runtime}/breakpoint_test.go | 23 +- pkg/{debug => runtime}/debugger.go | 9 +- pkg/{debug => runtime}/debugger_test.go | 39 ++- pkg/{agent => runtime}/frame.go | 2 +- pkg/{agent => runtime}/watcher.go | 12 +- pkg/secret/secret_test.go | 78 +++--- pkg/spec/spec_test.go | 59 ++--- pkg/symbol/symbol.go | 8 +- 22 files changed, 503 insertions(+), 421 deletions(-) rename pkg/{agent => runtime}/agent.go (98%) rename pkg/{agent => runtime}/agent_test.go (96%) rename pkg/{debug => runtime}/breakpoint.go (76%) rename pkg/{debug => runtime}/breakpoint_test.go (87%) rename pkg/{debug => runtime}/debugger.go (95%) rename pkg/{debug => runtime}/debugger_test.go (92%) rename pkg/{agent => runtime}/frame.go (98%) rename pkg/{agent => runtime}/watcher.go (71%) diff --git a/cmd/pkg/cli/debug.go b/cmd/pkg/cli/debug.go index a7988bce..8d5c5203 100644 --- a/cmd/pkg/cli/debug.go +++ b/cmd/pkg/cli/debug.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/siyul-park/uniflow/pkg/runtime" "slices" "strings" "time" @@ -13,8 +14,6 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/gofrs/uuid" "github.com/siyul-park/uniflow/cmd/pkg/resource" - "github.com/siyul-park/uniflow/pkg/agent" - "github.com/siyul-park/uniflow/pkg/debug" "github.com/siyul-park/uniflow/pkg/port" "github.com/siyul-park/uniflow/pkg/process" "github.com/siyul-park/uniflow/pkg/symbol" @@ -23,8 +22,8 @@ import ( // Debugger manages the debugger UI using Bubble Tea. type Debugger struct { - agent *agent.Agent - debugger *debug.Debugger + agent *runtime.Agent + debugger *runtime.Debugger program *tea.Program } @@ -32,8 +31,8 @@ type Debugger struct { type debugModel struct { view debugView input textinput.Model - agent *agent.Agent - debugger *debug.Debugger + agent *runtime.Agent + debugger *runtime.Debugger } // debugView defines an interface for different debug view types. @@ -44,10 +43,10 @@ type debugView interface { // Various debug view types type ( errDebugView struct{ err error } - frameDebugView struct{ frame *agent.Frame } - framesDebugView struct{ frames []*agent.Frame } - breakpointDebugView struct{ breakpoint *debug.Breakpoint } - breakpointsDebugView struct{ breakpoints []*debug.Breakpoint } + frameDebugView struct{ frame *runtime.Frame } + framesDebugView struct{ frames []*runtime.Frame } + breakpointDebugView struct{ breakpoint *runtime.Breakpoint } + breakpointsDebugView struct{ breakpoints []*runtime.Breakpoint } symbolDebugView struct{ symbol *symbol.Symbol } symbolsDebugView struct{ symbols []*symbol.Symbol } processDebugView struct{ process *process.Process } @@ -65,12 +64,12 @@ var _ debugView = (*processDebugView)(nil) var _ debugView = (*processesDebugView)(nil) // NewDebugger initializes a new Debugger with an input model and UI. -func NewDebugger(agent *agent.Agent, options ...tea.ProgramOption) *Debugger { +func NewDebugger(agent *runtime.Agent, options ...tea.ProgramOption) *Debugger { ti := textinput.New() ti.Prompt = "(debug) " ti.Focus() - debugger := debug.NewDebugger(agent) + debugger := runtime.NewDebugger(agent) model := &debugModel{ input: ti, agent: agent, @@ -140,9 +139,9 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "quit", "q": return m, tea.Quit case "break", "b": - var bps []*debug.Breakpoint + var bps []*runtime.Breakpoint if len(args) <= 1 { - bp := debug.NewBreakpoint() + bp := runtime.NewBreakpoint() m.debugger.AddBreakpoint(bp) bps = append(bps, bp) @@ -163,10 +162,10 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } - bp := debug.NewBreakpoint( - debug.WithSymbol(sb), - debug.WithInPort(inPort), - debug.WithOutPort(outPort), + bp := runtime.NewBreakpoint( + runtime.BreakWithSymbol(sb), + runtime.BreakWithInPort(inPort), + runtime.BreakWithOutPort(outPort), ) m.debugger.AddBreakpoint(bp) @@ -198,7 +197,7 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return nil } case "delete", "d": - var bp *debug.Breakpoint + var bp *runtime.Breakpoint if len(args) > 1 { bps := m.debugger.Breakpoints() for _, b := range bps { @@ -221,7 +220,7 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.view = &breakpointsDebugView{breakpoints: bps} return m, nil case "breakpoint", "bp": - var bp *debug.Breakpoint + var bp *runtime.Breakpoint if len(args) > 1 { bps := m.debugger.Breakpoints() for _, b := range bps { @@ -287,7 +286,7 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { proc = m.debugger.Process() } - var frames []*agent.Frame + var frames []*runtime.Frame if proc != nil { frames = m.agent.Frames(proc.ID()) } @@ -300,7 +299,7 @@ func (m *debugModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } } - case *agent.Frame: + case *runtime.Frame: if msg == nil { m.view = nil } else { diff --git a/cmd/pkg/cli/debug_test.go b/cmd/pkg/cli/debug_test.go index f0064256..41a54862 100644 --- a/cmd/pkg/cli/debug_test.go +++ b/cmd/pkg/cli/debug_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/siyul-park/uniflow/pkg/runtime" "testing" "time" @@ -11,8 +12,6 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" - "github.com/siyul-park/uniflow/pkg/agent" - "github.com/siyul-park/uniflow/pkg/debug" "github.com/siyul-park/uniflow/pkg/node" "github.com/siyul-park/uniflow/pkg/packet" "github.com/siyul-park/uniflow/pkg/port" @@ -25,7 +24,7 @@ import ( ) func TestNewDebugger(t *testing.T) { - d := NewDebugger(agent.New()) + d := NewDebugger(runtime.NewAgent()) defer d.Kill() assert.NotNil(t, d) @@ -33,10 +32,10 @@ func TestNewDebugger(t *testing.T) { func TestDebugModel_Update(t *testing.T) { t.Run("break ", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -66,10 +65,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("break", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -99,10 +98,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("continue", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -135,10 +134,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("delete ", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -171,10 +170,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("breakpoints", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -207,10 +206,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("breakpoint ", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -246,10 +245,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -303,10 +302,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("symbols", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -336,10 +335,10 @@ func TestDebugModel_Update(t *testing.T) { }) t.Run("symbol ", func(t *testing.T) { - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -375,10 +374,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -435,10 +434,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -496,10 +495,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -556,10 +555,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -616,10 +615,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -679,10 +678,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ @@ -742,10 +741,10 @@ func TestDebugModel_Update(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := runtime.NewAgent() defer a.Close() - d := debug.NewDebugger(a) + d := runtime.NewDebugger(a) defer d.Close() m := &debugModel{ diff --git a/cmd/pkg/cli/start.go b/cmd/pkg/cli/start.go index d09dba5a..80949d11 100644 --- a/cmd/pkg/cli/start.go +++ b/cmd/pkg/cli/start.go @@ -7,7 +7,6 @@ import ( "syscall" tea "github.com/charmbracelet/bubbletea" - "github.com/siyul-park/uniflow/pkg/agent" "github.com/siyul-park/uniflow/pkg/chart" "github.com/siyul-park/uniflow/pkg/hook" resourcebase "github.com/siyul-park/uniflow/pkg/resource" @@ -108,7 +107,7 @@ func runStartCommand(config StartConfig) func(cmd *cobra.Command, args []string) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) if enableDebug { - a := agent.New() + a := runtime.NewAgent() h.AddLoadHook(a) h.AddUnloadHook(a) diff --git a/ext/pkg/language/cel/adapter.go b/ext/pkg/language/cel/adapter.go index 837cc5a8..331fde44 100644 --- a/ext/pkg/language/cel/adapter.go +++ b/ext/pkg/language/cel/adapter.go @@ -9,10 +9,10 @@ type adapter struct{} var _ types.Adapter = (*adapter)(nil) -func (*adapter) SyscallToValue(value any) ref.Val { +func (*adapter) NativeToValue(value any) ref.Val { switch v := value.(type) { case error: return &Error{error: v} } - return types.DefaultTypeAdapter.SyscallToValue(value) + return types.DefaultTypeAdapter.NativeToValue(value) } diff --git a/ext/pkg/language/cel/error.go b/ext/pkg/language/cel/error.go index 6840a804..3fb722f4 100644 --- a/ext/pkg/language/cel/error.go +++ b/ext/pkg/language/cel/error.go @@ -18,9 +18,15 @@ var ErrorType = cel.ObjectType("error") var _ types.Error = (*Error)(nil) -// ConvertToSyscall converts the Error instance to a syscall Go type as per the provided type descriptor. -func (e *Error) ConvertToSyscall(typeDesc reflect.Type) (any, error) { - return nil, e.error +// ConvertToNative converts the Error instance to a syscall Go type as per the provided type descriptor. +func (e *Error) ConvertToNative(typeDesc reflect.Type) (any, error) { + if typeDesc == reflect.TypeOf("") { + return e.String(), nil + } + if typeDesc == reflect.TypeOf((*error)(nil)).Elem() { + return e.error, nil + } + return nil, errors.New("unsupported type") } // ConvertToType converts the Error instance to a specified ref.Type value. @@ -36,13 +42,13 @@ func (e *Error) ConvertToType(typeVal ref.Type) ref.Val { func (e *Error) Equal(other ref.Val) ref.Val { switch o := other.(type) { case types.String: - return types.Bool(errors.Is(e, errors.New(string(o)))) + return types.Bool(errors.Is(e.error, errors.New(string(o)))) case *types.Err: - return types.Bool(errors.Is(e, o.Unwrap())) + return types.Bool(errors.Is(e.error, o.Unwrap())) case *Error: - return types.Bool(errors.Is(e, o.Unwrap())) + return types.Bool(errors.Is(e.error, o.Unwrap())) } - return e + return types.Bool(false) } // String returns the string representation of the Error instance. @@ -62,25 +68,7 @@ func (e *Error) Value() any { // Is checks whether the Error instance matches the target error using errors.Is. func (e *Error) Is(target error) bool { - errs := []error{e.error} - for len(errs) > 0 { - err := errs[0] - errs = errs[1:] - - if err.Error() == target.Error() { - return true - } - - switch x := err.(type) { - case interface{ Unwrap() error }: - if err = x.Unwrap(); err != nil { - errs = append(errs, err) - } - case interface{ Unwrap() []error }: - errs = append(errs, x.Unwrap()...) - } - } - return false + return errors.Is(e.error, target) } // Unwrap returns the wrapped error instance from the Error. diff --git a/ext/pkg/language/cel/error_test.go b/ext/pkg/language/cel/error_test.go index 1bce1346..54ff8dac 100644 --- a/ext/pkg/language/cel/error_test.go +++ b/ext/pkg/language/cel/error_test.go @@ -1,6 +1,7 @@ package cel import ( + "reflect" "testing" "github.com/go-faker/faker/v4" @@ -9,62 +10,45 @@ import ( "github.com/stretchr/testify/assert" ) -func TestError_String(t *testing.T) { - cause := faker.Sentence() - err := &Error{error: errors.New(cause)} - - assert.Equal(t, cause, err.String()) -} - -func TestError_ConvertToType(t *testing.T) { - cause := faker.Sentence() - err := &Error{error: errors.New(cause)} - - str := err.ConvertToType(types.StringType) - - assert.Equal(t, types.String(cause), str) -} - -func TestError_Equal(t *testing.T) { - t.Run("String", func(t *testing.T) { +func TestError_ConvertToNative(t *testing.T) { + t.Run("ConvertToString", func(t *testing.T) { cause := faker.Sentence() - err := &Error{error: errors.New(cause)} + v := &Error{error: errors.New(cause)} - other := types.String(cause) - assert.Equal(t, types.True, err.Equal(other)) + native, err := v.ConvertToNative(reflect.TypeOf("")) + assert.NoError(t, err) + assert.Equal(t, cause, native) }) - t.Run("Error", func(t *testing.T) { + t.Run("ConvertToError", func(t *testing.T) { cause := faker.Sentence() - err := &Error{error: errors.New(cause)} + v := &Error{error: errors.New(cause)} - other := &Error{error: errors.New(cause)} - assert.Equal(t, types.True, err.Equal(other)) + native, err := v.ConvertToNative(reflect.TypeOf((*error)(nil)).Elem()) + assert.NoError(t, err) + assert.Equal(t, v.error, native) }) - t.Run("Unwrap", func(t *testing.T) { + t.Run("UnsupportedType", func(t *testing.T) { cause := faker.Sentence() - err := &Error{error: errors.WithMessage(errors.New(cause), faker.Sentence())} + v := &Error{error: errors.New(cause)} - other := types.String(cause) - assert.Equal(t, types.True, err.Equal(other)) + native, err := v.ConvertToNative(reflect.TypeOf(0)) + assert.Error(t, err) + assert.Nil(t, native) }) } -func TestError_Is(t *testing.T) { - t.Run("Error", func(t *testing.T) { - cause := faker.Sentence() - err := &Error{error: errors.New(cause)} +func TestError_Equal(t *testing.T) { + err1 := &Error{error: errors.New(faker.Sentence())} + err2 := &Error{error: errors.New(faker.Sentence())} - other := &Error{error: errors.New(cause)} - assert.True(t, err.Is(other)) - }) + assert.Equal(t, types.False, err1.Equal(err2)) +} - t.Run("Unwrap", func(t *testing.T) { - cause := faker.Sentence() - err := &Error{error: errors.WithMessage(errors.New(cause), faker.Sentence())} +func TestError_Is(t *testing.T) { + err1 := &Error{error: errors.New(faker.Sentence())} + err2 := &Error{error: errors.New(faker.Sentence())} - other := &Error{error: errors.New(cause)} - assert.True(t, err.Is(other)) - }) + assert.False(t, err1.Is(err2)) } diff --git a/ext/pkg/system/builder.go b/ext/pkg/system/builder.go index 9016e452..e97f15dd 100644 --- a/ext/pkg/system/builder.go +++ b/ext/pkg/system/builder.go @@ -13,6 +13,7 @@ import ( "reflect" ) +// SchemeRegister manages syscalls and signals for a scheme. type SchemeRegister struct { syscalls map[string]func(context.Context, []any) ([]any, error) signals map[string]func(context.Context) (<-chan any, error) @@ -20,7 +21,7 @@ type SchemeRegister struct { var _ scheme.Register = (*SchemeRegister)(nil) -// AddToHook returns a function that adds hook to the provided hook. +// AddToHook returns a function that adds hooks to the provided hook. func AddToHook() hook.Register { return hook.RegisterFunc(func(h *hook.Hook) error { h.AddLoadHook(symbol.LoadFunc(func(sb *symbol.Symbol) error { @@ -39,7 +40,7 @@ func AddToHook() hook.Register { }) } -// AddToScheme returns a function that adds node types and codecs to the provided spec. +// AddToScheme returns a new SchemeRegister instance. func AddToScheme() *SchemeRegister { return &SchemeRegister{ syscalls: make(map[string]func(context.Context, []any) ([]any, error)), @@ -47,6 +48,7 @@ func AddToScheme() *SchemeRegister { } } +// AddToScheme adds node types and codecs to the provided scheme. func (r *SchemeRegister) AddToScheme(s *scheme.Scheme) error { definitions := []struct { kind string @@ -65,24 +67,25 @@ func (r *SchemeRegister) AddToScheme(s *scheme.Scheme) error { return nil } +// SetSignal registers a signal function for a given topic. func (r *SchemeRegister) SetSignal(topic string, fn any) error { var signal func(context.Context) (<-chan any, error) - if s, ok := fn.(func(context.Context) (<-chan any, error)); ok { + switch s := fn.(type) { + case func(context.Context) (<-chan any, error): signal = s - } else if s, ok := fn.(func(context.Context) <-chan any); ok { + case func(context.Context) <-chan any: signal = func(ctx context.Context) (<-chan any, error) { return s(ctx), nil } - } else if s, ok := fn.(func() (<-chan any, error)); ok { + case func() (<-chan any, error): signal = func(_ context.Context) (<-chan any, error) { return s() } - } else if s, ok := fn.(func() <-chan any); ok { + case func() <-chan any: signal = func(_ context.Context) (<-chan any, error) { return s(), nil } - } - if signal == nil { + default: return errors.WithStack(encoding.ErrUnsupportedType) } @@ -90,19 +93,18 @@ func (r *SchemeRegister) SetSignal(topic string, fn any) error { return nil } +// Signal retrieves the signal function for a given topic. func (r *SchemeRegister) Signal(topic string) func(context.Context) (<-chan any, error) { return r.signals[topic] } +// SetSyscall registers a syscall function for a given opcode. func (r *SchemeRegister) SetSyscall(opcode string, fn any) error { fnValue := reflect.ValueOf(fn) if fnValue.Kind() != reflect.Func { return errors.WithStack(encoding.ErrUnsupportedType) } - typeContext := reflect.TypeOf((*context.Context)(nil)).Elem() - typeError := reflect.TypeOf((*error)(nil)).Elem() - fnType := fnValue.Type() numIn := fnType.NumIn() numOut := fnType.NumOut() @@ -111,7 +113,7 @@ func (r *SchemeRegister) SetSyscall(opcode string, fn any) error { ins := make([]reflect.Value, numIn) offset := 0 - if numIn > 0 && fnType.In(0).Implements(typeContext) { + if numIn > 0 && fnType.In(0).Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) { ins[0] = reflect.ValueOf(ctx) offset++ } @@ -134,7 +136,7 @@ func (r *SchemeRegister) SetSyscall(opcode string, fn any) error { outs := fnValue.Call(ins) - if numOut > 0 && fnType.Out(numOut-1).Implements(typeError) { + if numOut > 0 && fnType.Out(numOut-1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { if err, ok := outs[numOut-1].Interface().(error); ok && err != nil { return nil, err } @@ -150,6 +152,7 @@ func (r *SchemeRegister) SetSyscall(opcode string, fn any) error { return nil } +// Syscall retrieves the syscall function for a given opcode. func (r *SchemeRegister) Syscall(opcode string) func(context.Context, []any) ([]any, error) { return r.syscalls[opcode] } diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index efd4c306..e573ca1e 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -29,7 +29,7 @@ const ( KeyNamespace = "namespace" KeyName = "name" KeyAnnotations = "annotations" - KetSpecs = "specs" + KeySpecs = "specs" KeyInbounds = "inbounds" KeyOutbounds = "outbounds" KeyEnv = "env" diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index 6c836c59..b7e82316 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -12,120 +12,176 @@ import ( ) func TestChart_IsBound(t *testing.T) { - sec1 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), - } - sec2 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), - } - - chrt := &Chart{ - ID: uuid.Must(uuid.NewV7()), - Env: map[string][]spec.Value{ - "FOO": { - { - ID: sec1.ID, - Data: "foo", + t.Run("NoSecrets", func(t *testing.T) { + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ + "FOO": { + { + ID: uuid.Must(uuid.NewV7()), + Data: "foo", + }, }, }, - }, - } - - assert.True(t, chrt.IsBound(sec1)) - assert.False(t, chrt.IsBound(sec2)) + } + assert.False(t, chrt.IsBound()) + }) + + t.Run("WithSecrets", func(t *testing.T) { + sec1 := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + } + sec2 := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + } + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ + "FOO": { + { + ID: sec1.ID, + Data: "foo", + }, + }, + }, + } + assert.True(t, chrt.IsBound(sec1)) + assert.False(t, chrt.IsBound(sec2)) + }) } func TestChart_Bind(t *testing.T) { - scrt := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), - Data: "foo", - } - - chrt := &Chart{ - ID: uuid.Must(uuid.NewV7()), - Env: map[string][]spec.Value{ - "FOO": { - { - ID: scrt.ID, - Data: "{{ . }}", + t.Run("NoMatchingSecret", func(t *testing.T) { + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: "foo", + } + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ + "FOO": { + { + ID: uuid.Must(uuid.NewV7()), + Data: "{{ . }}", + }, }, }, - }, - } - - err := chrt.Bind(scrt) - assert.NoError(t, err) - assert.Equal(t, "foo", chrt.GetEnv()["FOO"][0].Data) + } + err := chrt.Bind(scrt) + assert.Error(t, err) + }) + + t.Run("MatchingSecret", func(t *testing.T) { + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: "foo", + } + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ + "FOO": { + { + ID: scrt.ID, + Data: "{{ . }}", + }, + }, + }, + } + err := chrt.Bind(scrt) + assert.NoError(t, err) + assert.Equal(t, "foo", chrt.GetEnv()["FOO"][0].Data) + }) } func TestChart_Build(t *testing.T) { - chrt := &Chart{ - ID: uuid.Must(uuid.NewV7()), - Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Unstructured{ - Meta: spec.Meta{ - ID: uuid.Must(uuid.NewV7()), - Kind: faker.UUIDHyphenated(), + t.Run("NoEnv", func(t *testing.T) { + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Name: faker.UUIDHyphenated(), + Specs: []spec.Spec{ + &spec.Unstructured{ + Meta: spec.Meta{ + ID: uuid.Must(uuid.NewV7()), + Kind: faker.UUIDHyphenated(), + }, + Fields: map[string]any{ + "foo": "{{ .FOO }}", + }, }, - Fields: map[string]any{ - "foo": "{{ .FOO }}", + }, + } + meta := &spec.Meta{ + Kind: chrt.GetName(), + Namespace: resource.DefaultNamespace, + } + specs, err := chrt.Build(meta) + assert.NoError(t, err) + assert.Len(t, specs, 1) + }) + + t.Run("WithEnv", func(t *testing.T) { + chrt := &Chart{ + ID: uuid.Must(uuid.NewV7()), + Name: faker.UUIDHyphenated(), + Specs: []spec.Spec{ + &spec.Unstructured{ + Meta: spec.Meta{ + ID: uuid.Must(uuid.NewV7()), + Kind: faker.UUIDHyphenated(), + }, + Fields: map[string]any{ + "foo": "{{ .FOO }}", + }, }, }, - }, - Env: map[string][]spec.Value{ - "FOO": { - { - Data: "foo", + Env: map[string][]spec.Value{ + "FOO": { + { + Data: "foo", + }, }, }, - }, - } - - meta := &spec.Meta{ - Kind: chrt.GetName(), - Namespace: resource.DefaultNamespace, - } - - specs, err := chrt.Build(meta) - assert.NoError(t, err) - assert.Len(t, specs, 1) + } + meta := &spec.Meta{ + Kind: chrt.GetName(), + Namespace: resource.DefaultNamespace, + } + specs, err := chrt.Build(meta) + assert.NoError(t, err) + assert.Len(t, specs, 1) + }) } -func TestChart_Get(t *testing.T) { - chrt := &Chart{ - ID: uuid.Must(uuid.NewV7()), - Namespace: "default", - Name: faker.Word(), - Annotations: map[string]string{"key": "value"}, - Specs: []spec.Spec{ - &spec.Meta{ - ID: uuid.Must(uuid.NewV7()), - Kind: faker.UUIDHyphenated(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), - }, - }, - Inbounds: map[string][]spec.Port{"out": {{Name: faker.Word(), Port: "in"}}}, - Env: map[string][]spec.Value{"env1": {{Name: "secret1", Data: "value1"}}}, - } - - assert.Equal(t, chrt.ID, chrt.GetID()) - assert.Equal(t, chrt.Namespace, chrt.GetNamespace()) - assert.Equal(t, chrt.Name, chrt.GetName()) - assert.Equal(t, chrt.Annotations, chrt.GetAnnotations()) - assert.Equal(t, chrt.Specs, chrt.GetSpecs()) - assert.Equal(t, chrt.Inbounds, chrt.GetInbounds()) - assert.Equal(t, chrt.Env, chrt.GetEnv()) +func TestChart_SetID(t *testing.T) { + chrt := New() + id := uuid.Must(uuid.NewV7()) + chrt.SetID(id) + assert.Equal(t, id, chrt.GetID()) } -func TestChart_Set(t *testing.T) { +func TestChart_SetNamespace(t *testing.T) { chrt := New() - - id := uuid.Must(uuid.NewV7()) namespace := "test-namespace" + chrt.SetNamespace(namespace) + assert.Equal(t, namespace, chrt.GetNamespace()) +} + +func TestChart_SetName(t *testing.T) { + chrt := New() name := "test-chart" + chrt.SetName(name) + assert.Equal(t, name, chrt.GetName()) +} + +func TestChart_SetAnnotations(t *testing.T) { + chrt := New() annotations := map[string]string{"key": "value"} + chrt.SetAnnotations(annotations) + assert.Equal(t, annotations, chrt.GetAnnotations()) +} + +func TestChart_SetSpecs(t *testing.T) { + chrt := New() specs := []spec.Spec{ &spec.Unstructured{ Meta: spec.Meta{ @@ -134,6 +190,12 @@ func TestChart_Set(t *testing.T) { }, }, } + chrt.SetSpecs(specs) + assert.Equal(t, specs, chrt.GetSpecs()) +} + +func TestChart_SetInbounds(t *testing.T) { + chrt := New() ports := map[string][]spec.Port{ "http": { { @@ -143,36 +205,35 @@ func TestChart_Set(t *testing.T) { }, }, } - env := map[string][]spec.Value{ - "FOO": { + chrt.SetInbounds(ports) + assert.Equal(t, ports, chrt.GetInbounds()) +} + +func TestChart_SetOutbounds(t *testing.T) { + chrt := New() + ports := map[string][]spec.Port{ + "http": { { ID: uuid.Must(uuid.NewV7()), - Data: "bar", + Name: "http", + Port: "80", }, }, } - - chrt.SetID(id) - assert.Equal(t, id, chrt.GetID()) - - chrt.SetNamespace(namespace) - assert.Equal(t, namespace, chrt.GetNamespace()) - - chrt.SetName(name) - assert.Equal(t, name, chrt.GetName()) - - chrt.SetAnnotations(annotations) - assert.Equal(t, annotations, chrt.GetAnnotations()) - - chrt.SetSpecs(specs) - assert.Equal(t, specs, chrt.GetSpecs()) - - chrt.SetInbounds(ports) - assert.Equal(t, ports, chrt.GetInbounds()) - chrt.SetOutbounds(ports) assert.Equal(t, ports, chrt.GetOutbounds()) +} +func TestChart_SetEnv(t *testing.T) { + chrt := New() + env := map[string][]spec.Value{ + "FOO": { + { + ID: uuid.Must(uuid.NewV7()), + Data: "bar", + }, + }, + } chrt.SetEnv(env) assert.Equal(t, env, chrt.GetEnv()) } diff --git a/pkg/node/proxy_test.go b/pkg/node/proxy_test.go index 878c6fab..05f87861 100644 --- a/pkg/node/proxy_test.go +++ b/pkg/node/proxy_test.go @@ -5,10 +5,36 @@ import ( "testing" ) -func TestUnwrap(t *testing.T) { +func TestNoCloser(t *testing.T) { n := NewOneToOneNode(nil) defer n.Close() p := NoCloser(n) assert.Equal(t, n, Unwrap(p)) + assert.NoError(t, p.Close()) +} + +func TestUnwrap(t *testing.T) { + t.Run("NoProxy", func(t *testing.T) { + n := NewOneToOneNode(nil) + defer n.Close() + + assert.Equal(t, n, Unwrap(n)) + }) + + t.Run("ProxyNode", func(t *testing.T) { + n := NewOneToOneNode(nil) + defer n.Close() + + p := NoCloser(n) + assert.Equal(t, n, Unwrap(p)) + }) +} + +func TestNoCloser_Close(t *testing.T) { + n := NewOneToOneNode(nil) + defer n.Close() + + p := NoCloser(n) + assert.NoError(t, p.Close()) } diff --git a/pkg/process/process.go b/pkg/process/process.go index d5f02c41..b5fcfa5d 100644 --- a/pkg/process/process.go +++ b/pkg/process/process.go @@ -9,23 +9,23 @@ import ( // Process represents a unit of execution with data, status, and lifecycle management. type Process struct { - parent *Process // Parent process, if any. - id uuid.UUID // Unique identifier. - data map[string]any // Process data storage. - status Status // Current status. - err error // Execution error, if any. - ctx context.Context // Process context. - exitHooks ExitHooks // Hooks to run on exit. - wait sync.WaitGroup // Manages child process completion. - mu sync.RWMutex // Synchronizes access to data and status. + parent *Process + id uuid.UUID + data map[string]any + status Status + err error + ctx context.Context + exitHooks ExitHooks + wait sync.WaitGroup + mu sync.RWMutex } // Status represents the process state. type Status int const ( - StatusRunning Status = iota // Process is active. - StatusTerminated // Process has ended. + StatusRunning Status = iota + StatusTerminated ) // New creates a new process with a background context and an exit hook. @@ -67,11 +67,10 @@ func (p *Process) Load(key string) any { if val, ok := p.data[key]; ok { return val } - - if p.parent == nil { - return nil + if p.parent != nil { + return p.parent.Load(key) } - return p.parent.Load(key) + return nil } // Store saves a value with the given key. @@ -101,11 +100,10 @@ func (p *Process) LoadAndDelete(key string) any { delete(p.data, key) return val } - - if p.parent == nil { - return nil + if p.parent != nil { + return p.parent.LoadAndDelete(key) } - return p.parent.LoadAndDelete(key) + return nil } // Status returns the process's status. @@ -160,23 +158,27 @@ func (p *Process) Fork() *Process { // Exit terminates the process with an error, running exit hooks. func (p *Process) Exit(err error) { - p.mu.Lock() + exitHooks := func() ExitHooks { + p.mu.Lock() + defer p.mu.Unlock() - if p.status == StatusTerminated { - p.mu.Unlock() - return - } + if p.status == StatusTerminated { + return nil + } - exitHooks := p.exitHooks + exitHooks := p.exitHooks - p.data = make(map[string]any) - p.status = StatusTerminated - p.err = err - p.exitHooks = nil + p.data = make(map[string]any) + p.status = StatusTerminated + p.err = err + p.exitHooks = nil - p.mu.Unlock() + return exitHooks + }() - exitHooks.Exit(err) + if exitHooks != nil { + exitHooks.Exit(err) + } } // AddExitHook adds an exit hook, executing immediately if terminated. diff --git a/pkg/agent/agent.go b/pkg/runtime/agent.go similarity index 98% rename from pkg/agent/agent.go rename to pkg/runtime/agent.go index 67b54e1e..b0bc3033 100644 --- a/pkg/agent/agent.go +++ b/pkg/runtime/agent.go @@ -1,4 +1,4 @@ -package agent +package runtime import ( "sync" @@ -29,8 +29,8 @@ var _ symbol.UnloadHook = (*Agent)(nil) var _ chart.LinkHook = (*Agent)(nil) var _ chart.UnlinkHook = (*Agent)(nil) -// New initializes and returns a new Agent. -func New() *Agent { +// NewAgent initializes and returns a new Agent. +func NewAgent() *Agent { return &Agent{ symbols: make(map[uuid.UUID]*symbol.Symbol), processes: make(map[uuid.UUID]*process.Process), diff --git a/pkg/agent/agent_test.go b/pkg/runtime/agent_test.go similarity index 96% rename from pkg/agent/agent_test.go rename to pkg/runtime/agent_test.go index c3c7acc8..5784c1f2 100644 --- a/pkg/agent/agent_test.go +++ b/pkg/runtime/agent_test.go @@ -1,4 +1,4 @@ -package agent +package runtime import ( "testing" @@ -17,7 +17,7 @@ import ( ) func TestAgent_Watch(t *testing.T) { - a := New() + a := NewAgent() defer a.Close() w := NewProcessWatcher(func(proc *process.Process) {}) @@ -36,7 +36,7 @@ func TestAgent_Watch(t *testing.T) { } func TestAgent_Symbol(t *testing.T) { - a := New() + a := NewAgent() defer a.Close() sb := &symbol.Symbol{ @@ -58,7 +58,7 @@ func TestAgent_Symbol(t *testing.T) { } func TestAgent_Process(t *testing.T) { - a := New() + a := NewAgent() defer a.Close() done := make(chan struct{}) @@ -96,7 +96,7 @@ func TestAgent_Process(t *testing.T) { } func TestAgent_Chart(t *testing.T) { - a := New() + a := NewAgent() defer a.Close() chrt := &chart.Chart{ @@ -111,7 +111,7 @@ func TestAgent_Chart(t *testing.T) { } func TestAgent_Frames(t *testing.T) { - a := New() + a := NewAgent() defer a.Close() count := 0 diff --git a/pkg/debug/breakpoint.go b/pkg/runtime/breakpoint.go similarity index 76% rename from pkg/debug/breakpoint.go rename to pkg/runtime/breakpoint.go index 7f53858e..3da4d7f8 100644 --- a/pkg/debug/breakpoint.go +++ b/pkg/runtime/breakpoint.go @@ -1,10 +1,9 @@ -package debug +package runtime import ( "github.com/gofrs/uuid" "sync" - "github.com/siyul-park/uniflow/pkg/agent" "github.com/siyul-park/uniflow/pkg/port" "github.com/siyul-park/uniflow/pkg/process" "github.com/siyul-park/uniflow/pkg/symbol" @@ -17,33 +16,33 @@ type Breakpoint struct { symbol *symbol.Symbol inPort *port.InPort outPort *port.OutPort - current *agent.Frame - in chan *agent.Frame - out chan *agent.Frame + current *Frame + in chan *Frame + out chan *Frame done chan struct{} rmu sync.RWMutex wmu sync.Mutex } -var _ agent.Watcher = (*Breakpoint)(nil) +var _ Watcher = (*Breakpoint)(nil) -// WithProcess sets the process associated with the breakpoint. -func WithProcess(proc *process.Process) func(*Breakpoint) { +// BreakWithProcess sets the process associated with the breakpoint. +func BreakWithProcess(proc *process.Process) func(*Breakpoint) { return func(b *Breakpoint) { b.process = proc } } -// WithSymbol sets the symbol associated with the breakpoint. -func WithSymbol(sb *symbol.Symbol) func(*Breakpoint) { +// BreakWithSymbol sets the symbol associated with the breakpoint. +func BreakWithSymbol(sb *symbol.Symbol) func(*Breakpoint) { return func(b *Breakpoint) { b.symbol = sb } } -// WithInPort sets the input port associated with the breakpoint. -func WithInPort(port *port.InPort) func(*Breakpoint) { +// BreakWithInPort sets the input port associated with the breakpoint. +func BreakWithInPort(port *port.InPort) func(*Breakpoint) { return func(b *Breakpoint) { b.inPort = port } } -// WithOutPort sets the output port associated with the breakpoint. -func WithOutPort(port *port.OutPort) func(*Breakpoint) { +// BreakWithOutPort sets the output port associated with the breakpoint. +func BreakWithOutPort(port *port.OutPort) func(*Breakpoint) { return func(b *Breakpoint) { b.outPort = port } } @@ -51,8 +50,8 @@ func WithOutPort(port *port.OutPort) func(*Breakpoint) { func NewBreakpoint(options ...func(*Breakpoint)) *Breakpoint { b := &Breakpoint{ id: uuid.Must(uuid.NewV7()), - in: make(chan *agent.Frame), - out: make(chan *agent.Frame), + in: make(chan *Frame), + out: make(chan *Frame), done: make(chan struct{}), } for _, opt := range options { @@ -61,7 +60,7 @@ func NewBreakpoint(options ...func(*Breakpoint)) *Breakpoint { return b } -// ID returns the unique identifier. +// ID returns the unique identifier of the breakpoint. func (b *Breakpoint) ID() uuid.UUID { return b.id } @@ -104,7 +103,7 @@ func (b *Breakpoint) Done() bool { } // Frame returns the current frame under lock protection. -func (b *Breakpoint) Frame() *agent.Frame { +func (b *Breakpoint) Frame() *Frame { if b.rmu.TryRLock() { defer b.rmu.RUnlock() return b.current @@ -133,7 +132,7 @@ func (b *Breakpoint) OutPort() *port.OutPort { } // OnFrame processes an incoming frame and synchronizes it. -func (b *Breakpoint) OnFrame(frame *agent.Frame) { +func (b *Breakpoint) OnFrame(frame *Frame) { if b.matches(frame) { select { case b.in <- frame: @@ -169,7 +168,7 @@ func (b *Breakpoint) Close() { b.current = nil } -func (b *Breakpoint) matches(frame *agent.Frame) bool { +func (b *Breakpoint) matches(frame *Frame) bool { return (b.process == nil || b.process == frame.Process) && (b.symbol == nil || b.symbol == frame.Symbol) && (b.inPort == nil || b.inPort == frame.InPort) && diff --git a/pkg/debug/breakpoint_test.go b/pkg/runtime/breakpoint_test.go similarity index 87% rename from pkg/debug/breakpoint_test.go rename to pkg/runtime/breakpoint_test.go index 89e13059..e9e1a054 100644 --- a/pkg/debug/breakpoint_test.go +++ b/pkg/runtime/breakpoint_test.go @@ -1,11 +1,10 @@ -package debug +package runtime import ( "testing" "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" - "github.com/siyul-park/uniflow/pkg/agent" "github.com/siyul-park/uniflow/pkg/node" "github.com/siyul-park/uniflow/pkg/process" "github.com/siyul-park/uniflow/pkg/resource" @@ -30,10 +29,10 @@ func TestNewBreakpoint(t *testing.T) { defer sb.Close() b := NewBreakpoint( - WithProcess(proc), - WithSymbol(sb), - WithInPort(sb.In(node.PortIn)), - WithOutPort(sb.Out(node.PortOut)), + BreakWithProcess(proc), + BreakWithSymbol(sb), + BreakWithInPort(sb.In(node.PortIn)), + BreakWithOutPort(sb.Out(node.PortOut)), ) defer b.Close() @@ -60,12 +59,12 @@ func TestBreakpoint_Next(t *testing.T) { defer sb.Close() b := NewBreakpoint( - WithProcess(proc), - WithSymbol(sb), + BreakWithProcess(proc), + BreakWithSymbol(sb), ) defer b.Close() - frame := &agent.Frame{ + frame := &Frame{ Process: proc, Symbol: sb, } @@ -92,12 +91,12 @@ func TestBreakpoint_Done(t *testing.T) { defer sb.Close() b := NewBreakpoint( - WithProcess(proc), - WithSymbol(sb), + BreakWithProcess(proc), + BreakWithSymbol(sb), ) defer b.Close() - frame := &agent.Frame{ + frame := &Frame{ Process: proc, Symbol: sb, } diff --git a/pkg/debug/debugger.go b/pkg/runtime/debugger.go similarity index 95% rename from pkg/debug/debugger.go rename to pkg/runtime/debugger.go index ef5226e2..d2f5a41f 100644 --- a/pkg/debug/debugger.go +++ b/pkg/runtime/debugger.go @@ -1,17 +1,16 @@ -package debug +package runtime import ( "context" "sync" - "github.com/siyul-park/uniflow/pkg/agent" "github.com/siyul-park/uniflow/pkg/process" "github.com/siyul-park/uniflow/pkg/symbol" ) // Debugger manages breakpoints and the debugging process. type Debugger struct { - agent *agent.Agent + agent *Agent breakpoints []*Breakpoint current *Breakpoint in chan *Breakpoint @@ -21,7 +20,7 @@ type Debugger struct { } // NewDebugger creates a new Debugger instance with the specified agent. -func NewDebugger(agent *agent.Agent) *Debugger { +func NewDebugger(agent *Agent) *Debugger { return &Debugger{ agent: agent, in: make(chan *Breakpoint), @@ -120,7 +119,7 @@ func (d *Debugger) Breakpoint() *Breakpoint { } // Frame returns the frame of the current breakpoint. -func (d *Debugger) Frame() *agent.Frame { +func (d *Debugger) Frame() *Frame { if d.rmu.TryRLock() { defer d.rmu.RUnlock() if d.current != nil { diff --git a/pkg/debug/debugger_test.go b/pkg/runtime/debugger_test.go similarity index 92% rename from pkg/debug/debugger_test.go rename to pkg/runtime/debugger_test.go index e2190853..d7024d7e 100644 --- a/pkg/debug/debugger_test.go +++ b/pkg/runtime/debugger_test.go @@ -1,4 +1,4 @@ -package debug +package runtime import ( "context" @@ -7,7 +7,6 @@ import ( "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" - "github.com/siyul-park/uniflow/pkg/agent" "github.com/siyul-park/uniflow/pkg/node" "github.com/siyul-park/uniflow/pkg/packet" "github.com/siyul-park/uniflow/pkg/port" @@ -20,7 +19,7 @@ import ( ) func TestDebugger_AddBreakpoint(t *testing.T) { - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -37,7 +36,7 @@ func TestDebugger_AddBreakpoint(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) ok := d.AddBreakpoint(bp) assert.True(t, ok) @@ -47,7 +46,7 @@ func TestDebugger_AddBreakpoint(t *testing.T) { } func TestDebugger_RemoveBreakpoint(t *testing.T) { - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -64,7 +63,7 @@ func TestDebugger_RemoveBreakpoint(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -76,7 +75,7 @@ func TestDebugger_RemoveBreakpoint(t *testing.T) { } func TestDebugger_Breakpoints(t *testing.T) { - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -93,7 +92,7 @@ func TestDebugger_Breakpoints(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -105,7 +104,7 @@ func TestDebugger_Pause(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -122,7 +121,7 @@ func TestDebugger_Pause(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -157,7 +156,7 @@ func TestDebugger_Step(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -174,7 +173,7 @@ func TestDebugger_Step(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -209,7 +208,7 @@ func TestDebugger_Breakpoint(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -226,7 +225,7 @@ func TestDebugger_Breakpoint(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -263,7 +262,7 @@ func TestDebugger_Frame(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -280,7 +279,7 @@ func TestDebugger_Frame(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -317,7 +316,7 @@ func TestDebugger_Process(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -334,7 +333,7 @@ func TestDebugger_Process(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) @@ -371,7 +370,7 @@ func TestDebugger_Symbol(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), time.Second) defer cancel() - a := agent.New() + a := NewAgent() defer a.Close() d := NewDebugger(a) @@ -388,7 +387,7 @@ func TestDebugger_Symbol(t *testing.T) { } defer sb.Close() - bp := NewBreakpoint(WithSymbol(sb)) + bp := NewBreakpoint(BreakWithSymbol(sb)) d.AddBreakpoint(bp) diff --git a/pkg/agent/frame.go b/pkg/runtime/frame.go similarity index 98% rename from pkg/agent/frame.go rename to pkg/runtime/frame.go index 657d85ef..0c8f2957 100644 --- a/pkg/agent/frame.go +++ b/pkg/runtime/frame.go @@ -1,4 +1,4 @@ -package agent +package runtime import ( "time" diff --git a/pkg/agent/watcher.go b/pkg/runtime/watcher.go similarity index 71% rename from pkg/agent/watcher.go rename to pkg/runtime/watcher.go index bdd252dd..8c922fc4 100644 --- a/pkg/agent/watcher.go +++ b/pkg/runtime/watcher.go @@ -1,4 +1,4 @@ -package agent +package runtime import ( "github.com/siyul-park/uniflow/pkg/process" @@ -6,8 +6,10 @@ import ( // Watcher defines methods for handling Frame and Process events. type Watcher interface { - OnFrame(*Frame) // Triggered when a Frame event occurs. - OnProcess(*process.Process) // Triggered when a Process event occurs. + // OnFrame is triggered when a Frame event occurs. + OnFrame(*Frame) + // OnProcess is triggered when a Process event occurs. + OnProcess(*process.Process) } // Watchers is a slice of Watcher interfaces. @@ -31,24 +33,28 @@ func NewProcessWatcher(handle func(*process.Process)) Watcher { return &watcher{onProcess: handle} } +// OnFrame triggers the OnFrame method for each Watcher in the slice. func (w Watchers) OnFrame(frame *Frame) { for _, watcher := range w { watcher.OnFrame(frame) } } +// OnProcess triggers the OnProcess method for each Watcher in the slice. func (w Watchers) OnProcess(proc *process.Process) { for _, watcher := range w { watcher.OnProcess(proc) } } +// OnFrame triggers the onFrame function if it is defined. func (w *watcher) OnFrame(frame *Frame) { if w.onFrame != nil { w.onFrame(frame) } } +// OnProcess triggers the onProcess function if it is defined. func (w *watcher) OnProcess(proc *process.Process) { if w.onProcess != nil { w.onProcess(proc) diff --git a/pkg/secret/secret_test.go b/pkg/secret/secret_test.go index 39ec239b..960e2938 100644 --- a/pkg/secret/secret_test.go +++ b/pkg/secret/secret_test.go @@ -1,49 +1,65 @@ package secret import ( + "github.com/go-faker/faker/v4" "testing" - "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" ) -func TestSecret_Get(t *testing.T) { - scrt := &Secret{ - ID: uuid.Must(uuid.NewV7()), - Namespace: "default", - Name: faker.Word(), - Annotations: map[string]string{"key": "value"}, - Data: faker.Word(), - } - - assert.Equal(t, scrt.ID, scrt.GetID()) - assert.Equal(t, scrt.Namespace, scrt.GetNamespace()) - assert.Equal(t, scrt.Name, scrt.GetName()) - assert.Equal(t, scrt.Annotations, scrt.GetAnnotations()) - assert.Equal(t, scrt.Data, scrt.GetData()) - assert.True(t, scrt.IsIdentified()) +func TestSecret_SetID(t *testing.T) { + scrt := New() + id := uuid.Must(uuid.NewV7()) + scrt.SetID(id) + assert.Equal(t, id, scrt.GetID()) } -func TestSecret_Set(t *testing.T) { +func TestSecret_SetNamespace(t *testing.T) { scrt := New() + namespace := faker.Word() + scrt.SetNamespace(namespace) + assert.Equal(t, namespace, scrt.GetNamespace()) +} - id := uuid.Must(uuid.NewV7()) - namespace := "default" +func TestSecret_SetName(t *testing.T) { + scrt := New() name := faker.Word() - annotations := map[string]string{"key": "value"} - data := faker.Word() - - scrt.SetID(id) - scrt.SetNamespace(namespace) scrt.SetName(name) - scrt.SetAnnotations(annotations) - scrt.SetData(data) - - assert.Equal(t, id, scrt.GetID()) - assert.Equal(t, namespace, scrt.GetNamespace()) assert.Equal(t, name, scrt.GetName()) - assert.Equal(t, annotations, scrt.GetAnnotations()) +} + +func TestSecret_SetAnnotations(t *testing.T) { + scrt := New() + annotation := map[string]string{"key": "value"} + scrt.SetAnnotations(annotation) + assert.Equal(t, annotation, scrt.GetAnnotations()) +} + +func TestSecret_SetData_Nil(t *testing.T) { + scrt := New() + data := faker.Word() + scrt.SetData(data) assert.Equal(t, data, scrt.GetData()) - assert.True(t, scrt.IsIdentified()) +} + +func TestSecret_IsIdentified(t *testing.T) { + t.Run("ID", func(t *testing.T) { + scrt := &Secret{ + ID: uuid.Must(uuid.NewV7()), + } + assert.True(t, scrt.IsIdentified()) + }) + + t.Run("Name", func(t *testing.T) { + scrt := &Secret{ + Name: faker.Word(), + } + assert.True(t, scrt.IsIdentified()) + }) + + t.Run("Nil", func(t *testing.T) { + scrt := &Secret{} + assert.False(t, scrt.IsIdentified()) + }) } diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go index 27a831ce..548286aa 100644 --- a/pkg/spec/spec_test.go +++ b/pkg/spec/spec_test.go @@ -25,60 +25,63 @@ func TestConvert(t *testing.T) { assert.NoError(t, err) } -func TestMeta_Get(t *testing.T) { - meta := &Meta{ - ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), - Namespace: "default", - Name: faker.Word(), - Annotations: map[string]string{"key": "value"}, - Ports: map[string][]Port{"out": {{Name: faker.Word(), Port: "in"}}}, - Env: map[string][]Value{"env1": {{Name: "secret1", Data: "value1"}}}, - } - - assert.Equal(t, meta.ID, meta.GetID()) - assert.Equal(t, meta.Kind, meta.GetKind()) - assert.Equal(t, meta.Namespace, meta.GetNamespace()) - assert.Equal(t, meta.Name, meta.GetName()) - assert.Equal(t, meta.Annotations, meta.GetAnnotations()) - assert.Equal(t, meta.Ports, meta.GetPorts()) - assert.Equal(t, meta.Env, meta.GetEnv()) -} - -func TestMeta_Set(t *testing.T) { +func TestMeta_SetID(t *testing.T) { meta := &Meta{} - id := uuid.Must(uuid.NewV7()) meta.SetID(id) assert.Equal(t, id, meta.GetID()) +} - kind := "testKind" +func TestMeta_SetKind(t *testing.T) { + meta := &Meta{} + kind := faker.Word() meta.SetKind(kind) assert.Equal(t, kind, meta.GetKind()) +} - namespace := "testNamespace" +func TestMeta_SetNamespace(t *testing.T) { + meta := &Meta{} + namespace := faker.Word() meta.SetNamespace(namespace) assert.Equal(t, namespace, meta.GetNamespace()) +} - name := "testName" +func TestMeta_SetName(t *testing.T) { + meta := &Meta{} + name := faker.Word() meta.SetName(name) assert.Equal(t, name, meta.GetName()) +} +func TestMeta_SetAnnotations(t *testing.T) { + meta := &Meta{} annotations := map[string]string{"key": "value"} meta.SetAnnotations(annotations) assert.Equal(t, annotations, meta.GetAnnotations()) +} +func TestMeta_SetPorts(t *testing.T) { + meta := &Meta{} ports := map[string][]Port{ - "http": { - {ID: uuid.Must(uuid.NewV7()), Name: "port1", Port: "8080"}, + "out": { + { + ID: uuid.Must(uuid.NewV7()), + Port: "in", + }, }, } meta.SetPorts(ports) assert.Equal(t, ports, meta.GetPorts()) +} +func TestMeta_SetEnv(t *testing.T) { + meta := &Meta{} env := map[string][]Value{ "FOO": { - {ID: uuid.Must(uuid.NewV7()), Name: "bar", Data: "baz"}, + { + ID: uuid.Must(uuid.NewV7()), + Data: "baz", + }, }, } meta.SetEnv(env) diff --git a/pkg/symbol/symbol.go b/pkg/symbol/symbol.go index 81a52068..a6122d1d 100644 --- a/pkg/symbol/symbol.go +++ b/pkg/symbol/symbol.go @@ -11,10 +11,10 @@ import ( // Symbol represents a Node that is identifiable within a Spec. type Symbol struct { - Spec spec.Spec - Node node.Node - ins map[string]*port.InPort - outs map[string]*port.OutPort + Spec spec.Spec // Spec holds the specification of the Symbol. + Node node.Node // Node is the underlying node of the Symbol. + ins map[string]*port.InPort // ins is a map of input ports. + outs map[string]*port.OutPort // outs is a map of output ports. mu sync.RWMutex }