mirror of
https://github.com/j3ssie/osmedeus.git
synced 2026-10-01 22:15:00 +02:00
Fixes four reported issues. #321 / #322 — POST /osm/api/runs was unusable when the server was started with --settings-file. That branch in pkg/cli/root.go loaded the settings via config.LoadFromFile (a plain YAML unmarshal) and never called ResolvePaths(), so every derived runtime path stayed empty. An empty WorkflowsPath made workflow lookups scan "" (reported as "Workflow not found") and made a flow's relative module refs resolve against the process working directory. - root.go now resolves paths (and applies env overrides) on that branch - ResolvePaths backfills any environments.* key a partial settings file omits, sourced from the new defaultEnvironments() so DefaultConfig and the backfill can no longer drift - parser.ErrWorkflowsDirNotConfigured replaces the silent cwd fallback, so all loader call sites report the misconfiguration instead of a misleading 404 #323 — a run submitted with run_mode:distributed could be lost permanently. BRPOP is at-most-once: a task popped but not yet recorded in osm:tasks:running existed nowhere, and the master's recovery sweep only reads that hash. - workers now claim via BLMOVE onto osm:tasks:processing:{worker_id} - the claim is acked only once SetTaskRunning succeeds; a failure requeues instead of executing the task untracked - recovery on worker startup, on dead workers, and for processing lists left by workers that are no longer registered - requires Redis 6.2+ #320 — settings values can now be overridden by OSM_* environment variables so secrets need not live in osm-settings.yaml. The mapping is derived from the YAML tags by reflection, so new settings are overridable with no extra code. Applied in config.Load, hotreload and the --settings-file branch, but deliberately not in LoadFromFile: `osmedeus config set` round-trips through it and writes back, which would persist env secrets to disk. Known gaps: pkg/cli/worker_queue.go still consumes the pending queue with the at-most-once PopTask, and two distributed e2e tests (TaskSubmission, FullWorkflow) fail on main independently of these changes.
89 lines
3.0 KiB
Go
89 lines
3.0 KiB
Go
package config
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// A settings file loaded via LoadFromFile (the --settings-file path) must still
|
|
// end up with every derived runtime path populated. Regression test for #321/#322,
|
|
// where WorkflowsPath stayed empty and every workflow lookup resolved against the
|
|
// process working directory instead of base_folder.
|
|
func TestResolvePaths_PopulatesDerivedPaths(t *testing.T) {
|
|
base := t.TempDir()
|
|
cfg := &Config{
|
|
BaseFolder: base,
|
|
Environments: EnvironmentConfig{
|
|
Workflows: "{{base_folder}}/workflows",
|
|
Workspaces: "{{base_folder}}/workspaces",
|
|
},
|
|
}
|
|
|
|
cfg.ResolvePaths()
|
|
|
|
assert.Equal(t, filepath.Join(base, "workflows"), cfg.WorkflowsPath)
|
|
assert.Equal(t, filepath.Join(base, "workspaces"), cfg.WorkspacesPath)
|
|
}
|
|
|
|
// A partial settings file that omits environment keys must not leave a derived
|
|
// path empty -- an empty WorkflowsPath makes filepath.Join fall through to a
|
|
// relative path rooted at the process cwd.
|
|
func TestResolvePaths_FillsMissingEnvironmentDefaults(t *testing.T) {
|
|
base := t.TempDir()
|
|
cfg := &Config{BaseFolder: base} // no Environments block at all
|
|
|
|
cfg.ResolvePaths()
|
|
|
|
assert.Equal(t, filepath.Join(base, "workflows"), cfg.WorkflowsPath)
|
|
assert.Equal(t, filepath.Join(base, "workspaces"), cfg.WorkspacesPath)
|
|
assert.Equal(t, filepath.Join(base, "external-binaries"), cfg.BinariesPath)
|
|
assert.Equal(t, filepath.Join(base, "external-data"), cfg.DataPath)
|
|
assert.Equal(t, filepath.Join(base, "external-configs"), cfg.ConfigsPath)
|
|
assert.Equal(t, filepath.Join(base, "snapshot"), cfg.SnapshotPath)
|
|
assert.Equal(t, filepath.Join(base, "external-scripts"), cfg.ExternalScriptsPath)
|
|
}
|
|
|
|
// An explicit path in the settings file always wins over the fallback.
|
|
func TestResolvePaths_ExplicitPathWinsOverDefault(t *testing.T) {
|
|
cfg := &Config{
|
|
BaseFolder: "/srv/osm",
|
|
Environments: EnvironmentConfig{Workflows: "/custom/workflows"},
|
|
}
|
|
|
|
cfg.ResolvePaths()
|
|
|
|
assert.Equal(t, "/custom/workflows", cfg.WorkflowsPath)
|
|
assert.Equal(t, "/srv/osm/workspaces", cfg.WorkspacesPath)
|
|
}
|
|
|
|
// ResolvePaths must be idempotent -- root.go and hotreload both call it on
|
|
// configs that may already be resolved.
|
|
func TestResolvePaths_Idempotent(t *testing.T) {
|
|
base := t.TempDir()
|
|
cfg := &Config{BaseFolder: base}
|
|
|
|
cfg.ResolvePaths()
|
|
first := cfg.WorkflowsPath
|
|
cfg.ResolvePaths()
|
|
|
|
assert.Equal(t, first, cfg.WorkflowsPath)
|
|
}
|
|
|
|
// LoadFromFile itself stays a plain unmarshal; callers resolve. This pins the
|
|
// contract so the root.go fix is not silently undone.
|
|
func TestLoadFromFile_LeavesDerivedPathsUnresolved(t *testing.T) {
|
|
base := t.TempDir()
|
|
body := "base_folder: " + base + "\nenvironments:\n workflows: \"{{base_folder}}/workflows\"\n"
|
|
settings := writeSettings(t, base, body)
|
|
|
|
cfg, err := LoadFromFile(settings)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, cfg.WorkflowsPath, "LoadFromFile should not resolve; Load and callers do")
|
|
|
|
cfg.ResolvePaths()
|
|
assert.Equal(t, filepath.Join(base, "workflows"), cfg.WorkflowsPath)
|
|
}
|