feat(coredeno): wire Service into framework DI with ServiceRuntime[T]

Service embeds ServiceRuntime[Options] for Core/Opts access.
NewServiceFactory returns factory for core.WithService registration.
Correct Startable/Stoppable signatures with context.Context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude 2026-02-17 21:12:27 +00:00
parent e8695b72a6
commit 7d047fbdcc
No known key found for this signature in database
GPG key ID: AF404715446AEB41
2 changed files with 64 additions and 19 deletions

View file

@ -1,29 +1,39 @@
package coredeno package coredeno
import "context" import (
"context"
// Service wraps the CoreDeno sidecar for framework lifecycle integration. core "forge.lthn.ai/core/go/pkg/framework/core"
// Implements Startable (OnStartup) and Stoppable (OnShutdown) interfaces. )
// 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 { type Service struct {
*core.ServiceRuntime[Options]
sidecar *Sidecar sidecar *Sidecar
opts Options
} }
// NewService creates a CoreDeno service ready for framework registration. // NewServiceFactory returns a factory function for framework registration via WithService.
func NewService(opts Options) *Service { func NewServiceFactory(opts Options) func(*core.Core) (any, error) {
return func(c *core.Core) (any, error) {
return &Service{ return &Service{
ServiceRuntime: core.NewServiceRuntime(c, opts),
sidecar: NewSidecar(opts), sidecar: NewSidecar(opts),
opts: 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 { func (s *Service) OnStartup(ctx context.Context) error {
return nil return nil
} }
// OnShutdown stops the Deno sidecar. Called by the framework. // OnShutdown stops the Deno sidecar. Called by the framework on app shutdown.
func (s *Service) OnShutdown() error { func (s *Service) OnShutdown(_ context.Context) error {
return s.sidecar.Stop() return s.sidecar.Stop()
} }

View file

@ -1,30 +1,65 @@
package coredeno package coredeno
import ( import (
"context"
"testing" "testing"
core "forge.lthn.ai/core/go/pkg/framework/core"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNewService_Good(t *testing.T) { func TestNewServiceFactory_Good(t *testing.T) {
opts := Options{ opts := Options{
DenoPath: "echo", DenoPath: "echo",
SocketPath: "/tmp/test-service.sock", SocketPath: "/tmp/test-service.sock",
} }
svc := NewService(opts) c, err := core.New()
require.NotNil(t, svc) 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.NotNil(t, svc.sidecar)
assert.Equal(t, "echo", svc.sidecar.opts.DenoPath) 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) { func TestService_WithService_Good(t *testing.T) {
svc := NewService(Options{DenoPath: "echo"}) opts := Options{DenoPath: "echo"}
err := svc.OnShutdown() 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) assert.NoError(t, err)
} }
func TestService_Sidecar_Good(t *testing.T) { 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()) assert.NotNil(t, svc.Sidecar())
} }