@@ -14,7 +14,7 @@ import (
1414 "github.com/onflow/flow-go/utils/unittest"
1515)
1616
17- // TestInsertProtocolKVStore tests if basic badger operations on ProtocolKVStore work as expected.
17+ // TestInsertProtocolKVStore tests if basic store and index operations on ProtocolKVStore work as expected.
1818func TestInsertProtocolKVStore (t * testing.T ) {
1919 dbtest .RunWithDB (t , func (t * testing.T , db storage.DB ) {
2020 lockManager := storage .NewTestingLockManager ()
@@ -52,3 +52,134 @@ func TestInsertProtocolKVStore(t *testing.T) {
5252 assert .Equal (t , kvStoreStateID , actualProtocolKVStoreID )
5353 })
5454}
55+
56+ // TestInsertProtocolKVStore_ErrAlreadyExists tests that InsertProtocolKVStore returns ErrAlreadyExists
57+ // when attempting to insert a protocol KV store that already exists.
58+ func TestInsertProtocolKVStore_ErrAlreadyExists (t * testing.T ) {
59+ dbtest .RunWithDB (t , func (t * testing.T , db storage.DB ) {
60+ lockManager := storage .NewTestingLockManager ()
61+ expected := & flow.PSKeyValueStoreData {
62+ Version : 2 ,
63+ Data : unittest .RandomBytes (32 ),
64+ }
65+
66+ kvStoreStateID := unittest .IdentifierFixture ()
67+
68+ // First insertion should succeed
69+ err := unittest .WithLock (t , lockManager , storage .LockInsertBlock , func (lctx lockctx.Context ) error {
70+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
71+ return operation .InsertProtocolKVStore (lctx , rw , kvStoreStateID , expected )
72+ })
73+ })
74+ require .NoError (t , err )
75+
76+ // Second insertion with same ID should fail with ErrAlreadyExists
77+ differentData := & flow.PSKeyValueStoreData {
78+ Version : 3 ,
79+ Data : unittest .RandomBytes (32 ),
80+ }
81+ err = unittest .WithLock (t , lockManager , storage .LockInsertBlock , func (lctx lockctx.Context ) error {
82+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
83+ return operation .InsertProtocolKVStore (lctx , rw , kvStoreStateID , differentData )
84+ })
85+ })
86+ require .Error (t , err )
87+ require .ErrorIs (t , err , storage .ErrAlreadyExists )
88+
89+ // Verify original data is still there and unchanged
90+ var actual flow.PSKeyValueStoreData
91+ err = operation .RetrieveProtocolKVStore (db .Reader (), kvStoreStateID , & actual )
92+ require .NoError (t , err )
93+ assert .Equal (t , expected , & actual )
94+ })
95+ }
96+
97+ // TestIndexProtocolKVStore_ErrAlreadyExists tests that IndexProtocolKVStore returns ErrAlreadyExists
98+ // when attempting to index a protocol KV store for a block ID that already has an index.
99+ func TestIndexProtocolKVStore_ErrAlreadyExists (t * testing.T ) {
100+ dbtest .RunWithDB (t , func (t * testing.T , db storage.DB ) {
101+ lockManager := storage .NewTestingLockManager ()
102+ expected := & flow.PSKeyValueStoreData {
103+ Version : 2 ,
104+ Data : unittest .RandomBytes (32 ),
105+ }
106+
107+ kvStoreStateID := unittest .IdentifierFixture ()
108+ blockID := unittest .IdentifierFixture ()
109+
110+ // Insert the protocol KV store first
111+ err := unittest .WithLock (t , lockManager , storage .LockInsertBlock , func (lctx lockctx.Context ) error {
112+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
113+ return operation .InsertProtocolKVStore (lctx , rw , kvStoreStateID , expected )
114+ })
115+ })
116+ require .NoError (t , err )
117+
118+ // First indexing should succeed
119+ err = unittest .WithLock (t , lockManager , storage .LockInsertBlock , func (lctx lockctx.Context ) error {
120+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
121+ return operation .IndexProtocolKVStore (lctx , rw , blockID , kvStoreStateID )
122+ })
123+ })
124+ require .NoError (t , err )
125+
126+ // Second indexing with same block ID should fail with ErrAlreadyExists
127+ differentKVStoreID := unittest .IdentifierFixture ()
128+ err = unittest .WithLock (t , lockManager , storage .LockInsertBlock , func (lctx lockctx.Context ) error {
129+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
130+ return operation .IndexProtocolKVStore (lctx , rw , blockID , differentKVStoreID )
131+ })
132+ })
133+ require .Error (t , err )
134+ require .ErrorIs (t , err , storage .ErrAlreadyExists )
135+
136+ // Verify original index is still there and unchanged
137+ var actualProtocolKVStoreID flow.Identifier
138+ err = operation .LookupProtocolKVStore (db .Reader (), blockID , & actualProtocolKVStoreID )
139+ require .NoError (t , err )
140+ assert .Equal (t , kvStoreStateID , actualProtocolKVStoreID )
141+ })
142+ }
143+
144+ // TestInsertProtocolKVStore_MissingLock tests that InsertProtocolKVStore requires LockInsertBlock.
145+ func TestInsertProtocolKVStore_MissingLock (t * testing.T ) {
146+ dbtest .RunWithDB (t , func (t * testing.T , db storage.DB ) {
147+ lockManager := storage .NewTestingLockManager ()
148+ expected := & flow.PSKeyValueStoreData {
149+ Version : 2 ,
150+ Data : unittest .RandomBytes (32 ),
151+ }
152+
153+ kvStoreStateID := unittest .IdentifierFixture ()
154+
155+ // Attempt to insert without holding the required lock
156+ lctx := lockManager .NewContext ()
157+ defer lctx .Release ()
158+
159+ err := db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
160+ return operation .InsertProtocolKVStore (lctx , rw , kvStoreStateID , expected )
161+ })
162+ require .Error (t , err )
163+ require .Contains (t , err .Error (), storage .LockInsertBlock )
164+ })
165+ }
166+
167+ // TestIndexProtocolKVStore_MissingLock tests that IndexProtocolKVStore requires LockInsertBlock.
168+ func TestIndexProtocolKVStore_MissingLock (t * testing.T ) {
169+ dbtest .RunWithDB (t , func (t * testing.T , db storage.DB ) {
170+ lockManager := storage .NewTestingLockManager ()
171+ kvStoreStateID := unittest .IdentifierFixture ()
172+ blockID := unittest .IdentifierFixture ()
173+
174+ // Attempt to index without holding the required lock
175+ lctx := lockManager .NewContext ()
176+ defer lctx .Release ()
177+
178+ err := db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
179+ return operation .IndexProtocolKVStore (lctx , rw , blockID , kvStoreStateID )
180+ })
181+ require .Error (t , err )
182+ require .Contains (t , err .Error (), storage .LockInsertBlock )
183+
184+ })
185+ }
0 commit comments