package blossom import ( "bytes" "crypto/sha256" "os" "path/filepath" "testing" "git.smesh.lol/torly/pkg/nostr" ) func putTestBlob(t *testing.T, s *Server, data []byte, pub, typ string, created int64) string { t.Helper() sum := sha256.Sum256(data) hash := nostr.Hex(sum[:]) path := s.blobPath(hash) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, data, 0o644); err != nil { t.Fatal(err) } b := &Blob{Hash: hash, PubKey: pub, Size: int64(len(data)), Type: typ, Created: created} s.mu.Lock() s.putMem(b) err := s.appendRecord('p', b) s.mu.Unlock() if err != nil { t.Fatal(err) } return hash } func TestBlossomBackupRestore(t *testing.T) { src, err := Open(filepath.Join(t.TempDir(), "blossom"), 1<<20) if err != nil { t.Fatal(err) } pub := "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" h1 := putTestBlob(t, src, []byte("first blob"), pub, "text/plain", 1700000000) h2 := putTestBlob(t, src, []byte("second blob"), pub, "application/octet-stream", 1700000001) var buf bytes.Buffer if err := src.Backup(&buf); err != nil { t.Fatal(err) } if err := src.Close(); err != nil { t.Fatal(err) } dst, err := Open(filepath.Join(t.TempDir(), "blossom"), 1<<20) if err != nil { t.Fatal(err) } defer dst.Close() stats, err := dst.Restore(bytes.NewReader(buf.Bytes())) if err != nil { t.Fatal(err) } if stats.Restored != 2 { t.Fatalf("restored = %d, want 2", stats.Restored) } blobs := dst.Snapshot() if len(blobs) != 2 || blobs[0].Hash != h1 || blobs[1].Hash != h2 { t.Fatalf("snapshot: %+v", blobs) } for _, b := range blobs { if b.PubKey != pub || b.Size == 0 || b.Type == "" || b.Created == 0 { t.Fatalf("metadata: %+v", b) } body, err := os.ReadFile(dst.blobPath(b.Hash)) if err != nil { t.Fatal(err) } sum := sha256.Sum256(body) if nostr.Hex(sum[:]) != b.Hash { t.Fatalf("content hash mismatch for %s", b.Hash) } } // A second restore must not duplicate blobs or fail. stats, err = dst.Restore(bytes.NewReader(buf.Bytes())) if err != nil { t.Fatal(err) } if stats.Restored != 0 || stats.Skipped != 2 { t.Fatalf("second restore: %+v", stats) } if len(dst.Snapshot()) != 2 { t.Fatal("second restore duplicated blobs") } }