Files
osmedeus/internal/parser/loader_test.go
T
j3ssie bb15efdf60 feat: db replay and snapshot improvements
- Add replayDBOperations to reinitialize databases from imported workspaces, with proper parameter resolution and pre-condition skipping
- Implement ISO 8601 timestamp format for snapshots (2026-02-13T18-20-34Z) instead of Unix epoch
- Add --include-heavy flag to include large fields (raw_response, screenshot, blob_content) in database queries
- Fix asset table default columns (url, status_code, content_length, title) for better UX
- Skip heavy initialization for lightweight commands (help, version, completion) to avoid ~50MB overhead
- Optimize database function execution via lazy config initialization
- Fix binary installation via Nix to copy already-installed binaries to binaries folder
2026-02-13 09:06:51 +07:00

358 lines
9.1 KiB
Go

package parser
import (
"os"
"path/filepath"
"testing"
"github.com/j3ssie/osmedeus/v5/internal/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupTestWorkflows(t *testing.T) string {
tmpDir := t.TempDir()
// Create modules directory
modulesDir := filepath.Join(tmpDir, "modules")
err := os.MkdirAll(modulesDir, 0755)
require.NoError(t, err)
// Create a test flow
flowContent := `kind: flow
name: test-flow
description: Test flow for unit testing
params:
- name: target
required: true
modules:
- name: test-module
path: modules/test-module.yaml
`
err = os.WriteFile(filepath.Join(tmpDir, "test-flow.yaml"), []byte(flowContent), 0644)
require.NoError(t, err)
// Create a test module
moduleContent := `kind: module
name: test-module
description: Test module for unit testing
params:
- name: target
required: true
- name: threads
default: "10"
steps:
- name: echo-test
type: bash
command: echo "Hello {{target}}"
`
err = os.WriteFile(filepath.Join(modulesDir, "test-module.yaml"), []byte(moduleContent), 0644)
require.NoError(t, err)
// Create another module with triggers
moduleWithTriggersContent := `kind: module
name: triggered-module
description: Module with triggers
triggers:
- name: manual
on: manual
enabled: true
- name: cron-daily
on: cron
schedule: "0 0 * * *"
enabled: true
params:
- name: target
required: true
steps:
- name: run-task
type: bash
command: echo "Running on {{target}}"
`
err = os.WriteFile(filepath.Join(modulesDir, "triggered-module.yaml"), []byte(moduleWithTriggersContent), 0644)
require.NoError(t, err)
return tmpDir
}
func TestLoader_ListFlows(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
flows, err := loader.ListFlows()
require.NoError(t, err)
assert.Contains(t, flows, "test-flow")
}
func TestLoader_ListModules(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
modules, err := loader.ListModules()
require.NoError(t, err)
assert.Len(t, modules, 2)
assert.Contains(t, modules, "test-module")
assert.Contains(t, modules, "triggered-module")
}
func TestLoader_LoadWorkflow_Flow(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
workflow, err := loader.LoadWorkflow("test-flow")
require.NoError(t, err)
assert.Equal(t, "test-flow", workflow.Name)
assert.Equal(t, core.KindFlow, workflow.Kind)
assert.Equal(t, "Test flow for unit testing", workflow.Description)
assert.True(t, workflow.IsFlow())
assert.False(t, workflow.IsModule())
assert.Len(t, workflow.Modules, 1)
}
func TestLoader_LoadWorkflow_Module(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
workflow, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.Equal(t, "test-module", workflow.Name)
assert.Equal(t, core.KindModule, workflow.Kind)
assert.True(t, workflow.IsModule())
assert.False(t, workflow.IsFlow())
assert.Len(t, workflow.Steps, 1)
assert.Equal(t, "echo-test", workflow.Steps[0].Name)
assert.Equal(t, core.StepTypeBash, workflow.Steps[0].Type)
}
func TestLoader_LoadWorkflow_WithTriggers(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
workflow, err := loader.LoadWorkflow("triggered-module")
require.NoError(t, err)
assert.Equal(t, "triggered-module", workflow.Name)
assert.True(t, workflow.HasTriggers())
assert.Len(t, workflow.Triggers, 2)
// Check manual trigger
var manualTrigger *core.Trigger
for i := range workflow.Triggers {
if workflow.Triggers[i].Name == "manual" {
manualTrigger = &workflow.Triggers[i]
break
}
}
require.NotNil(t, manualTrigger)
assert.Equal(t, core.TriggerManual, manualTrigger.On)
assert.True(t, manualTrigger.Enabled)
}
func TestLoader_LoadWorkflow_NotFound(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
_, err := loader.LoadWorkflow("nonexistent")
assert.Error(t, err)
assert.Contains(t, err.Error(), "not found")
}
func TestLoader_LoadAllWorkflows(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
workflows, err := loader.LoadAllWorkflows()
require.NoError(t, err)
assert.Len(t, workflows, 3) // 1 flow + 2 modules
// Check we have both flows and modules
var flowCount, moduleCount int
for _, w := range workflows {
if w.IsFlow() {
flowCount++
} else if w.IsModule() {
moduleCount++
}
}
assert.Equal(t, 1, flowCount)
assert.Equal(t, 2, moduleCount)
}
func TestLoader_GetRequiredParams(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
workflow, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
required := workflow.GetRequiredParams()
assert.Len(t, required, 1)
assert.Equal(t, "target", required[0].Name)
}
func TestLoader_CacheWorkflow(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
// First load
workflow1, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
// Second load should come from cache
workflow2, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.Same(t, workflow1, workflow2)
}
func TestLoader_ClearCache(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
// Load workflow
workflow1, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
// Clear cache
loader.ClearCache()
// Load again - should be different instance
workflow2, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.NotSame(t, workflow1, workflow2)
assert.Equal(t, workflow1.Name, workflow2.Name)
}
func TestLoader_GetAllCached(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
// Initially empty
cached := loader.GetAllCached()
assert.Len(t, cached, 0)
// Load some workflows
_, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
_, err = loader.LoadWorkflow("test-flow")
require.NoError(t, err)
// Should now have 2 cached
cached = loader.GetAllCached()
assert.Len(t, cached, 2)
}
func TestLoader_IsManualExecutionAllowed(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
// Workflow with manual trigger enabled
workflow, err := loader.LoadWorkflow("triggered-module")
require.NoError(t, err)
assert.True(t, workflow.IsManualExecutionAllowed())
// Workflow without triggers - manual allowed by default
workflow, err = loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.True(t, workflow.IsManualExecutionAllowed())
}
func TestLoader_LoadWorkflowByPath_ExplicitLocalPath(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
// Create a workflow file in a separate location (not in workflows dir)
localDir := t.TempDir()
localWorkflow := filepath.Join(localDir, "local-module.yaml")
content := `kind: module
name: local-module
description: Local module
steps:
- name: test
type: bash
command: echo "test"
`
err := os.WriteFile(localWorkflow, []byte(content), 0644)
require.NoError(t, err)
// Change to localDir to test relative path
oldWd, _ := os.Getwd()
defer func() { _ = os.Chdir(oldWd) }()
require.NoError(t, os.Chdir(localDir))
// Test: ./local-module.yaml should load from CWD
workflow, err := loader.LoadWorkflowByPath("./local-module.yaml")
require.NoError(t, err)
assert.Equal(t, "local-module", workflow.Name)
// Test: ./nonexistent.yaml should error, not fall back
_, err = loader.LoadWorkflowByPath("./nonexistent.yaml")
require.Error(t, err)
assert.Contains(t, err.Error(), "not found")
assert.NotContains(t, err.Error(), "workflows") // Should not mention fallback
// Test: ../nonexistent.yaml should also error, not fall back
_, err = loader.LoadWorkflowByPath("../nonexistent.yaml")
require.Error(t, err)
assert.Contains(t, err.Error(), "not found")
}
func TestLoader_CacheMtimeInvalidation(t *testing.T) {
tmpDir := setupTestWorkflows(t)
loader := NewLoader(tmpDir)
modulePath := filepath.Join(tmpDir, "modules", "test-module.yaml")
// First load
workflow1, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.Equal(t, "test-module", workflow1.Name)
assert.Len(t, workflow1.Steps, 1)
// Second load should come from cache (same instance)
workflow2, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.Same(t, workflow1, workflow2)
// Modify the file - add a new step
modifiedContent := `kind: module
name: test-module
description: Test module for unit testing (MODIFIED)
params:
- name: target
required: true
- name: threads
default: "10"
steps:
- name: echo-test
type: bash
command: echo "Hello {{target}}"
- name: new-step
type: bash
command: echo "New step"
`
err = os.WriteFile(modulePath, []byte(modifiedContent), 0644)
require.NoError(t, err)
// Third load should detect the change and re-parse (different instance)
workflow3, err := loader.LoadWorkflow("test-module")
require.NoError(t, err)
assert.NotSame(t, workflow1, workflow3)
assert.Equal(t, "Test module for unit testing (MODIFIED)", workflow3.Description)
assert.Len(t, workflow3.Steps, 2)
assert.Equal(t, "new-step", workflow3.Steps[1].Name)
}