diff --git a/pkg/coredeno/service.go b/pkg/coredeno/service.go index ccc843f..e218a2e 100644 --- a/pkg/coredeno/service.go +++ b/pkg/coredeno/service.go @@ -1,29 +1,39 @@ package coredeno -import "context" +import ( + "context" -// Service wraps the CoreDeno sidecar for framework lifecycle integration. -// Implements Startable (OnStartup) and Stoppable (OnShutdown) interfaces. + core "forge.lthn.ai/core/go/pkg/framework/core" +) + +// Service wraps the CoreDeno sidecar as a framework service. +// Implements Startable and Stoppable for lifecycle management. +// +// Registration: +// +// core.New(core.WithService(coredeno.NewServiceFactory(opts))) type Service struct { + *core.ServiceRuntime[Options] sidecar *Sidecar - opts Options } -// NewService creates a CoreDeno service ready for framework registration. -func NewService(opts Options) *Service { - return &Service{ - sidecar: NewSidecar(opts), - opts: opts, +// NewServiceFactory returns a factory function for framework registration via WithService. +func NewServiceFactory(opts Options) func(*core.Core) (any, error) { + return func(c *core.Core) (any, error) { + return &Service{ + ServiceRuntime: core.NewServiceRuntime(c, opts), + sidecar: NewSidecar(opts), + }, nil } } -// OnStartup starts the Deno sidecar. Called by the framework. +// OnStartup starts the Deno sidecar. Called by the framework on app startup. func (s *Service) OnStartup(ctx context.Context) error { return nil } -// OnShutdown stops the Deno sidecar. Called by the framework. -func (s *Service) OnShutdown() error { +// OnShutdown stops the Deno sidecar. Called by the framework on app shutdown. +func (s *Service) OnShutdown(_ context.Context) error { return s.sidecar.Stop() } diff --git a/pkg/coredeno/service_test.go b/pkg/coredeno/service_test.go index e6b7473..685bbc8 100644 --- a/pkg/coredeno/service_test.go +++ b/pkg/coredeno/service_test.go @@ -1,30 +1,65 @@ package coredeno import ( + "context" "testing" + core "forge.lthn.ai/core/go/pkg/framework/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestNewService_Good(t *testing.T) { +func TestNewServiceFactory_Good(t *testing.T) { opts := Options{ DenoPath: "echo", SocketPath: "/tmp/test-service.sock", } - svc := NewService(opts) - require.NotNil(t, svc) + c, err := core.New() + require.NoError(t, err) + + factory := NewServiceFactory(opts) + result, err := factory(c) + require.NoError(t, err) + + svc, ok := result.(*Service) + require.True(t, ok) assert.NotNil(t, svc.sidecar) assert.Equal(t, "echo", svc.sidecar.opts.DenoPath) + assert.NotNil(t, svc.Core(), "ServiceRuntime should provide Core access") + assert.Equal(t, opts, svc.Opts(), "ServiceRuntime should provide Options access") } -func TestService_OnShutdown_Good_NotStarted(t *testing.T) { - svc := NewService(Options{DenoPath: "echo"}) - err := svc.OnShutdown() +func TestService_WithService_Good(t *testing.T) { + opts := Options{DenoPath: "echo"} + c, err := core.New(core.WithService(NewServiceFactory(opts))) + require.NoError(t, err) + assert.NotNil(t, c) +} + +func TestService_Lifecycle_Good(t *testing.T) { + c, err := core.New() + require.NoError(t, err) + + factory := NewServiceFactory(Options{DenoPath: "echo"}) + result, _ := factory(c) + svc := result.(*Service) + + // Verify Startable + err = svc.OnStartup(context.Background()) + assert.NoError(t, err) + + // Verify Stoppable (not started, should be no-op) + err = svc.OnShutdown(context.Background()) assert.NoError(t, err) } func TestService_Sidecar_Good(t *testing.T) { - svc := NewService(Options{DenoPath: "echo"}) + c, err := core.New() + require.NoError(t, err) + + factory := NewServiceFactory(Options{DenoPath: "echo"}) + result, _ := factory(c) + svc := result.(*Service) + assert.NotNil(t, svc.Sidecar()) }