Ref/store ectd (#45)

Improved unit & integration tests for store, by making them independent and test a single thing.
This commit is contained in:
datosh 2022-04-12 09:38:10 +02:00 committed by GitHub
parent dfee5910b3
commit 4abb483902
6 changed files with 484 additions and 329 deletions

View File

@ -147,7 +147,7 @@ type EtcdTransaction struct {
func (t *EtcdTransaction) Get(request string) ([]byte, error) {
if !t.ongoingTransaction {
return nil, fmt.Errorf("EtcdTransaction Pointer is nil, but Get function is called")
return nil, &TransactionAlreadyCommittedError{op: "Get"}
}
if value, ok := t.dataInsert[request]; ok {
return value, nil
@ -161,7 +161,7 @@ func (t *EtcdTransaction) Get(request string) ([]byte, error) {
// Put saves a value.
func (t *EtcdTransaction) Put(request string, requestData []byte) error {
if !t.ongoingTransaction {
return fmt.Errorf("EtcdTransaction Pointer is nil, but Put function is called")
return &TransactionAlreadyCommittedError{op: "Put"}
}
t.dataInsert[request] = requestData
return nil
@ -170,7 +170,7 @@ func (t *EtcdTransaction) Put(request string, requestData []byte) error {
// Delete deletes the key if it exists. Only errors if there is no ongoing Transaction.
func (t *EtcdTransaction) Delete(key string) error {
if !t.ongoingTransaction {
return fmt.Errorf("EtcdTransaction Pointer is nil, but Delete function is called")
return &TransactionAlreadyCommittedError{op: "Delete"}
}
delete(t.dataInsert, key)
t.dataDelete[key] = struct{}{}

View File

@ -16,7 +16,7 @@ import (
)
const (
etcdImageName = "bitnami/etcd:3.5.1"
etcdImageName = "bitnami/etcd:3.5.2"
)
func TestEtcdStore(t *testing.T) {
@ -72,9 +72,21 @@ func TestEtcdStore(t *testing.T) {
// TODO: since the etcd store does network, it should be canceled with a timeout.
testStore(t, func() (Store, error) {
clearStore(require, store)
return store, nil
})
// Usually call it with a defer statement. However this causes problems with the construct above
require.NoError(dockerClient.ContainerStop(ctx, createResp.ID, nil))
}
func clearStore(require *require.Assertions, store Store) {
iter, err := store.Iterator("")
require.NoError(err)
for iter.HasNext() {
key, err := iter.GetNext()
require.NoError(err)
err = store.Delete(key)
require.NoError(err)
}
}

View File

@ -74,7 +74,11 @@ func (s *StdStore) Iterator(prefix string) (Iterator, error) {
// BeginTransaction starts a new transaction.
func (s *StdStore) BeginTransaction() (Transaction, error) {
tx := stdTransaction{store: s, data: map[string]string{}}
tx := stdTransaction{
store: s,
data: map[string]string{},
ongoingTransaction: true,
}
s.txmut.Lock()
s.mut.Lock()
@ -111,10 +115,14 @@ func (s *StdStore) Transfer(newstore Store) error {
type stdTransaction struct {
store *StdStore
data map[string]string
ongoingTransaction bool
}
// Get retrieves a value.
func (t *stdTransaction) Get(request string) ([]byte, error) {
if !t.ongoingTransaction {
return nil, &TransactionAlreadyCommittedError{op: "Get"}
}
if value, ok := t.data[request]; ok {
return []byte(value), nil
}
@ -123,11 +131,17 @@ func (t *stdTransaction) Get(request string) ([]byte, error) {
// Put saves a value.
func (t *stdTransaction) Put(request string, requestData []byte) error {
if !t.ongoingTransaction {
return &TransactionAlreadyCommittedError{op: "Put"}
}
t.data[request] = string(requestData)
return nil
}
func (t *stdTransaction) Delete(key string) error {
if !t.ongoingTransaction {
return &TransactionAlreadyCommittedError{op: "Delete"}
}
delete(t.data, key)
return nil
}
@ -150,6 +164,7 @@ func (t *stdTransaction) Commit() error {
return err
}
t.store = nil
t.ongoingTransaction = false
return nil
}

View File

@ -6,18 +6,18 @@ import (
// Store is the interface for persistence.
type Store interface {
// BeginTransaction starts a new transaction.
BeginTransaction() (Transaction, error)
// Get returns a value from store by key.
Get(string) ([]byte, error)
// Put saves a value to store by key.
Put(string, []byte) error
// Iterator returns an Iterator for a given prefix.
Iterator(string) (Iterator, error)
// Transfer copies the whole store Database.
Transfer(Store) error
// Delete deletes the key.
Delete(string) error
// Iterator returns an Iterator for a given prefix.
Iterator(string) (Iterator, error)
// BeginTransaction starts a new transaction.
BeginTransaction() (Transaction, error)
// Transfer copies the whole store Database.
Transfer(Store) error
}
// Transaction is a Store transaction.
@ -64,3 +64,13 @@ type NoElementsLeftError struct {
func (n *NoElementsLeftError) Error() string {
return fmt.Sprintf("index out of range [%d]", n.idx)
}
// TransactionAlreadyCommittedError occurs when further operations:
// Get, Put, Delete or Iterate are called on a committed transaction.
type TransactionAlreadyCommittedError struct {
op string
}
func (t *TransactionAlreadyCommittedError) Error() string {
return fmt.Sprintf("transaction is already committed, but %s is called", t.op)
}

View File

@ -17,170 +17,446 @@ var newStore func() (Store, error)
func testStore(t *testing.T, storeFactory func() (Store, error)) {
newStore = storeFactory
t.Run("basic", testBasic)
t.Run("iterator", testIterator)
t.Run("rollback", testRollback)
t.Run("testConcurrency", testConcurrency)
t.Run("testTransaction", testTransaction)
t.Run("testTransactionGet", testTransactionGet)
t.Run("testTransactionDelete_1", testTransactionDelete1)
t.Run("testTransactionDelete_2", testTransactionDelete2)
t.Run("testIteratorKey", testIteratorKey)
t.Run("testTransactionIterator", testTransactionIterator)
t.Run("testTransactionDeleteIterator", testTransactionDeleteIterator)
t.Run("testEmptyIterator", testEmptyIterator)
t.Run("testIteratorRace", testIteratorRace)
t.Run("testTransactionIteratorPutPrefix", testTransactionIteratorPutPrefix)
t.Run("testStoreByValue", testStoreByValue)
t.Run("NewStore", testNewStore)
t.Run("NewStoreIsEmpty", testNewStoreIsEmpty)
t.Run("NewStoreClearsStore", testNewStoreClearsStore)
t.Run("Put", testPut)
t.Run("PutTwice", testPutTwice)
t.Run("Get", testGet)
t.Run("GetNonExisting", testGetNonExisting)
t.Run("Delete", testDelete)
t.Run("DeleteNonExisting", testDeleteNonExisting)
t.Run("Iterator", testIterator)
t.Run("IteratorSingleKey", testIteratorSingleKey)
t.Run("IteratorNoValues", testIteratorNoValues)
t.Run("IteratorRace", testIteratorRace)
t.Run("Transaction", testTransaction)
t.Run("TransactionInternalChangesVisible", testTransactionInternalChangesVisible)
t.Run("TransactionInternalChangesNotVisibleOutside", testTransactionInternalChangesNotVisibleOutside)
t.Run("TransactionNoop", testTransactionNoop)
t.Run("TransactionDeleteThenPut", testTransactionDeleteThenPut)
t.Run("TransactionDelete", testTransactionDelete)
t.Run("TransactionIterator", testTransactionIterator)
t.Run("TransactionIterateNotSeeDeleted", testTransactionIterateNotSeeDeleted)
t.Run("TransactionGetAfterCommit", testTransactionGetAfterCommit)
t.Run("TransactionPutAfterCommit", testTransactionPutAfterCommit)
t.Run("TransactionDeleteAfterCommit", testTransactionDeleteAfterCommit)
t.Run("RollbackPut", testRollbackPut)
t.Run("RollbackDelete", testRollbackDelete)
t.Run("Concurrency", testConcurrency)
t.Run("StoreByValue", testStoreByValue)
t.Run("IndependentTest", testIndependentTest)
t.Run("IndependentTestReader", testIndependentTestReader)
}
func testBasic(t *testing.T) {
assert := assert.New(t)
func testNewStore(t *testing.T) {
require := require.New(t)
_, err := newStore()
require.NoError(err)
}
func testNewStoreIsEmpty(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
testData1 := []byte("test data")
testData2 := []byte("more test data")
// request unset value
_, err = store.Get("test:input")
assert.Error(err)
// test Put method
tx, err := store.BeginTransaction()
iter, err := store.Iterator("")
require.NoError(err)
assert.NoError(tx.Put("test:input", testData1))
assert.NoError(tx.Put("another:input", testData2))
assert.NoError(tx.Commit())
require.False(iter.HasNext())
}
// make sure values have been set
val, err := store.Get("test:input")
func testNewStoreClearsStore(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
assert.Equal(testData1, val)
val, err = store.Get("another:input")
require.NoError(store.Put("key", []byte("value")))
store, err = newStore()
require.NoError(err)
assert.Equal(testData2, val)
_, err = store.Get("invalid:key")
assert.Error(err)
var unsetErr *ValueUnsetError
assert.ErrorAs(err, &unsetErr)
assert.NoError(store.Delete("test:input"))
assert.NoError(store.Delete("another:input"))
iter, err := store.Iterator("")
require.NoError(err)
require.False(iter.HasNext())
}
_, err = store.Get("test:input")
assert.Error(err)
func testPut(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Put("key", []byte("value"))
require.NoError(err)
}
func testPutTwice(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Put("key", []byte("value"))
require.NoError(err)
err = store.Put("key", []byte("newValue"))
require.NoError(err)
fetchedValue, err := store.Get("key")
require.NoError(err)
require.Equal([]byte("newValue"), fetchedValue)
}
func testGet(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Put("key", []byte("value"))
require.NoError(err)
fetchedValue, err := store.Get("key")
require.NoError(err)
require.Equal([]byte("value"), fetchedValue)
}
func testGetNonExisting(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
_, err = store.Get("key")
var unsetError *ValueUnsetError
require.ErrorAs(err, &unsetError)
}
func testDelete(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Put("key", []byte("value"))
require.NoError(err)
err = store.Delete("key")
require.NoError(err)
_, err = store.Get("key")
var unsetError *ValueUnsetError
require.ErrorAs(err, &unsetError)
}
// Deleting a non-existing key is fine, and should not result in error.
func testDeleteNonExisting(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Delete("key")
require.NoError(err)
}
func testIterator(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
assert := assert.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("iterate:1", []byte("one")))
require.NoError(store.Put("iterate:2", []byte("two")))
require.NoError(store.Put("iterate:3", []byte("three")))
require.NoError(store.Put("test:1", []byte{0x00, 0x11}))
require.NoError(store.Put("test:2", []byte{0x00, 0x11}))
require.NoError(store.Put("test:3", []byte{0x00, 0x11}))
require.NoError(store.Put("value:1", []byte{0x00, 0x11}))
require.NoError(store.Put("something:1", []byte{0x00}))
iter, err := store.Iterator("test")
iter, err := store.Iterator("iterate")
require.NoError(err)
idx := 0
for iter.HasNext() {
idx++
val, err := iter.GetNext()
assert.NoError(err)
assert.Contains(val, "test:")
assert.Contains(val, "iterate:")
}
assert.EqualValues(3, idx)
iter, err = store.Iterator("value")
require.NoError(err)
idx = 0
for iter.HasNext() {
idx++
val, err := iter.GetNext()
assert.NoError(err)
assert.Contains(val, "value:")
assert.Equal(3, idx)
}
assert.EqualValues(1, idx)
iter, err = store.Iterator("")
func testIteratorSingleKey(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
idx = 0
for iter.HasNext() {
idx++
_, err = iter.GetNext()
assert.NoError(err)
require.NoError(store.Put("key", []byte("value")))
iter, err := store.Iterator("key")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("key", key)
require.False(iter.HasNext())
}
assert.EqualValues(5, idx)
iter, err = store.Iterator("empty")
func testIteratorNoValues(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
assert.False(iter.HasNext())
iter, err := store.Iterator("iterate")
require.NoError(err)
require.False(iter.HasNext())
_, err = iter.GetNext()
var noElementsLeftError *NoElementsLeftError
require.ErrorAs(err, &noElementsLeftError)
}
// Test the race condition in the stdStore.
// This must be specified in the test through [-race].
func testIteratorRace(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put("key", []byte("value")))
go func() {
_, err = store.Iterator("key")
require.NoError(err)
}()
require.NoError(tx.Commit())
}
func testTransaction(t *testing.T) {
require := require.New(t)
assert := assert.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("toBeDeleted", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx1.Put("newKey", []byte{0x11, 0x11}))
require.NoError(tx1.Delete("toBeDeleted"))
require.NoError(tx1.Commit())
result, err := store.Get("newKey")
require.NoError(err)
assert.Equal(result, []byte{0x11, 0x11})
_, err = store.Get("toBeDeleted")
require.Error(err)
}
func testTransactionInternalChangesVisible(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put(("key"), []byte("value")))
fetchedValue, err := tx.Get("key")
require.NoError(err)
require.Equal([]byte("value"), fetchedValue)
}
func testTransactionInternalChangesNotVisibleOutside(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put(("key"), []byte("value")))
_, err = store.Get("key")
var valueUnsetError *ValueUnsetError
require.ErrorAs(err, &valueUnsetError)
}
func testTransactionNoop(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NotNil(tx)
err = tx.Commit()
require.NoError(err)
}
func testTransactionDeleteThenPut(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("key", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx1.Put("key", []byte{0x00, 0x11}))
assert.NoError(tx1.Delete("key"))
require.NoError(tx1.Put("key", []byte{0x7, 0x8}))
assert.NoError(tx1.Commit())
result, err := store.Get("key")
assert.NoError(err)
assert.Equal([]byte{0x7, 0x8}, result)
}
func testTransactionDelete(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("key", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
assert.NoError(tx1.Delete("key"))
_, err = tx1.Get("key")
assert.Error(err)
require.NoError(store.Delete("test:2"))
require.NoError(store.Delete("test:1"))
require.NoError(store.Delete("test:3"))
require.NoError(store.Delete("value:1"))
require.NoError(store.Delete("something:1"))
assert.NoError(tx1.Commit())
}
func testRollback(t *testing.T) {
func testTransactionIterator(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("key", []byte("value")))
tx, err := store.BeginTransaction()
require.NoError(err)
iter, err := tx.Iterator("key")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("key", key)
require.NoError(tx.Commit())
require.False(iter.HasNext())
}
func testTransactionIterateNotSeeDeleted(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("key:1", []byte("value")))
require.NoError(store.Put("key:2", []byte("otherValue")))
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Delete("key:1"))
iter, err := tx.Iterator("key")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("key:2", key)
require.NoError(tx.Commit())
require.False(iter.HasNext())
}
func testTransactionGetAfterCommit(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put("key", []byte("value")))
require.NoError(tx.Commit())
_, err = tx.Get("key")
var alreadyCommittedError *TransactionAlreadyCommittedError
require.ErrorAs(err, &alreadyCommittedError)
}
func testTransactionPutAfterCommit(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put("key", []byte("value")))
require.NoError(tx.Commit())
err = tx.Put("key", []byte("newValue"))
var alreadyCommittedError *TransactionAlreadyCommittedError
require.ErrorAs(err, &alreadyCommittedError)
}
func testTransactionDeleteAfterCommit(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put("key", []byte("value")))
require.NoError(tx.Commit())
err = tx.Delete("key")
var alreadyCommittedError *TransactionAlreadyCommittedError
require.ErrorAs(err, &alreadyCommittedError)
}
func testRollbackPut(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
testData1 := []byte("test data")
testData2 := []byte("more test data")
testData3 := []byte("and even more data")
// save data to store and seal
tx, err := store.BeginTransaction()
require.NoError(err)
assert.NoError(tx.Put("test:input", testData1))
assert.NoError(tx.Commit())
// save more data to store
tx, err = store.BeginTransaction()
err = tx.Put("key", []byte("value"))
require.NoError(err)
assert.NoError(tx.Put("another:input", testData2))
// rollback and verify only testData1 exists
tx.Rollback()
val, err := store.Get("test:input")
require.NoError(err)
assert.Equal(testData1, val)
_, err = store.Get("another:input")
assert.Error(err)
// save something new
tx, err = store.BeginTransaction()
require.NoError(err)
assert.NoError(tx.Put("last:input", testData3))
assert.NoError(tx.Commit())
_, err = store.Get("key")
var valueUnsetError *ValueUnsetError
assert.ErrorAs(err, &valueUnsetError)
}
// verify values
val, err = store.Get("test:input")
require.NoError(err)
assert.Equal(testData1, val)
val, err = store.Get("last:input")
require.NoError(err)
assert.Equal(testData3, val)
_, err = store.Get("another:input")
assert.Error(err)
func testRollbackDelete(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
assert.NoError(store.Delete("test:input"))
assert.NoError(store.Delete("last:input"))
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("key", []byte("value")))
tx, err := store.BeginTransaction()
require.NoError(err)
err = tx.Delete("key")
require.NoError(err)
tx.Rollback()
fetchedValue, err := store.Get("key")
require.NoError(err)
assert.Equal([]byte("value"), fetchedValue)
}
// Test explicitly the storeLocking mechanism.
@ -193,7 +469,7 @@ func testConcurrency(t *testing.T) {
require.NoError(err)
tx1, err := store.BeginTransaction()
require.NoError(err)
assert.NoError(tx1.Put("concurrent", []byte{0x00, 0x00}))
assert.NoError(tx1.Put("key", []byte("one")))
go func() {
time.Sleep(200 * time.Millisecond)
@ -201,202 +477,14 @@ func testConcurrency(t *testing.T) {
}()
tx2, err := store.BeginTransaction()
require.NoError(err)
result, err := tx2.Get("concurrent")
result, err := tx2.Get("key")
require.NoError(err)
assert.Equal(result, []byte{0x00, 0x00})
assert.NoError(tx2.Put("concurrent", []byte{0x11, 0x11}))
assert.Equal(result, []byte("one"))
assert.NoError(tx2.Put("key", []byte("two")))
assert.NoError(tx2.Commit())
result, err = store.Get("concurrent")
result, err = store.Get("key")
require.NoError(err)
assert.Equal(result, []byte{0x11, 0x11})
assert.NoError(store.Delete("concurrent"))
}
func testTransaction(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
assert.NoError(store.Put("transactionDelete", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
assert.NoError(tx1.Put("transaction", []byte{0x11, 0x11}))
assert.NoError(tx1.Delete("transactionDelete"))
assert.NoError(tx1.Commit())
result, err := store.Get("transaction")
require.NoError(err)
assert.Equal(result, []byte{0x11, 0x11})
_, err = store.Get("transactionDelete")
assert.Error(err)
}
func testTransactionGet(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("transactionGet", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
result, err := tx1.Get("transactionGet")
require.NoError(err)
assert.Equal(result, []byte{0x00, 0x00})
assert.NoError(tx1.Put("transactionGet", []byte{0x11, 0x11}))
result, err = tx1.Get("transactionGet")
require.NoError(err)
assert.Equal(result, []byte{0x11, 0x11})
assert.NoError(tx1.Commit())
result, err = store.Get("transactionGet")
require.Equal(result, []byte{0x11, 0x11})
assert.NoError(err)
}
func testTransactionDelete1(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("transactionDelete", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx1.Put("transactionDelete", []byte{0x00, 0x11}))
assert.NoError(tx1.Delete("transactionDelete"))
require.NoError(tx1.Put("transactionDelete", []byte{0x7, 0x8}))
assert.NoError(tx1.Commit())
result, err := store.Get("transactionDelete")
assert.NoError(err)
assert.Equal([]byte{0x7, 0x8}, result)
}
func testTransactionDelete2(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("transactionDelete", []byte{0x00, 0x00}))
tx1, err := store.BeginTransaction()
require.NoError(err)
assert.NoError(tx1.Delete("transactionDelete"))
_, err = tx1.Get("transactionDelete")
assert.Error(err)
assert.NoError(tx1.Commit())
}
func testIteratorKey(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("testIteratorKey", []byte{0xF1, 0xFF}))
iter, err := store.Iterator("testIteratorKey")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("testIteratorKey", key)
}
func testTransactionIterator(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("testTransactionIterator", []byte{0xF1, 0xFF}))
txdata, err := store.BeginTransaction()
require.NoError(err)
iter, err := txdata.Iterator("testTransactionIterator")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("testTransactionIterator", key)
require.NoError(txdata.Commit())
}
func testTransactionDeleteIterator(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
require.NoError(store.Put("testTransactionDeleteIterator", []byte{0xF1, 0xFF}))
require.NoError(store.Put("testTransactionDeleteIterator15", []byte{0x5, 0xFF}))
txdata, err := store.BeginTransaction()
require.NoError(err)
require.NoError(txdata.Delete("testTransactionDeleteIterator"))
iter, err := txdata.Iterator("testTransactionDeleteIterator")
require.NoError(err)
key, err := iter.GetNext()
require.NoError(err)
assert.Equal("testTransactionDeleteIterator15", key)
require.NoError(txdata.Commit())
}
func testEmptyIterator(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
txdata, err := store.BeginTransaction()
require.NoError(err)
iter, err := txdata.Iterator("ThisKeyTestsAnEmptyIterator")
require.NoError(err)
assert.False(iter.HasNext())
_, err = iter.GetNext()
assert.Error(err)
require.NoError(txdata.Commit())
}
// Test the race condition in the stdStore.
// This must be specified in the test through [-race].
func testIteratorRace(t *testing.T) {
require := require.New(t)
store, err := newStore()
require.NoError(err)
tx, err := store.BeginTransaction()
require.NoError(err)
require.NoError(tx.Put("testIteratorRace", []byte{1, 2, 3, 4, 5}))
go func() {
_, err = store.Iterator("testIteratorRace")
require.NoError(err)
}()
require.NoError(tx.Commit())
}
func testTransactionIteratorPutPrefix(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
expectedKey := "testTransactionIteratorPutPrefix"
store, err := newStore()
require.NoError(err)
txdata, err := store.BeginTransaction()
require.NoError(err)
require.NoError(txdata.Put("IteratorNotInIterator", []byte{0xF2, 0xFF}))
require.NoError(txdata.Put(expectedKey, []byte{0xF1, 0xFF}))
iter, err := txdata.Iterator(expectedKey)
require.NoError(err)
require.True(iter.HasNext())
key, err := iter.GetNext()
require.NoError(err)
assert.Equal(expectedKey, key)
assert.False(iter.HasNext())
assert.NoError(txdata.Commit())
assert.Equal(result, []byte("two"))
}
func testStoreByValue(t *testing.T) {
@ -407,8 +495,38 @@ func testStoreByValue(t *testing.T) {
require.NoError(err)
testValue := []byte{0xF1, 0xFF}
require.NoError(store.Put("StoreByValue", testValue))
testValue[0] = 0x00
storeValue, err := store.Get("StoreByValue")
require.NoError(err)
assert.NotEqual(storeValue[0], testValue[0])
}
func testIndependentTest(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
err = store.Put("uniqueTestKey253", []byte("value"))
require.NoError(err)
value, err := store.Get("uniqueTestKey253")
require.NoError(err)
assert.Equal([]byte("value"), value)
}
func testIndependentTestReader(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
store, err := newStore()
require.NoError(err)
// This test should not see & depend on the key `testIndependentTest` sets.
_, err = store.Get("uniqueTestKey253")
var unsetErr *ValueUnsetError
assert.ErrorAs(err, &unsetErr)
}

View File

@ -53,7 +53,7 @@ for the termination. However, to keep the code clean, we accept this tradeoff an
const (
publicgRPCPort = "9000"
constellationImageName = "constellation:latest"
etcdImageName = "bitnami/etcd:3.5.1"
etcdImageName = "bitnami/etcd:3.5.2"
etcdOverlayNetwork = "constellationIntegrationTest"
masterSecret = "ConstellationIntegrationTest"
numberFirstActivation = 3