code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/oracle_spec_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package sqlstore_test 17 18 import ( 19 "context" 20 "fmt" 21 "testing" 22 "time" 23 24 dstypes "code.vegaprotocol.io/vega/core/datasource/common" 25 "code.vegaprotocol.io/vega/datanode/entities" 26 "code.vegaprotocol.io/vega/datanode/sqlstore" 27 "code.vegaprotocol.io/vega/protos/vega" 28 vegapb "code.vegaprotocol.io/vega/protos/vega" 29 datapb "code.vegaprotocol.io/vega/protos/vega/data/v1" 30 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 "google.golang.org/protobuf/types/known/structpb" 34 ) 35 36 func TestOracleSpec(t *testing.T) { 37 t.Run("Upsert should insert an OracleSpec when the id does not exist in the current block", testInsertIntoNewBlock) 38 t.Run("Upsert should update an OracleSpec when the id already exists in the current block", testUpdateExistingInBlock) 39 t.Run("GetSpecByID should retrieve the latest version of the specified OracleSpec", testGetSpecByID) 40 t.Run("GetByTxHash", testGetSpecByTxHash) 41 } 42 43 func setupOracleSpecTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.OracleSpec, sqlstore.Connection) { 44 t.Helper() 45 46 bs := sqlstore.NewBlocks(connectionSource) 47 os := sqlstore.NewOracleSpec(connectionSource) 48 49 return bs, os, connectionSource 50 } 51 52 func testInsertIntoNewBlock(t *testing.T) { 53 ctx := tempTransaction(t) 54 55 bs, os, conn := setupOracleSpecTest(t) 56 57 var rowCount int 58 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 59 assert.Equal(t, 0, rowCount) 60 61 block := addTestBlock(t, ctx, bs) 62 specProtos := getTestSpecs() 63 64 proto := specProtos[0] 65 data := entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 66 assert.NoError(t, os.Upsert(ctx, data)) 67 68 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 69 assert.Equal(t, 1, rowCount) 70 71 proto = specProtos[4] 72 data = entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 73 assert.NoError(t, os.Upsert(ctx, data)) 74 75 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 76 assert.Equal(t, 2, rowCount) 77 } 78 79 func testUpdateExistingInBlock(t *testing.T) { 80 ctx := tempTransaction(t) 81 82 bs, os, conn := setupOracleSpecTest(t) 83 84 var rowCount int 85 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 86 assert.Equal(t, 0, rowCount) 87 88 block := addTestBlock(t, ctx, bs) 89 specProtos := getTestSpecs() 90 91 proto := specProtos[0] 92 data := entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 93 assert.NoError(t, os.Upsert(ctx, data)) 94 95 data.ExternalDataSourceSpec.Spec.Status = entities.OracleSpecDeactivated 96 assert.NoError(t, os.Upsert(ctx, data)) 97 98 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 99 assert.Equal(t, 1, rowCount) 100 101 proto = specProtos[4] 102 data = entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 103 assert.NoError(t, os.Upsert(ctx, data)) 104 105 data.ExternalDataSourceSpec.Spec.Status = entities.OracleSpecDeactivated 106 assert.NoError(t, os.Upsert(ctx, data)) 107 108 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 109 assert.Equal(t, 2, rowCount) 110 } 111 112 func testGetSpecByID(t *testing.T) { 113 ctx := tempTransaction(t) 114 115 bs, os, conn := setupOracleSpecTest(t) 116 117 var rowCount int 118 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 119 assert.Equal(t, 0, rowCount) 120 121 block := addTestBlock(t, ctx, bs) 122 specProtos := getTestSpecs() 123 124 for _, proto := range specProtos { 125 data := entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 126 assert.NoError(t, os.Upsert(ctx, data)) 127 } 128 129 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 130 assert.Equal(t, 6, rowCount) 131 132 got, err := os.GetSpecByID(ctx, "DEADBEEF") 133 require.NoError(t, err) 134 135 want := entities.DataSourceSpecFromProto(specProtos[0].ExternalDataSourceSpec.Spec, got.ExternalDataSourceSpec.Spec.TxHash, block.VegaTime) 136 137 // truncate the time to microseconds as postgres doesn't support nanosecond granularity. 138 want.UpdatedAt = want.UpdatedAt.Truncate(time.Microsecond) 139 want.CreatedAt = want.CreatedAt.Truncate(time.Microsecond) 140 s := got.ExternalDataSourceSpec.Spec 141 assert.Equal(t, want, s) 142 143 got, err = os.GetSpecByID(ctx, "beef000d") 144 require.NoError(t, err) 145 146 want = entities.DataSourceSpecFromProto(specProtos[4].ExternalDataSourceSpec.Spec, got.ExternalDataSourceSpec.Spec.TxHash, block.VegaTime) 147 want.UpdatedAt = want.UpdatedAt.Truncate(time.Microsecond) 148 want.CreatedAt = want.CreatedAt.Truncate(time.Microsecond) 149 s = got.ExternalDataSourceSpec.Spec 150 assert.Equal(t, want, s) 151 152 got, err = os.GetSpecByID(ctx, "beef000e") 153 require.NoError(t, err) 154 155 want = entities.DataSourceSpecFromProto(specProtos[5].ExternalDataSourceSpec.Spec, got.ExternalDataSourceSpec.Spec.TxHash, block.VegaTime) 156 want.UpdatedAt = want.UpdatedAt.Truncate(time.Microsecond) 157 want.CreatedAt = want.CreatedAt.Truncate(time.Microsecond) 158 s = got.ExternalDataSourceSpec.Spec 159 assert.Equal(t, want, s) 160 } 161 162 func testGetSpecByTxHash(t *testing.T) { 163 ctx := tempTransaction(t) 164 165 bs, os, conn := setupOracleSpecTest(t) 166 167 var rowCount int 168 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 169 assert.Equal(t, 0, rowCount) 170 171 block := addTestBlock(t, ctx, bs) 172 specProtos := getTestSpecs() 173 174 specs := make([]entities.OracleSpec, 0, len(specProtos)) 175 for _, proto := range specProtos { 176 data := entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 177 assert.NoError(t, os.Upsert(ctx, data)) 178 179 specs = append(specs, *data) 180 } 181 182 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_specs").Scan(&rowCount)) 183 assert.Equal(t, 6, rowCount) 184 185 foundSpecs, err := os.GetByTxHash(ctx, specs[0].ExternalDataSourceSpec.Spec.TxHash) 186 require.NoError(t, err) 187 188 got := foundSpecs[0] 189 want := entities.DataSourceSpecFromProto(specProtos[0].ExternalDataSourceSpec.Spec, got.ExternalDataSourceSpec.Spec.TxHash, block.VegaTime) 190 191 // truncate the time to microseconds as postgres doesn't support nanosecond granularity. 192 want.UpdatedAt = want.UpdatedAt.Truncate(time.Microsecond) 193 want.CreatedAt = want.CreatedAt.Truncate(time.Microsecond) 194 s := got.ExternalDataSourceSpec.Spec 195 assert.Equal(t, want, s) 196 } 197 198 func getTestSpecs() []*vegapb.OracleSpec { 199 pk1 := dstypes.CreateSignerFromString("b105f00d", dstypes.SignerTypePubKey) 200 pk2 := dstypes.CreateSignerFromString("0x124dd8a6044ef048614aea0aac86643a8ae1312d", dstypes.SignerTypeEthAddress) 201 202 timeNow := uint64(time.Now().UnixNano()) 203 return []*vegapb.OracleSpec{ 204 { 205 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 206 Spec: &vegapb.DataSourceSpec{ 207 Id: "deadbeef", 208 CreatedAt: time.Now().UnixNano(), 209 UpdatedAt: time.Now().UnixNano(), 210 Data: vegapb.NewDataSourceDefinition( 211 vegapb.DataSourceContentTypeOracle, 212 ).SetOracleConfig( 213 &vega.DataSourceDefinitionExternal_Oracle{ 214 Oracle: &vegapb.DataSourceSpecConfiguration{ 215 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 216 Filters: []*datapb.Filter{ 217 { 218 Key: &datapb.PropertyKey{ 219 Name: "Ticker", 220 Type: datapb.PropertyKey_TYPE_STRING, 221 }, 222 Conditions: []*datapb.Condition{ 223 { 224 Operator: datapb.Condition_OPERATOR_EQUALS, 225 Value: "USDETH", 226 }, 227 }, 228 }, 229 }, 230 }, 231 }, 232 ), 233 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 234 }, 235 }, 236 }, 237 { 238 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 239 Spec: &vegapb.DataSourceSpec{ 240 Id: "cafed00d", 241 CreatedAt: time.Now().UnixNano(), 242 UpdatedAt: time.Now().UnixNano(), 243 Data: vegapb.NewDataSourceDefinition( 244 vegapb.DataSourceContentTypeOracle, 245 ).SetOracleConfig( 246 &vega.DataSourceDefinitionExternal_Oracle{ 247 Oracle: &vegapb.DataSourceSpecConfiguration{ 248 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 249 Filters: []*datapb.Filter{ 250 { 251 Key: &datapb.PropertyKey{ 252 Name: "Ticker", 253 Type: datapb.PropertyKey_TYPE_STRING, 254 }, 255 Conditions: []*datapb.Condition{ 256 { 257 Operator: datapb.Condition_OPERATOR_EQUALS, 258 Value: "USDBTC", 259 }, 260 }, 261 }, 262 }, 263 }, 264 }, 265 ), 266 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 267 }, 268 }, 269 }, 270 { 271 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 272 Spec: &vegapb.DataSourceSpec{ 273 Id: "deadbaad", 274 CreatedAt: time.Now().UnixNano(), 275 UpdatedAt: time.Now().UnixNano(), 276 Data: vegapb.NewDataSourceDefinition( 277 vegapb.DataSourceContentTypeOracle, 278 ).SetOracleConfig( 279 &vega.DataSourceDefinitionExternal_Oracle{ 280 Oracle: &vegapb.DataSourceSpecConfiguration{ 281 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 282 Filters: []*datapb.Filter{ 283 { 284 Key: &datapb.PropertyKey{ 285 Name: "Ticker", 286 Type: datapb.PropertyKey_TYPE_STRING, 287 }, 288 Conditions: []*datapb.Condition{ 289 { 290 Operator: datapb.Condition_OPERATOR_EQUALS, 291 Value: "USDSOL", 292 }, 293 }, 294 }, 295 }, 296 }, 297 }, 298 ), 299 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 300 }, 301 }, 302 }, 303 { 304 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 305 Spec: &vegapb.DataSourceSpec{ 306 Id: "beefbeef", 307 CreatedAt: time.Now().UnixNano(), 308 UpdatedAt: time.Now().UnixNano(), 309 Data: vegapb.NewDataSourceDefinition( 310 vegapb.DataSourceContentTypeInternalTimeTermination, 311 ).SetTimeTriggerConditionConfig( 312 []*datapb.Condition{ 313 { 314 Operator: datapb.Condition_OPERATOR_EQUALS, 315 Value: fmt.Sprintf("%v", time.Now().UnixNano()), 316 }, 317 }, 318 ), 319 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 320 }, 321 }, 322 }, 323 { 324 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 325 Spec: &vegapb.DataSourceSpec{ 326 Id: "beef000d", 327 CreatedAt: time.Now().UnixNano(), 328 UpdatedAt: time.Now().UnixNano(), 329 Data: vegapb.NewDataSourceDefinition( 330 vegapb.DataSourceContentTypeEthOracle, 331 ).SetOracleConfig( 332 &vega.DataSourceDefinitionExternal_EthOracle{ 333 EthOracle: &vegapb.EthCallSpec{ 334 Address: "some-eth-address", 335 Abi: "{\"string-value\"}", 336 Method: "test-method", 337 Args: []*structpb.Value{ 338 { 339 Kind: &structpb.Value_StringValue{ 340 StringValue: "string-arg", 341 }, 342 }, 343 }, 344 Trigger: &vegapb.EthCallTrigger{ 345 Trigger: &vegapb.EthCallTrigger_TimeTrigger{ 346 TimeTrigger: &vegapb.EthTimeTrigger{ 347 Initial: &timeNow, 348 }, 349 }, 350 }, 351 RequiredConfirmations: 256, 352 Filters: []*datapb.Filter{ 353 { 354 Key: &datapb.PropertyKey{ 355 Name: "test-key-name-0", 356 Type: dstypes.SpecPropertyKeyType(2), 357 }, 358 }, 359 }, 360 }, 361 }, 362 ), 363 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 364 }, 365 }, 366 }, 367 { 368 ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{ 369 Spec: &vegapb.DataSourceSpec{ 370 Id: "beef000e", 371 CreatedAt: time.Now().UnixNano(), 372 UpdatedAt: time.Now().UnixNano(), 373 Data: vegapb.NewDataSourceDefinition( 374 vegapb.DataSourceContentTypeEthOracle, 375 ).SetOracleConfig( 376 &vega.DataSourceDefinitionExternal_EthOracle{ 377 EthOracle: &vegapb.EthCallSpec{ 378 Address: "some-eth-address", 379 Abi: "{\"string-value\"}", 380 Method: "test-method", 381 // Args: []*structpb.Value{}, 382 Trigger: &vegapb.EthCallTrigger{ 383 Trigger: &vegapb.EthCallTrigger_TimeTrigger{ 384 TimeTrigger: &vegapb.EthTimeTrigger{ 385 Initial: &timeNow, 386 }, 387 }, 388 }, 389 RequiredConfirmations: 256, 390 Filters: []*datapb.Filter{ 391 { 392 Key: &datapb.PropertyKey{ 393 Name: "test-key-name-0", 394 Type: dstypes.SpecPropertyKeyType(2), 395 }, 396 }, 397 }, 398 }, 399 }, 400 ), 401 Status: vegapb.DataSourceSpec_STATUS_ACTIVE, 402 }, 403 }, 404 }, 405 } 406 } 407 408 func TestOracleSpec_GetSpecsWithCursorPagination(t *testing.T) { 409 t.Run("should return the request spec of spec id is requested", testOracleSpecPaginationGetSpecID) 410 t.Run("should return all specs if no spec id and no pagination is provided", testOracleSpecPaginationNoPagination) 411 t.Run("should return the first page if no spec id and first is provided", testOracleSpecPaginationFirst) 412 t.Run("should return the last page if no spec id and last is provided", testOracleSpecPaginationLast) 413 t.Run("should return the requested page if no spec id and first and after is provided", testOracleSpecPaginationFirstAfter) 414 t.Run("should return the requested page if no spec id and last and before is provided", testOracleSpecPaginationLastBefore) 415 416 t.Run("should return all specs if no spec id and no pagination is provided - newest first", testOracleSpecPaginationNoPaginationNewestFirst) 417 t.Run("should return the first page if no spec id and first is provided - newest first", testOracleSpecPaginationFirstNewestFirst) 418 t.Run("should return the last page if no spec id and last is provided - newest first", testOracleSpecPaginationLastNewestFirst) 419 t.Run("should return the requested page if no spec id and first and after is provided - newest first", testOracleSpecPaginationFirstAfterNewestFirst) 420 t.Run("should return the requested page if no spec id and last and before is provided - newest first", testOracleSpecPaginationLastBeforeNewestFirst) 421 } 422 423 func createOracleSpecPaginationTestData(t *testing.T, ctx context.Context, bs *sqlstore.Blocks, os *sqlstore.OracleSpec) []entities.OracleSpec { 424 t.Helper() 425 specs := make([]entities.OracleSpec, 0, 10) 426 427 block := addTestBlockForTime(t, ctx, bs, time.Now().Truncate(time.Second)) 428 429 for i := 0; i < 10; i++ { 430 pubKey := dstypes.CreateSignerFromString(GenerateID(), dstypes.SignerTypePubKey) 431 432 spec := entities.OracleSpec{ 433 ExternalDataSourceSpec: &entities.ExternalDataSourceSpec{ 434 Spec: &entities.DataSourceSpec{ 435 ID: entities.SpecID(fmt.Sprintf("deadbeef%02d", i+1)), 436 CreatedAt: time.Now().Truncate(time.Microsecond), 437 UpdatedAt: time.Now().Truncate(time.Microsecond), 438 Data: &entities.DataSourceDefinition{ 439 DataSourceDefinition: &vegapb.DataSourceDefinition{ 440 SourceType: &vegapb.DataSourceDefinition_External{ 441 External: &vegapb.DataSourceDefinitionExternal{ 442 SourceType: &vegapb.DataSourceDefinitionExternal_Oracle{ 443 Oracle: &vegapb.DataSourceSpecConfiguration{ 444 Signers: []*datapb.Signer{ 445 { 446 Signer: &datapb.Signer_PubKey{ 447 PubKey: pubKey.IntoProto().GetPubKey(), 448 }, 449 }, 450 }, 451 Filters: nil, 452 }, 453 }, 454 }, 455 }, 456 }, 457 }, 458 Status: entities.OracleSpecActive, 459 VegaTime: block.VegaTime, 460 }, 461 }, 462 } 463 464 err := os.Upsert(ctx, &spec) 465 require.NoError(t, err) 466 specs = append(specs, spec) 467 } 468 469 return specs 470 } 471 472 func testOracleSpecPaginationGetSpecID(t *testing.T) { 473 ctx := tempTransaction(t) 474 475 bs, os, _ := setupOracleSpecTest(t) 476 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 477 478 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "deadbeef05", entities.CursorPagination{}) 479 require.NoError(t, err) 480 481 assert.Equal(t, specs[4], got[0]) 482 assert.Equal(t, entities.PageInfo{ 483 HasNextPage: false, 484 HasPreviousPage: false, 485 StartCursor: specs[4].Cursor().Encode(), 486 EndCursor: specs[4].Cursor().Encode(), 487 }, pageInfo) 488 } 489 490 func testOracleSpecPaginationNoPagination(t *testing.T) { 491 ctx := tempTransaction(t) 492 493 bs, os, _ := setupOracleSpecTest(t) 494 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 495 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", entities.CursorPagination{}) 496 require.NoError(t, err) 497 498 assert.Equal(t, specs, got) 499 assert.Equal(t, entities.PageInfo{ 500 HasNextPage: false, 501 HasPreviousPage: false, 502 StartCursor: specs[0].Cursor().Encode(), 503 EndCursor: specs[9].Cursor().Encode(), 504 }, pageInfo) 505 } 506 507 func testOracleSpecPaginationFirst(t *testing.T) { 508 ctx := tempTransaction(t) 509 510 bs, os, _ := setupOracleSpecTest(t) 511 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 512 first := int32(3) 513 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 514 require.NoError(t, err) 515 516 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 517 require.NoError(t, err) 518 519 assert.Equal(t, specs[:3], got) 520 assert.Equal(t, entities.PageInfo{ 521 HasNextPage: true, 522 HasPreviousPage: false, 523 StartCursor: specs[0].Cursor().Encode(), 524 EndCursor: specs[2].Cursor().Encode(), 525 }, pageInfo) 526 } 527 528 func testOracleSpecPaginationLast(t *testing.T) { 529 ctx := tempTransaction(t) 530 531 bs, os, _ := setupOracleSpecTest(t) 532 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 533 last := int32(3) 534 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 535 require.NoError(t, err) 536 537 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 538 require.NoError(t, err) 539 540 assert.Equal(t, specs[7:], got) 541 assert.Equal(t, entities.PageInfo{ 542 HasNextPage: false, 543 HasPreviousPage: true, 544 StartCursor: specs[7].Cursor().Encode(), 545 EndCursor: specs[9].Cursor().Encode(), 546 }, pageInfo) 547 } 548 549 func testOracleSpecPaginationFirstAfter(t *testing.T) { 550 ctx := tempTransaction(t) 551 552 bs, os, _ := setupOracleSpecTest(t) 553 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 554 first := int32(3) 555 after := specs[2].Cursor().Encode() 556 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 557 require.NoError(t, err) 558 559 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 560 require.NoError(t, err) 561 562 assert.Equal(t, specs[3:6], got) 563 assert.Equal(t, entities.PageInfo{ 564 HasNextPage: true, 565 HasPreviousPage: true, 566 StartCursor: specs[3].Cursor().Encode(), 567 EndCursor: specs[5].Cursor().Encode(), 568 }, pageInfo) 569 } 570 571 func testOracleSpecPaginationLastBefore(t *testing.T) { 572 ctx := tempTransaction(t) 573 574 bs, os, _ := setupOracleSpecTest(t) 575 specs := createOracleSpecPaginationTestData(t, ctx, bs, os) 576 last := int32(3) 577 before := specs[7].Cursor().Encode() 578 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 579 require.NoError(t, err) 580 581 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 582 require.NoError(t, err) 583 584 assert.Equal(t, specs[4:7], got) 585 assert.Equal(t, entities.PageInfo{ 586 HasNextPage: true, 587 HasPreviousPage: true, 588 StartCursor: specs[4].Cursor().Encode(), 589 EndCursor: specs[6].Cursor().Encode(), 590 }, pageInfo) 591 } 592 593 func testOracleSpecPaginationNoPaginationNewestFirst(t *testing.T) { 594 ctx := tempTransaction(t) 595 596 bs, os, _ := setupOracleSpecTest(t) 597 specs := entities.ReverseSlice(createOracleSpecPaginationTestData(t, ctx, bs, os)) 598 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", entities.CursorPagination{NewestFirst: true}) 599 require.NoError(t, err) 600 601 assert.Equal(t, specs, got) 602 assert.Equal(t, entities.PageInfo{ 603 HasNextPage: false, 604 HasPreviousPage: false, 605 StartCursor: specs[0].Cursor().Encode(), 606 EndCursor: specs[9].Cursor().Encode(), 607 }, pageInfo) 608 } 609 610 func testOracleSpecPaginationFirstNewestFirst(t *testing.T) { 611 ctx := tempTransaction(t) 612 613 bs, os, _ := setupOracleSpecTest(t) 614 specs := entities.ReverseSlice(createOracleSpecPaginationTestData(t, ctx, bs, os)) 615 first := int32(3) 616 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 617 require.NoError(t, err) 618 619 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 620 require.NoError(t, err) 621 622 assert.Equal(t, specs[:3], got) 623 assert.Equal(t, entities.PageInfo{ 624 HasNextPage: true, 625 HasPreviousPage: false, 626 StartCursor: specs[0].Cursor().Encode(), 627 EndCursor: specs[2].Cursor().Encode(), 628 }, pageInfo) 629 } 630 631 func testOracleSpecPaginationLastNewestFirst(t *testing.T) { 632 ctx := tempTransaction(t) 633 634 bs, os, _ := setupOracleSpecTest(t) 635 specs := entities.ReverseSlice(createOracleSpecPaginationTestData(t, ctx, bs, os)) 636 last := int32(3) 637 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 638 require.NoError(t, err) 639 640 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 641 require.NoError(t, err) 642 643 assert.Equal(t, specs[7:], got) 644 assert.Equal(t, entities.PageInfo{ 645 HasNextPage: false, 646 HasPreviousPage: true, 647 StartCursor: specs[7].Cursor().Encode(), 648 EndCursor: specs[9].Cursor().Encode(), 649 }, pageInfo) 650 } 651 652 func testOracleSpecPaginationFirstAfterNewestFirst(t *testing.T) { 653 ctx := tempTransaction(t) 654 655 bs, os, _ := setupOracleSpecTest(t) 656 specs := entities.ReverseSlice(createOracleSpecPaginationTestData(t, ctx, bs, os)) 657 first := int32(3) 658 after := specs[2].Cursor().Encode() 659 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 660 require.NoError(t, err) 661 662 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 663 require.NoError(t, err) 664 665 assert.Equal(t, specs[3:6], got) 666 assert.Equal(t, entities.PageInfo{ 667 HasNextPage: true, 668 HasPreviousPage: true, 669 StartCursor: specs[3].Cursor().Encode(), 670 EndCursor: specs[5].Cursor().Encode(), 671 }, pageInfo) 672 } 673 674 func testOracleSpecPaginationLastBeforeNewestFirst(t *testing.T) { 675 ctx := tempTransaction(t) 676 677 bs, os, _ := setupOracleSpecTest(t) 678 specs := entities.ReverseSlice(createOracleSpecPaginationTestData(t, ctx, bs, os)) 679 last := int32(3) 680 before := specs[7].Cursor().Encode() 681 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 682 require.NoError(t, err) 683 684 got, pageInfo, err := os.GetSpecsWithCursorPagination(ctx, "", pagination) 685 require.NoError(t, err) 686 687 assert.Equal(t, specs[4:7], got) 688 assert.Equal(t, entities.PageInfo{ 689 HasNextPage: true, 690 HasPreviousPage: true, 691 StartCursor: specs[4].Cursor().Encode(), 692 EndCursor: specs[6].Cursor().Encode(), 693 }, pageInfo) 694 } 695 696 func TestOracleSpecStatusEnum(t *testing.T) { 697 var oracleSpecStatus vegapb.DataSourceSpec_Status 698 states := getEnums(t, oracleSpecStatus) 699 assert.Len(t, states, 3) 700 for s, state := range states { 701 t.Run(state, func(t *testing.T) { 702 ctx := tempTransaction(t) 703 704 bs, os, _ := setupOracleSpecTest(t) 705 706 block := addTestBlock(t, ctx, bs) 707 specProtos := getTestSpecs() 708 709 proto := specProtos[0] 710 proto.ExternalDataSourceSpec.Spec.Status = vegapb.DataSourceSpec_Status(s) 711 data := entities.OracleSpecFromProto(proto, generateTxHash(), block.VegaTime) 712 assert.NoError(t, os.Upsert(ctx, data)) 713 714 got, err := os.GetByTxHash(ctx, data.ExternalDataSourceSpec.Spec.TxHash) 715 require.NoError(t, err) 716 assert.Len(t, got, 1) 717 assert.Equal(t, data.ExternalDataSourceSpec.Spec.Status, got[0].ExternalDataSourceSpec.Spec.Status) 718 }) 719 } 720 }