fix: add command executor interface for better testing

Introduce the CommandExecutor interface to abstract command execution, 
allowing for easier mocking in tests. Implement DefaultCommandExecutor 
to use the os/exec package for executing commands. Update the 
GenerateCosmoRouterConfig function to utilize the new 
GenerateCosmoRouterConfigWithExecutor function that accepts a command 
executor parameter. Add a MockCommandExecutor for simulating command 
execution in unit tests with realistic behavior based on input YAML 
files. This enhances test coverage and simplifies error handling.
This commit is contained in:
2025-11-20 21:09:00 +01:00
parent df44ddbb8e
commit 47dbf827f2
2 changed files with 233 additions and 4 deletions
+22 -3
View File
@@ -11,9 +11,30 @@ import (
"gitlab.com/unboundsoftware/schemas/graph/model"
)
// CommandExecutor is an interface for executing external commands
// This allows for mocking in tests
type CommandExecutor interface {
Execute(name string, args ...string) ([]byte, error)
}
// DefaultCommandExecutor implements CommandExecutor using os/exec
type DefaultCommandExecutor struct{}
// Execute runs a command and returns its combined output
func (e *DefaultCommandExecutor) Execute(name string, args ...string) ([]byte, error) {
cmd := exec.Command(name, args...)
return cmd.CombinedOutput()
}
// GenerateCosmoRouterConfig generates a Cosmo Router execution config from subgraphs
// using the official wgc CLI tool via npx
func GenerateCosmoRouterConfig(subGraphs []*model.SubGraph) (string, error) {
return GenerateCosmoRouterConfigWithExecutor(subGraphs, &DefaultCommandExecutor{})
}
// GenerateCosmoRouterConfigWithExecutor generates a Cosmo Router execution config from subgraphs
// using the provided command executor (useful for testing)
func GenerateCosmoRouterConfigWithExecutor(subGraphs []*model.SubGraph, executor CommandExecutor) (string, error) {
if len(subGraphs) == 0 {
return "", fmt.Errorf("no subgraphs provided")
}
@@ -85,13 +106,11 @@ func GenerateCosmoRouterConfig(subGraphs []*model.SubGraph) (string, error) {
// Execute wgc router compose
// wgc is installed globally in the Docker image
outputFile := filepath.Join(tmpDir, "config.json")
cmd := exec.Command("wgc", "router", "compose",
output, err := executor.Execute("wgc", "router", "compose",
"--input", inputFile,
"--out", outputFile,
"--suppress-warnings",
)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("wgc router compose failed: %w\nOutput: %s", err, string(output))
}