Introduces the web backend (auth, RBAC, project tokens, revisions), YouTrack-or-taskmaster backend choice in the TUI, and a first-pass embedded Svelte UI. The frontend is functional but needs a major rework. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
2.3 KiB
Go
99 lines
2.3 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"task/internal/ticket"
|
|
)
|
|
|
|
func TestStoresRoundTrip(t *testing.T) {
|
|
db, err := Open(filepath.Join(t.TempDir(), "test.db"), []byte("test-secret"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
ps := NewProjectStore(db)
|
|
if err := ps.Ensure("inbox"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ts := NewTicketStore(db)
|
|
created, err := ts.Create(ticket.Ticket{Title: "Hello", ProjectID: "inbox", Status: ticket.StatusTodo})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := ts.Get(created.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Title != "Hello" {
|
|
t.Fatalf("title=%q", got.Title)
|
|
}
|
|
got.Title = "Updated"
|
|
if err := ts.Update(got); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := ts.MarkSynced(got.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
synced, _ := ts.Get(got.ID)
|
|
if synced.SyncedAt.IsZero() || !synced.SyncedAt.Equal(synced.UpdatedAt) {
|
|
t.Fatalf("syncedAt=%v updatedAt=%v", synced.SyncedAt, synced.UpdatedAt)
|
|
}
|
|
|
|
timeStore := NewTimeStore(db)
|
|
_, err = timeStore.Create(ticket.TimeEntry{
|
|
TicketID: created.ID,
|
|
ProjectID: "inbox",
|
|
Duration: time.Hour,
|
|
Source: ticket.SourceManual,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sum, err := timeStore.SumByTicket(created.ID)
|
|
if err != nil || sum != time.Hour {
|
|
t.Fatalf("sum=%v err=%v", sum, err)
|
|
}
|
|
|
|
u, err := db.CreateUser("admin", "secret", true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
token, _, err := db.CreateSession(u.ID, time.Hour)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
me, err := db.UserFromSession(token)
|
|
if err != nil || me.Username != "admin" {
|
|
t.Fatalf("session user=%v err=%v", me, err)
|
|
}
|
|
if err := db.SetMember("inbox", u.ID, RoleOwner); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
role, _ := db.MemberRole("inbox", u.ID)
|
|
if role != RoleOwner {
|
|
t.Fatalf("role=%s", role)
|
|
}
|
|
|
|
_, err = db.AppendRevision("ticket", created.ID, "inbox", "update", u.ID, synced)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
revs, err := db.ListRevisions("ticket", created.ID)
|
|
if err != nil || len(revs) != 1 {
|
|
t.Fatalf("revs=%v err=%v", revs, err)
|
|
}
|
|
|
|
conn, err := db.CreateConnection("YT", "youtrack", "https://yt.example", "instance", "tok-123", u.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err := db.GetConnection(conn.ID)
|
|
if err != nil || loaded.Token != "tok-123" {
|
|
t.Fatalf("token=%q err=%v", loaded.Token, err)
|
|
}
|
|
}
|