
update messages-go to v16.0.1 bump gomod version comment on log line in std os.Stderr examples to non rc version go mod tidy update circle (tbd)
323 строки
9,3 КиБ
Go
323 строки
9,3 КиБ
Go
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/cucumber/messages-go/v16"
|
|
"github.com/hashicorp/go-memdb"
|
|
|
|
"github.com/cucumber/godog/internal/models"
|
|
)
|
|
|
|
const (
|
|
writeMode bool = true
|
|
readMode bool = false
|
|
|
|
tableFeature string = "feature"
|
|
tableFeatureIndexURI string = "id"
|
|
|
|
tablePickle string = "pickle"
|
|
tablePickleIndexID string = "id"
|
|
tablePickleIndexURI string = "uri"
|
|
|
|
tablePickleStep string = "pickle_step"
|
|
tablePickleStepIndexID string = "id"
|
|
|
|
tablePickleResult string = "pickle_result"
|
|
tablePickleResultIndexPickleID string = "id"
|
|
|
|
tablePickleStepResult string = "pickle_step_result"
|
|
tablePickleStepResultIndexPickleStepID string = "id"
|
|
tablePickleStepResultIndexPickleID string = "pickle_id"
|
|
tablePickleStepResultIndexStatus string = "status"
|
|
|
|
tableStepDefintionMatch string = "step_defintion_match"
|
|
tableStepDefintionMatchIndexStepID string = "id"
|
|
)
|
|
|
|
// Storage is a thread safe in-mem storage
|
|
type Storage struct {
|
|
db *memdb.MemDB
|
|
|
|
testRunStarted models.TestRunStarted
|
|
testRunStartedLock *sync.Mutex
|
|
}
|
|
|
|
// NewStorage will create an in-mem storage that
|
|
// is used across concurrent runners and formatters
|
|
func NewStorage() *Storage {
|
|
schema := memdb.DBSchema{
|
|
Tables: map[string]*memdb.TableSchema{
|
|
tableFeature: {
|
|
Name: tableFeature,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tableFeatureIndexURI: {
|
|
Name: tableFeatureIndexURI,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "Uri"},
|
|
},
|
|
},
|
|
},
|
|
tablePickle: {
|
|
Name: tablePickle,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tablePickleIndexID: {
|
|
Name: tablePickleIndexID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "Id"},
|
|
},
|
|
tablePickleIndexURI: {
|
|
Name: tablePickleIndexURI,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{Field: "Uri"},
|
|
},
|
|
},
|
|
},
|
|
tablePickleStep: {
|
|
Name: tablePickleStep,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tablePickleStepIndexID: {
|
|
Name: tablePickleStepIndexID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "Id"},
|
|
},
|
|
},
|
|
},
|
|
tablePickleResult: {
|
|
Name: tablePickleResult,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tablePickleResultIndexPickleID: {
|
|
Name: tablePickleResultIndexPickleID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "PickleID"},
|
|
},
|
|
},
|
|
},
|
|
tablePickleStepResult: {
|
|
Name: tablePickleStepResult,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tablePickleStepResultIndexPickleStepID: {
|
|
Name: tablePickleStepResultIndexPickleStepID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "PickleStepID"},
|
|
},
|
|
tablePickleStepResultIndexPickleID: {
|
|
Name: tablePickleStepResultIndexPickleID,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{Field: "PickleID"},
|
|
},
|
|
tablePickleStepResultIndexStatus: {
|
|
Name: tablePickleStepResultIndexStatus,
|
|
Unique: false,
|
|
Indexer: &memdb.IntFieldIndex{Field: "Status"},
|
|
},
|
|
},
|
|
},
|
|
tableStepDefintionMatch: {
|
|
Name: tableStepDefintionMatch,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
tableStepDefintionMatchIndexStepID: {
|
|
Name: tableStepDefintionMatchIndexStepID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{Field: "StepID"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
db, err := memdb.NewMemDB(&schema)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &Storage{db: db, testRunStartedLock: new(sync.Mutex)}
|
|
}
|
|
|
|
// MustInsertPickle will insert a pickle and it's steps,
|
|
// will panic on error.
|
|
func (s *Storage) MustInsertPickle(p *messages.Pickle) {
|
|
txn := s.db.Txn(writeMode)
|
|
|
|
if err := txn.Insert(tablePickle, p); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for _, step := range p.Steps {
|
|
if err := txn.Insert(tablePickleStep, step); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
txn.Commit()
|
|
}
|
|
|
|
// MustGetPickle will retrieve a pickle by id and panic on error.
|
|
func (s *Storage) MustGetPickle(id string) *messages.Pickle {
|
|
v := s.mustFirst(tablePickle, tablePickleIndexID, id)
|
|
return v.(*messages.Pickle)
|
|
}
|
|
|
|
// MustGetPickles will retrieve pickles by URI and panic on error.
|
|
func (s *Storage) MustGetPickles(uri string) (ps []*messages.Pickle) {
|
|
it := s.mustGet(tablePickle, tablePickleIndexURI, uri)
|
|
for v := it.Next(); v != nil; v = it.Next() {
|
|
ps = append(ps, v.(*messages.Pickle))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// MustGetPickleStep will retrieve a pickle step and panic on error.
|
|
func (s *Storage) MustGetPickleStep(id string) *messages.PickleStep {
|
|
v := s.mustFirst(tablePickleStep, tablePickleStepIndexID, id)
|
|
return v.(*messages.PickleStep)
|
|
}
|
|
|
|
// MustInsertTestRunStarted will set the test run started event and panic on error.
|
|
func (s *Storage) MustInsertTestRunStarted(trs models.TestRunStarted) {
|
|
s.testRunStartedLock.Lock()
|
|
defer s.testRunStartedLock.Unlock()
|
|
|
|
s.testRunStarted = trs
|
|
}
|
|
|
|
// MustGetTestRunStarted will retrieve the test run started event and panic on error.
|
|
func (s *Storage) MustGetTestRunStarted() models.TestRunStarted {
|
|
s.testRunStartedLock.Lock()
|
|
defer s.testRunStartedLock.Unlock()
|
|
|
|
return s.testRunStarted
|
|
}
|
|
|
|
// MustInsertPickleResult will instert a pickle result and panic on error.
|
|
func (s *Storage) MustInsertPickleResult(pr models.PickleResult) {
|
|
s.mustInsert(tablePickleResult, pr)
|
|
}
|
|
|
|
// MustInsertPickleStepResult will insert a pickle step result and panic on error.
|
|
func (s *Storage) MustInsertPickleStepResult(psr models.PickleStepResult) {
|
|
s.mustInsert(tablePickleStepResult, psr)
|
|
}
|
|
|
|
// MustGetPickleResult will retrieve a pickle result by id and panic on error.
|
|
func (s *Storage) MustGetPickleResult(id string) models.PickleResult {
|
|
v := s.mustFirst(tablePickleResult, tablePickleResultIndexPickleID, id)
|
|
return v.(models.PickleResult)
|
|
}
|
|
|
|
// MustGetPickleResults will retrieve all pickle results and panic on error.
|
|
func (s *Storage) MustGetPickleResults() (prs []models.PickleResult) {
|
|
it := s.mustGet(tablePickleResult, tablePickleResultIndexPickleID)
|
|
for v := it.Next(); v != nil; v = it.Next() {
|
|
prs = append(prs, v.(models.PickleResult))
|
|
}
|
|
|
|
return prs
|
|
}
|
|
|
|
// MustGetPickleStepResult will retrieve a pickle strep result by id and panic on error.
|
|
func (s *Storage) MustGetPickleStepResult(id string) models.PickleStepResult {
|
|
v := s.mustFirst(tablePickleStepResult, tablePickleStepResultIndexPickleStepID, id)
|
|
return v.(models.PickleStepResult)
|
|
}
|
|
|
|
// MustGetPickleStepResultsByPickleID will retrieve pickle strep results by pickle id and panic on error.
|
|
func (s *Storage) MustGetPickleStepResultsByPickleID(pickleID string) (psrs []models.PickleStepResult) {
|
|
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexPickleID, pickleID)
|
|
for v := it.Next(); v != nil; v = it.Next() {
|
|
psrs = append(psrs, v.(models.PickleStepResult))
|
|
}
|
|
|
|
return psrs
|
|
}
|
|
|
|
// MustGetPickleStepResultsByStatus will retrieve pickle strep results by status and panic on error.
|
|
func (s *Storage) MustGetPickleStepResultsByStatus(status models.StepResultStatus) (psrs []models.PickleStepResult) {
|
|
it := s.mustGet(tablePickleStepResult, tablePickleStepResultIndexStatus, status)
|
|
for v := it.Next(); v != nil; v = it.Next() {
|
|
psrs = append(psrs, v.(models.PickleStepResult))
|
|
}
|
|
|
|
return psrs
|
|
}
|
|
|
|
// MustInsertFeature will insert a feature and panic on error.
|
|
func (s *Storage) MustInsertFeature(f *models.Feature) {
|
|
s.mustInsert(tableFeature, f)
|
|
}
|
|
|
|
// MustGetFeature will retrieve a feature by URI and panic on error.
|
|
func (s *Storage) MustGetFeature(uri string) *models.Feature {
|
|
v := s.mustFirst(tableFeature, tableFeatureIndexURI, uri)
|
|
return v.(*models.Feature)
|
|
}
|
|
|
|
// MustGetFeatures will retrieve all features by and panic on error.
|
|
func (s *Storage) MustGetFeatures() (fs []*models.Feature) {
|
|
it := s.mustGet(tableFeature, tableFeatureIndexURI)
|
|
for v := it.Next(); v != nil; v = it.Next() {
|
|
fs = append(fs, v.(*models.Feature))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
type stepDefinitionMatch struct {
|
|
StepID string
|
|
StepDefinition *models.StepDefinition
|
|
}
|
|
|
|
// MustInsertStepDefintionMatch will insert the matched StepDefintion for the step ID and panic on error.
|
|
func (s *Storage) MustInsertStepDefintionMatch(stepID string, match *models.StepDefinition) {
|
|
d := stepDefinitionMatch{
|
|
StepID: stepID,
|
|
StepDefinition: match,
|
|
}
|
|
|
|
s.mustInsert(tableStepDefintionMatch, d)
|
|
}
|
|
|
|
// MustGetStepDefintionMatch will retrieve the matched StepDefintion for the step ID and panic on error.
|
|
func (s *Storage) MustGetStepDefintionMatch(stepID string) *models.StepDefinition {
|
|
v := s.mustFirst(tableStepDefintionMatch, tableStepDefintionMatchIndexStepID, stepID)
|
|
return v.(stepDefinitionMatch).StepDefinition
|
|
}
|
|
|
|
func (s *Storage) mustInsert(table string, obj interface{}) {
|
|
txn := s.db.Txn(writeMode)
|
|
|
|
if err := txn.Insert(table, obj); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
txn.Commit()
|
|
}
|
|
|
|
func (s *Storage) mustFirst(table, index string, args ...interface{}) interface{} {
|
|
txn := s.db.Txn(readMode)
|
|
defer txn.Abort()
|
|
|
|
v, err := txn.First(table, index, args...)
|
|
if err != nil {
|
|
panic(err)
|
|
} else if v == nil {
|
|
err = fmt.Errorf("Couldn't find index: %q in table: %q with args: %+v", index, table, args)
|
|
panic(err)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func (s *Storage) mustGet(table, index string, args ...interface{}) memdb.ResultIterator {
|
|
txn := s.db.Txn(readMode)
|
|
defer txn.Abort()
|
|
|
|
it, err := txn.Get(table, index, args...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return it
|
|
}
|