#include "pipeline.h" #include "runner.h" #include #include #include #include #include static const PIString testDir = "/tmp/pipeline-runner-test/"; static const PIString testPipelinesDir = testDir + "pipelines/"; static const PIString testLogsDir = testDir + "logs/"; static void setupDirs() { PIDir::make(testDir); PIDir::make(testPipelinesDir); PIDir::make(testLogsDir); } static void cleanupDirs() { PIDir pdir(testPipelinesDir); for (const auto & e: pdir.entries()) { if (e.isFile()) PIFile::remove(e.path); } PIDir ldir(testLogsDir); for (const auto & e: ldir.entries()) { if (e.isFile()) PIFile::remove(e.path); } PIDir::remove(testPipelinesDir); PIDir::remove(testLogsDir); PIDir::remove(testDir); } static Pipeline makeEchoPipeline() { Pipeline pl; pl.id = "echo-test"; pl.name = "Echo Test"; pl.working_dir = "/tmp"; pl.created_at = nowISO(); pl.updated_at = pl.created_at; Prompt p; p.id = "prompt-1"; p.text = "echo hello"; p.title = "Echo Step"; p.order = 0; pl.prompts << p; return pl; } TEST(RunnerTest, StartRunNotFound) { setupDirs(); PipelineRunner runner(testPipelinesDir, testLogsDir); PIString runId = runner.startRun("nonexistent"); EXPECT_TRUE(runId.isEmpty()); cleanupDirs(); } TEST(RunnerTest, StartRunAndGetState) { setupDirs(); PipelineRunner runner(testPipelinesDir, testLogsDir); // Create a pipeline that runs 'echo hello' (uses shell command, not opencode) Pipeline pl; pl.id = "state-test"; pl.name = "State Test"; pl.working_dir = "/tmp"; pl.created_at = nowISO(); pl.updated_at = pl.created_at; Prompt p; p.id = "p1"; p.text = "test"; p.title = "Step 1"; p.order = 0; pl.prompts << p; savePipeline(testPipelinesDir, pl); PIString runId = runner.startRun("state-test"); EXPECT_FALSE(runId.isEmpty()); RunState state = runner.getRunState(runId); EXPECT_EQ(state.run_id, runId); EXPECT_EQ(state.pipeline_id, "state-test"); EXPECT_EQ(state.status, RunStatus::Running); EXPECT_EQ(state.steps.size(), 1); EXPECT_EQ(state.steps[0].title, "Step 1"); cleanupDirs(); } TEST(RunnerTest, GetStateNotFound) { setupDirs(); PipelineRunner runner(testPipelinesDir, testLogsDir); RunState state = runner.getRunState("nonexistent"); EXPECT_TRUE(state.run_id.isEmpty()); cleanupDirs(); } TEST(RunnerTest, IsRunActive) { setupDirs(); PipelineRunner runner(testPipelinesDir, testLogsDir); Pipeline pl; pl.id = "active-test"; pl.name = "Active Test"; pl.working_dir = "/tmp"; pl.created_at = nowISO(); pl.updated_at = pl.created_at; Prompt p; p.id = "p1"; p.text = "test"; p.title = "Step 1"; p.order = 0; pl.prompts << p; savePipeline(testPipelinesDir, pl); PIString runId = runner.startRun("active-test"); EXPECT_TRUE(runner.isRunActive(runId)); cleanupDirs(); } TEST(RunnerTest, RunStatusToString) { EXPECT_EQ(runStatusToString(RunStatus::Pending), "pending"); EXPECT_EQ(runStatusToString(RunStatus::Running), "running"); EXPECT_EQ(runStatusToString(RunStatus::Completed), "completed"); EXPECT_EQ(runStatusToString(RunStatus::Error), "error"); }