refactor(cef): inject engine dependencies from bootstrap
- commit
- feb43a6499399b3bcc8587b4caca1a4418615bc5
- author
- brice · · 2026-04-11 12:58 UTC
- parent
- b6125b8
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +101 -7
M internal/bootstrap/engine.go +31 -1
| @@ -2,12 +2,16 @@ package bootstrap | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "context" | |
| 5 | + | "encoding/json" | |
| 5 | 6 | "fmt" | |
| 6 | 7 | ||
| 7 | 8 | "github.com/bnema/dumber/internal/application/port" | |
| 8 | 9 | audiofactory "github.com/bnema/dumber/internal/infrastructure/audio/factory" | |
| 9 | 10 | "github.com/bnema/dumber/internal/infrastructure/cef" | |
| 10 | 11 | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 12 | + | "github.com/bnema/dumber/internal/infrastructure/env" | |
| 13 | + | "github.com/bnema/dumber/internal/infrastructure/handlers" | |
| 14 | + | "github.com/bnema/dumber/internal/infrastructure/transcoder" | |
| 11 | 15 | "github.com/bnema/dumber/internal/infrastructure/webkit" | |
| 12 | 16 | "github.com/bnema/dumber/internal/ui/theme" | |
| 13 | 17 | "github.com/rs/zerolog" | |
| @@ -62,8 +66,34 @@ func BuildEngine(input EngineInput) (port.Engine, error) { | |||
| 62 | 66 | MaxConcurrent: cfg.Transcoding.MaxConcurrent, | |
| 63 | 67 | Quality: cfg.Transcoding.Quality, | |
| 64 | 68 | } | |
| 69 | + | surveyor := env.NewHardwareSurveyor() | |
| 70 | + | buildConfigPayload := func(cfgf func() *config.Config) func() ([]byte, error) { | |
| 71 | + | return func() ([]byte, error) { | |
| 72 | + | cfg := cfgf() | |
| 73 | + | var hw *port.HardwareInfo | |
| 74 | + | if surveyor != nil { | |
| 75 | + | survey := surveyor.Survey(context.Background()) | |
| 76 | + | hw = &survey | |
| 77 | + | } | |
| 78 | + | return json.Marshal(config.BuildWebUIConfigPayload(cfg, hw)) | |
| 79 | + | } | |
| 80 | + | } | |
| 81 | + | deps := cef.EngineDependencies{ | |
| 82 | + | RegisterHandlers: handlers.RegisterAll, | |
| 83 | + | RegisterAccentHandlers: handlers.RegisterAccentHandlers, | |
| 84 | + | CurrentConfigPayload: buildConfigPayload(config.Get), | |
| 85 | + | DefaultConfigPayload: buildConfigPayload(config.DefaultConfig), | |
| 86 | + | MediaClassifier: cef.MediaClassifier{ | |
| 87 | + | IsProprietaryVideoMIME: transcoder.IsProprietaryVideoMIME, | |
| 88 | + | IsOpenVideoMIME: transcoder.IsOpenVideoMIME, | |
| 89 | + | IsStreamingManifestMIME: transcoder.IsStreamingManifestMIME, | |
| 90 | + | IsStreamingManifestURL: transcoder.IsStreamingManifestURL, | |
| 91 | + | IsEagerTranscodeURL: transcoder.IsEagerTranscodeURL, | |
| 92 | + | ParseSyntheticTranscodeURL: transcoder.ParseSyntheticTranscodeURL, | |
| 93 | + | }, | |
| 94 | + | } | |
| 65 | 95 | audioFactory := audiofactory.NewAudioOutputFactory() | |
| 66 | - | return cef.NewEngine(input.Ctx, opts, cefCfg, transcodingCfg, audioFactory, cef.EngineDependencies{}) | |
| 96 | + | return cef.NewEngine(input.Ctx, opts, cefCfg, transcodingCfg, audioFactory, deps) | |
| 67 | 97 | default: | |
| 68 | 98 | return nil, fmt.Errorf("unknown engine type: %q", engineType) | |
| 69 | 99 | } | |
| @@ -2,12 +2,16 @@ package bootstrap | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "context" | 4 | "context" | ||
| 5 | + | "encoding/json" | |||
| 5 | "fmt" | 6 | "fmt" | ||
| 6 | 7 | ||||
| 7 | "github.com/bnema/dumber/internal/application/port" | 8 | "github.com/bnema/dumber/internal/application/port" | ||
| 8 | audiofactory "github.com/bnema/dumber/internal/infrastructure/audio/factory" | 9 | audiofactory "github.com/bnema/dumber/internal/infrastructure/audio/factory" | ||
| 9 | "github.com/bnema/dumber/internal/infrastructure/cef" | 10 | "github.com/bnema/dumber/internal/infrastructure/cef" | ||
| 10 | "github.com/bnema/dumber/internal/infrastructure/config" | 11 | "github.com/bnema/dumber/internal/infrastructure/config" | ||
| 12 | + | "github.com/bnema/dumber/internal/infrastructure/env" | |||
| 13 | + | "github.com/bnema/dumber/internal/infrastructure/handlers" | |||
| 14 | + | "github.com/bnema/dumber/internal/infrastructure/transcoder" | |||
| 11 | "github.com/bnema/dumber/internal/infrastructure/webkit" | 15 | "github.com/bnema/dumber/internal/infrastructure/webkit" | ||
| 12 | "github.com/bnema/dumber/internal/ui/theme" | 16 | "github.com/bnema/dumber/internal/ui/theme" | ||
| 13 | "github.com/rs/zerolog" | 17 | "github.com/rs/zerolog" | ||
| @@ -62,8 +66,34 @@ func BuildEngine(input EngineInput) (port.Engine, error) { | |||||
| 62 | MaxConcurrent: cfg.Transcoding.MaxConcurrent, | 66 | MaxConcurrent: cfg.Transcoding.MaxConcurrent, | ||
| 63 | Quality: cfg.Transcoding.Quality, | 67 | Quality: cfg.Transcoding.Quality, | ||
| 64 | } | 68 | } | ||
| 69 | + | surveyor := env.NewHardwareSurveyor() | |||
| 70 | + | buildConfigPayload := func(cfgf func() *config.Config) func() ([]byte, error) { | |||
| 71 | + | return func() ([]byte, error) { | |||
| 72 | + | cfg := cfgf() | |||
| 73 | + | var hw *port.HardwareInfo | |||
| 74 | + | if surveyor != nil { | |||
| 75 | + | survey := surveyor.Survey(context.Background()) | |||
| 76 | + | hw = &survey | |||
| 77 | + | } | |||
| 78 | + | return json.Marshal(config.BuildWebUIConfigPayload(cfg, hw)) | |||
| 79 | + | } | |||
| 80 | + | } | |||
| 81 | + | deps := cef.EngineDependencies{ | |||
| 82 | + | RegisterHandlers: handlers.RegisterAll, | |||
| 83 | + | RegisterAccentHandlers: handlers.RegisterAccentHandlers, | |||
| 84 | + | CurrentConfigPayload: buildConfigPayload(config.Get), | |||
| 85 | + | DefaultConfigPayload: buildConfigPayload(config.DefaultConfig), | |||
| 86 | + | MediaClassifier: cef.MediaClassifier{ | |||
| 87 | + | IsProprietaryVideoMIME: transcoder.IsProprietaryVideoMIME, | |||
| 88 | + | IsOpenVideoMIME: transcoder.IsOpenVideoMIME, | |||
| 89 | + | IsStreamingManifestMIME: transcoder.IsStreamingManifestMIME, | |||
| 90 | + | IsStreamingManifestURL: transcoder.IsStreamingManifestURL, | |||
| 91 | + | IsEagerTranscodeURL: transcoder.IsEagerTranscodeURL, | |||
| 92 | + | ParseSyntheticTranscodeURL: transcoder.ParseSyntheticTranscodeURL, | |||
| 93 | + | }, | |||
| 94 | + | } | |||
| 65 | audioFactory := audiofactory.NewAudioOutputFactory() | 95 | audioFactory := audiofactory.NewAudioOutputFactory() | ||
| 66 | - | return cef.NewEngine(input.Ctx, opts, cefCfg, transcodingCfg, audioFactory, cef.EngineDependencies{}) | 96 | + | return cef.NewEngine(input.Ctx, opts, cefCfg, transcodingCfg, audioFactory, deps) |
| 67 | default: | 97 | default: | ||
| 68 | return nil, fmt.Errorf("unknown engine type: %q", engineType) | 98 | return nil, fmt.Errorf("unknown engine type: %q", engineType) | ||
| 69 | } | 99 | } | ||
M internal/infrastructure/cef/engine.go +10 -5
| @@ -9,7 +9,6 @@ import ( | |||
| 9 | 9 | purecef "github.com/bnema/purego-cef/cef" | |
| 10 | 10 | ||
| 11 | 11 | "github.com/bnema/dumber/internal/application/port" | |
| 12 | - | "github.com/bnema/dumber/internal/infrastructure/handlers" | |
| 13 | 12 | "github.com/bnema/dumber/internal/logging" | |
| 14 | 13 | ) | |
| 15 | 14 | ||
| @@ -28,6 +27,12 @@ type Engine struct { | |||
| 28 | 27 | schemeHandler *dumbSchemeHandler | |
| 29 | 28 | contentInj *contentInjector | |
| 30 | 29 | ||
| 30 | + | registerHandlers HandlerRegistrar | |
| 31 | + | registerAccentHandlers AccentHandlerRegistrar | |
| 32 | + | currentConfigPayload func() ([]byte, error) | |
| 33 | + | defaultConfigPayload func() ([]byte, error) | |
| 34 | + | mediaClassifier MediaClassifier | |
| 35 | + | ||
| 31 | 36 | // activeWebViews tracks all live webviews for CSS broadcast. | |
| 32 | 37 | activeWebViews sync.Map // map[port.WebViewID]*WebView | |
| 33 | 38 | activeCount atomic.Int32 | |
| @@ -210,17 +215,17 @@ func (e *Engine) closeActiveWebViews() { | |||
| 210 | 215 | // each handler is registered by message type with the router, which dispatches | |
| 211 | 216 | // incoming /api/message POSTs to the correct handler based on Message.Type. | |
| 212 | 217 | func (e *Engine) RegisterHandlers(ctx context.Context, deps port.HandlerDependencies) error { | |
| 213 | - | if e.messageRouter == nil { | |
| 218 | + | if e.messageRouter == nil || e.registerHandlers == nil { | |
| 214 | 219 | return nil | |
| 215 | 220 | } | |
| 216 | - | return handlers.RegisterAll(ctx, e.messageRouter, deps) | |
| 221 | + | return e.registerHandlers(ctx, e.messageRouter, deps) | |
| 217 | 222 | } | |
| 218 | 223 | ||
| 219 | 224 | func (e *Engine) RegisterAccentHandlers(ctx context.Context, handler port.AccentKeyHandler) error { | |
| 220 | - | if e.messageRouter == nil || handler == nil { | |
| 225 | + | if e.messageRouter == nil || handler == nil || e.registerAccentHandlers == nil { | |
| 221 | 226 | return nil | |
| 222 | 227 | } | |
| 223 | - | return handlers.RegisterAccentHandlers(ctx, e.messageRouter, handler) | |
| 228 | + | return e.registerAccentHandlers(ctx, e.messageRouter, handler) | |
| 224 | 229 | } | |
| 225 | 230 | ||
| 226 | 231 | // ConfigureDownloads sets up download handling (Phase 1 stub). | |
| @@ -9,7 +9,6 @@ import ( | |||||
| 9 | purecef "github.com/bnema/purego-cef/cef" | 9 | purecef "github.com/bnema/purego-cef/cef" | ||
| 10 | 10 | ||||
| 11 | "github.com/bnema/dumber/internal/application/port" | 11 | "github.com/bnema/dumber/internal/application/port" | ||
| 12 | - | "github.com/bnema/dumber/internal/infrastructure/handlers" | |||
| 13 | "github.com/bnema/dumber/internal/logging" | 12 | "github.com/bnema/dumber/internal/logging" | ||
| 14 | ) | 13 | ) | ||
| 15 | 14 | ||||
| @@ -28,6 +27,12 @@ type Engine struct { | |||||
| 28 | schemeHandler *dumbSchemeHandler | 27 | schemeHandler *dumbSchemeHandler | ||
| 29 | contentInj *contentInjector | 28 | contentInj *contentInjector | ||
| 30 | 29 | ||||
| 30 | + | registerHandlers HandlerRegistrar | |||
| 31 | + | registerAccentHandlers AccentHandlerRegistrar | |||
| 32 | + | currentConfigPayload func() ([]byte, error) | |||
| 33 | + | defaultConfigPayload func() ([]byte, error) | |||
| 34 | + | mediaClassifier MediaClassifier | |||
| 35 | + | ||||
| 31 | // activeWebViews tracks all live webviews for CSS broadcast. | 36 | // activeWebViews tracks all live webviews for CSS broadcast. | ||
| 32 | activeWebViews sync.Map // map[port.WebViewID]*WebView | 37 | activeWebViews sync.Map // map[port.WebViewID]*WebView | ||
| 33 | activeCount atomic.Int32 | 38 | activeCount atomic.Int32 | ||
| @@ -210,17 +215,17 @@ func (e *Engine) closeActiveWebViews() { | |||||
| 210 | // each handler is registered by message type with the router, which dispatches | 215 | // each handler is registered by message type with the router, which dispatches | ||
| 211 | // incoming /api/message POSTs to the correct handler based on Message.Type. | 216 | // incoming /api/message POSTs to the correct handler based on Message.Type. | ||
| 212 | func (e *Engine) RegisterHandlers(ctx context.Context, deps port.HandlerDependencies) error { | 217 | func (e *Engine) RegisterHandlers(ctx context.Context, deps port.HandlerDependencies) error { | ||
| 213 | - | if e.messageRouter == nil { | 218 | + | if e.messageRouter == nil || e.registerHandlers == nil { |
| 214 | return nil | 219 | return nil | ||
| 215 | } | 220 | } | ||
| 216 | - | return handlers.RegisterAll(ctx, e.messageRouter, deps) | 221 | + | return e.registerHandlers(ctx, e.messageRouter, deps) |
| 217 | } | 222 | } | ||
| 218 | 223 | ||||
| 219 | func (e *Engine) RegisterAccentHandlers(ctx context.Context, handler port.AccentKeyHandler) error { | 224 | func (e *Engine) RegisterAccentHandlers(ctx context.Context, handler port.AccentKeyHandler) error { | ||
| 220 | - | if e.messageRouter == nil || handler == nil { | 225 | + | if e.messageRouter == nil || handler == nil || e.registerAccentHandlers == nil { |
| 221 | return nil | 226 | return nil | ||
| 222 | } | 227 | } | ||
| 223 | - | return handlers.RegisterAccentHandlers(ctx, e.messageRouter, handler) | 228 | + | return e.registerAccentHandlers(ctx, e.messageRouter, handler) |
| 224 | } | 229 | } | ||
| 225 | 230 | ||||
| 226 | // ConfigureDownloads sets up download handling (Phase 1 stub). | 231 | // ConfigureDownloads sets up download handling (Phase 1 stub). | ||
M internal/infrastructure/cef/engine_init.go +7 -1
| @@ -33,6 +33,7 @@ func NewEngine( | |||
| 33 | 33 | deps EngineDependencies, | |
| 34 | 34 | ) (*Engine, error) { | |
| 35 | 35 | logger := logging.FromContext(ctx) | |
| 36 | + | deps.MediaClassifier = deps.MediaClassifier.normalize() | |
| 36 | 37 | stateRoot := resolvedStateRoot(opts) | |
| 37 | 38 | cleanStaleSingletonLocks(logger, stateRoot) | |
| 38 | 39 | windowlessFrameRate := config.CEFEngineConfig{WindowlessFrameRate: cfg.WindowlessFrameRate}.CEFWindowlessFrameRate() | |
| @@ -48,7 +49,12 @@ func NewEngine( | |||
| 48 | 49 | os.Args = appendIfMissing(os.Args, "--no-zygote") | |
| 49 | 50 | ||
| 50 | 51 | eng := &Engine{ | |
| 51 | - | ctx: ctx, | |
| 52 | + | ctx: ctx, | |
| 53 | + | registerHandlers: deps.RegisterHandlers, | |
| 54 | + | registerAccentHandlers: deps.RegisterAccentHandlers, | |
| 55 | + | currentConfigPayload: deps.CurrentConfigPayload, | |
| 56 | + | defaultConfigPayload: deps.DefaultConfigPayload, | |
| 57 | + | mediaClassifier: deps.MediaClassifier, | |
| 52 | 58 | } | |
| 53 | 59 | ||
| 54 | 60 | logger.Info(). | |
| @@ -33,6 +33,7 @@ func NewEngine( | |||||
| 33 | deps EngineDependencies, | 33 | deps EngineDependencies, | ||
| 34 | ) (*Engine, error) { | 34 | ) (*Engine, error) { | ||
| 35 | logger := logging.FromContext(ctx) | 35 | logger := logging.FromContext(ctx) | ||
| 36 | + | deps.MediaClassifier = deps.MediaClassifier.normalize() | |||
| 36 | stateRoot := resolvedStateRoot(opts) | 37 | stateRoot := resolvedStateRoot(opts) | ||
| 37 | cleanStaleSingletonLocks(logger, stateRoot) | 38 | cleanStaleSingletonLocks(logger, stateRoot) | ||
| 38 | windowlessFrameRate := config.CEFEngineConfig{WindowlessFrameRate: cfg.WindowlessFrameRate}.CEFWindowlessFrameRate() | 39 | windowlessFrameRate := config.CEFEngineConfig{WindowlessFrameRate: cfg.WindowlessFrameRate}.CEFWindowlessFrameRate() | ||
| @@ -48,7 +49,12 @@ func NewEngine( | |||||
| 48 | os.Args = appendIfMissing(os.Args, "--no-zygote") | 49 | os.Args = appendIfMissing(os.Args, "--no-zygote") | ||
| 49 | 50 | ||||
| 50 | eng := &Engine{ | 51 | eng := &Engine{ | ||
| 51 | - | ctx: ctx, | 52 | + | ctx: ctx, |
| 53 | + | registerHandlers: deps.RegisterHandlers, | |||
| 54 | + | registerAccentHandlers: deps.RegisterAccentHandlers, | |||
| 55 | + | currentConfigPayload: deps.CurrentConfigPayload, | |||
| 56 | + | defaultConfigPayload: deps.DefaultConfigPayload, | |||
| 57 | + | mediaClassifier: deps.MediaClassifier, | |||
| 52 | } | 58 | } | ||
| 53 | 59 | ||||
| 54 | logger.Info(). | 60 | logger.Info(). | ||
A internal/infrastructure/cef/engine_runtime_test.go +53 -0
| @@ -0,0 +1,53 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "context" | |
| 5 | + | "errors" | |
| 6 | + | "testing" | |
| 7 | + | ||
| 8 | + | "github.com/bnema/dumber/internal/application/port" | |
| 9 | + | "github.com/stretchr/testify/require" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | type stubAccentHandler struct{} | |
| 13 | + | ||
| 14 | + | func (stubAccentHandler) OnKeyPressed(context.Context, rune, bool) bool { return true } | |
| 15 | + | func (stubAccentHandler) OnKeyReleased(context.Context, rune) {} | |
| 16 | + | ||
| 17 | + | func TestEngineRegisterHandlers_UsesInjectedRegistrar(t *testing.T) { | |
| 18 | + | called := false | |
| 19 | + | eng := &Engine{ | |
| 20 | + | messageRouter: NewMessageRouter(context.Background()), | |
| 21 | + | registerHandlers: func(context.Context, port.WebUIHandlerRouter, port.HandlerDependencies) error { | |
| 22 | + | called = true | |
| 23 | + | return nil | |
| 24 | + | }, | |
| 25 | + | } | |
| 26 | + | require.NoError(t, eng.RegisterHandlers(context.Background(), port.HandlerDependencies{})) | |
| 27 | + | require.True(t, called) | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | func TestEngineRegisterAccentHandlers_UsesInjectedRegistrar(t *testing.T) { | |
| 31 | + | called := false | |
| 32 | + | eng := &Engine{ | |
| 33 | + | messageRouter: NewMessageRouter(context.Background()), | |
| 34 | + | registerAccentHandlers: func(context.Context, port.WebUIHandlerRouter, port.AccentKeyHandler) error { | |
| 35 | + | called = true | |
| 36 | + | return nil | |
| 37 | + | }, | |
| 38 | + | } | |
| 39 | + | require.NoError(t, eng.RegisterAccentHandlers(context.Background(), stubAccentHandler{})) | |
| 40 | + | require.True(t, called) | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | func TestEngineRegisterHandlers_PropagatesRegistrarError(t *testing.T) { | |
| 44 | + | want := errors.New("boom") | |
| 45 | + | eng := &Engine{ | |
| 46 | + | messageRouter: NewMessageRouter(context.Background()), | |
| 47 | + | registerHandlers: func(context.Context, port.WebUIHandlerRouter, port.HandlerDependencies) error { | |
| 48 | + | return want | |
| 49 | + | }, | |
| 50 | + | } | |
| 51 | + | err := eng.RegisterHandlers(context.Background(), port.HandlerDependencies{}) | |
| 52 | + | require.ErrorIs(t, err, want) | |
| 53 | + | } | |
| @@ -0,0 +1,53 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "context" | |||
| 5 | + | "errors" | |||
| 6 | + | "testing" | |||
| 7 | + | ||||
| 8 | + | "github.com/bnema/dumber/internal/application/port" | |||
| 9 | + | "github.com/stretchr/testify/require" | |||
| 10 | + | ) | |||
| 11 | + | ||||
| 12 | + | type stubAccentHandler struct{} | |||
| 13 | + | ||||
| 14 | + | func (stubAccentHandler) OnKeyPressed(context.Context, rune, bool) bool { return true } | |||
| 15 | + | func (stubAccentHandler) OnKeyReleased(context.Context, rune) {} | |||
| 16 | + | ||||
| 17 | + | func TestEngineRegisterHandlers_UsesInjectedRegistrar(t *testing.T) { | |||
| 18 | + | called := false | |||
| 19 | + | eng := &Engine{ | |||
| 20 | + | messageRouter: NewMessageRouter(context.Background()), | |||
| 21 | + | registerHandlers: func(context.Context, port.WebUIHandlerRouter, port.HandlerDependencies) error { | |||
| 22 | + | called = true | |||
| 23 | + | return nil | |||
| 24 | + | }, | |||
| 25 | + | } | |||
| 26 | + | require.NoError(t, eng.RegisterHandlers(context.Background(), port.HandlerDependencies{})) | |||
| 27 | + | require.True(t, called) | |||
| 28 | + | } | |||
| 29 | + | ||||
| 30 | + | func TestEngineRegisterAccentHandlers_UsesInjectedRegistrar(t *testing.T) { | |||
| 31 | + | called := false | |||
| 32 | + | eng := &Engine{ | |||
| 33 | + | messageRouter: NewMessageRouter(context.Background()), | |||
| 34 | + | registerAccentHandlers: func(context.Context, port.WebUIHandlerRouter, port.AccentKeyHandler) error { | |||
| 35 | + | called = true | |||
| 36 | + | return nil | |||
| 37 | + | }, | |||
| 38 | + | } | |||
| 39 | + | require.NoError(t, eng.RegisterAccentHandlers(context.Background(), stubAccentHandler{})) | |||
| 40 | + | require.True(t, called) | |||
| 41 | + | } | |||
| 42 | + | ||||
| 43 | + | func TestEngineRegisterHandlers_PropagatesRegistrarError(t *testing.T) { | |||
| 44 | + | want := errors.New("boom") | |||
| 45 | + | eng := &Engine{ | |||
| 46 | + | messageRouter: NewMessageRouter(context.Background()), | |||
| 47 | + | registerHandlers: func(context.Context, port.WebUIHandlerRouter, port.HandlerDependencies) error { | |||
| 48 | + | return want | |||
| 49 | + | }, | |||
| 50 | + | } | |||
| 51 | + | err := eng.RegisterHandlers(context.Background(), port.HandlerDependencies{}) | |||
| 52 | + | require.ErrorIs(t, err, want) | |||
| 53 | + | } | |||