Skip to content
quarry Artifact [6fe822a5dd]
Login

Artifact [6fe822a5dd]

Artifact 6fe822a5ddb971e1fcb41861a446c69cc00fe96e1c30732e59805b994f173ec4:


package main

import (
	"errors"
	"path/filepath"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/oltp"
	"craftdesign.group/quarry/internal/ops"
)

// A failed import is a record, not a repository: its owner (or their
// agent) asking for the name again starts it over, and anybody else
// still meets the name as taken. An import still copying holds its name
// against everybody.
func TestAFailedImportGivesItsNameBackToItsOwner(t *testing.T) {
	db, err := oltp.Open(filepath.Join(t.TempDir(), "oltp.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	for _, who := range []string{"dan", "eve"} {
		if err := db.AddAccount(who, "a-long-enough-password", false); err != nil {
			t.Fatal(err)
		}
	}
	if err := db.NewAgent("dan-bot", "dan", -1); err != nil {
		t.Fatal(err)
	}
	rg := &registrar{odb: db, deps: &api.Deps{Repos: api.NewRepos(nil)}, repoQuota: 25}
	importing := func(name, state string) {
		t.Helper()
		if err := db.AddImportingRepo(name, filepath.Join(t.TempDir(), name), "", oltp.Public, "https://example.com/"+name); err != nil {
			t.Fatal(err)
		}
		if err := db.SetOwner(name, "dan"); err != nil {
			t.Fatal(err)
		}
		if state != oltp.Cloning {
			if err := db.SetRepoState(name, state, "import failed: Corrupt"); err != nil {
				t.Fatal(err)
			}
		}
	}
	importing("broke", oltp.Failed)
	importing("copying", oltp.Cloning)

	for _, c := range []struct {
		name, who string
		free      bool
	}{
		{"broke", "dan", true},
		{"broke", "dan-bot", true},
		{"broke", "eve", false},
		{"copying", "dan", false},
		{"fresh", "eve", true},
	} {
		err := rg.NameFree(c.name, c.who)
		if c.free && err != nil {
			t.Errorf("FAIL: %s may not name %s: %v", c.who, c.name, err)
		}
		if !c.free && !errors.Is(err, ops.ErrInvalid) {
			t.Errorf("FAIL: %s may name %s: %v", c.who, c.name, err)
		}
	}

	// Somebody else's attempt leaves the record alone; the owner's clears it.
	if err := rg.retryFailedImport(api.RepoSpec{Name: "broke", Author: "eve"}); err != nil {
		t.Fatal(err)
	}
	if _, found, _ := db.RepoByName("broke"); !found {
		t.Fatal("FAIL: another account's attempt cleared the owner's failed import")
	}
	if err := rg.retryFailedImport(api.RepoSpec{Name: "broke", Author: "dan"}); err != nil {
		t.Fatal(err)
	}
	if _, found, _ := db.RepoByName("broke"); found {
		t.Error("FAIL: the owner's new attempt left the failed record holding the name")
	}
}