go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit cd9478f3b3893090aab15305e948ea875f8e9649
parent 2108b77e5392058c82acf98871aaf951a6bdc65e
Author: lash <dev@holbrook.no>
Date:   Sun,  1 Sep 2024 17:02:04 +0100

WIP db test vectors

Diffstat:
Mdb/db.go | 40+++++++++++++++++++++++++++++++---------
Mdb/db_test.go | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mdb/fs_test.go | 2+-
Mdb/gdbm_test.go | 2+-
Mdb/mem.go | 1+
Mdb/mem_test.go | 37+++++--------------------------------
Mdb/pg_test.go | 2+-
7 files changed, 148 insertions(+), 56 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -8,6 +8,10 @@ import ( ) const ( + safeLock =DATATYPE_BIN | DATATYPE_MENU | DATATYPE_TEMPLATE | DATATYPE_STATICLOAD +) + +const ( // Invalid datatype, must raise error if attempted used. DATATYPE_UNKNOWN = 0 // Bytecode @@ -21,11 +25,11 @@ const ( // State and cache from persister DATATYPE_STATE = 16 // Application data - DATATYPE_USERSTART = 32 + DATATYPE_USERDATA = 32 ) const ( - datatype_sessioned_threshold = DATATYPE_TEMPLATE + datatype_sessioned_threshold = DATATYPE_STATICLOAD ) // Db abstracts all data storage and retrieval as a key-value store @@ -45,7 +49,11 @@ type Db interface { // * DATATYPE_STATE // * DATATYPE_USERSTART SetSession(sessionId string) - SetLock(typ uint8, locked bool) + // SetLock disables modification of data that is readonly in the vm context. + // If called with typ value 0, it will permanently lock all readonly members. + SetLock(typ uint8, locked bool) error + // Safe returns true if db is safe for use with a vm. + Safe() bool } type lookupKey struct { @@ -73,30 +81,44 @@ type baseDb struct { sid []byte lock uint8 lang *lang.Language + seal bool } // ensures default locking of read-only entries func(db *baseDb) defaultLock() { - db.lock = DATATYPE_BIN | DATATYPE_MENU | DATATYPE_TEMPLATE | DATATYPE_STATICLOAD + db.lock |= safeLock +} + +func(db *baseDb) Safe() bool { + return db.lock & safeLock == safeLock } -// SetPrefix implements Db. +// SetPrefix implements the Db interface. func(db *baseDb) SetPrefix(pfx uint8) { db.pfx = pfx } -// SetSession implements Db. +// SetSession implements the Db interface. func(db *baseDb) SetSession(sessionId string) { db.sid = append([]byte(sessionId), 0x2E) } -// SetSafety disables modification of data that -func(db *baseDb) SetLock(pfx uint8, lock bool) { +// SetLock implements the Db interface. +func(db *baseDb) SetLock(pfx uint8, lock bool) error { + if db.seal { + return errors.New("SetLock on sealed db") + } + if pfx == 0 { + db.seal = true + db.defaultLock() + return nil + } if lock { db.lock |= pfx } else { db.lock &= ^pfx } + return nil } func(db *baseDb) checkPut() bool { @@ -125,6 +147,6 @@ func(db *baseDb) ToKey(ctx context.Context, key []byte) (lookupKey, error) { if ok { lk.Translation = ToDbKey(db.pfx, b, &ln) } - } + } return lk, nil } diff --git a/db/db_test.go b/db/db_test.go @@ -1,9 +1,16 @@ package db import ( + "bytes" "context" "encoding/hex" + "errors" + "fmt" "path" + "strconv" + "testing" + + "git.defalsify.org/vise.git/lang" ) type testCase struct { @@ -11,12 +18,15 @@ type testCase struct { s string k []byte v []byte + x []byte + l *lang.Language } type testVector struct { c map[string]*testCase v []string i int + s string } func(tc *testCase) Key() []byte { @@ -35,17 +45,36 @@ func(tc *testCase) Session() string { return tc.s } -func(tv *testVector) add(typ uint8, k string, v string, session string) { +func(tc *testCase) Expect() []byte { + return tc.x +} + +func(tv *testVector) add(typ uint8, k string, v string, session string, expect string, language string) { var b []byte + var x []byte var err error + var ln *lang.Language if typ == DATATYPE_BIN { b, err = hex.DecodeString(v) if err != nil { panic(err) } + x, err = hex.DecodeString(expect) + if err != nil { + panic(err) + } } else { b = []byte(v) + x = []byte(expect) + } + + if language != "" { + lo, err := lang.LanguageFromCode(language) + if err != nil { + panic(err) + } + ln = &lo } o := &testCase { @@ -53,10 +82,15 @@ func(tv *testVector) add(typ uint8, k string, v string, session string) { k: []byte(k), v: b, s: session, + x: x, + l: ln, } - s := path.Join(session, k) + s := path.Join(strconv.Itoa(int(typ)), session) + s = path.Join(s, k) tv.c[s] = o + i := len(tv.v) tv.v = append(tv.v, s) + logg.Tracef("add testcase", "i", i, "s", s, "k", o.k) } func(tv *testVector) next() (int, *testCase) { @@ -94,16 +128,78 @@ func(tv *testVector) put(ctx context.Context, db Db) error { return nil } -func generateTestVectors() testVector { - tv := testVector{c: make(map[string]*testCase)} - tv.add(DATATYPE_BIN, "foo", "deadbeef", "") - tv.add(DATATYPE_BIN, "foo", "beeffeed", "tinkywinky") - tv.add(DATATYPE_TEMPLATE, "foo", "inky", "") - tv.add(DATATYPE_TEMPLATE, "foo", "pinky", "dipsy") - tv.add(DATATYPE_MENU, "foo", "blinky", "") - tv.add(DATATYPE_MENU, "foo", "clyde", "lala") - tv.add(DATATYPE_STATICLOAD, "foo", "bar", "") - tv.add(DATATYPE_STATICLOAD, "foo", "baz", "po") +func(tv *testVector) label() string { + return tv.s +} + +func generateSessionTestVectors() testVector { + tv := testVector{c: make(map[string]*testCase), s: "session"} + tv.add(DATATYPE_BIN, "foo", "deadbeef", "", "beeffeed", "") + tv.add(DATATYPE_BIN, "foo", "beeffeed", "inky", "beeffeed", "") + tv.add(DATATYPE_TEMPLATE, "foo", "tinkywinky", "", "dipsy", "") + tv.add(DATATYPE_TEMPLATE, "foo", "dipsy", "pinky", "dipsy", "") + tv.add(DATATYPE_MENU, "foo", "lala", "", "pu", "") + tv.add(DATATYPE_MENU, "foo", "pu", "blinky", "pu", "") + tv.add(DATATYPE_STATICLOAD, "foo", "bar", "", "baz", "") + tv.add(DATATYPE_STATICLOAD, "foo", "baz", "clyde", "baz", "") + tv.add(DATATYPE_STATE, "foo", "xyzzy", "", "xyzzy", "") + tv.add(DATATYPE_STATE, "foo", "plugh", "sue", "plugh", "") + tv.add(DATATYPE_USERDATA, "foo", "itchy", "", "itchy", "") + tv.add(DATATYPE_USERDATA, "foo", "scratchy", "poochie", "scratchy", "") + return tv +} + +func generateLanguageTestVectors() testVector { + tv := testVector{c: make(map[string]*testCase), s: "language"} + tv.add(DATATYPE_BIN, "foo", "deadbeef", "", "beeffeed", "") + tv.add(DATATYPE_BIN, "foo", "deadbeef", "", "deadbeef", "nor") return tv } +func runTest(t *testing.T, ctx context.Context, db Db, vs testVector) error { + err := vs.put(ctx, db) + if err != nil { + return err + } + for true { + i, tc := vs.next() + if i == -1 { + break + } + s := fmt.Sprintf("Test%sTyp%dKey%s", vs.label(), tc.Typ(), tc.Key()) + if tc.Session() != "" { + s += "Session" + tc.Session() + } else { + s += "NoSession" + } + r := t.Run(s, func(t *testing.T) { + db.SetPrefix(tc.Typ()) + db.SetSession(tc.Session()) + v, err := db.Get(ctx, tc.Key()) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(tc.Expect(), v) { + t.Fatalf("expected %s, got %s", tc.Expect(), v) + } + }) + if !r { + return errors.New("subtest fail") + } + } + return nil + +} +func runTests(t *testing.T, ctx context.Context, db Db) error { + err := runTest(t, ctx, db, generateSessionTestVectors()) + if err != nil { + return err + } + + err = runTest(t, ctx, db, generateLanguageTestVectors()) + if err != nil { + return err + } + + return nil +} diff --git a/db/fs_test.go b/db/fs_test.go @@ -18,7 +18,7 @@ func TestPutGetFs(t *testing.T) { t.Fatal(err) } db := NewFsDb() - db.SetPrefix(DATATYPE_USERSTART) + db.SetPrefix(DATATYPE_USERDATA) db.SetSession(sid) dbi = db diff --git a/db/gdbm_test.go b/db/gdbm_test.go @@ -16,7 +16,7 @@ func TestPutGetGdbm(t *testing.T) { t.Fatal(err) } db := NewGdbmDb() - db.SetPrefix(DATATYPE_USERSTART) + db.SetPrefix(DATATYPE_USERDATA) db.SetSession(sid) dbi = db diff --git a/db/mem.go b/db/mem.go @@ -42,6 +42,7 @@ func(mdb *memDb) toHexKey(ctx context.Context, key []byte) (memLookupKey, error) if lk.Translation != nil { mk.Translation = hex.EncodeToString(lk.Translation) } + logg.TraceCtxf(ctx, "converted key", "orig", key, "b", lk, "s", mk) return mk, err } diff --git a/db/mem_test.go b/db/mem_test.go @@ -3,48 +3,21 @@ package db import ( "bytes" "context" - "fmt" "testing" ) func TestCasesMem(t *testing.T) { - var i int - var tc *testCase - ctx := context.Background() - vs := generateTestVectors() + db := NewMemDb() err := db.Connect(ctx, "") if err != nil { t.Fatal(err) } - err = vs.put(ctx, db) - for true { - i, tc = vs.next() - if i == -1 { - break - } - s := fmt.Sprintf("TestTyp%dKey%s", tc.Typ(), tc.Key()) - if tc.Session() != "" { - s += "Session" + tc.Session() - } else { - s += "NoSession" - } - r := t.Run(s, func(t *testing.T) { - db.SetPrefix(tc.Typ()) - db.SetSession(tc.Session()) - v, err := db.Get(ctx, tc.Key()) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(tc.Val(), v) { - t.Fatalf("expected %x, got %x", tc.Val(), v) - } - }) - if !r { - t.Fatalf("subtest fail") - } + err = runTests(t, ctx, db) + if err != nil { + t.Fatal(err) } } @@ -53,7 +26,7 @@ func TestPutGetMem(t *testing.T) { ctx := context.Background() sid := "ses" db := NewMemDb() - db.SetPrefix(DATATYPE_USERSTART) + db.SetPrefix(DATATYPE_USERDATA) db.SetSession(sid) dbi = db diff --git a/db/pg_test.go b/db/pg_test.go @@ -10,7 +10,7 @@ func TestPutGetPg(t *testing.T) { var dbi Db ses := "xyzzy" db := NewPgDb().WithSchema("vvise") - db.SetPrefix(DATATYPE_USERSTART) + db.SetPrefix(DATATYPE_USERDATA) db.SetSession(ses) ctx := context.Background()