refactor(ax): remove legacy global process singleton
This commit is contained in:
parent
15e4c8ddeb
commit
aa3602fbb0
2 changed files with 0 additions and 397 deletions
267
global_test.go
267
global_test.go
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue