Files

413 lines
9.4 KiB
Go

package labeler
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestOpenDB(t *testing.T) {
dir := t.TempDir()
dbPath := filepath.Join(dir, "subdir", "test.db")
db, err := OpenDB(dbPath)
if err != nil {
t.Fatalf("OpenDB failed: %v", err)
}
defer db.Close()
// Verify directory was created
if _, err := os.Stat(filepath.Dir(dbPath)); os.IsNotExist(err) {
t.Error("expected directory to be created")
}
// Verify tables exist
var count int
err = db.QueryRow("SELECT COUNT(*) FROM labels").Scan(&count)
if err != nil {
t.Fatalf("failed to query labels table: %v", err)
}
if count != 0 {
t.Errorf("expected 0 labels, got %d", count)
}
}
func TestCreateLabel(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
now := time.Now().UTC().Truncate(time.Second)
label := &Label{
Src: "did:web:labeler.atcr.io",
URI: "at://did:plc:abc/io.atcr.manifest/sha256-123",
Val: "!takedown",
Cts: now,
SubjectDID: "did:plc:abc",
SubjectRepo: "myimage",
}
id, err := CreateLabel(db, label)
if err != nil {
t.Fatalf("CreateLabel failed: %v", err)
}
if id <= 0 {
t.Errorf("expected positive id, got %d", id)
}
// Verify it was stored
labels, err := GetLabelsSince(db, 0, 10)
if err != nil {
t.Fatal(err)
}
if len(labels) != 1 {
t.Fatalf("expected 1 label, got %d", len(labels))
}
if labels[0].Src != "did:web:labeler.atcr.io" {
t.Errorf("expected src did:web:labeler.atcr.io, got %s", labels[0].Src)
}
if labels[0].Val != "!takedown" {
t.Errorf("expected val !takedown, got %s", labels[0].Val)
}
if labels[0].SubjectDID != "did:plc:abc" {
t.Errorf("expected subject_did did:plc:abc, got %s", labels[0].SubjectDID)
}
if labels[0].SubjectRepo != "myimage" {
t.Errorf("expected subject_repo myimage, got %s", labels[0].SubjectRepo)
}
}
func TestCreateLabel_Upsert(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
now := time.Now().UTC()
label := &Label{
Src: "did:web:labeler.atcr.io",
URI: "at://did:plc:abc/io.atcr.manifest/sha256-123",
Val: "!takedown",
Cts: now,
SubjectDID: "did:plc:abc",
SubjectRepo: "myimage",
}
// First insert
_, err = CreateLabel(db, label)
if err != nil {
t.Fatal(err)
}
// Same (src, uri, val) - should upsert, not error
label.Cts = now.Add(time.Hour)
_, err = CreateLabel(db, label)
if err != nil {
t.Fatalf("upsert should not fail: %v", err)
}
// Should still be 1 label
labels, err := GetLabelsSince(db, 0, 10)
if err != nil {
t.Fatal(err)
}
if len(labels) != 1 {
t.Errorf("expected 1 label after upsert, got %d", len(labels))
}
}
func TestNegateLabel(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
// Create a label
_, err = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.manifest/sha256-123",
Val: "!takedown", Cts: now,
SubjectDID: "did:plc:abc", SubjectRepo: "myimage",
})
if err != nil {
t.Fatal(err)
}
// Negate it
err = NegateLabel(db, src, "at://did:plc:abc/io.atcr.manifest/sha256-123", "!takedown", "did:plc:abc", "myimage")
if err != nil {
t.Fatalf("NegateLabel failed: %v", err)
}
// Should have 2 labels now (original + negation)
labels, err := GetLabelsSince(db, 0, 10)
if err != nil {
t.Fatal(err)
}
if len(labels) != 2 {
t.Fatalf("expected 2 labels, got %d", len(labels))
}
// The negation label should have neg=true
negLabel := labels[1]
if !negLabel.Neg {
t.Error("expected negation label to have neg=true")
}
}
func TestListActiveTakedowns(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
// Create 3 labels
for i, repo := range []string{"repo1", "repo2", "repo3"} {
_, err = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.repo/" + repo,
Val: "!takedown", Cts: now.Add(time.Duration(i) * time.Minute),
SubjectDID: "did:plc:abc", SubjectRepo: repo,
})
if err != nil {
t.Fatal(err)
}
}
// All 3 should be active
labels, total, err := ListActiveTakedowns(db, 10, 0)
if err != nil {
t.Fatal(err)
}
if total != 3 {
t.Errorf("expected 3 active takedowns, got %d", total)
}
if len(labels) != 3 {
t.Errorf("expected 3 labels returned, got %d", len(labels))
}
// Negate one
err = NegateLabel(db, src, "at://did:plc:abc/io.atcr.repo/repo2", "!takedown", "did:plc:abc", "repo2")
if err != nil {
t.Fatal(err)
}
// Should be 2 active
_, total, err = ListActiveTakedowns(db, 10, 0)
if err != nil {
t.Fatal(err)
}
if total != 2 {
t.Errorf("expected 2 active takedowns after negation, got %d", total)
}
}
func TestNegateRepoLabels(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
did := "did:plc:abc"
// Create multiple labels for same repo
uris := []string{
"at://did:plc:abc/io.atcr.manifest/sha256-111",
"at://did:plc:abc/io.atcr.manifest/sha256-222",
"at://did:plc:abc/io.atcr.tag/myimage-latest",
}
for _, uri := range uris {
_, err = CreateLabel(db, &Label{
Src: src, URI: uri, Val: "!takedown", Cts: now,
SubjectDID: did, SubjectRepo: "myimage",
})
if err != nil {
t.Fatal(err)
}
}
// Negate all labels for the repo
err = NegateRepoLabels(db, src, did, "myimage")
if err != nil {
t.Fatal(err)
}
// Should have 0 active takedowns
_, total, err := ListActiveTakedowns(db, 10, 0)
if err != nil {
t.Fatal(err)
}
if total != 0 {
t.Errorf("expected 0 active takedowns after repo negation, got %d", total)
}
}
func TestNegateUserLabels(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
did := "did:plc:abc"
// Create labels for different repos + a user-level label
_, err = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc", Val: "!takedown", Cts: now,
SubjectDID: did, SubjectRepo: "",
})
if err != nil {
t.Fatal(err)
}
_, err = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.repo/repo1", Val: "!takedown", Cts: now,
SubjectDID: did, SubjectRepo: "repo1",
})
if err != nil {
t.Fatal(err)
}
// Negate all labels for the user
err = NegateUserLabels(db, src, did)
if err != nil {
t.Fatal(err)
}
// Should have 0 active
_, total, err := ListActiveTakedowns(db, 10, 0)
if err != nil {
t.Fatal(err)
}
if total != 0 {
t.Errorf("expected 0 active takedowns after user negation, got %d", total)
}
}
func TestGetLabelsSince(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
// Create 5 labels
for i := 0; i < 5; i++ {
_, err = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.manifest/" + string(rune('a'+i)),
Val: "!takedown", Cts: now.Add(time.Duration(i) * time.Minute),
SubjectDID: "did:plc:abc", SubjectRepo: "repo",
})
if err != nil {
t.Fatal(err)
}
}
// Get all since 0
labels, err := GetLabelsSince(db, 0, 10)
if err != nil {
t.Fatal(err)
}
if len(labels) != 5 {
t.Errorf("expected 5 labels, got %d", len(labels))
}
// Get since cursor (skip first 3)
if len(labels) >= 3 {
cursor := labels[2].ID
after, err := GetLabelsSince(db, cursor, 10)
if err != nil {
t.Fatal(err)
}
if len(after) != 2 {
t.Errorf("expected 2 labels after cursor %d, got %d", cursor, len(after))
}
}
// Get with limit
limited, err := GetLabelsSince(db, 0, 2)
if err != nil {
t.Fatal(err)
}
if len(limited) != 2 {
t.Errorf("expected 2 labels with limit, got %d", len(limited))
}
}
func TestGetLabelsForRepo(t *testing.T) {
dir := t.TempDir()
db, err := OpenDB(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
src := "did:web:labeler.atcr.io"
now := time.Now().UTC()
// Labels for different repos
_, _ = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.repo/repo1",
Val: "!takedown", Cts: now, SubjectDID: "did:plc:abc", SubjectRepo: "repo1",
})
_, _ = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:abc/io.atcr.repo/repo2",
Val: "!takedown", Cts: now, SubjectDID: "did:plc:abc", SubjectRepo: "repo2",
})
_, _ = CreateLabel(db, &Label{
Src: src, URI: "at://did:plc:def/io.atcr.repo/repo1",
Val: "!takedown", Cts: now, SubjectDID: "did:plc:def", SubjectRepo: "repo1",
})
// Get labels for specific did+repo
labels, err := GetLabelsForRepo(db, "did:plc:abc", "repo1")
if err != nil {
t.Fatal(err)
}
if len(labels) != 1 {
t.Errorf("expected 1 label for did:plc:abc/repo1, got %d", len(labels))
}
// Different user same repo
labels, err = GetLabelsForRepo(db, "did:plc:def", "repo1")
if err != nil {
t.Fatal(err)
}
if len(labels) != 1 {
t.Errorf("expected 1 label for did:plc:def/repo1, got %d", len(labels))
}
// No labels
labels, err = GetLabelsForRepo(db, "did:plc:xyz", "repo1")
if err != nil {
t.Fatal(err)
}
if len(labels) != 0 {
t.Errorf("expected 0 labels for unknown did, got %d", len(labels))
}
}