Refactor plugins to use interface for testability: - Add PodmanInterface to container package (StartContainer, StopContainer, RemoveContainer) - Update MLflow plugin to use container.PodmanInterface - Update TensorBoard plugin to use container.PodmanInterface - Add comprehensive mocked tests for all three plugins (wandb, mlflow, tensorboard) - Coverage increased from 18% to 91.4%
353 lines
7.5 KiB
Go
353 lines
7.5 KiB
Go
package filesystem_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/jfraeys/fetch_ml/internal/domain"
|
|
"github.com/jfraeys/fetch_ml/internal/queue/filesystem"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestNewQueue tests queue creation
|
|
func TestNewQueue(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
queueRoot := filepath.Join(tmpDir, "queue")
|
|
|
|
q, err := filesystem.NewQueue(queueRoot)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, q)
|
|
defer q.Close()
|
|
|
|
// Verify directories were created
|
|
for _, dir := range []string{"pending/entries", "running", "finished", "failed"} {
|
|
path := filepath.Join(queueRoot, dir)
|
|
info, err := os.Stat(path)
|
|
require.NoError(t, err, "Directory %s should exist", dir)
|
|
assert.True(t, info.IsDir())
|
|
}
|
|
}
|
|
|
|
// TestNewQueueEmptyRoot tests queue creation with empty root
|
|
func TestNewQueueEmptyRoot(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := filesystem.NewQueue("")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "root is required")
|
|
}
|
|
|
|
// TestClose tests queue closing
|
|
func TestClose(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
err = q.Close()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// TestAddTask tests adding tasks
|
|
func TestAddTask(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "test-task-1",
|
|
Status: "pending",
|
|
Args: "test args",
|
|
Output: "test output",
|
|
}
|
|
|
|
err = q.AddTask(task)
|
|
require.NoError(t, err)
|
|
|
|
// Verify file was created
|
|
taskFile := filepath.Join(tmpDir, "pending", "entries", "test-task-1.json")
|
|
_, err = os.Stat(taskFile)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// TestAddTaskNil tests adding nil task
|
|
func TestAddTaskNil(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
err = q.AddTask(nil)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "task is nil")
|
|
}
|
|
|
|
// TestAddTaskInvalidID tests adding task with invalid ID
|
|
func TestAddTaskInvalidID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "invalid/id/with/slashes",
|
|
Status: "pending",
|
|
}
|
|
|
|
err = q.AddTask(task)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid task ID")
|
|
}
|
|
|
|
// TestGetTask tests retrieving tasks
|
|
func TestGetTask(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "get-task-1",
|
|
Status: "pending",
|
|
Args: "test args",
|
|
}
|
|
|
|
err = q.AddTask(task)
|
|
require.NoError(t, err)
|
|
|
|
retrieved, err := q.GetTask("get-task-1")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, task.ID, retrieved.ID)
|
|
assert.Equal(t, task.Status, retrieved.Status)
|
|
assert.Equal(t, task.Args, retrieved.Args)
|
|
}
|
|
|
|
// TestGetTaskNotFound tests retrieving nonexistent task
|
|
func TestGetTaskNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
_, err = q.GetTask("nonexistent-task")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "task not found")
|
|
}
|
|
|
|
// TestGetTaskInvalidID tests retrieving with invalid ID
|
|
func TestGetTaskInvalidID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
_, err = q.GetTask("invalid/id")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid task ID")
|
|
}
|
|
|
|
// TestListTasks tests listing all tasks
|
|
func TestListTasks(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
// Add multiple tasks
|
|
tasks := []*domain.Task{
|
|
{ID: "list-task-1", Status: "pending"},
|
|
{ID: "list-task-2", Status: "pending"},
|
|
{ID: "list-task-3", Status: "pending"},
|
|
}
|
|
|
|
for _, task := range tasks {
|
|
err := q.AddTask(task)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
listed, err := q.ListTasks()
|
|
require.NoError(t, err)
|
|
assert.Len(t, listed, 3)
|
|
}
|
|
|
|
// TestListTasksEmpty tests listing with no tasks
|
|
func TestListTasksEmpty(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
listed, err := q.ListTasks()
|
|
require.NoError(t, err)
|
|
assert.Empty(t, listed)
|
|
}
|
|
|
|
// TestCancelTask tests canceling tasks
|
|
func TestCancelTask(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "cancel-task-1",
|
|
Status: "pending",
|
|
}
|
|
|
|
err = q.AddTask(task)
|
|
require.NoError(t, err)
|
|
|
|
// Verify file exists
|
|
taskFile := filepath.Join(tmpDir, "pending", "entries", "cancel-task-1.json")
|
|
_, err = os.Stat(taskFile)
|
|
require.NoError(t, err)
|
|
|
|
// Cancel task
|
|
err = q.CancelTask("cancel-task-1")
|
|
require.NoError(t, err)
|
|
|
|
// Verify file is gone
|
|
_, err = os.Stat(taskFile)
|
|
require.True(t, os.IsNotExist(err))
|
|
}
|
|
|
|
// TestCancelTaskNotFound tests canceling nonexistent task
|
|
func TestCancelTaskNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
// Should not error for nonexistent task
|
|
err = q.CancelTask("nonexistent-task")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// TestCancelTaskInvalidID tests canceling with invalid ID
|
|
func TestCancelTaskInvalidID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
err = q.CancelTask("invalid/id")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid task ID")
|
|
}
|
|
|
|
// TestUpdateTask tests updating tasks
|
|
func TestUpdateTask(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "update-task-1",
|
|
Status: "pending",
|
|
Args: "original args",
|
|
}
|
|
|
|
err = q.AddTask(task)
|
|
require.NoError(t, err)
|
|
|
|
// Update task
|
|
updated := &domain.Task{
|
|
ID: "update-task-1",
|
|
Status: "running",
|
|
Args: "updated args",
|
|
Output: "new output",
|
|
}
|
|
|
|
err = q.UpdateTask(updated)
|
|
require.NoError(t, err)
|
|
|
|
// Verify update
|
|
retrieved, err := q.GetTask("update-task-1")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "running", retrieved.Status)
|
|
assert.Equal(t, "updated args", retrieved.Args)
|
|
assert.Equal(t, "new output", retrieved.Output)
|
|
}
|
|
|
|
// TestUpdateTaskNil tests updating with nil task
|
|
func TestUpdateTaskNil(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
err = q.UpdateTask(nil)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "task is nil")
|
|
}
|
|
|
|
// TestUpdateTaskNotFound tests updating nonexistent task
|
|
func TestUpdateTaskNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "nonexistent-task",
|
|
Status: "pending",
|
|
}
|
|
|
|
err = q.UpdateTask(task)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "task not found")
|
|
}
|
|
|
|
// TestUpdateTaskInvalidID tests updating with invalid ID
|
|
func TestUpdateTaskInvalidID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
q, err := filesystem.NewQueue(tmpDir)
|
|
require.NoError(t, err)
|
|
defer q.Close()
|
|
|
|
task := &domain.Task{
|
|
ID: "invalid/id",
|
|
Status: "pending",
|
|
}
|
|
|
|
err = q.UpdateTask(task)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid task ID")
|
|
}
|