// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package state import ( "fmt" "github.com/hashicorp/go-memdb" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "testing" "time" ) func testValidSchema() *memdb.DBSchema { return &memdb.DBSchema{ Tables: map[string]*memdb.TableSchema{ "main": { Name: "main", Indexes: map[string]*memdb.IndexSchema{ "id": { Name: "id", Unique: true, Indexer: &memdb.StringFieldIndex{Field: "ID"}, }, "foo": { Name: "foo", Indexer: &memdb.StringFieldIndex{Field: "Foo"}, }, }, }, }, } } type TestObject struct { ID string Foo string } // This test verify that the new data in a TXN is commited at the time that publishFunc is called. // To do so, the publish func is mocked, a read on ch1 means that publish is called and blocked, // ch2 permit to control the publish func and unblock it when receiving a signal. func Test_txn_Commit(t *testing.T) { db, err := memdb.NewMemDB(testValidSchema()) require.NoError(t, err) publishFunc := mockPublishFuncType{} tx := txn{ Txn: db.Txn(true), Index: 0, publish: publishFunc.Execute, } ch1 := make(chan struct{}) ch2 := make(chan struct{}) getCh := make(chan memdb.ResultIterator) group := errgroup.Group{} group.Go(func() error { after := time.After(2 * time.Second) select { case <-ch1: tx2 := txn{ Txn: db.Txn(false), Index: 0, publish: publishFunc.Execute, } get, err := tx2.Get("main", "id") if err != nil { return err } close(ch2) getCh <- get case <-after: close(ch2) return fmt.Errorf("test timed out") } return nil }) publishFunc.On("Execute", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(ch1) <-ch2 }).Return(nil) err = tx.Insert("main", TestObject{ID: "1", Foo: "foo"}) require.NoError(t, err) err = tx.Commit() require.NoError(t, err) get := <-getCh require.NotNil(t, get) next := get.Next() require.NotNil(t, next) val := next.(TestObject) require.Equal(t, val.ID, "1") require.Equal(t, val.Foo, "foo") err = group.Wait() require.NoError(t, err) }