Add Promptkit configuration and inspection seams
This commit is contained in:
59
internal/cli/executor_factory.go
Normal file
59
internal/cli/executor_factory.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
promptkitadapter "gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/promptkit"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptexec"
|
||||
)
|
||||
|
||||
// PromptExecutorConfig is the project-owned construction input for one prompt
|
||||
// executor. It keeps adapter implementation types out of Runner's API.
|
||||
type PromptExecutorConfig struct {
|
||||
Profile string
|
||||
ProfileFile string
|
||||
ProfileDirectory string
|
||||
Timeout time.Duration
|
||||
LocalEndpoint string
|
||||
LocalConcurrencyLimit int
|
||||
}
|
||||
|
||||
// ExecutorFactory constructs one executor for an action.
|
||||
type ExecutorFactory func(PromptExecutorConfig) (promptexec.Executor, error)
|
||||
|
||||
func (r Runner) promptExecutor(cfg config.PromptkitConfig) (promptexec.Executor, error) {
|
||||
factory := r.ExecutorFactory
|
||||
if factory == nil {
|
||||
factory = newPromptkitExecutor
|
||||
}
|
||||
return factory(promptExecutorConfig(cfg))
|
||||
}
|
||||
|
||||
func promptExecutorConfig(cfg config.PromptkitConfig) PromptExecutorConfig {
|
||||
result := PromptExecutorConfig{
|
||||
Profile: cfg.Profile,
|
||||
ProfileFile: cfg.ProfileFile,
|
||||
ProfileDirectory: cfg.ProfileDir,
|
||||
Timeout: cfg.Timeout,
|
||||
}
|
||||
if cfg.Local.Endpoint != "" {
|
||||
result.LocalEndpoint = cfg.Local.Endpoint
|
||||
result.LocalConcurrencyLimit = cfg.Local.ConcurrencyLimit
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func newPromptkitExecutor(cfg PromptExecutorConfig) (promptexec.Executor, error) {
|
||||
return promptkitadapter.New(promptkitAdapterConfig(cfg))
|
||||
}
|
||||
|
||||
func promptkitAdapterConfig(cfg PromptExecutorConfig) promptkitadapter.Config {
|
||||
return promptkitadapter.Config{
|
||||
ProfileDirectory: cfg.ProfileDirectory,
|
||||
ProfileFile: cfg.ProfileFile,
|
||||
LocalEndpoint: cfg.LocalEndpoint,
|
||||
LocalConcurrencyLimit: cfg.LocalConcurrencyLimit,
|
||||
Timeout: cfg.Timeout,
|
||||
}
|
||||
}
|
||||
78
internal/cli/executor_factory_test.go
Normal file
78
internal/cli/executor_factory_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
promptkitadapter "gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/promptkit"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptexec"
|
||||
)
|
||||
|
||||
func TestRunnerPromptExecutorMapsConfigurationOnce(t *testing.T) {
|
||||
var calls int
|
||||
var received PromptExecutorConfig
|
||||
runner := Runner{ExecutorFactory: func(value PromptExecutorConfig) (promptexec.Executor, error) {
|
||||
calls++
|
||||
received = value
|
||||
return factoryExecutor{}, nil
|
||||
}}
|
||||
executor, err := runner.promptExecutor(config.PromptkitConfig{
|
||||
Profile: "selected-profile",
|
||||
ProfileFile: "/etc/weatherreporter/profile.yml",
|
||||
Timeout: 45 * time.Second,
|
||||
Local: config.PromptkitLocalConfig{
|
||||
Endpoint: "http://127.0.0.1:8080",
|
||||
ConcurrencyLimit: 3,
|
||||
},
|
||||
})
|
||||
if err != nil || executor == nil || calls != 1 {
|
||||
t.Fatalf("executor/error/calls = %#v/%v/%d", executor, err, calls)
|
||||
}
|
||||
want := PromptExecutorConfig{
|
||||
Profile: "selected-profile", ProfileFile: "/etc/weatherreporter/profile.yml", Timeout: 45 * time.Second,
|
||||
LocalEndpoint: "http://127.0.0.1:8080", LocalConcurrencyLimit: 3,
|
||||
}
|
||||
if received != want {
|
||||
t.Fatalf("factory config = %#v, want %#v", received, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptExecutorConfigLeavesBlankLocalBackendUnregistered(t *testing.T) {
|
||||
value := promptExecutorConfig(config.PromptkitConfig{
|
||||
Timeout: 2 * time.Minute,
|
||||
Local: config.PromptkitLocalConfig{ConcurrencyLimit: 1},
|
||||
})
|
||||
if value.LocalEndpoint != "" || value.LocalConcurrencyLimit != 0 {
|
||||
t.Fatalf("executor config = %#v, want no local backend", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptkitAdapterConfigMapsExecutorSettings(t *testing.T) {
|
||||
adapterConfig := promptkitAdapterConfig(PromptExecutorConfig{
|
||||
ProfileDirectory: "/etc/weatherreporter/profiles",
|
||||
Timeout: 30 * time.Second, LocalEndpoint: "http://127.0.0.1:8080", LocalConcurrencyLimit: 2,
|
||||
})
|
||||
want := promptkitadapter.Config{
|
||||
ProfileDirectory: "/etc/weatherreporter/profiles",
|
||||
Timeout: 30 * time.Second, LocalEndpoint: "http://127.0.0.1:8080", LocalConcurrencyLimit: 2,
|
||||
}
|
||||
if adapterConfig != want {
|
||||
t.Fatalf("adapter config = %#v, want %#v", adapterConfig, want)
|
||||
}
|
||||
}
|
||||
|
||||
type factoryExecutor struct{}
|
||||
|
||||
func (factoryExecutor) InspectPrompt(context.Context, string, string) (promptexec.PromptInspection, error) {
|
||||
return promptexec.PromptInspection{}, nil
|
||||
}
|
||||
|
||||
func (factoryExecutor) InspectProfile(context.Context, string) (promptexec.ProfileInspection, error) {
|
||||
return promptexec.ProfileInspection{}, nil
|
||||
}
|
||||
|
||||
func (factoryExecutor) Execute(context.Context, promptexec.ExecuteRequest, promptexec.PreparationCallback) (*promptexec.Execution, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -40,7 +40,8 @@ Options:
|
||||
`
|
||||
|
||||
type Runner struct {
|
||||
Clock timeutil.Clock
|
||||
Clock timeutil.Clock
|
||||
ExecutorFactory ExecutorFactory
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, args []string, stdout io.Writer, stderr io.Writer) error {
|
||||
|
||||
Reference in New Issue
Block a user