Replace UUID-looking sync labels in TUI and web with keys like TAS-1, while keeping the remote UUID for task-master matching. Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
3.1 KiB
Go
125 lines
3.1 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"task/internal/ticket"
|
|
)
|
|
|
|
func TestTicketKeysSequential(t *testing.T) {
|
|
db, err := Open(filepath.Join(t.TempDir(), "keys.db"), []byte("test-secret"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
ps := NewProjectStore(db)
|
|
p, err := ps.Create("", "Task Master")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p.Code != "TAS" {
|
|
t.Fatalf("code=%q want TAS", p.Code)
|
|
}
|
|
|
|
ts := NewTicketStore(db)
|
|
a, err := ts.Create(ticket.Ticket{Title: "One", ProjectID: p.ID})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := ts.Create(ticket.Ticket{Title: "Two", ProjectID: p.ID})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a.Key != "TAS-1" || a.Number != 1 {
|
|
t.Fatalf("first=%+v", a)
|
|
}
|
|
if b.Key != "TAS-2" || b.Number != 2 {
|
|
t.Fatalf("second=%+v", b)
|
|
}
|
|
|
|
got, err := ts.Get(a.ID)
|
|
if err != nil || got.Key != "TAS-1" {
|
|
t.Fatalf("get=%+v err=%v", got, err)
|
|
}
|
|
|
|
// Update must preserve key.
|
|
got.Title = "One*"
|
|
if err := ts.Update(got); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, _ = ts.Get(a.ID)
|
|
if got.Key != "TAS-1" || got.Title != "One*" {
|
|
t.Fatalf("after update=%+v", got)
|
|
}
|
|
}
|
|
|
|
func TestTicketKeyBackfill(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "backfill.db")
|
|
db, err := Open(path, []byte("test-secret"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Insert legacy-shaped rows as if pre-migration (columns exist after Open).
|
|
_, err = db.SQL.Exec(`INSERT INTO projects(id, name, code, ticket_seq, created_at, updated_at)
|
|
VALUES('p1', 'Inbox', '', 0, '2020-01-01T00:00:00Z', '2020-01-01T00:00:00Z')`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = db.SQL.Exec(`INSERT INTO tickets(id, title, description, status, project_id, created_at, updated_at, source, external_id, external_url, synced_at, number, key)
|
|
VALUES('t1', 'Old', '', 'todo', 'p1', '2020-01-02T00:00:00Z', '2020-01-02T00:00:00Z', '', '', '', '', NULL, '')`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.backfillTicketKeys(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var code string
|
|
var seq int
|
|
if err := db.SQL.QueryRow(`SELECT code, ticket_seq FROM projects WHERE id='p1'`).Scan(&code, &seq); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if code != "INB" || seq != 1 {
|
|
t.Fatalf("project code=%q seq=%d", code, seq)
|
|
}
|
|
var key string
|
|
var num int
|
|
if err := db.SQL.QueryRow(`SELECT key, number FROM tickets WHERE id='t1'`).Scan(&key, &num); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if key != "INB-1" || num != 1 {
|
|
t.Fatalf("ticket key=%q num=%d", key, num)
|
|
}
|
|
_ = db.Close()
|
|
}
|
|
|
|
func TestMoveReassignsKey(t *testing.T) {
|
|
db, err := Open(filepath.Join(t.TempDir(), "move.db"), []byte("test-secret"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
ps := NewProjectStore(db)
|
|
a, err := ps.Create("", "Alpha")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := ps.Create("", "Beta")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ts := NewTicketStore(db)
|
|
tk, err := ts.Create(ticket.Ticket{Title: "Move me", ProjectID: a.ID})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
moved, err := ts.Move(tk.ID, b.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if moved.ProjectID != b.ID || moved.Key != b.Code+"-1" {
|
|
t.Fatalf("moved=%+v betaCode=%s", moved, b.Code)
|
|
}
|
|
}
|