164 lines
5.3 KiB
Go
164 lines
5.3 KiB
Go
package accountstate
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
func TestEntriesShareRequestTransaction(t *testing.T) {
|
|
r, _ := openTestRepository(t)
|
|
if _, err := r.SaveContext(context.Background(), "collection", []byte("unchanged")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
op, err := r.BeginOperation()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := r.PutEntry("collection", "grants", "draw:1", []byte(`{"id":1}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := r.PutEntry("collection", "applied", "draw:1", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := r.Save("wallet", []byte("charged")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, found, err := r.LoadEntry("collection", "grants", "draw:1"); err != nil || !found || !bytes.Equal(got, []byte(`{"id":1}`)) {
|
|
t.Fatalf("read own entry write: %q, %t, %v", got, found, err)
|
|
}
|
|
if err := op.Commit(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
requireState(t, r, "collection", []byte("unchanged"), 1)
|
|
requireState(t, r, "wallet", []byte("charged"), 1)
|
|
entries, err := r.ListEntries("collection", "grants")
|
|
if err != nil || len(entries) != 1 || !bytes.Equal(entries["draw:1"], []byte(`{"id":1}`)) {
|
|
t.Fatalf("grant entries: %#v, %v", entries, err)
|
|
}
|
|
if got, found, err := r.LoadEntry("collection", "applied", "draw:1"); err != nil || !found || len(got) != 0 {
|
|
t.Fatalf("empty marker: %q, %t, %v", got, found, err)
|
|
}
|
|
}
|
|
|
|
func TestEntryRollbackAndDelete(t *testing.T) {
|
|
r, _ := openTestRepository(t)
|
|
if err := r.PutEntry("collection", "grants", "draw:1", []byte("before")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tx, err := r.Begin(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.PutEntry("collection", "grants", "draw:1", []byte("after")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.PutEntry("collection", "grants", "draw:2", []byte("new")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.Rollback(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, found, err := r.LoadEntry("collection", "grants", "draw:1"); err != nil || !found || !bytes.Equal(got, []byte("before")) {
|
|
t.Fatalf("rolled-back replacement: %q, %t, %v", got, found, err)
|
|
}
|
|
if _, found, err := r.LoadEntry("collection", "grants", "draw:2"); err != nil || found {
|
|
t.Fatalf("rolled-back insertion: %t, %v", found, err)
|
|
}
|
|
if deleted, err := r.DeleteEntry("collection", "grants", "draw:1"); err != nil || !deleted {
|
|
t.Fatalf("delete existing entry: %t, %v", deleted, err)
|
|
}
|
|
if deleted, err := r.DeleteEntry("collection", "grants", "draw:1"); err != nil || deleted {
|
|
t.Fatalf("delete missing entry: %t, %v", deleted, err)
|
|
}
|
|
if _, found, err := r.LoadEntry("collection", "grants", "draw:1"); err != nil || found {
|
|
t.Fatalf("deleted entry: %t, %v", found, err)
|
|
}
|
|
}
|
|
|
|
func TestEntryWriteMarksRequestRollbackDirty(t *testing.T) {
|
|
r, _ := openTestRepository(t)
|
|
op, err := r.BeginOperation()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := r.PutEntry("collection", "grants", "draw:1", []byte("pending")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := op.Rollback(); err == nil {
|
|
t.Fatal("dirty entry rollback did not require restart")
|
|
}
|
|
if err := r.Check(); err == nil {
|
|
t.Fatal("repository accepted requests after dirty entry rollback")
|
|
}
|
|
var count int
|
|
if err := r.db.QueryRow(`SELECT COUNT(*) FROM domain_entry`).Scan(&count); err != nil || count != 0 {
|
|
t.Fatalf("entry survived rollback: count %d, error %v", count, err)
|
|
}
|
|
}
|
|
|
|
func TestEntryScopeAndClosedTransaction(t *testing.T) {
|
|
r, _ := openTestRepository(t)
|
|
if err := r.PutEntry("", "grants", "key", nil); err == nil {
|
|
t.Fatal("accepted empty domain")
|
|
}
|
|
if err := r.PutEntry("collection", "", "key", nil); err == nil {
|
|
t.Fatal("accepted empty bucket")
|
|
}
|
|
if err := r.PutEntry("collection", "grants", "", nil); err == nil {
|
|
t.Fatal("accepted empty key")
|
|
}
|
|
tx, err := r.Begin(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.PutEntry("collection", "grants", "key", nil); !errors.Is(err, ErrClosed) {
|
|
t.Fatalf("put after commit: %v", err)
|
|
}
|
|
if _, err := tx.ListEntries("collection", "grants"); !errors.Is(err, ErrClosed) {
|
|
t.Fatalf("list after commit: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOldSchemaIsRejectedWithoutMutation(t *testing.T) {
|
|
r, path := openTestRepository(t)
|
|
if _, err := r.SaveContext(context.Background(), "collection", []byte("legacy snapshot")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := r.db.Exec(`DROP TABLE domain_entry`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := r.db.Exec(`UPDATE metadata SET value = '0' WHERE key = 'schema_version'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := r.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if reopened, err := Open(path); err == nil {
|
|
_ = reopened.Close()
|
|
t.Fatal("opened unsupported schema version")
|
|
}
|
|
db, err := sql.Open("sqlite", path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
if err := db.Close(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}()
|
|
var version string
|
|
if err := db.QueryRow(`SELECT value FROM metadata WHERE key = 'schema_version'`).Scan(&version); err != nil || version != "0" {
|
|
t.Fatalf("changed unsupported version %q: %v", version, err)
|
|
}
|
|
var entryTables int
|
|
if err := db.QueryRow(`SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'domain_entry'`).Scan(&entryTables); err != nil || entryTables != 0 {
|
|
t.Fatalf("created table during failed open: %d, %v", entryTables, err)
|
|
}
|
|
}
|