go-vise

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

commit 4bd7742672fc8f9f0bfb75cbf5528098ee7998d9
parent f968d80d5e87723702e9d64777f735747b4ba95e
Author: lash <dev@holbrook.no>
Date:   Mon,  2 Sep 2024 02:15:09 +0100

Complete engine refactor

Diffstat:
Mengine/db.go | 46+++++++++++++++++++++++-----------------------
Mengine/db_test.go | 6+++---
Dengine/default.go | 94-------------------------------------------------------------------------------
Mengine/engine.go | 36++++++++++++++++++------------------
Mengine/engine_test.go | 36++++++++++++++++++++++++++----------
Mengine/loop.go | 2+-
Mengine/loop_test.go | 21+++++++++++++++------
Dengine/persist.go | 93-------------------------------------------------------------------------------
Dengine/persist_test.go | 146-------------------------------------------------------------------------------
9 files changed, 86 insertions(+), 394 deletions(-)

diff --git a/engine/db.go b/engine/db.go @@ -15,7 +15,7 @@ import ( "git.defalsify.org/vise.git/vm" ) -type DbEngine struct { +type dbEngine struct { st *state.State ca cache.Memory vm *vm.Vm @@ -28,11 +28,11 @@ type DbEngine struct { exit string } -func NewDbEngine(cfg Config, rs resource.Resource) *DbEngine { +func NewEngine(cfg Config, rs resource.Resource) *dbEngine { if rs == nil { panic("resource cannot be nil") } - en := &DbEngine{ + en := &dbEngine{ rs: rs, cfg: cfg, } @@ -42,7 +42,7 @@ func NewDbEngine(cfg Config, rs resource.Resource) *DbEngine { return en } -func(en *DbEngine) WithState(st *state.State) *DbEngine { +func(en *dbEngine) WithState(st *state.State) *dbEngine { if en.st != nil { panic("state already set") } @@ -53,7 +53,7 @@ func(en *DbEngine) WithState(st *state.State) *DbEngine { return en } -func(en *DbEngine) WithCache(ca cache.Memory) *DbEngine { +func(en *dbEngine) WithMemory(ca cache.Memory) *dbEngine { if en.ca != nil { panic("cache already set") } @@ -64,7 +64,7 @@ func(en *DbEngine) WithCache(ca cache.Memory) *DbEngine { return en } -func(en *DbEngine) WithResource(rs resource.Resource) *DbEngine { +func(en *dbEngine) WithResource(rs resource.Resource) *dbEngine { if en.rs != nil { panic("resource already set") } @@ -75,7 +75,7 @@ func(en *DbEngine) WithResource(rs resource.Resource) *DbEngine { return en } -func(en *DbEngine) WithPersister(pe *persist.Persister) *DbEngine { +func(en *dbEngine) WithPersister(pe *persist.Persister) *dbEngine { if en.pe != nil { panic("persister already set") } @@ -86,7 +86,7 @@ func(en *DbEngine) WithPersister(pe *persist.Persister) *DbEngine { return en } -func(en *DbEngine) WithDebug(dbg Debug) *DbEngine { +func(en *dbEngine) WithDebug(dbg Debug) *dbEngine { if en.dbg != nil { panic("debugger already set") } @@ -98,7 +98,7 @@ func(en *DbEngine) WithDebug(dbg Debug) *DbEngine { return en } -func(en *DbEngine) WithFirst(fn resource.EntryFunc) *DbEngine { +func(en *dbEngine) WithFirst(fn resource.EntryFunc) *dbEngine { if en.first != nil { panic("firstfunc already set") } @@ -109,7 +109,7 @@ func(en *DbEngine) WithFirst(fn resource.EntryFunc) *DbEngine { return en } -func(en *DbEngine) ensureState() { +func(en *dbEngine) ensureState() { if en.st == nil { st := state.NewState(en.cfg.FlagCount) en.st = &st @@ -130,7 +130,7 @@ func(en *DbEngine) ensureState() { } } -func(en *DbEngine) ensureMemory() error { +func(en *dbEngine) ensureMemory() error { cac, ok := en.ca.(*cache.Cache) if cac == nil { ca := cache.NewCache() @@ -146,7 +146,7 @@ func(en *DbEngine) ensureMemory() error { return nil } -func(en *DbEngine) preparePersist() error { +func(en *dbEngine) preparePersist() error { if en.pe == nil { return nil } @@ -185,7 +185,7 @@ func(en *DbEngine) preparePersist() error { return nil } -func(en *DbEngine) ensurePersist() error { +func(en *dbEngine) ensurePersist() error { if en.pe == nil { return nil } @@ -208,7 +208,7 @@ func(en *DbEngine) ensurePersist() error { return nil } -func(en *DbEngine) setupVm() { +func(en *dbEngine) setupVm() { var szr *render.Sizer if en.cfg.OutputSize > 0 { szr = render.NewSizer(en.cfg.OutputSize) @@ -216,7 +216,7 @@ func(en *DbEngine) setupVm() { en.vm = vm.NewVm(en.st, en.rs, en.ca, szr) } -func(en *DbEngine) prepare() error { +func(en *dbEngine) prepare() error { err := en.preparePersist() if err != nil { return err @@ -235,7 +235,7 @@ func(en *DbEngine) prepare() error { } // execute the first function, if set -func(en *DbEngine) runFirst(ctx context.Context) (bool, error) { +func(en *dbEngine) runFirst(ctx context.Context) (bool, error) { var err error var r bool if en.first == nil { @@ -274,7 +274,7 @@ func(en *DbEngine) runFirst(ctx context.Context) (bool, error) { } // Finish implements EngineIsh interface -func(en *DbEngine) Finish() error { +func(en *dbEngine) Finish() error { var perr error if en.pe != nil { perr = en.pe.Save(en.cfg.SessionId) @@ -294,7 +294,7 @@ func(en *DbEngine) Finish() error { } // change root to current state location if non-empty. -func(en *DbEngine) restore() { +func(en *dbEngine) restore() { location, _ := en.st.Where() if len(location) == 0 { return @@ -308,7 +308,7 @@ func(en *DbEngine) restore() { // Init must be explicitly called before using the Engine instance. // // It loads and executes code for the start node. -func(en *DbEngine) Init(ctx context.Context) (bool, error) { +func(en *dbEngine) Init(ctx context.Context) (bool, error) { err := en.prepare() if err != nil { return false, err @@ -364,7 +364,7 @@ func(en *DbEngine) Init(ctx context.Context) (bool, error) { // - input is formally invalid (too long etc) // - no current bytecode is available // - input processing against bytcode failed -func (en *DbEngine) Exec(ctx context.Context, input []byte) (bool, error) { +func (en *dbEngine) Exec(ctx context.Context, input []byte) (bool, error) { var err error if en.st.Language != nil { ctx = context.WithValue(ctx, "Language", *en.st.Language) @@ -388,7 +388,7 @@ func (en *DbEngine) Exec(ctx context.Context, input []byte) (bool, error) { } // backend for Exec, after the input validity check -func(en *DbEngine) exec(ctx context.Context, input []byte) (bool, error) { +func(en *dbEngine) exec(ctx context.Context, input []byte) (bool, error) { logg.InfoCtxf(ctx, "new VM execution with input", "input", string(input)) code, err := en.st.GetCode() if err != nil { @@ -436,7 +436,7 @@ func(en *DbEngine) exec(ctx context.Context, input []byte) (bool, error) { // - required data inputs to the template are not available. // - the template for the given node point is note available for retrieval using the resource.Resource implementer. // - the supplied writer fails to process the writes. -func(en *DbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) { +func(en *dbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) { var l int if en.st.Language != nil { ctx = context.WithValue(ctx, "Language", *en.st.Language) @@ -464,7 +464,7 @@ func(en *DbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) { } // start execution over at top node while keeping current state of client error flags. -func(en *DbEngine) reset(ctx context.Context) (bool, error) { +func(en *dbEngine) reset(ctx context.Context) (bool, error) { var err error var isTop bool for !isTop { diff --git a/engine/db_test.go b/engine/db_test.go @@ -46,7 +46,7 @@ func TestDbEngineMinimal(t *testing.T) { ctx := context.Background() cfg := Config{} rs := resource.NewMenuResource() - en := NewDbEngine(cfg, rs) + en := NewEngine(cfg, rs) cont, err := en.Init(ctx) if err != nil { t.Fatal(err) @@ -67,7 +67,7 @@ func TestDbEngineRoot(t *testing.T) { cfg := Config{} rs := resource.NewMenuResource() rs.WithCodeGetter(codeGet) - en := NewDbEngine(cfg, rs) + en := NewEngine(cfg, rs) cont, err := en.Init(ctx) if err != nil { t.Fatal(err) @@ -110,7 +110,7 @@ func TestDbEnginePersist(t *testing.T) { rs := resource.NewMenuResource() rs.WithCodeGetter(codeGet) rs.AddLocalFunc("foo", flagSet) - en := NewDbEngine(cfg, rs) + en := NewEngine(cfg, rs) en = en.WithPersister(pe) cont, err := en.Init(ctx) if err != nil { diff --git a/engine/default.go b/engine/default.go @@ -1,94 +0,0 @@ -package engine - -import ( - "context" - "fmt" - - "git.defalsify.org/vise.git/cache" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" - "git.defalsify.org/vise.git/state" - "git.defalsify.org/vise.git/db" - fsdb "git.defalsify.org/vise.git/db/fs" -) - -// NewDefaultEngine is a convenience function to instantiate a filesystem-backed engine with no output constraints. -func NewDefaultEngine(dir string, persistDb db.Db, session *string) (EngineIsh, error) { - st := state.NewState(0) - ctx := context.Background() - store := fsdb.NewFsDb() - err := store.Connect(ctx, dir) - if err != nil { - return nil, err - } - rs := resource.NewDbResource(store) - rs.With(db.DATATYPE_STATICLOAD) - ca := cache.NewCache() - cfg := Config{ - Root: "root", - } - if session != nil { - cfg.SessionId = *session - } else if persistDb != nil { - return nil, fmt.Errorf("session must be set if persist is used") - } - var en EngineIsh - if persistDb != nil { - pr := persist.NewPersister(persistDb) - en, err = NewPersistedEngine(ctx, cfg, pr, rs) - if err != nil { - logg.Infof("persisted engine create error. trying again with persisting empty state first...") - pr = pr.WithContent(&st, ca) - err = pr.Save(cfg.SessionId) - if err != nil { - return nil, err - } - en, err = NewPersistedEngine(ctx, cfg, pr, rs) - } - } else { - enb := NewEngine(ctx, cfg, &st, rs, ca) - en = &enb - } - return en, err -} - -// NewSizedEngine is a convenience function to instantiate a filesystem-backed engine with a specified output constraint. -func NewSizedEngine(dir string, size uint32, persistDb db.Db, session *string) (EngineIsh, error) { - st := state.NewState(0) - ca := cache.NewCache() - ctx := context.Background() - store := fsdb.NewFsDb() - err := store.Connect(ctx, dir) - if err != nil { - return nil, err - } - rs := resource.NewDbResource(store) - rs.With(db.DATATYPE_STATICLOAD) - cfg := Config{ - OutputSize: size, - Root: "root", - } - if session != nil { - cfg.SessionId = *session - } else if persistDb != nil { - return nil, fmt.Errorf("session must be set if persist is used") - } - var en EngineIsh - if persistDb != nil { - pr := persist.NewPersister(persistDb) - en, err = NewPersistedEngine(ctx, cfg, pr, rs) - if err != nil { - logg.Infof("persisted engine create error. trying again with persisting empty state first...") - pr = pr.WithContent(&st, ca) - err = pr.Save(cfg.SessionId) - if err != nil { - return nil, err - } - en, err = NewPersistedEngine(ctx, cfg, pr, rs) - } - } else { - enb := NewEngine(ctx, cfg, &st, rs, ca) - en = &enb - } - return en, err -} diff --git a/engine/engine.go b/engine/engine.go @@ -13,15 +13,15 @@ import ( ) // EngineIsh defines the interface for execution engines that handle vm initialization and execution, and rendering outputs. -type EngineIsh interface { +type Engine interface { Init(ctx context.Context) (bool, error) Exec(ctx context.Context, input []byte) (bool, error) WriteResult(ctx context.Context, w io.Writer) (int, error) Finish() error } -// Engine is an execution engine that handles top-level errors when running client inputs against code in the bytecode buffer. -type Engine struct { +// LegacyEngine is an execution engine that handles top-level errors when running client inputs against code in the bytecode buffer. +type LegacyEngine struct { st *state.State rs resource.Resource ca cache.Memory @@ -34,14 +34,14 @@ type Engine struct { exit string } -// NewEngine creates a new Engine -func NewEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Resource, ca cache.Memory) Engine { +// NewLegacyEngine creates a new LegacyEngine +func NewLegacyEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Resource, ca cache.Memory) LegacyEngine { var szr *render.Sizer if cfg.OutputSize > 0 { szr = render.NewSizer(cfg.OutputSize) } ctx = context.WithValue(ctx, "sessionId", cfg.SessionId) - engine := Engine{ + engine := LegacyEngine{ st: st, rs: rs, ca: ca, @@ -70,23 +70,23 @@ func NewEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Res // SetDebugger sets a debugger to use. // // No debugger is set by default. -func (en *Engine) SetDebugger(debugger Debug) { +func (en *LegacyEngine) SetDebugger(debugger Debug) { en.dbg = debugger } // SetFirst sets a function which will be executed before bytecode -func(en *Engine) SetFirst(fn resource.EntryFunc) { +func(en *LegacyEngine) SetFirst(fn resource.EntryFunc) { en.first = fn } -// Finish implements EngineIsh interface -func(en *Engine) Finish() error { +// Finish implements LegacyEngineIsh interface +func(en *LegacyEngine) Finish() error { logg.Tracef("that's a wrap", "engine", en) return nil } // change root to current state location if non-empty. -func(en *Engine) restore() { +func(en *LegacyEngine) restore() { location, _ := en.st.Where() if len(location) == 0 { return @@ -98,7 +98,7 @@ func(en *Engine) restore() { } // execute the first function, if set -func(en *Engine) runFirst(ctx context.Context) (bool, error) { +func(en *LegacyEngine) runFirst(ctx context.Context) (bool, error) { var err error var r bool if en.first == nil { @@ -136,10 +136,10 @@ func(en *Engine) runFirst(ctx context.Context) (bool, error) { return r, err } -// Init must be explicitly called before using the Engine instance. +// Init must be explicitly called before using the LegacyEngine instance. // // It loads and executes code for the start node. -func(en *Engine) Init(ctx context.Context) (bool, error) { +func(en *LegacyEngine) Init(ctx context.Context) (bool, error) { en.restore() if en.initd { logg.DebugCtxf(ctx, "already initialized") @@ -191,7 +191,7 @@ func(en *Engine) Init(ctx context.Context) (bool, error) { // - input is formally invalid (too long etc) // - no current bytecode is available // - input processing against bytcode failed -func (en *Engine) Exec(ctx context.Context, input []byte) (bool, error) { +func (en *LegacyEngine) Exec(ctx context.Context, input []byte) (bool, error) { var err error if en.st.Language != nil { ctx = context.WithValue(ctx, "Language", *en.st.Language) @@ -215,7 +215,7 @@ func (en *Engine) Exec(ctx context.Context, input []byte) (bool, error) { } // backend for Exec, after the input validity check -func(en *Engine) exec(ctx context.Context, input []byte) (bool, error) { +func(en *LegacyEngine) exec(ctx context.Context, input []byte) (bool, error) { logg.InfoCtxf(ctx, "new VM execution with input", "input", string(input)) code, err := en.st.GetCode() if err != nil { @@ -263,7 +263,7 @@ func(en *Engine) exec(ctx context.Context, input []byte) (bool, error) { // - required data inputs to the template are not available. // - the template for the given node point is note available for retrieval using the resource.Resource implementer. // - the supplied writer fails to process the writes. -func(en *Engine) WriteResult(ctx context.Context, w io.Writer) (int, error) { +func(en *LegacyEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) { var l int if en.st.Language != nil { ctx = context.WithValue(ctx, "Language", *en.st.Language) @@ -291,7 +291,7 @@ func(en *Engine) WriteResult(ctx context.Context, w io.Writer) (int, error) { } // start execution over at top node while keeping current state of client error flags. -func(en *Engine) reset(ctx context.Context) (bool, error) { +func(en *LegacyEngine) reset(ctx context.Context) (bool, error) { var err error var isTop bool for !isTop { diff --git a/engine/engine_test.go b/engine/engine_test.go @@ -125,7 +125,9 @@ func TestEngineInit(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) _, err = en.Init(ctx) if err != nil { @@ -183,7 +185,9 @@ func TestEngineExecInvalidInput(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) var err error _, err = en.Init(ctx) if err != nil { @@ -205,7 +209,9 @@ func TestEngineResumeTerminated(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) var err error _, err = en.Init(ctx) if err != nil { @@ -241,7 +247,9 @@ func TestLanguageSet(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) var err error _, err = en.Init(ctx) @@ -294,7 +302,9 @@ func TestLanguageRender(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) var err error _, err = en.Init(ctx) @@ -335,7 +345,9 @@ func TestConfigLanguageRender(t *testing.T) { Root: "root", Language: "nor", } - en := NewEngine(ctx, cfg, &st, &rs, ca) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) var err error _, err = en.Init(ctx) @@ -391,8 +403,10 @@ func TestPreVm(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, &rs, ca) - en.SetFirst(preBlock) + en := NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) + en = en.WithFirst(preBlock) r, err := en.Init(ctx) if err != nil { t.Fatal(err) @@ -411,8 +425,10 @@ func TestPreVm(t *testing.T) { st = state.NewState(0) ca = cache.NewCache() - en = NewEngine(ctx, cfg, &st, &rs, ca) - en.SetFirst(preAllow) + en = NewEngine(cfg, &rs) + en = en.WithState(&st) + en = en.WithMemory(ca) + en = en.WithFirst(preAllow) r, err = en.Init(ctx) if err != nil { t.Fatal(err) diff --git a/engine/loop.go b/engine/loop.go @@ -17,7 +17,7 @@ import ( // Any error not handled by the engine will terminate the oop and return an error. // // Rendered output is written to the provided writer. -func Loop(ctx context.Context, en EngineIsh, reader io.Reader, writer io.Writer) error { +func Loop(ctx context.Context, en Engine, reader io.Reader, writer io.Writer) error { defer en.Finish() l, err := en.WriteResult(ctx, writer) if err != nil { diff --git a/engine/loop_test.go b/engine/loop_test.go @@ -23,7 +23,10 @@ func TestLoopTop(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, rs, ca) + en := NewEngine(cfg, rs) + en = en.WithState(&st) + en = en.WithMemory(ca) + _, err = en.Init(ctx) if err != nil { t.Fatal(err) @@ -39,7 +42,7 @@ func TestLoopTop(t *testing.T) { outputBuf := bytes.NewBuffer(nil) log.Printf("running with input: %s", inputBuf.Bytes()) - err = Loop(ctx, &en, inputBuf, outputBuf) + err = Loop(ctx, en, inputBuf, outputBuf) if err != nil { t.Fatal(err) } @@ -60,7 +63,10 @@ func TestLoopBackForth(t *testing.T) { cfg := Config{ Root: "root", } - en := NewEngine(ctx, cfg, &st, rs, ca) + en := NewEngine(cfg, rs) + en = en.WithState(&st) + en = en.WithMemory(ca) + _, err = en.Init(ctx) if err != nil { t.Fatal(err) @@ -77,7 +83,7 @@ func TestLoopBackForth(t *testing.T) { outputBuf := bytes.NewBuffer(nil) log.Printf("running with input: %s", inputBuf.Bytes()) - err = Loop(ctx, &en, inputBuf, outputBuf) + err = Loop(ctx, en, inputBuf, outputBuf) if err != nil { t.Fatal(err) } @@ -95,7 +101,10 @@ func TestLoopBrowse(t *testing.T) { OutputSize: 68, Root: "root", } - en := NewEngine(ctx, cfg, &st, rs, ca) + en := NewEngine(cfg, rs) + en = en.WithState(&st) + en = en.WithMemory(ca) + _, err = en.Init(ctx) if err != nil { t.Fatal(err) @@ -113,7 +122,7 @@ func TestLoopBrowse(t *testing.T) { outputBuf := bytes.NewBuffer(nil) log.Printf("running with input: %s", inputBuf.Bytes()) - err = Loop(ctx, &en, inputBuf, outputBuf) + err = Loop(ctx, en, inputBuf, outputBuf) if err != nil { t.Fatal(err) } diff --git a/engine/persist.go b/engine/persist.go @@ -1,93 +0,0 @@ -package engine - -import ( - "context" - "io" - - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" -) - -// PersistedEngine adds persisted state to the Engine object. It provides a persisted state option for synchronous/interactive clients. -type PersistedEngine struct { - *Engine - pr *persist.Persister -} - - -// NewPersistedEngine creates a new PersistedEngine -func NewPersistedEngine(ctx context.Context, cfg Config, pr *persist.Persister, rs resource.Resource) (PersistedEngine, error) { - err := pr.Load(cfg.SessionId) - if err != nil { - return PersistedEngine{}, err - } - st := pr.GetState() - ca := pr.GetMemory() - - enb := NewEngine(ctx, cfg, st, rs, ca) - en := PersistedEngine{ - &enb, - pr, - } - return en, err -} - -// Exec executes the parent method Engine.Exec, and afterwards persists the new state. -func(pe PersistedEngine) Exec(ctx context.Context, input []byte) (bool, error) { - v, err := pe.Engine.Exec(ctx, input) - if err != nil { - return v, err - } - err = pe.pr.Save(pe.Engine.session) - return v, err -} - -// Finish implements EngineIsh interface -func(pe PersistedEngine) Finish() error { - logg.Tracef("that's a wrap", "engine", pe) - return pe.pr.Save(pe.Engine.session) -} - -// RunPersisted performs a single vm execution from client input using a persisted state. -// -// State is first loaded from storage. The vm is initialized with the state and executed. The new state is then saved to storage. -// -// The resulting output of the execution will be written to the provided writer. -// -// The state is identified by the SessionId member of the Config. Before first execution, the caller must ensure that an -// initialized state actually is available for the identifier, otherwise the method will fail. -// -// It will also fail if execution by the underlying Engine fails. -func RunPersisted(cfg Config, rs resource.Resource, pr *persist.Persister, input []byte, w io.Writer, ctx context.Context) error { - err := pr.Load(cfg.SessionId) - if err != nil { - return err - } - - st := pr.GetState() - ca := pr.GetMemory() - en := NewEngine(ctx, cfg, st, rs, ca) - - c, err := en.WriteResult(ctx, w) - if err != nil { - return err - } - err = pr.Save(cfg.SessionId) - if err != nil { - return err - } - if c > 0 { - return err - } - - _, err = en.Exec(ctx, input) - if err != nil { - return err - } - _, err = en.WriteResult(ctx, w) - if err != nil { - return err - } - en.Finish() - return pr.Save(cfg.SessionId) -} diff --git a/engine/persist_test.go b/engine/persist_test.go @@ -1,146 +0,0 @@ -package engine - -import ( - "context" - "os" - "testing" - - "git.defalsify.org/vise.git/cache" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/state" - memdb "git.defalsify.org/vise.git/db/mem" -) - -func TestRunPersist(t *testing.T) { - generateTestData(t) - ctx := context.Background() - cfg := Config{ - OutputSize: 83, - SessionId: "xyzzy", - Root: "root", - } - rs := newTestWrapper(dataDir, nil) - - st := state.NewState(3) - ca := cache.NewCache().WithCacheSize(1024) - store := memdb.NewMemDb() - store.Connect(ctx, "") - pr := persist.NewPersister(store).WithContent(&st, ca) - - w := os.Stdout - ctx = context.Background() - - st = state.NewState(cfg.FlagCount) - ca = cache.NewCache() - ca = ca.WithCacheSize(cfg.CacheSize) - pr = persist.NewPersister(store).WithContent(&st, ca) - err := pr.Save(cfg.SessionId) - if err != nil { - t.Fatal(err) - } - - pr = persist.NewPersister(store) - inputs := []string{ - "", // trigger init, will not exec - "1", - "2", - "00", - } - for _, v := range inputs { - err = RunPersisted(cfg, rs, pr, []byte(v), w, ctx) - if err != nil { - t.Fatal(err) - } - } - - pr = persist.NewPersister(store) - err = pr.Load(cfg.SessionId) - if err != nil { - t.Fatal(err) - } - - stAfter := pr.GetState() - location, idx := stAfter.Where() - if location != "long" { - t.Fatalf("expected 'long', got %s", location) - } - if idx != 1 { - t.Fatalf("expected '1', got %v", idx) - } -} - -func TestEnginePersist(t *testing.T) { - generateTestData(t) - ctx := context.Background() - cfg := Config{ - OutputSize: 83, - SessionId: "xyzzy", - Root: "root", - } - rs := newTestWrapper(dataDir, nil) - - st := state.NewState(3) - ca := cache.NewCache().WithCacheSize(1024) - store := memdb.NewMemDb() - store.Connect(ctx, "") - pr := persist.NewPersister(store).WithContent(&st, ca) - - st = state.NewState(cfg.FlagCount) - ca = cache.NewCache() - ca = ca.WithCacheSize(cfg.CacheSize) - pr = persist.NewPersister(store).WithContent(&st, ca) - err := pr.Save(cfg.SessionId) - if err != nil { - t.Fatal(err) - } - - en, err := NewPersistedEngine(ctx, cfg, pr, rs) - if err != nil { - t.Fatal(err) - } - - _, err = en.Init(ctx) - if err != nil { - t.Fatal(err) - } - - _, err = en.Exec(ctx, []byte("1")) - if err != nil { - t.Fatal(err) - } - - _, err = en.Exec(ctx, []byte("2")) - if err != nil { - t.Fatal(err) - } - _, err = en.Exec(ctx, []byte("00")) - if err != nil { - t.Fatal(err) - } - location, idx := st.Where() - if location != "long" { - t.Fatalf("expected location 'long', got %s", location) - } - if idx != 1 { - t.Fatalf("expected index '1', got %v", idx) - } - - pr = persist.NewPersister(store) - en, err = NewPersistedEngine(ctx, cfg, pr, rs) - if err != nil { - t.Fatal(err) - } - st_loaded := pr.GetState() - location, _ = st_loaded.Where() - if location != "long" { - t.Fatalf("expected location 'long', got %s", location) - } - if idx != 1 { - t.Fatalf("expected index '1', got %v", idx) - } - - _, err = en.Exec(ctx, []byte("11")) - if err != nil { - t.Fatal(err) - } -}