package depot import ( "bytes" "context" "crypto/sha256" "fmt" "os" "path/filepath" "testing" ) func TestLocalRoundTrip(t *testing.T) { tmpDir := t.TempDir() backend := &LocalBackend{Root: tmpDir} // Generate test data testData := []byte("hello world") testSHA := fmt.Sprintf("%x", sha256.Sum256(testData)) // Create source file srcFile := filepath.Join(tmpDir, "source.txt") if err := os.WriteFile(srcFile, testData, 0644); err != nil { t.Fatalf("failed to create source file: %v", err) } // Put ctx := context.Background() if err := backend.Put(ctx, testSHA, srcFile); err != nil { t.Fatalf("Put failed: %v", err) } // Probe should be Present state, transient, err := backend.Probe(ctx, testSHA) if err != nil { t.Fatalf("Probe failed: %v", err) } if state != Present { t.Fatalf("expected Present, got %v", state) } if transient { t.Fatalf("local backend should never be transient") } // Get destFile := filepath.Join(tmpDir, "dest.txt") if err := backend.Get(ctx, testSHA, destFile); err != nil { t.Fatalf("Get failed: %v", err) } // Verify bytes match gotData, err := os.ReadFile(destFile) if err != nil { t.Fatalf("failed to read dest file: %v", err) } if !bytes.Equal(gotData, testData) { t.Fatalf("data mismatch: want %s, got %s", testData, gotData) } } func TestLocalProbeAbsent(t *testing.T) { tmpDir := t.TempDir() backend := &LocalBackend{Root: tmpDir} ctx := context.Background() state, transient, err := backend.Probe(ctx, "0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d") if err != nil { t.Fatalf("Probe should not error on missing blob: %v", err) } if state != Absent { t.Fatalf("expected Absent, got %v", state) } if transient { t.Fatalf("local backend should never be transient") } } func TestLocalGetHashMismatch(t *testing.T) { tmpDir := t.TempDir() backend := &LocalBackend{Root: tmpDir} // Create a corrupt blob at the expected path sha := "0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d0b1d" blobKey := BlobKey(sha) blobPath := filepath.Join(tmpDir, blobKey) if err := os.MkdirAll(filepath.Dir(blobPath), 0755); err != nil { t.Fatalf("failed to create blob dir: %v", err) } if err := os.WriteFile(blobPath, []byte("wrong data"), 0644); err != nil { t.Fatalf("failed to create blob file: %v", err) } // Get should error ctx := context.Background() destFile := filepath.Join(tmpDir, "dest.txt") err := backend.Get(ctx, sha, destFile) if err == nil { t.Fatalf("Get should error on hash mismatch") } // Destination file should not exist _, err = os.Stat(destFile) if !os.IsNotExist(err) { t.Fatalf("dest file should not exist after Get error: %v", err) } } func TestLocalPutIdempotent(t *testing.T) { tmpDir := t.TempDir() backend := &LocalBackend{Root: tmpDir} testData := []byte("hello world") testSHA := fmt.Sprintf("%x", sha256.Sum256(testData)) srcFile := filepath.Join(tmpDir, "source.txt") if err := os.WriteFile(srcFile, testData, 0644); err != nil { t.Fatalf("failed to create source file: %v", err) } ctx := context.Background() // Put twice if err := backend.Put(ctx, testSHA, srcFile); err != nil { t.Fatalf("first Put failed: %v", err) } if err := backend.Put(ctx, testSHA, srcFile); err != nil { t.Fatalf("second Put failed: %v", err) } // Verify blob exists state, _, err := backend.Probe(ctx, testSHA) if err != nil { t.Fatalf("Probe failed: %v", err) } if state != Present { t.Fatalf("expected Present after Put, got %v", state) } }