From aa3602fbb0bcea474b29e7655e26c4d45f93c71c Mon Sep 17 00:00:00 2001 From: Virgil Date: Mon, 30 Mar 2026 00:45:45 +0000 Subject: [PATCH] refactor(ax): remove legacy global process singleton --- global_test.go | 267 ---------------------------------------------- process_global.go | 130 ---------------------- 2 files changed, 397 deletions(-) delete mode 100644 global_test.go delete mode 100644 process_global.go diff --git a/global_test.go b/global_test.go deleted file mode 100644 index 975d682..0000000 --- a/global_test.go +++ /dev/null @@ -1,267 +0,0 @@ -package process - -import ( - "context" - "sync" - "testing" - - framework "dappco.re/go/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGlobal_DefaultNotInitialized(t *testing.T) { - // Reset global state for this test - old := defaultService.Swap(nil) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - assert.Nil(t, Default()) - - _, err := Start(context.Background(), "echo", "test") - assert.ErrorIs(t, err, ErrServiceNotInitialized) - - _, err = Run(context.Background(), "echo", "test") - assert.ErrorIs(t, err, ErrServiceNotInitialized) - - _, err = Get("proc-1") - assert.ErrorIs(t, err, ErrServiceNotInitialized) - - assert.Nil(t, List()) - assert.Nil(t, Running()) - - err = Kill("proc-1") - assert.ErrorIs(t, err, ErrServiceNotInitialized) - - _, err = StartWithOptions(context.Background(), RunOptions{Command: "echo"}) - assert.ErrorIs(t, err, ErrServiceNotInitialized) - - _, err = RunWithOptions(context.Background(), RunOptions{Command: "echo"}) - assert.ErrorIs(t, err, ErrServiceNotInitialized) -} - -func newGlobalTestService(t *testing.T) *Service { - t.Helper() - c := framework.New() - factory := NewService(Options{}) - raw, err := factory(c) - require.NoError(t, err) - return raw.(*Service) -} - -func TestGlobal_SetDefault(t *testing.T) { - t.Run("sets and retrieves service", func(t *testing.T) { - old := defaultService.Swap(nil) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - svc := newGlobalTestService(t) - - err := SetDefault(svc) - require.NoError(t, err) - assert.Equal(t, svc, Default()) - }) - - t.Run("errors on nil", func(t *testing.T) { - err := SetDefault(nil) - assert.Error(t, err) - }) -} - -func TestGlobal_ConcurrentDefault(t *testing.T) { - old := defaultService.Swap(nil) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - svc := newGlobalTestService(t) - - err := SetDefault(svc) - require.NoError(t, err) - - var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() - s := Default() - assert.NotNil(t, s) - assert.Equal(t, svc, s) - }() - } - wg.Wait() -} - -func TestGlobal_ConcurrentSetDefault(t *testing.T) { - old := defaultService.Swap(nil) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - var services []*Service - for i := 0; i < 10; i++ { - svc := newGlobalTestService(t) - services = append(services, svc) - } - - var wg sync.WaitGroup - for _, svc := range services { - wg.Add(1) - go func(s *Service) { - defer wg.Done() - _ = SetDefault(s) - }(svc) - } - wg.Wait() - - final := Default() - assert.NotNil(t, final) - - found := false - for _, svc := range services { - if svc == final { - found = true - break - } - } - assert.True(t, found, "Default should be one of the set services") -} - -func TestGlobal_ConcurrentOperations(t *testing.T) { - old := defaultService.Swap(nil) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - svc := newGlobalTestService(t) - - err := SetDefault(svc) - require.NoError(t, err) - - var wg sync.WaitGroup - var processes []*Process - var procMu sync.Mutex - - for i := 0; i < 20; i++ { - wg.Add(1) - go func() { - defer wg.Done() - proc, err := Start(context.Background(), "echo", "concurrent") - if err == nil { - procMu.Lock() - processes = append(processes, proc) - procMu.Unlock() - } - }() - } - - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - _ = List() - _ = Running() - }() - } - - wg.Wait() - - procMu.Lock() - for _, p := range processes { - <-p.Done() - } - procMu.Unlock() - - assert.Len(t, processes, 20) - - var wg2 sync.WaitGroup - for _, p := range processes { - wg2.Add(1) - go func(id string) { - defer wg2.Done() - got, err := Get(id) - assert.NoError(t, err) - assert.NotNil(t, got) - }(p.ID) - } - wg2.Wait() -} - -func TestGlobal_StartWithOptions(t *testing.T) { - svc, _ := newTestService(t) - - old := defaultService.Swap(svc) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - proc, err := StartWithOptions(context.Background(), RunOptions{ - Command: "echo", - Args: []string{"with", "options"}, - }) - require.NoError(t, err) - - <-proc.Done() - - assert.Equal(t, 0, proc.ExitCode) - assert.Contains(t, proc.Output(), "with options") -} - -func TestGlobal_RunWithOptions(t *testing.T) { - svc, _ := newTestService(t) - - old := defaultService.Swap(svc) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - output, err := RunWithOptions(context.Background(), RunOptions{ - Command: "echo", - Args: []string{"run", "options"}, - }) - require.NoError(t, err) - assert.Contains(t, output, "run options") -} - -func TestGlobal_Running(t *testing.T) { - svc, _ := newTestService(t) - - old := defaultService.Swap(svc) - defer func() { - if old != nil { - defaultService.Store(old) - } - }() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - proc, err := Start(ctx, "sleep", "60") - require.NoError(t, err) - - running := Running() - assert.Len(t, running, 1) - assert.Equal(t, proc.ID, running[0].ID) - - cancel() - <-proc.Done() - - running = Running() - assert.Len(t, running, 0) -} diff --git a/process_global.go b/process_global.go deleted file mode 100644 index 041fe4d..0000000 --- a/process_global.go +++ /dev/null @@ -1,130 +0,0 @@ -package process - -import ( - "context" - "sync" - "sync/atomic" - - "dappco.re/go/core" - coreerr "dappco.re/go/core/log" -) - -// Global default service (follows i18n pattern). -var ( - defaultService atomic.Pointer[Service] - defaultOnce sync.Once - defaultErr error -) - -// Default returns the global process service. -// Returns nil if not initialized. -func Default() *Service { - return defaultService.Load() -} - -// SetDefault sets the global process service. -// Thread-safe: can be called concurrently with Default(). -func SetDefault(s *Service) error { - if s == nil { - return ErrSetDefaultNil - } - defaultService.Store(s) - return nil -} - -// Init initializes the default global service with a Core instance. -// This is typically called during application startup. -func Init(c *core.Core) error { - defaultOnce.Do(func() { - factory := NewService(Options{}) - svc, err := factory(c) - if err != nil { - defaultErr = err - return - } - defaultService.Store(svc.(*Service)) - }) - return defaultErr -} - -// --- Global convenience functions --- - -// Start spawns a new process using the default service. -func Start(ctx context.Context, command string, args ...string) (*Process, error) { - svc := Default() - if svc == nil { - return nil, ErrServiceNotInitialized - } - return svc.Start(ctx, command, args...) -} - -// Run executes a command and waits for completion using the default service. -func Run(ctx context.Context, command string, args ...string) (string, error) { - svc := Default() - if svc == nil { - return "", ErrServiceNotInitialized - } - return svc.Run(ctx, command, args...) -} - -// Get returns a process by ID from the default service. -func Get(id string) (*Process, error) { - svc := Default() - if svc == nil { - return nil, ErrServiceNotInitialized - } - return svc.Get(id) -} - -// List returns all processes from the default service. -func List() []*Process { - svc := Default() - if svc == nil { - return nil - } - return svc.List() -} - -// Kill terminates a process by ID using the default service. -func Kill(id string) error { - svc := Default() - if svc == nil { - return ErrServiceNotInitialized - } - return svc.Kill(id) -} - -// StartWithOptions spawns a process with full configuration using the default service. -func StartWithOptions(ctx context.Context, opts RunOptions) (*Process, error) { - svc := Default() - if svc == nil { - return nil, ErrServiceNotInitialized - } - return svc.StartWithOptions(ctx, opts) -} - -// RunWithOptions executes a command with options and waits using the default service. -func RunWithOptions(ctx context.Context, opts RunOptions) (string, error) { - svc := Default() - if svc == nil { - return "", ErrServiceNotInitialized - } - return svc.RunWithOptions(ctx, opts) -} - -// Running returns all currently running processes from the default service. -func Running() []*Process { - svc := Default() - if svc == nil { - return nil - } - return svc.Running() -} - -// Errors -var ( - // ErrServiceNotInitialized is returned when the service is not initialized. - ErrServiceNotInitialized = coreerr.E("", "process: service not initialized; call process.Init(core) first", nil) - // ErrSetDefaultNil is returned when SetDefault is called with nil. - ErrSetDefaultNil = coreerr.E("", "process: SetDefault called with nil service", nil) -)