filed

Job queue using FUSE

git clone git://mccd.space/filed

commit 4d3ecaa53688cd0cd5c24245a0d076142b799a54
parent 0a4ee2af087fa3aa1f0973c5a35692772398dc98
Author: Marc Coquand <marc@coquand.email>
Date:   Sun, 14 Dec 2025 20:15:21 +0100

Move out jobs

Diffstat:
Mmain.go | 6+++---
Rstore/store.go -> store/jobs.go | 0
Astore/jobs_test.go | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dstore/store_test.go | 157-------------------------------------------------------------------------------
4 files changed, 160 insertions(+), 160 deletions(-)
diff --git a/main.go b/main.go
@@ -152,13 +152,13 @@ func (d PendingDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *f
 	return f, f, nil
 }
 func (jd PendingDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
-	slog.Info("FUSE: Lookup", "name", name)
+	slog.Debug("FUSE: Lookup", "name", name)
 	job, err := jd.manager.store.GetJob(name)
 	if err != nil {
 		return nil, syscall.ENOENT
 	}
 	if job.State == store.StatePending {
-		slog.Info("FUSE: Found job", "id", job.ID)
+		slog.Debug("FUSE: Found job", "id", job.ID)
 		return &File{job, jd.manager}, nil
 	} else {
 		return nil, syscall.ENOENT
@@ -187,7 +187,7 @@ func (f File) Attr(ctx context.Context, a *fuse.Attr) error {
 }
 
 func (f *File) ReadAll(ctx context.Context) ([]byte, error) {
-	slog.Info("FUSE: Read file content")
+	slog.Debug("FUSE: Read file content")
 	return f.readContent()
 }
 
diff --git a/store/store.go b/store/jobs.go
diff --git a/store/jobs_test.go b/store/jobs_test.go
@@ -0,0 +1,157 @@
+package store
+
+import (
+	"path/filepath"
+	"testing"
+)
+
+// Create a new store in a temporary directory for each test.
+func setupTestDB(t *testing.T) *Store {
+	t.Helper()
+	tmpDir := t.TempDir()
+	dbPath := filepath.Join(tmpDir, "jobs.db")
+
+	store, err := NewStore(dbPath)
+	if err != nil {
+		t.Fatalf("Failed to create store: %v", err)
+	}
+
+	t.Cleanup(func() {
+		store.Close()
+	})
+
+	return store
+}
+
+func TestCreateJob(t *testing.T) {
+	s := setupTestDB(t)
+
+	jobID := "job-123"
+	cmd := "echo hello"
+
+	job, err := s.CreateJob(jobID, cmd)
+	if err != nil {
+		t.Fatalf("Failed to create job: %v", err)
+	}
+
+	if job.ID != jobID {
+		t.Errorf("Expected ID %s, got %s", jobID, job.ID)
+	}
+	if job.State != StatePending {
+		t.Errorf("Expected state %s, got %s", StatePending, job.State)
+	}
+	if job.Command != cmd {
+		t.Errorf("Expected command %s, got %s", cmd, job.Command)
+	}
+}
+
+func TestGetJob(t *testing.T) {
+	s := setupTestDB(t)
+	jobID := "test-job-get"
+
+	_, err := s.CreateJob(jobID, "sleep 1")
+	if err != nil {
+		t.Fatalf("CreateJob failed: %v", err)
+	}
+
+	// Retrieve it
+	job, err := s.GetJob(jobID)
+	if err != nil {
+		t.Fatalf("GetJob failed: %v", err)
+	}
+
+	if job.ID != jobID {
+		t.Errorf("Expected retrieved ID to match")
+	}
+}
+
+func TestLifecycleTransitions(t *testing.T) {
+	s := setupTestDB(t)
+	jobID := "lifecycle-1"
+
+	_, err := s.CreateJob(jobID, "echo hello")
+	if err != nil {
+		t.Fatalf("CreateJob failed: %v", err)
+	}
+
+	// 1. Pending -> Running (AttemptJob)
+	if err := s.AttemptJob(jobID); err != nil {
+		t.Fatalf("AttemptJob failed: %v", err)
+	}
+
+	j, _ := s.GetJob(jobID)
+	if j.State != StateRunning {
+		t.Errorf("Expected state Running, got %s", j.State)
+	}
+	if j.Attempts != 1 {
+		t.Errorf("Expected attempts 1, got %d", j.Attempts)
+	}
+
+	// 2. Running -> Completed
+	if err := s.CompleteJob(jobID, []byte("hello")); err != nil {
+		t.Fatalf("CompleteJob failed: %v", err)
+	}
+
+	j, _ = s.GetJob(jobID)
+	if j.State != StateCompleted {
+		t.Errorf("Expected state Completed, got %s", j.State)
+	}
+
+	// 3. Restart (Completed -> Pending)
+	if err := s.RestartJob(jobID, nil); err != nil {
+		t.Fatalf("RestartJob failed: %v", err)
+	}
+
+	j, _ = s.GetJob(jobID)
+	if j.State != StatePending {
+		t.Errorf("Expected state Pending after restart, got %s", j.State)
+	}
+}
+
+func TestListJobsByState(t *testing.T) {
+	s := setupTestDB(t)
+
+	s.CreateJob("p1", "cmd1")
+	s.CreateJob("p2", "cmd2")
+
+	s.CreateJob("c1", "cmd3")
+	s.CompleteJob("c1", []byte("out"))
+
+	// List Pending
+	pending, err := s.ListJobsByState(StatePending)
+	if err != nil {
+		t.Fatalf("ListJobsByState failed: %v", err)
+	}
+
+	if len(pending) != 2 {
+		t.Errorf("Expected 2 pending jobs, got %d", len(pending))
+	}
+
+	// List Completed
+	completed, err := s.ListJobsByState(StateCompleted)
+	if err != nil {
+		t.Fatalf("ListJobsByState failed: %v", err)
+	}
+	if len(completed) != 1 {
+		t.Errorf("Expected 1 completed job, got %d", len(completed))
+	}
+	if completed[0].ID != "c1" {
+		t.Errorf("Expected completed job to be c1")
+	}
+}
+
+func TestDeleteJob(t *testing.T) {
+	s := setupTestDB(t)
+	jobID := "del-1"
+
+	s.CreateJob(jobID, "cmd")
+
+	if err := s.DeleteJob(jobID); err != nil {
+		t.Fatalf("DeleteJob failed: %v", err)
+	}
+
+	_, err := s.GetJob(jobID)
+	if err == nil {
+		t.Error("Expected error getting deleted job, got nil")
+	}
+}
diff --git a/store/store_test.go b/store/store_test.go
@@ -1,157 +0,0 @@
-package store
-
-import (
-	"path/filepath"
-	"testing"
-)
-
-// Create a new store in a temporary directory for each test.
-func setupTestDB(t *testing.T) *Store {
-	t.Helper()
-	tmpDir := t.TempDir()
-	dbPath := filepath.Join(tmpDir, "jobs.db")
-
-	store, err := NewStore(dbPath)
-	if err != nil {
-		t.Fatalf("Failed to create store: %v", err)
-	}
-
-	t.Cleanup(func() {
-		store.Close()
-	})
-
-	return store
-}
-
-func TestCreateJob(t *testing.T) {
-	s := setupTestDB(t)
-
-	jobID := "job-123"
-	cmd := "echo hello"
-
-	job, err := s.CreateJob(jobID, cmd)
-	if err != nil {
-		t.Fatalf("Failed to create job: %v", err)
-	}
-
-	if job.ID != jobID {
-		t.Errorf("Expected ID %s, got %s", jobID, job.ID)
-	}
-	if job.State != StatePending {
-		t.Errorf("Expected state %s, got %s", StatePending, job.State)
-	}
-	if job.Command != cmd {
-		t.Errorf("Expected command %s, got %s", cmd, job.Command)
-	}
-}
-
-func TestGetJob(t *testing.T) {
-	s := setupTestDB(t)
-	jobID := "test-job-get"
-
-	_, err := s.CreateJob(jobID, "sleep 1")
-	if err != nil {
-		t.Fatalf("CreateJob failed: %v", err)
-	}
-
-	// Retrieve it
-	job, err := s.GetJob(jobID)
-	if err != nil {
-		t.Fatalf("GetJob failed: %v", err)
-	}
-
-	if job.ID != jobID {
-		t.Errorf("Expected retrieved ID to match")
-	}
-}
-
-func TestLifecycleTransitions(t *testing.T) {
-	s := setupTestDB(t)
-	jobID := "lifecycle-1"
-
-	_, err := s.CreateJob(jobID, "echo hello")
-	if err != nil {
-		t.Fatalf("CreateJob failed: %v", err)
-	}
-
-	// 1. Pending -> Running (AttemptJob)
-	if err := s.AttemptJob(jobID); err != nil {
-		t.Fatalf("AttemptJob failed: %v", err)
-	}
-
-	j, _ := s.GetJob(jobID)
-	if j.State != StateRunning {
-		t.Errorf("Expected state Running, got %s", j.State)
-	}
-	if j.Attempts != 1 {
-		t.Errorf("Expected attempts 1, got %d", j.Attempts)
-	}
-
-	// 2. Running -> Completed
-	if err := s.CompleteJob(jobID, []byte("hello")); err != nil {
-		t.Fatalf("CompleteJob failed: %v", err)
-	}
-
-	j, _ = s.GetJob(jobID)
-	if j.State != StateCompleted {
-		t.Errorf("Expected state Completed, got %s", j.State)
-	}
-
-	// 3. Restart (Completed -> Pending)
-	if err := s.RestartJob(jobID); err != nil {
-		t.Fatalf("RestartJob failed: %v", err)
-	}
-
-	j, _ = s.GetJob(jobID)
-	if j.State != StatePending {
-		t.Errorf("Expected state Pending after restart, got %s", j.State)
-	}
-}
-
-func TestListJobsByState(t *testing.T) {
-	s := setupTestDB(t)
-
-	s.CreateJob("p1", "cmd1")
-	s.CreateJob("p2", "cmd2")
-
-	s.CreateJob("c1", "cmd3")
-	s.CompleteJob("c1", []byte("out"))
-
-	// List Pending
-	pending, err := s.ListJobsByState(StatePending)
-	if err != nil {
-		t.Fatalf("ListJobsByState failed: %v", err)
-	}
-
-	if len(pending) != 2 {
-		t.Errorf("Expected 2 pending jobs, got %d", len(pending))
-	}
-
-	// List Completed
-	completed, err := s.ListJobsByState(StateCompleted)
-	if err != nil {
-		t.Fatalf("ListJobsByState failed: %v", err)
-	}
-	if len(completed) != 1 {
-		t.Errorf("Expected 1 completed job, got %d", len(completed))
-	}
-	if completed[0].ID != "c1" {
-		t.Errorf("Expected completed job to be c1")
-	}
-}
-
-func TestDeleteJob(t *testing.T) {
-	s := setupTestDB(t)
-	jobID := "del-1"
-
-	s.CreateJob(jobID, "cmd")
-
-	if err := s.DeleteJob(jobID); err != nil {
-		t.Fatalf("DeleteJob failed: %v", err)
-	}
-
-	_, err := s.GetJob(jobID)
-	if err == nil {
-		t.Error("Expected error getting deleted job, got nil")
-	}
-}