I am currently writing an application that is writing to a QLDB ledger. I have a function like:
// Use an interface that matches the QLDB Driver so we can inject / mock
type ILedgerDriver interface {
Execute(ctx context.Context, fn func(txn qldbdriver.Transaction) (interface{}, error)) (interface{}, error)
Shutdown(ctx context.Context)
}
// Create checks for a records existence before inserting on to the ledger.
func Create(driver ILedgerDriver, document interface{}) (interface{}, error) {
return ls.Driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
result, err := txn.Execute("SELECT * FROM People WHERE ID = ?", id)
if err != nil {
return nil, errors.Wrap(err, "error selecting document")
}
// Check if there are any results
if result.Next(txn) {
// document exists
return nil, nil
}
result, err = txn.Execute("INSERT INTO People ?", document)
if err != nil {
return nil, errors.Wrap(err, "error inserting document")
}
return result, nil
})
}
Then I try to mock with something like this:
// implements qldbdriver.Transaction.
type mockQldbTx struct{}
func (mockQldbTx) Execute(statement string, parameters ...interface{}) (*qldbdriver.Result, error) {
for _, p := range parameters {
if ps, _ := p.(string); ps == "ERROR" {
return nil, errors.New("execute failed")
}
if ps, _ := p.(string); ps == "WILLFINDME" {
emptyResult := &qldbdriver.Result{}
return emptyResult, nil
}
}
return nil, nil
}
func (mockQldbTx) BufferResult(result *qldbdriver.Result) (*qldbdriver.BufferedResult, error) {
return nil, nil
}
func (mockQldbTx) Abort() error {
return nil
}
// implements ILedgerDriver
type mockDriver struct{}
func (mockDriver) Execute(ctx context.Context, fn func(txn qldbdriver.Transaction) (interface{}, error)) (interface{}, error) {
mockTx1 := mockQldbTx{}
result, err := fn(mockTx1)
return result, err
}
func (mockDriver) Shutdown(ctx context.Context) {
}
Which, largely works. However, since qldbdriver.Result
is not an interface, it seems I can't mock the transaction to test the case when a result would have index
and pageValues
properties (which would trigger the if result.Next(txn)
block).
Anyone had any experience with this or can point to any guides? Or am I really just being a bit over-cautious and I shouldn't really need to test that my create function works? (and any other larger business logic beyond this would be in another function which could be tested in isolation?)
In the latest commit to the QLDB Driver the QLDB team introduced the
Result
interface to solve the problem you are experiencing. See this commit which resolve this issue.Copying from the guidance in that issue: the below is a simplified code snippet that shows testing of a function passed through to
Execute
.Transaction
andResult
are now interfaces, thatmockTransaction
andmockResult
implement in our test scenario.This isn't released yet, so if you are able to build against the latest code, great, otherwise we (I work for QLDB) can organize an official release.