github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/orm_scenario_test.go (about) 1 package orm 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 storetypes "cosmossdk.io/store/types" 13 14 "github.com/cosmos/cosmos-sdk/codec" 15 "github.com/cosmos/cosmos-sdk/codec/types" 16 "github.com/cosmos/cosmos-sdk/testutil/testdata" 17 "github.com/cosmos/cosmos-sdk/x/group/errors" 18 ) 19 20 // Testing ORM with arbitrary metadata length 21 const metadataLen = 10 22 23 func TestKeeperEndToEndWithAutoUInt64Table(t *testing.T) { 24 interfaceRegistry := types.NewInterfaceRegistry() 25 cdc := codec.NewProtoCodec(interfaceRegistry) 26 27 ctx := NewMockContext() 28 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 29 30 k := NewTestKeeper(cdc) 31 32 tm := testdata.TableModel{ 33 Id: 1, 34 Name: "name", 35 Number: 123, 36 Metadata: []byte("metadata"), 37 } 38 // when stored 39 rowID, err := k.autoUInt64Table.Create(store, &tm) 40 require.NoError(t, err) 41 // then we should find it 42 exists := k.autoUInt64Table.Has(store, rowID) 43 require.True(t, exists) 44 45 // and load it 46 var loaded testdata.TableModel 47 48 binKey, err := k.autoUInt64Table.GetOne(store, rowID, &loaded) 49 require.NoError(t, err) 50 51 require.Equal(t, rowID, binary.BigEndian.Uint64(binKey)) 52 require.Equal(t, tm, loaded) 53 54 // and exists in MultiKeyIndex 55 exists, err = k.autoUInt64TableModelByMetadataIndex.Has(store, []byte("metadata")) 56 require.NoError(t, err) 57 require.True(t, exists) 58 59 // and when loaded 60 it, err := k.autoUInt64TableModelByMetadataIndex.Get(store, []byte("metadata")) 61 require.NoError(t, err) 62 63 // then 64 binKey, loaded = first(t, it) 65 assert.Equal(t, rowID, binary.BigEndian.Uint64(binKey)) 66 assert.Equal(t, tm, loaded) 67 68 // when updated 69 tm.Metadata = []byte("new-metadata") 70 err = k.autoUInt64Table.Update(store, rowID, &tm) 71 require.NoError(t, err) 72 73 binKey, err = k.autoUInt64Table.GetOne(store, rowID, &loaded) 74 require.NoError(t, err) 75 76 require.Equal(t, rowID, binary.BigEndian.Uint64(binKey)) 77 require.Equal(t, tm, loaded) 78 79 // then indexes are updated, too 80 exists, err = k.autoUInt64TableModelByMetadataIndex.Has(store, []byte("new-metadata")) 81 require.NoError(t, err) 82 require.True(t, exists) 83 84 exists, err = k.autoUInt64TableModelByMetadataIndex.Has(store, []byte("metadata")) 85 require.NoError(t, err) 86 require.False(t, exists) 87 88 // when deleted 89 err = k.autoUInt64Table.Delete(store, rowID) 90 require.NoError(t, err) 91 92 exists = k.autoUInt64Table.Has(store, rowID) 93 require.False(t, exists) 94 95 // and also removed from secondary MultiKeyIndex 96 exists, err = k.autoUInt64TableModelByMetadataIndex.Has(store, []byte("new-metadata")) 97 require.NoError(t, err) 98 require.False(t, exists) 99 } 100 101 func TestKeeperEndToEndWithPrimaryKeyTable(t *testing.T) { 102 interfaceRegistry := types.NewInterfaceRegistry() 103 cdc := codec.NewProtoCodec(interfaceRegistry) 104 105 ctx := NewMockContext() 106 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 107 108 k := NewTestKeeper(cdc) 109 110 tm := testdata.TableModel{ 111 Id: 1, 112 Name: "name", 113 Number: 123, 114 Metadata: []byte("metadata"), 115 } 116 // when stored 117 err := k.primaryKeyTable.Create(store, &tm) 118 require.NoError(t, err) 119 // then we should find it by primary key 120 primaryKey := PrimaryKey(&tm) 121 exists := k.primaryKeyTable.Has(store, primaryKey) 122 require.True(t, exists) 123 124 // and load it by primary key 125 var loaded testdata.TableModel 126 err = k.primaryKeyTable.GetOne(store, primaryKey, &loaded) 127 require.NoError(t, err) 128 129 // then values should match expectations 130 require.Equal(t, tm, loaded) 131 132 // and then the data should exists in MultiKeyIndex 133 exists, err = k.primaryKeyTableModelByNumberIndex.Has(store, tm.Number) 134 require.NoError(t, err) 135 require.True(t, exists) 136 137 // and when loaded from MultiKeyIndex 138 it, err := k.primaryKeyTableModelByNumberIndex.Get(store, tm.Number) 139 require.NoError(t, err) 140 141 // then values should match as before 142 _, err = First(it, &loaded) 143 require.NoError(t, err) 144 assert.Equal(t, tm, loaded) 145 146 // and when we create another entry with the same primary key 147 err = k.primaryKeyTable.Create(store, &tm) 148 // then it should fail as the primary key must be unique 149 require.True(t, errors.ErrORMUniqueConstraint.Is(err), err) 150 151 // and when entity updated with new primary key 152 updatedMember := &testdata.TableModel{ 153 Id: 2, 154 Name: tm.Name, 155 Number: tm.Number, 156 Metadata: tm.Metadata, 157 } 158 // then it should fail as the primary key is immutable 159 err = k.primaryKeyTable.Update(store, updatedMember) 160 require.Error(t, err) 161 162 // and when entity updated with non primary key attribute modified 163 updatedMember = &testdata.TableModel{ 164 Id: 1, 165 Name: "new name", 166 Number: tm.Number, 167 Metadata: tm.Metadata, 168 } 169 // then it should not fail 170 err = k.primaryKeyTable.Update(store, updatedMember) 171 require.NoError(t, err) 172 173 // and when entity deleted 174 err = k.primaryKeyTable.Delete(store, &tm) 175 require.NoError(t, err) 176 177 // it is removed from primaryKeyTable 178 exists = k.primaryKeyTable.Has(store, primaryKey) 179 require.False(t, exists) 180 181 // and removed from secondary MultiKeyIndex 182 exists, err = k.primaryKeyTableModelByNumberIndex.Has(store, tm.Number) 183 require.NoError(t, err) 184 require.False(t, exists) 185 } 186 187 func TestGasCostsPrimaryKeyTable(t *testing.T) { 188 interfaceRegistry := types.NewInterfaceRegistry() 189 cdc := codec.NewProtoCodec(interfaceRegistry) 190 191 ctx := NewMockContext() 192 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 193 194 k := NewTestKeeper(cdc) 195 196 tm := testdata.TableModel{ 197 Id: 1, 198 Name: "name", 199 Number: 123, 200 Metadata: []byte("metadata"), 201 } 202 rowID, err := k.autoUInt64Table.Create(store, &tm) 203 require.NoError(t, err) 204 require.Equal(t, uint64(1), rowID) 205 206 gCtx := NewGasCountingMockContext() 207 err = k.primaryKeyTable.Create(gCtx.KVStore(store), &tm) 208 require.NoError(t, err) 209 t.Logf("gas consumed on create: %d", gCtx.GasConsumed()) 210 211 // get by primary key 212 gCtx.ResetGasMeter() 213 var loaded testdata.TableModel 214 err = k.primaryKeyTable.GetOne(gCtx.KVStore(store), PrimaryKey(&tm), &loaded) 215 require.NoError(t, err) 216 t.Logf("gas consumed on get by primary key: %d", gCtx.GasConsumed()) 217 218 // get by secondary index 219 gCtx.ResetGasMeter() 220 // and when loaded from MultiKeyIndex 221 it, err := k.primaryKeyTableModelByNumberIndex.Get(gCtx.KVStore(store), tm.Number) 222 require.NoError(t, err) 223 var loadedSlice []testdata.TableModel 224 _, err = ReadAll(it, &loadedSlice) 225 require.NoError(t, err) 226 t.Logf("gas consumed on get by multi index key: %d", gCtx.GasConsumed()) 227 228 // delete 229 gCtx.ResetGasMeter() 230 err = k.primaryKeyTable.Delete(gCtx.KVStore(store), &tm) 231 require.NoError(t, err) 232 t.Logf("gas consumed on delete by primary key: %d", gCtx.GasConsumed()) 233 234 // with 3 elements 235 var tms []testdata.TableModel 236 for i := 1; i < 4; i++ { 237 gCtx.ResetGasMeter() 238 tm := testdata.TableModel{ 239 Id: uint64(i), 240 Name: fmt.Sprintf("name%d", i), 241 Number: 123, 242 Metadata: []byte("metadata"), 243 } 244 err = k.primaryKeyTable.Create(gCtx.KVStore(store), &tm) 245 require.NoError(t, err) 246 t.Logf("%d: gas consumed on create: %d", i, gCtx.GasConsumed()) 247 tms = append(tms, tm) 248 } 249 250 for i := 1; i < 4; i++ { 251 gCtx.ResetGasMeter() 252 tm := testdata.TableModel{ 253 Id: uint64(i), 254 Name: fmt.Sprintf("name%d", i), 255 Number: 123, 256 Metadata: []byte("metadata"), 257 } 258 err = k.primaryKeyTable.GetOne(gCtx.KVStore(store), PrimaryKey(&tm), &loaded) 259 require.NoError(t, err) 260 t.Logf("%d: gas consumed on get by primary key: %d", i, gCtx.GasConsumed()) 261 } 262 263 // get by secondary index 264 gCtx.ResetGasMeter() 265 // and when loaded from MultiKeyIndex 266 it, err = k.primaryKeyTableModelByNumberIndex.Get(gCtx.KVStore(store), tm.Number) 267 require.NoError(t, err) 268 _, err = ReadAll(it, &loadedSlice) 269 require.NoError(t, err) 270 require.Len(t, loadedSlice, 3) 271 t.Logf("gas consumed on get by multi index key: %d", gCtx.GasConsumed()) 272 273 // delete 274 for i, m := range tms { 275 gCtx.ResetGasMeter() 276 277 m := m 278 err = k.primaryKeyTable.Delete(gCtx.KVStore(store), &m) 279 280 require.NoError(t, err) 281 t.Logf("%d: gas consumed on delete: %d", i, gCtx.GasConsumed()) 282 } 283 } 284 285 func TestExportImportStateAutoUInt64Table(t *testing.T) { 286 interfaceRegistry := types.NewInterfaceRegistry() 287 cdc := codec.NewProtoCodec(interfaceRegistry) 288 289 ctx := NewMockContext() 290 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 291 292 k := NewTestKeeper(cdc) 293 294 testRecordsNum := 10 295 for i := 1; i <= testRecordsNum; i++ { 296 tm := testdata.TableModel{ 297 Id: uint64(i), 298 Name: fmt.Sprintf("my test %d", i), 299 Metadata: bytes.Repeat([]byte{byte(i)}, metadataLen), 300 } 301 302 rowID, err := k.autoUInt64Table.Create(store, &tm) 303 require.NoError(t, err) 304 require.Equal(t, uint64(i), rowID) 305 } 306 var tms []*testdata.TableModel 307 seqVal, err := k.autoUInt64Table.Export(store, &tms) 308 require.NoError(t, err) 309 require.Equal(t, seqVal, uint64(testRecordsNum)) 310 311 // when a new db seeded 312 ctx = NewMockContext() 313 store = ctx.KVStore(storetypes.NewKVStoreKey("test")) 314 315 err = k.autoUInt64Table.Import(store, tms, seqVal) 316 require.NoError(t, err) 317 318 // then all data is set again 319 for i := 1; i <= testRecordsNum; i++ { 320 require.True(t, k.autoUInt64Table.Has(store, uint64(i))) 321 var loaded testdata.TableModel 322 rowID, err := k.autoUInt64Table.GetOne(store, uint64(i), &loaded) 323 require.NoError(t, err) 324 325 require.Equal(t, RowID(EncodeSequence(uint64(i))), rowID) 326 assert.Equal(t, fmt.Sprintf("my test %d", i), loaded.Name) 327 exp := bytes.Repeat([]byte{byte(i)}, metadataLen) 328 assert.Equal(t, exp, loaded.Metadata) 329 330 // and also the indexes 331 exists, err := k.autoUInt64TableModelByMetadataIndex.Has(store, exp) 332 require.NoError(t, err) 333 require.True(t, exists) 334 335 it, err := k.autoUInt64TableModelByMetadataIndex.Get(store, exp) 336 require.NoError(t, err) 337 var all []testdata.TableModel 338 ReadAll(it, &all) 339 require.Len(t, all, 1) 340 assert.Equal(t, loaded, all[0]) 341 } 342 require.Equal(t, uint64(testRecordsNum), k.autoUInt64Table.Sequence().CurVal(store)) 343 } 344 345 func TestExportImportStatePrimaryKeyTable(t *testing.T) { 346 interfaceRegistry := types.NewInterfaceRegistry() 347 cdc := codec.NewProtoCodec(interfaceRegistry) 348 349 ctx := NewMockContext() 350 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 351 352 k := NewTestKeeper(cdc) 353 354 testRecordsNum := 10 355 testRecords := make([]testdata.TableModel, testRecordsNum) 356 for i := 1; i <= testRecordsNum; i++ { 357 tm := testdata.TableModel{ 358 Id: uint64(i), 359 Name: fmt.Sprintf("my test %d", i), 360 Number: uint64(i - 1), 361 Metadata: bytes.Repeat([]byte{byte(i)}, metadataLen), 362 } 363 364 err := k.primaryKeyTable.Create(store, &tm) 365 require.NoError(t, err) 366 testRecords[i-1] = tm 367 } 368 var tms []*testdata.TableModel 369 _, err := k.primaryKeyTable.Export(store, &tms) 370 require.NoError(t, err) 371 372 // when a new db seeded 373 ctx = NewMockContext() 374 store = ctx.KVStore(storetypes.NewKVStoreKey("test")) 375 376 err = k.primaryKeyTable.Import(store, tms, 0) 377 require.NoError(t, err) 378 379 // then all data is set again 380 it, err := k.primaryKeyTable.PrefixScan(store, nil, nil) 381 require.NoError(t, err) 382 var loaded []testdata.TableModel 383 keys, err := ReadAll(it, &loaded) 384 require.NoError(t, err) 385 for i := range keys { 386 assert.Equal(t, PrimaryKey(&testRecords[i]), keys[i].Bytes()) 387 } 388 assert.Equal(t, testRecords, loaded) 389 390 // all indexes setup 391 for _, v := range testRecords { 392 assertIndex(t, store, k.primaryKeyTableModelByNameIndex, v, v.Name) 393 assertIndex(t, store, k.primaryKeyTableModelByNumberIndex, v, v.Number) 394 assertIndex(t, store, k.primaryKeyTableModelByMetadataIndex, v, v.Metadata) 395 } 396 } 397 398 func assertIndex(t *testing.T, store storetypes.KVStore, index Index, v testdata.TableModel, searchKey interface{}) { 399 it, err := index.Get(store, searchKey) 400 require.NoError(t, err) 401 402 var loaded []testdata.TableModel 403 keys, err := ReadAll(it, &loaded) 404 require.NoError(t, err) 405 assert.Equal(t, []RowID{PrimaryKey(&v)}, keys) 406 assert.Equal(t, []testdata.TableModel{v}, loaded) 407 } 408 409 func first(t *testing.T, it Iterator) ([]byte, testdata.TableModel) { 410 var loaded testdata.TableModel 411 key, err := First(it, &loaded) 412 require.NoError(t, err) 413 return key, loaded 414 }