code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/markets_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 "testing" 21 "time" 22 23 dstypes "code.vegaprotocol.io/vega/core/datasource/common" 24 "code.vegaprotocol.io/vega/datanode/entities" 25 "code.vegaprotocol.io/vega/datanode/sqlstore" 26 "code.vegaprotocol.io/vega/libs/num" 27 "code.vegaprotocol.io/vega/protos/vega" 28 v1 "code.vegaprotocol.io/vega/protos/vega/data/v1" 29 30 "github.com/georgysavva/scany/pgxscan" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 "google.golang.org/protobuf/proto" 34 ) 35 36 func TestMarkets_Add(t *testing.T) { 37 t.Run("Add should insert a valid market record", shouldInsertAValidMarketRecord) 38 t.Run("Add should update a valid market record if the block number already exists", shouldUpdateAValidMarketRecord) 39 t.Run("Add should insert a valid spot market record", shouldInsertAValidSpotMarketRecord) 40 t.Run("Add should insert a valid perpetual market record", shouldInsertAValidPerpetualMarketRecord) 41 } 42 43 func TestMarkets_Get(t *testing.T) { 44 t.Run("GetByID should return the request market if it exists", getByIDShouldReturnTheRequestedMarketIfItExists) 45 t.Run("GetByID should return error if the market does not exist", getByIDShouldReturnErrorIfTheMarketDoesNotExist) 46 t.Run("GetAllPaged should not include rejected markets", getAllPagedShouldNotIncludeRejectedMarkets) 47 t.Run("GetByTxHash", getByTxHashReturnsMatchingMarkets) 48 t.Run("GetByID should return a spot market if it exists", getByIDShouldReturnASpotMarketIfItExists) 49 t.Run("GetByID should return a perpetual market if it exists", getByIDShouldReturnAPerpetualMarketIfItExists) 50 } 51 52 func TestGetAllFees(t *testing.T) { 53 bs, md := setupMarketsTest(t) 54 55 ctx := tempTransaction(t) 56 57 block := addTestBlock(t, ctx, bs) 58 59 market := entities.Market{ 60 ID: "deadbeef", 61 TxHash: generateTxHash(), 62 VegaTime: block.VegaTime, 63 State: entities.MarketStateActive, 64 Fees: entities.Fees{ 65 Factors: &entities.FeeFactors{ 66 MakerFee: "0.1", 67 InfrastructureFee: "0.2", 68 LiquidityFee: "0.3", 69 BuyBackFee: "0.4", 70 TreasuryFee: "0.5", 71 }, 72 }, 73 } 74 err := md.Upsert(ctx, &market) 75 require.NoError(t, err) 76 77 market2 := entities.Market{ 78 ID: "beefdead", 79 TxHash: generateTxHash(), 80 VegaTime: block.VegaTime, 81 State: entities.MarketStateActive, 82 Fees: entities.Fees{ 83 Factors: &entities.FeeFactors{ 84 MakerFee: "0.5", 85 InfrastructureFee: "0.4", 86 LiquidityFee: "0.3", 87 BuyBackFee: "0.2", 88 TreasuryFee: "0.1", 89 }, 90 }, 91 } 92 err = md.Upsert(ctx, &market2) 93 require.NoError(t, err, "Saving market entity to database") 94 95 mkts, err := md.GetAllFees(ctx) 96 require.NoError(t, err) 97 require.Equal(t, 2, len(mkts)) 98 99 require.Equal(t, "beefdead", mkts[0].ID.String()) 100 require.Equal(t, "0.5", mkts[0].Fees.Factors.MakerFee) 101 require.Equal(t, "0.4", mkts[0].Fees.Factors.InfrastructureFee) 102 require.Equal(t, "0.3", mkts[0].Fees.Factors.LiquidityFee) 103 require.Equal(t, "0.2", mkts[0].Fees.Factors.BuyBackFee) 104 require.Equal(t, "0.1", mkts[0].Fees.Factors.TreasuryFee) 105 require.Equal(t, "deadbeef", mkts[1].ID.String()) 106 require.Equal(t, "0.1", mkts[1].Fees.Factors.MakerFee) 107 require.Equal(t, "0.2", mkts[1].Fees.Factors.InfrastructureFee) 108 require.Equal(t, "0.3", mkts[1].Fees.Factors.LiquidityFee) 109 require.Equal(t, "0.4", mkts[1].Fees.Factors.BuyBackFee) 110 require.Equal(t, "0.5", mkts[1].Fees.Factors.TreasuryFee) 111 } 112 113 func getByIDShouldReturnTheRequestedMarketIfItExists(t *testing.T) { 114 bs, md := setupMarketsTest(t) 115 116 ctx := tempTransaction(t) 117 118 block := addTestBlock(t, ctx, bs) 119 120 market := entities.Market{ 121 ID: "deadbeef", 122 TxHash: generateTxHash(), 123 VegaTime: block.VegaTime, 124 State: entities.MarketStateActive, 125 } 126 err := md.Upsert(ctx, &market) 127 require.NoError(t, err, "Saving market entity to database") 128 129 marketFromDB, err := md.GetByID(ctx, market.ID.String()) 130 require.NoError(t, err) 131 assert.Equal(t, market.ID, marketFromDB.ID) 132 assert.Equal(t, market.TxHash, marketFromDB.TxHash) 133 assert.Equal(t, market.VegaTime, marketFromDB.VegaTime) 134 assert.Equal(t, market.State, marketFromDB.State) 135 } 136 137 func getByIDShouldReturnASpotMarketIfItExists(t *testing.T) { 138 bs, md := setupMarketsTest(t) 139 140 ctx := tempTransaction(t) 141 142 block := addTestBlock(t, ctx, bs) 143 144 marketProto := getTestSpotMarket() 145 146 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 147 require.NoError(t, err, "Converting market proto to database entity") 148 err = md.Upsert(ctx, market) 149 require.NoError(t, err, "Saving market entity to database") 150 151 marketFromDB, err := md.GetByID(ctx, market.ID.String()) 152 require.NoError(t, err) 153 marketToProto := marketFromDB.ToProto() 154 assert.IsType(t, &vega.Spot{}, marketToProto.TradableInstrument.GetInstrument().GetSpot()) 155 } 156 157 func getByIDShouldReturnAPerpetualMarketIfItExists(t *testing.T) { 158 bs, md := setupMarketsTest(t) 159 160 ctx := tempTransaction(t) 161 162 block := addTestBlock(t, ctx, bs) 163 164 marketProto := getTestSpotMarket() 165 166 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 167 require.NoError(t, err, "Converting market proto to database entity") 168 err = md.Upsert(ctx, market) 169 require.NoError(t, err, "Saving market entity to database") 170 171 marketFromDB, err := md.GetByID(ctx, market.ID.String()) 172 require.NoError(t, err) 173 marketToProto := marketFromDB.ToProto() 174 assert.IsType(t, &vega.Perpetual{}, marketToProto.TradableInstrument.GetInstrument().GetPerpetual()) 175 } 176 177 func getByTxHashReturnsMatchingMarkets(t *testing.T) { 178 bs, md := setupMarketsTest(t) 179 180 ctx := tempTransaction(t) 181 182 block := addTestBlock(t, ctx, bs) 183 184 market := entities.Market{ 185 ID: "deadbeef", 186 TxHash: generateTxHash(), 187 VegaTime: block.VegaTime, 188 State: entities.MarketStateActive, 189 } 190 err := md.Upsert(ctx, &market) 191 require.NoError(t, err, "Saving market entity to database") 192 193 foundMarkets, err := md.GetByTxHash(ctx, market.TxHash) 194 require.NoError(t, err) 195 require.Len(t, foundMarkets, 1) 196 assert.Equal(t, market.ID, foundMarkets[0].ID) 197 assert.Equal(t, market.TxHash, foundMarkets[0].TxHash) 198 assert.Equal(t, market.VegaTime, foundMarkets[0].VegaTime) 199 assert.Equal(t, market.State, foundMarkets[0].State) 200 } 201 202 func getByIDShouldReturnErrorIfTheMarketDoesNotExist(t *testing.T) { 203 bs, md := setupMarketsTest(t) 204 205 ctx := tempTransaction(t) 206 207 block := addTestBlock(t, ctx, bs) 208 209 market := entities.Market{ 210 ID: "deadbeef", 211 TxHash: generateTxHash(), 212 VegaTime: block.VegaTime, 213 State: entities.MarketStateActive, 214 } 215 err := md.Upsert(ctx, &market) 216 require.NoError(t, err, "Saving market entity to database") 217 218 _, err = md.GetByID(ctx, "not-a-market") 219 require.Error(t, err) 220 } 221 222 func getAllPagedShouldNotIncludeRejectedMarkets(t *testing.T) { 223 bs, md := setupMarketsTest(t) 224 225 ctx := tempTransaction(t) 226 227 block := addTestBlock(t, ctx, bs) 228 229 market := entities.Market{ 230 ID: "deadbeef", 231 TxHash: generateTxHash(), 232 VegaTime: block.VegaTime, 233 State: entities.MarketStateActive, 234 } 235 err := md.Upsert(ctx, &market) 236 require.NoError(t, err, "Saving market entity to database") 237 238 rejected := entities.Market{ 239 ID: "DEADBAAD", 240 TxHash: generateTxHash(), 241 VegaTime: block.VegaTime, 242 State: entities.MarketStateRejected, 243 } 244 err = md.Upsert(ctx, &rejected) 245 require.NoError(t, err, "Saving market entity to database") 246 247 markets, pageInfo, err := md.GetAllPaged(ctx, "", entities.CursorPagination{}, true) 248 require.NoError(t, err) 249 assert.Len(t, markets, 1) 250 assert.Equal(t, market.ID, markets[0].ID) 251 assert.Equal(t, market.TxHash, markets[0].TxHash) 252 assert.Equal(t, market.VegaTime, markets[0].VegaTime) 253 assert.Equal(t, market.State, markets[0].State) 254 assert.Equal(t, entities.PageInfo{ 255 HasNextPage: false, 256 HasPreviousPage: false, 257 StartCursor: market.Cursor().Encode(), 258 EndCursor: market.Cursor().Encode(), 259 }, pageInfo) 260 } 261 262 func shouldInsertAValidMarketRecord(t *testing.T) { 263 bs, md := setupMarketsTest(t) 264 265 ctx := tempTransaction(t) 266 267 var rowCount int 268 269 err := connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 270 require.NoError(t, err) 271 assert.Equal(t, 0, rowCount) 272 273 block := addTestBlock(t, ctx, bs) 274 275 marketProto := getTestFutureMarket(true) 276 277 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 278 require.NoError(t, err, "Converting market proto to database entity") 279 280 err = md.Upsert(ctx, market) 281 require.NoError(t, err, "Saving market entity to database") 282 err = connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 283 assert.NoError(t, err) 284 assert.Equal(t, 1, rowCount) 285 } 286 287 func setupMarketsTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.Markets) { 288 t.Helper() 289 bs := sqlstore.NewBlocks(connectionSource) 290 md := sqlstore.NewMarkets(connectionSource) 291 return bs, md 292 } 293 294 func shouldUpdateAValidMarketRecord(t *testing.T) { 295 bs, md := setupMarketsTest(t) 296 ctx := tempTransaction(t) 297 298 var rowCount int 299 300 t.Run("should have no markets in the database", func(t *testing.T) { 301 err := connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 302 require.NoError(t, err) 303 assert.Equal(t, 0, rowCount) 304 }) 305 306 var block entities.Block 307 var marketProto *vega.Market 308 309 t.Run("should insert a valid market record to the database with liquidation strategy", func(t *testing.T) { 310 block = addTestBlock(t, ctx, bs) 311 marketProto = getTestFutureMarketWithLiquidationStrategy(false) 312 313 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 314 require.NoError(t, err, "Converting market proto to database entity") 315 316 err = md.Upsert(ctx, market) 317 require.NoError(t, err, "Saving market entity to database") 318 319 var got entities.Market 320 err = pgxscan.Get(ctx, connectionSource, &got, `select * from markets where id = $1 and vega_time = $2`, market.ID, market.VegaTime) 321 assert.NoError(t, err) 322 assert.Equal(t, "TEST_INSTRUMENT", market.InstrumentID) 323 assert.NotNil(t, got.LiquidationStrategy) 324 325 assert.Equal(t, marketProto.TradableInstrument, got.TradableInstrument.ToProto()) 326 assert.Equal(t, marketProto.LiquidationStrategy, got.LiquidationStrategy.IntoProto()) 327 }) 328 329 t.Run("should insert a valid market record to the database", func(t *testing.T) { 330 block = addTestBlock(t, ctx, bs) 331 marketProto = getTestFutureMarket(false) 332 333 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 334 require.NoError(t, err, "Converting market proto to database entity") 335 336 err = md.Upsert(ctx, market) 337 require.NoError(t, err, "Saving market entity to database") 338 339 var got entities.Market 340 err = pgxscan.Get(ctx, connectionSource, &got, `select * from markets where id = $1 and vega_time = $2`, market.ID, market.VegaTime) 341 assert.NoError(t, err) 342 assert.Equal(t, "TEST_INSTRUMENT", market.InstrumentID) 343 344 assert.Equal(t, marketProto.TradableInstrument, got.TradableInstrument.ToProto()) 345 }) 346 347 marketProto.TradableInstrument.Instrument.Name = "Updated Test Instrument" 348 marketProto.TradableInstrument.Instrument.Metadata.Tags = append(marketProto.TradableInstrument.Instrument.Metadata.Tags, "CCC") 349 350 t.Run("should update a valid market record to the database if the block number already exists", func(t *testing.T) { 351 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 352 353 require.NoError(t, err, "Converting market proto to database entity") 354 355 err = md.Upsert(ctx, market) 356 require.NoError(t, err, "Saving market entity to database") 357 358 var got entities.Market 359 err = pgxscan.Get(ctx, connectionSource, &got, `select * from markets where id = $1 and vega_time = $2`, market.ID, market.VegaTime) 360 assert.NoError(t, err) 361 assert.Equal(t, "TEST_INSTRUMENT", market.InstrumentID) 362 363 assert.Equal(t, marketProto.TradableInstrument, got.TradableInstrument.ToProto()) 364 }) 365 366 t.Run("should add the updated market record to the database if the block number has changed", func(t *testing.T) { 367 newMarketProto := proto.Clone(marketProto).(*vega.Market) 368 newMarketProto.TradableInstrument.Instrument.Metadata.Tags = append(newMarketProto.TradableInstrument.Instrument.Metadata.Tags, "DDD") 369 newBlock := addTestBlockForTime(t, ctx, bs, time.Now().Add(time.Second)) 370 371 market, err := entities.NewMarketFromProto(newMarketProto, generateTxHash(), newBlock.VegaTime) 372 require.NoError(t, err, "Converting market proto to database entity") 373 374 err = md.Upsert(ctx, market) 375 require.NoError(t, err, "Saving market entity to database") 376 377 err = connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 378 require.NoError(t, err) 379 assert.Equal(t, 3, rowCount) 380 381 var gotFirstBlock, gotSecondBlock entities.Market 382 383 err = pgxscan.Get(ctx, connectionSource, &gotFirstBlock, `select * from markets where id = $1 and vega_time = $2`, market.ID, block.VegaTime) 384 assert.NoError(t, err) 385 assert.Equal(t, "TEST_INSTRUMENT", market.InstrumentID) 386 387 assert.Equal(t, marketProto.TradableInstrument, gotFirstBlock.TradableInstrument.ToProto()) 388 389 err = pgxscan.Get(ctx, connectionSource, &gotSecondBlock, `select * from markets where id = $1 and vega_time = $2`, market.ID, newBlock.VegaTime) 390 assert.NoError(t, err) 391 assert.Equal(t, "TEST_INSTRUMENT", market.InstrumentID) 392 393 assert.Equal(t, newMarketProto.TradableInstrument, gotSecondBlock.TradableInstrument.ToProto()) 394 }) 395 } 396 397 func shouldInsertAValidSpotMarketRecord(t *testing.T) { 398 bs, md := setupMarketsTest(t) 399 400 ctx := tempTransaction(t) 401 402 var rowCount int 403 404 err := connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 405 require.NoError(t, err) 406 assert.Equal(t, 0, rowCount) 407 408 block := addTestBlock(t, ctx, bs) 409 410 marketProto := getTestSpotMarket() 411 412 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 413 require.NoError(t, err, "Converting market proto to database entity") 414 415 err = md.Upsert(ctx, market) 416 require.NoError(t, err, "Saving market entity to database") 417 err = connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 418 assert.NoError(t, err) 419 assert.Equal(t, 1, rowCount) 420 } 421 422 func shouldInsertAValidPerpetualMarketRecord(t *testing.T) { 423 bs, md := setupMarketsTest(t) 424 425 ctx := tempTransaction(t) 426 427 var rowCount int 428 429 err := connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 430 require.NoError(t, err) 431 assert.Equal(t, 0, rowCount) 432 433 block := addTestBlock(t, ctx, bs) 434 435 marketProto := getTestPerpetualMarket() 436 437 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 438 require.NoError(t, err, "Converting market proto to database entity") 439 440 err = md.Upsert(ctx, market) 441 require.NoError(t, err, "Saving market entity to database") 442 err = connectionSource.QueryRow(ctx, `select count(*) from markets`).Scan(&rowCount) 443 assert.NoError(t, err) 444 assert.Equal(t, 1, rowCount) 445 } 446 447 func getTestSpotMarket() *vega.Market { 448 mkt := getTestMarket() 449 450 mkt.TradableInstrument.Instrument.Product = &vega.Instrument_Spot{ 451 Spot: &vega.Spot{ 452 BaseAsset: "Ethereum", 453 QuoteAsset: "USD", 454 }, 455 } 456 457 return mkt 458 } 459 460 func getTestPerpetualMarket() *vega.Market { 461 pk := dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey) 462 mkt := getTestMarket() 463 mkt.TradableInstrument.Instrument.Product = &vega.Instrument_Perpetual{ 464 Perpetual: &vega.Perpetual{ 465 SettlementAsset: "Ethereum/Ether", 466 QuoteName: "ETH-230929", 467 MarginFundingFactor: "0.5", 468 InterestRate: "0.012", 469 ClampLowerBound: "0.2", 470 ClampUpperBound: "0.8", 471 DataSourceSpecForSettlementSchedule: &vega.DataSourceSpec{ 472 Id: "test-settlement-schedule", 473 CreatedAt: time.Now().UnixNano(), 474 UpdatedAt: time.Now().UnixNano(), 475 Data: vega.NewDataSourceDefinition( 476 vega.DataSourceContentTypeOracle, 477 ).SetOracleConfig( 478 &vega.DataSourceDefinitionExternal_Oracle{ 479 Oracle: &vega.DataSourceSpecConfiguration{ 480 Signers: []*v1.Signer{pk.IntoProto()}, 481 Filters: []*v1.Filter{ 482 { 483 Key: &v1.PropertyKey{ 484 Name: "prices.ETH.value", 485 Type: v1.PropertyKey_TYPE_INTEGER, 486 }, 487 Conditions: []*v1.Condition{}, 488 }, 489 }, 490 }, 491 }, 492 ), 493 Status: vega.DataSourceSpec_STATUS_ACTIVE, 494 }, 495 DataSourceSpecForSettlementData: &vega.DataSourceSpec{ 496 Id: "test-settlement-data", 497 CreatedAt: time.Now().UnixNano(), 498 UpdatedAt: time.Now().UnixNano(), 499 Data: vega.NewDataSourceDefinition( 500 vega.DataSourceContentTypeOracle, 501 ).SetOracleConfig( 502 &vega.DataSourceDefinitionExternal_Oracle{ 503 Oracle: &vega.DataSourceSpecConfiguration{ 504 Signers: []*v1.Signer{pk.IntoProto()}, 505 Filters: []*v1.Filter{ 506 { 507 Key: &v1.PropertyKey{ 508 Name: "prices.ETH.value", 509 Type: v1.PropertyKey_TYPE_INTEGER, 510 }, 511 Conditions: []*v1.Condition{}, 512 }, 513 }, 514 }, 515 }, 516 ), 517 Status: vega.DataSourceSpec_STATUS_ACTIVE, 518 }, 519 DataSourceSpecBinding: &vega.DataSourceSpecToPerpetualBinding{ 520 SettlementDataProperty: "prices.ETH.value", 521 SettlementScheduleProperty: "2023-09-29T00:00:00.000000000Z", 522 }, 523 }, 524 } 525 return mkt 526 } 527 528 func getTestMarket() *vega.Market { 529 return &vega.Market{ 530 Id: GenerateID(), 531 TradableInstrument: &vega.TradableInstrument{ 532 Instrument: &vega.Instrument{ 533 Id: "Crypto/BTCUSD/Futures/Dec19", 534 Code: "FX:BTCUSD/DEC19", 535 Name: "December 2019 BTC vs USD future", 536 Metadata: &vega.InstrumentMetadata{ 537 Tags: []string{ 538 "asset_class:fx/crypto", 539 "product:futures", 540 }, 541 }, 542 }, 543 MarginCalculator: &vega.MarginCalculator{ 544 ScalingFactors: &vega.ScalingFactors{ 545 SearchLevel: 1.1, 546 InitialMargin: 1.2, 547 CollateralRelease: 1.4, 548 }, 549 }, 550 RiskModel: &vega.TradableInstrument_LogNormalRiskModel{ 551 LogNormalRiskModel: &vega.LogNormalRiskModel{ 552 RiskAversionParameter: 0.01, 553 Tau: 1.0 / 365.25 / 24, 554 Params: &vega.LogNormalModelParams{ 555 Mu: 0, 556 R: 0.016, 557 Sigma: 0.09, 558 }, 559 }, 560 }, 561 }, 562 Fees: &vega.Fees{ 563 Factors: &vega.FeeFactors{ 564 MakerFee: "", 565 InfrastructureFee: "", 566 LiquidityFee: "", 567 }, 568 LiquidityFeeSettings: &vega.LiquidityFeeSettings{ 569 Method: vega.LiquidityFeeSettings_METHOD_MARGINAL_COST, 570 }, 571 }, 572 OpeningAuction: &vega.AuctionDuration{ 573 Duration: 0, 574 Volume: 0, 575 }, 576 PriceMonitoringSettings: &vega.PriceMonitoringSettings{ 577 Parameters: &vega.PriceMonitoringParameters{ 578 Triggers: []*vega.PriceMonitoringTrigger{ 579 { 580 Horizon: 0, 581 Probability: "", 582 AuctionExtension: 0, 583 }, 584 }, 585 }, 586 }, 587 LiquidityMonitoringParameters: &vega.LiquidityMonitoringParameters{ 588 TargetStakeParameters: &vega.TargetStakeParameters{ 589 TimeWindow: 0, 590 ScalingFactor: 0, 591 }, 592 }, 593 TradingMode: vega.Market_TRADING_MODE_CONTINUOUS, 594 State: vega.Market_STATE_ACTIVE, 595 MarketTimestamps: &vega.MarketTimestamps{ 596 Proposed: 0, 597 Pending: 0, 598 Open: 0, 599 Close: 0, 600 }, 601 PositionDecimalPlaces: 8, 602 LpPriceRange: "0.95", 603 LinearSlippageFactor: "1.23", 604 QuadraticSlippageFactor: "5.67", 605 } 606 } 607 608 func getTestFutureMarketWithLiquidationStrategy(termInt bool) *vega.Market { 609 mkt := getTestFutureMarket(termInt) 610 mkt.LiquidationStrategy = &vega.LiquidationStrategy{ 611 DisposalTimeStep: 10, 612 DisposalFraction: "0.1", 613 FullDisposalSize: 20, 614 MaxFractionConsumed: "0.01", 615 DisposalSlippageRange: "0.1", 616 } 617 return mkt 618 } 619 620 func getTestFutureMarket(termInt bool) *vega.Market { 621 term := &vega.DataSourceSpec{ 622 Id: "", 623 CreatedAt: 0, 624 UpdatedAt: 0, 625 Data: vega.NewDataSourceDefinition( 626 vega.DataSourceContentTypeOracle, 627 ).SetOracleConfig( 628 &vega.DataSourceDefinitionExternal_Oracle{ 629 Oracle: &vega.DataSourceSpecConfiguration{ 630 Signers: nil, 631 Filters: nil, 632 }, 633 }, 634 ), 635 Status: 0, 636 } 637 638 if termInt { 639 term = &vega.DataSourceSpec{ 640 Id: "", 641 CreatedAt: 0, 642 UpdatedAt: 0, 643 Data: vega.NewDataSourceDefinition( 644 vega.DataSourceContentTypeInternalTimeTermination, 645 ).SetTimeTriggerConditionConfig( 646 []*v1.Condition{ 647 { 648 Operator: v1.Condition_OPERATOR_GREATER_THAN, 649 Value: "test-value", 650 }, 651 }, 652 ), 653 Status: 0, 654 } 655 } 656 657 return &vega.Market{ 658 Id: "DEADBEEF", 659 TradableInstrument: &vega.TradableInstrument{ 660 Instrument: &vega.Instrument{ 661 Id: "TEST_INSTRUMENT", 662 Code: "TEST", 663 Name: "Test Instrument", 664 Metadata: &vega.InstrumentMetadata{ 665 Tags: []string{"AAA", "BBB"}, 666 }, 667 Product: &vega.Instrument_Future{ 668 Future: &vega.Future{ 669 SettlementAsset: "Test Asset", 670 QuoteName: "Test Quote", 671 DataSourceSpecForSettlementData: &vega.DataSourceSpec{ 672 Id: "", 673 CreatedAt: 0, 674 UpdatedAt: 0, 675 Data: vega.NewDataSourceDefinition( 676 vega.DataSourceContentTypeOracle, 677 ).SetOracleConfig( 678 &vega.DataSourceDefinitionExternal_Oracle{ 679 Oracle: &vega.DataSourceSpecConfiguration{ 680 Signers: nil, 681 Filters: nil, 682 }, 683 }, 684 ), 685 Status: 0, 686 }, 687 DataSourceSpecForTradingTermination: term, 688 DataSourceSpecBinding: &vega.DataSourceSpecToFutureBinding{ 689 SettlementDataProperty: "", 690 TradingTerminationProperty: "", 691 }, 692 }, 693 }, 694 }, 695 MarginCalculator: &vega.MarginCalculator{ 696 ScalingFactors: &vega.ScalingFactors{ 697 SearchLevel: 0, 698 InitialMargin: 0, 699 CollateralRelease: 0, 700 }, 701 }, 702 RiskModel: &vega.TradableInstrument_SimpleRiskModel{ 703 SimpleRiskModel: &vega.SimpleRiskModel{ 704 Params: &vega.SimpleModelParams{ 705 FactorLong: 0, 706 FactorShort: 0, 707 MaxMoveUp: 0, 708 MinMoveDown: 0, 709 ProbabilityOfTrading: 0, 710 }, 711 }, 712 }, 713 }, 714 DecimalPlaces: 16, 715 Fees: &vega.Fees{ 716 Factors: &vega.FeeFactors{ 717 MakerFee: "", 718 InfrastructureFee: "", 719 LiquidityFee: "", 720 }, 721 LiquidityFeeSettings: &vega.LiquidityFeeSettings{ 722 Method: vega.LiquidityFeeSettings_METHOD_MARGINAL_COST, 723 }, 724 }, 725 OpeningAuction: &vega.AuctionDuration{ 726 Duration: 0, 727 Volume: 0, 728 }, 729 PriceMonitoringSettings: &vega.PriceMonitoringSettings{ 730 Parameters: &vega.PriceMonitoringParameters{ 731 Triggers: []*vega.PriceMonitoringTrigger{ 732 { 733 Horizon: 0, 734 Probability: "", 735 AuctionExtension: 0, 736 }, 737 }, 738 }, 739 }, 740 LiquidityMonitoringParameters: &vega.LiquidityMonitoringParameters{ 741 TargetStakeParameters: &vega.TargetStakeParameters{ 742 TimeWindow: 0, 743 ScalingFactor: 0, 744 }, 745 }, 746 TradingMode: vega.Market_TRADING_MODE_CONTINUOUS, 747 State: vega.Market_STATE_ACTIVE, 748 MarketTimestamps: &vega.MarketTimestamps{ 749 Proposed: 0, 750 Pending: 0, 751 Open: 0, 752 Close: 0, 753 }, 754 PositionDecimalPlaces: 8, 755 LpPriceRange: "0.95", 756 LinearSlippageFactor: "1.23", 757 QuadraticSlippageFactor: "5.67", 758 LiquiditySlaParams: &vega.LiquiditySLAParameters{ 759 PriceRange: "0.75", 760 CommitmentMinTimeFraction: "0.5", 761 PerformanceHysteresisEpochs: 0, 762 SlaCompetitionFactor: "1.0", 763 }, 764 } 765 } 766 767 func populateTestMarkets(ctx context.Context, t *testing.T, bs *sqlstore.Blocks, md *sqlstore.Markets, blockTimes map[string]time.Time) { 768 t.Helper() 769 770 markets := []entities.Market{ 771 { 772 ID: entities.MarketID("02a16077"), 773 InstrumentID: "AAA", 774 }, 775 { 776 ID: entities.MarketID("44eea1bc"), 777 InstrumentID: "BBB", 778 }, 779 { 780 ID: entities.MarketID("65be62cd"), 781 InstrumentID: "CCC", 782 }, 783 { 784 ID: entities.MarketID("7a797e0e"), 785 InstrumentID: "DDD", 786 }, 787 { 788 ID: entities.MarketID("7bb2356e"), 789 InstrumentID: "EEE", 790 }, 791 { 792 ID: entities.MarketID("b7c84b8e"), 793 InstrumentID: "FFF", 794 }, 795 { 796 ID: entities.MarketID("c612300d"), 797 InstrumentID: "GGG", 798 }, 799 { 800 ID: entities.MarketID("c8744329"), 801 InstrumentID: "HHH", 802 }, 803 { 804 ID: entities.MarketID("da8d1803"), 805 InstrumentID: "III", 806 }, 807 { 808 ID: entities.MarketID("fb1528a5"), 809 InstrumentID: "JJJ", 810 }, 811 } 812 813 source := &testBlockSource{bs, time.Now()} 814 for _, market := range markets { 815 block := source.getNextBlock(t, ctx) 816 market.VegaTime = block.VegaTime 817 blockTimes[market.ID.String()] = block.VegaTime 818 err := md.Upsert(ctx, &market) 819 require.NoError(t, err) 820 } 821 } 822 823 func TestMarketsCursorPagination(t *testing.T) { 824 t.Run("Should return the market if Market ID is provided", testCursorPaginationReturnsTheSpecifiedMarket) 825 t.Run("Should return all markets if no market ID and no cursor is provided", testCursorPaginationReturnsAllMarkets) 826 t.Run("Should return the first page when first limit is provided with no after cursor", testCursorPaginationReturnsFirstPage) 827 t.Run("Should return the last page when last limit is provided with first before cursor", testCursorPaginationReturnsLastPage) 828 t.Run("Should return the page specified by the first limit and after cursor", testCursorPaginationReturnsPageTraversingForward) 829 t.Run("Should return the page specified by the last limit and before cursor", testCursorPaginationReturnsPageTraversingBackward) 830 831 t.Run("Should return the market if Market ID is provided - newest first", testCursorPaginationReturnsTheSpecifiedMarketNewestFirst) 832 t.Run("Should return all markets if no market ID and no cursor is provided - newest first", testCursorPaginationReturnsAllMarketsNewestFirst) 833 t.Run("Should return the first page when first limit is provided with no after cursor - newest first", testCursorPaginationReturnsFirstPageNewestFirst) 834 t.Run("Should return the last page when last limit is provided with first before cursor - newest first", testCursorPaginationReturnsLastPageNewestFirst) 835 t.Run("Should return the page specified by the first limit and after cursor - newest first", testCursorPaginationReturnsPageTraversingForwardNewestFirst) 836 t.Run("Should return the page specified by the last limit and before cursor - newest first", testCursorPaginationReturnsPageTraversingBackwardNewestFirst) 837 } 838 839 func testCursorPaginationReturnsTheSpecifiedMarket(t *testing.T) { 840 ctx := tempTransaction(t) 841 842 bs, md := setupMarketsTest(t) 843 844 blockTimes := make(map[string]time.Time) 845 populateTestMarkets(ctx, t, bs, md, blockTimes) 846 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 847 require.NoError(t, err) 848 849 got, pageInfo, err := md.GetAllPaged(ctx, "c612300d", pagination, true) 850 require.NoError(t, err) 851 assert.Equal(t, 1, len(got)) 852 assert.Equal(t, "c612300d", got[0].ID.String()) 853 assert.Equal(t, "GGG", got[0].InstrumentID) 854 855 mc := entities.MarketCursor{ 856 VegaTime: blockTimes["c612300d"], 857 ID: "c612300d", 858 } 859 860 wantStartCursor := entities.NewCursor(mc.String()).Encode() 861 wantEndCursor := entities.NewCursor(mc.String()).Encode() 862 863 assert.Equal(t, entities.PageInfo{ 864 HasNextPage: false, 865 HasPreviousPage: false, 866 StartCursor: wantStartCursor, 867 EndCursor: wantEndCursor, 868 }, pageInfo) 869 } 870 871 func testCursorPaginationReturnsAllMarkets(t *testing.T) { 872 bs, md := setupMarketsTest(t) 873 ctx := tempTransaction(t) 874 875 blockTimes := make(map[string]time.Time) 876 populateTestMarkets(ctx, t, bs, md, blockTimes) 877 878 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 879 require.NoError(t, err) 880 881 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 882 require.NoError(t, err) 883 assert.Equal(t, 10, len(got)) 884 assert.Equal(t, "02a16077", got[0].ID.String()) 885 assert.Equal(t, "fb1528a5", got[9].ID.String()) 886 assert.Equal(t, "AAA", got[0].InstrumentID) 887 assert.Equal(t, "JJJ", got[9].InstrumentID) 888 889 wantStartCursor := entities.NewCursor( 890 entities.MarketCursor{ 891 VegaTime: blockTimes["02a16077"], 892 ID: "02a16077", 893 }.String(), 894 ).Encode() 895 wantEndCursor := entities.NewCursor( 896 entities.MarketCursor{ 897 VegaTime: blockTimes["fb1528a5"], 898 ID: "fb1528a5", 899 }.String(), 900 ).Encode() 901 assert.Equal(t, entities.PageInfo{ 902 HasNextPage: false, 903 HasPreviousPage: false, 904 StartCursor: wantStartCursor, 905 EndCursor: wantEndCursor, 906 }, pageInfo) 907 } 908 909 func testCursorPaginationReturnsFirstPage(t *testing.T) { 910 bs, md := setupMarketsTest(t) 911 ctx := tempTransaction(t) 912 913 blockTimes := make(map[string]time.Time) 914 populateTestMarkets(ctx, t, bs, md, blockTimes) 915 first := int32(3) 916 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 917 require.NoError(t, err) 918 919 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 920 require.NoError(t, err) 921 922 assert.Equal(t, 3, len(got)) 923 assert.Equal(t, "02a16077", got[0].ID.String()) 924 assert.Equal(t, "65be62cd", got[2].ID.String()) 925 assert.Equal(t, "AAA", got[0].InstrumentID) 926 assert.Equal(t, "CCC", got[2].InstrumentID) 927 928 wantStartCursor := entities.NewCursor( 929 entities.MarketCursor{ 930 VegaTime: blockTimes["02a16077"], 931 ID: "02a16077", 932 }.String(), 933 ).Encode() 934 wantEndCursor := entities.NewCursor( 935 entities.MarketCursor{ 936 VegaTime: blockTimes["65be62cd"], 937 ID: "65be62cd", 938 }.String(), 939 ).Encode() 940 assert.Equal(t, entities.PageInfo{ 941 HasNextPage: true, 942 HasPreviousPage: false, 943 StartCursor: wantStartCursor, 944 EndCursor: wantEndCursor, 945 }, pageInfo) 946 } 947 948 func testCursorPaginationReturnsLastPage(t *testing.T) { 949 bs, md := setupMarketsTest(t) 950 ctx := tempTransaction(t) 951 952 blockTimes := make(map[string]time.Time) 953 populateTestMarkets(ctx, t, bs, md, blockTimes) 954 last := int32(3) 955 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 956 require.NoError(t, err) 957 958 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 959 require.NoError(t, err) 960 961 assert.Equal(t, 3, len(got)) 962 assert.Equal(t, "c8744329", got[0].ID.String()) 963 assert.Equal(t, "fb1528a5", got[2].ID.String()) 964 assert.Equal(t, "HHH", got[0].InstrumentID) 965 assert.Equal(t, "JJJ", got[2].InstrumentID) 966 967 wantStartCursor := entities.NewCursor( 968 entities.MarketCursor{ 969 VegaTime: blockTimes["c8744329"], 970 ID: "c8744329", 971 }.String(), 972 ).Encode() 973 wantEndCursor := entities.NewCursor( 974 entities.MarketCursor{ 975 VegaTime: blockTimes["fb1528a5"], 976 ID: "fb1528a5", 977 }.String(), 978 ).Encode() 979 assert.Equal(t, entities.PageInfo{ 980 HasNextPage: false, 981 HasPreviousPage: true, 982 StartCursor: wantStartCursor, 983 EndCursor: wantEndCursor, 984 }, pageInfo) 985 } 986 987 func testCursorPaginationReturnsPageTraversingForward(t *testing.T) { 988 bs, md := setupMarketsTest(t) 989 ctx := tempTransaction(t) 990 991 blockTimes := make(map[string]time.Time) 992 populateTestMarkets(ctx, t, bs, md, blockTimes) 993 first := int32(3) 994 after := entities.NewCursor( 995 entities.MarketCursor{ 996 VegaTime: blockTimes["65be62cd"], 997 ID: "65be62cd", 998 }.String(), 999 ).Encode() 1000 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 1001 require.NoError(t, err) 1002 1003 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1004 require.NoError(t, err) 1005 1006 assert.Equal(t, 3, len(got)) 1007 assert.Equal(t, "7a797e0e", got[0].ID.String()) 1008 assert.Equal(t, "b7c84b8e", got[2].ID.String()) 1009 assert.Equal(t, "DDD", got[0].InstrumentID) 1010 assert.Equal(t, "FFF", got[2].InstrumentID) 1011 1012 wantStartCursor := entities.NewCursor( 1013 entities.MarketCursor{ 1014 VegaTime: blockTimes["7a797e0e"], 1015 ID: "7a797e0e", 1016 }.String(), 1017 ).Encode() 1018 wantEndCursor := entities.NewCursor( 1019 entities.MarketCursor{ 1020 VegaTime: blockTimes["b7c84b8e"], 1021 ID: "b7c84b8e", 1022 }.String(), 1023 ).Encode() 1024 assert.Equal(t, entities.PageInfo{ 1025 HasNextPage: true, 1026 HasPreviousPage: true, 1027 StartCursor: wantStartCursor, 1028 EndCursor: wantEndCursor, 1029 }, pageInfo) 1030 } 1031 1032 func testCursorPaginationReturnsPageTraversingBackward(t *testing.T) { 1033 bs, md := setupMarketsTest(t) 1034 ctx := tempTransaction(t) 1035 1036 blockTimes := make(map[string]time.Time) 1037 populateTestMarkets(ctx, t, bs, md, blockTimes) 1038 last := int32(3) 1039 before := entities.NewCursor( 1040 entities.MarketCursor{ 1041 VegaTime: blockTimes["c8744329"], 1042 ID: "c8744329", 1043 }.String(), 1044 ).Encode() 1045 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 1046 require.NoError(t, err) 1047 1048 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1049 require.NoError(t, err) 1050 1051 assert.Equal(t, 3, len(got)) 1052 assert.Equal(t, "7bb2356e", got[0].ID.String()) 1053 assert.Equal(t, "c612300d", got[2].ID.String()) 1054 assert.Equal(t, "EEE", got[0].InstrumentID) 1055 assert.Equal(t, "GGG", got[2].InstrumentID) 1056 1057 wantStartCursor := entities.NewCursor( 1058 entities.MarketCursor{ 1059 VegaTime: blockTimes["7bb2356e"], 1060 ID: "7bb2356e", 1061 }.String(), 1062 ).Encode() 1063 wantEndCursor := entities.NewCursor( 1064 entities.MarketCursor{ 1065 VegaTime: blockTimes["c612300d"], 1066 ID: "c612300d", 1067 }.String(), 1068 ).Encode() 1069 assert.Equal(t, entities.PageInfo{ 1070 HasNextPage: true, 1071 HasPreviousPage: true, 1072 StartCursor: wantStartCursor, 1073 EndCursor: wantEndCursor, 1074 }, pageInfo) 1075 } 1076 1077 func testCursorPaginationReturnsTheSpecifiedMarketNewestFirst(t *testing.T) { 1078 bs, md := setupMarketsTest(t) 1079 ctx := tempTransaction(t) 1080 1081 blockTimes := make(map[string]time.Time) 1082 populateTestMarkets(ctx, t, bs, md, blockTimes) 1083 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true) 1084 require.NoError(t, err) 1085 1086 got, pageInfo, err := md.GetAllPaged(ctx, "c612300d", pagination, true) 1087 require.NoError(t, err) 1088 assert.Equal(t, 1, len(got)) 1089 assert.Equal(t, "c612300d", got[0].ID.String()) 1090 assert.Equal(t, "GGG", got[0].InstrumentID) 1091 1092 wantStartCursor := entities.NewCursor( 1093 entities.MarketCursor{ 1094 VegaTime: blockTimes["c612300d"], 1095 ID: "c612300d", 1096 }.String(), 1097 ).Encode() 1098 wantEndCursor := entities.NewCursor( 1099 entities.MarketCursor{ 1100 VegaTime: blockTimes["c612300d"], 1101 ID: "c612300d", 1102 }.String(), 1103 ).Encode() 1104 1105 assert.Equal(t, entities.PageInfo{ 1106 HasNextPage: false, 1107 HasPreviousPage: false, 1108 StartCursor: wantStartCursor, 1109 EndCursor: wantEndCursor, 1110 }, pageInfo) 1111 } 1112 1113 func testCursorPaginationReturnsAllMarketsNewestFirst(t *testing.T) { 1114 bs, md := setupMarketsTest(t) 1115 ctx := tempTransaction(t) 1116 1117 blockTimes := make(map[string]time.Time) 1118 populateTestMarkets(ctx, t, bs, md, blockTimes) 1119 1120 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true) 1121 require.NoError(t, err) 1122 1123 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1124 require.NoError(t, err) 1125 assert.Equal(t, 10, len(got)) 1126 assert.Equal(t, "fb1528a5", got[0].ID.String()) 1127 assert.Equal(t, "02a16077", got[9].ID.String()) 1128 assert.Equal(t, "JJJ", got[0].InstrumentID) 1129 assert.Equal(t, "AAA", got[9].InstrumentID) 1130 1131 wantStartCursor := entities.NewCursor( 1132 entities.MarketCursor{ 1133 VegaTime: blockTimes["fb1528a5"], 1134 ID: "fb1528a5", 1135 }.String(), 1136 ).Encode() 1137 wantEndCursor := entities.NewCursor( 1138 entities.MarketCursor{ 1139 VegaTime: blockTimes["02a16077"], 1140 ID: "02a16077", 1141 }.String(), 1142 ).Encode() 1143 assert.Equal(t, entities.PageInfo{ 1144 HasNextPage: false, 1145 HasPreviousPage: false, 1146 StartCursor: wantStartCursor, 1147 EndCursor: wantEndCursor, 1148 }, pageInfo) 1149 } 1150 1151 func testCursorPaginationReturnsFirstPageNewestFirst(t *testing.T) { 1152 bs, md := setupMarketsTest(t) 1153 ctx := tempTransaction(t) 1154 1155 blockTimes := make(map[string]time.Time) 1156 populateTestMarkets(ctx, t, bs, md, blockTimes) 1157 first := int32(3) 1158 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 1159 require.NoError(t, err) 1160 1161 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1162 require.NoError(t, err) 1163 1164 assert.Equal(t, 3, len(got)) 1165 assert.Equal(t, "fb1528a5", got[0].ID.String()) 1166 assert.Equal(t, "c8744329", got[2].ID.String()) 1167 assert.Equal(t, "JJJ", got[0].InstrumentID) 1168 assert.Equal(t, "HHH", got[2].InstrumentID) 1169 1170 wantStartCursor := entities.NewCursor( 1171 entities.MarketCursor{ 1172 VegaTime: blockTimes["fb1528a5"], 1173 ID: "fb1528a5", 1174 }.String(), 1175 ).Encode() 1176 wantEndCursor := entities.NewCursor( 1177 entities.MarketCursor{ 1178 VegaTime: blockTimes["c8744329"], 1179 ID: "c8744329", 1180 }.String(), 1181 ).Encode() 1182 assert.Equal(t, entities.PageInfo{ 1183 HasNextPage: true, 1184 HasPreviousPage: false, 1185 StartCursor: wantStartCursor, 1186 EndCursor: wantEndCursor, 1187 }, pageInfo) 1188 } 1189 1190 func testCursorPaginationReturnsLastPageNewestFirst(t *testing.T) { 1191 bs, md := setupMarketsTest(t) 1192 ctx := tempTransaction(t) 1193 1194 blockTimes := make(map[string]time.Time) 1195 populateTestMarkets(ctx, t, bs, md, blockTimes) 1196 last := int32(3) 1197 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 1198 require.NoError(t, err) 1199 1200 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1201 require.NoError(t, err) 1202 1203 assert.Equal(t, 3, len(got)) 1204 assert.Equal(t, "65be62cd", got[0].ID.String()) 1205 assert.Equal(t, "02a16077", got[2].ID.String()) 1206 assert.Equal(t, "CCC", got[0].InstrumentID) 1207 assert.Equal(t, "AAA", got[2].InstrumentID) 1208 1209 wantStartCursor := entities.NewCursor( 1210 entities.MarketCursor{ 1211 VegaTime: blockTimes["65be62cd"], 1212 ID: "65be62cd", 1213 }.String(), 1214 ).Encode() 1215 wantEndCursor := entities.NewCursor( 1216 entities.MarketCursor{ 1217 VegaTime: blockTimes["02a16077"], 1218 ID: "02a16077", 1219 }.String(), 1220 ).Encode() 1221 assert.Equal(t, entities.PageInfo{ 1222 HasNextPage: false, 1223 HasPreviousPage: true, 1224 StartCursor: wantStartCursor, 1225 EndCursor: wantEndCursor, 1226 }, pageInfo) 1227 } 1228 1229 func testCursorPaginationReturnsPageTraversingForwardNewestFirst(t *testing.T) { 1230 bs, md := setupMarketsTest(t) 1231 ctx := tempTransaction(t) 1232 1233 blockTimes := make(map[string]time.Time) 1234 populateTestMarkets(ctx, t, bs, md, blockTimes) 1235 first := int32(3) 1236 after := entities.NewCursor( 1237 entities.MarketCursor{ 1238 VegaTime: blockTimes["c8744329"], 1239 ID: "c8744329", 1240 }.String(), 1241 ).Encode() 1242 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 1243 require.NoError(t, err) 1244 1245 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1246 require.NoError(t, err) 1247 1248 assert.Equal(t, 3, len(got)) 1249 assert.Equal(t, "c612300d", got[0].ID.String()) 1250 assert.Equal(t, "7bb2356e", got[2].ID.String()) 1251 assert.Equal(t, "GGG", got[0].InstrumentID) 1252 assert.Equal(t, "EEE", got[2].InstrumentID) 1253 1254 wantStartCursor := entities.NewCursor( 1255 entities.MarketCursor{ 1256 VegaTime: blockTimes["c612300d"], 1257 ID: "c612300d", 1258 }.String(), 1259 ).Encode() 1260 wantEndCursor := entities.NewCursor( 1261 entities.MarketCursor{ 1262 VegaTime: blockTimes["7bb2356e"], 1263 ID: "7bb2356e", 1264 }.String(), 1265 ).Encode() 1266 assert.Equal(t, entities.PageInfo{ 1267 HasNextPage: true, 1268 HasPreviousPage: true, 1269 StartCursor: wantStartCursor, 1270 EndCursor: wantEndCursor, 1271 }, pageInfo) 1272 } 1273 1274 func testCursorPaginationReturnsPageTraversingBackwardNewestFirst(t *testing.T) { 1275 bs, md := setupMarketsTest(t) 1276 ctx := tempTransaction(t) 1277 1278 blockTimes := make(map[string]time.Time) 1279 populateTestMarkets(ctx, t, bs, md, blockTimes) 1280 last := int32(3) 1281 before := entities.NewCursor( 1282 entities.MarketCursor{ 1283 VegaTime: blockTimes["65be62cd"], 1284 ID: "65be62cd", 1285 }.String(), 1286 ).Encode() 1287 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 1288 require.NoError(t, err) 1289 1290 got, pageInfo, err := md.GetAllPaged(ctx, "", pagination, true) 1291 require.NoError(t, err) 1292 1293 assert.Equal(t, 3, len(got)) 1294 assert.Equal(t, "b7c84b8e", got[0].ID.String()) 1295 assert.Equal(t, "7a797e0e", got[2].ID.String()) 1296 assert.Equal(t, "FFF", got[0].InstrumentID) 1297 assert.Equal(t, "DDD", got[2].InstrumentID) 1298 1299 wantStartCursor := entities.NewCursor( 1300 entities.MarketCursor{ 1301 VegaTime: blockTimes["b7c84b8e"], 1302 ID: "b7c84b8e", 1303 }.String(), 1304 ).Encode() 1305 wantEndCursor := entities.NewCursor( 1306 entities.MarketCursor{ 1307 VegaTime: blockTimes["7a797e0e"], 1308 ID: "7a797e0e", 1309 }.String(), 1310 ).Encode() 1311 assert.Equal(t, entities.PageInfo{ 1312 HasNextPage: true, 1313 HasPreviousPage: true, 1314 StartCursor: wantStartCursor, 1315 EndCursor: wantEndCursor, 1316 }, pageInfo) 1317 } 1318 1319 func TestSuccessorMarkets(t *testing.T) { 1320 t.Run("should create a market lineage record when a successor market proposal is approved", testMarketLineageCreated) 1321 t.Run("ListSuccessorMarkets should return the market lineage", testListSuccessorMarkets) 1322 t.Run("GetMarket should return the market with its parent and successor if they exist", testGetMarketWithParentAndSuccessor) 1323 } 1324 1325 func testMarketLineageCreated(t *testing.T) { 1326 ctx := tempTransaction(t) 1327 1328 bs, md := setupMarketsTest(t) 1329 parentMarket := entities.Market{ 1330 ID: entities.MarketID("deadbeef01"), 1331 InstrumentID: "deadbeef01", 1332 } 1333 1334 successorMarketA := entities.Market{ 1335 ID: entities.MarketID("deadbeef02"), 1336 InstrumentID: "deadbeef02", 1337 ParentMarketID: parentMarket.ID, 1338 } 1339 1340 successorMarketB := entities.Market{ 1341 ID: entities.MarketID("deadbeef03"), 1342 InstrumentID: "deadbeef03", 1343 ParentMarketID: successorMarketA.ID, 1344 } 1345 1346 var rowCount int64 1347 1348 source := &testBlockSource{bs, time.Now()} 1349 block := source.getNextBlock(t, ctx) 1350 t.Run("parent market should create a market lineage record with no parent market id", func(t *testing.T) { 1351 parentMarket.VegaTime = block.VegaTime 1352 parentMarket.State = entities.MarketStateProposed 1353 err := md.Upsert(ctx, &parentMarket) 1354 require.NoError(t, err) 1355 err = connectionSource.QueryRow(ctx, `select count(*) from market_lineage where market_id = $1`, parentMarket.ID).Scan(&rowCount) 1356 require.NoError(t, err) 1357 assert.Equal(t, int64(0), rowCount) 1358 1359 block = source.getNextBlock(t, ctx) 1360 parentMarket.State = entities.MarketStatePending 1361 parentMarket.TradingMode = entities.MarketTradingModeOpeningAuction 1362 parentMarket.VegaTime = block.VegaTime 1363 err = md.Upsert(ctx, &parentMarket) 1364 require.NoError(t, err) 1365 1366 block = source.getNextBlock(t, ctx) 1367 parentMarket.State = entities.MarketStateActive 1368 parentMarket.TradingMode = entities.MarketTradingModeContinuous 1369 parentMarket.VegaTime = block.VegaTime 1370 err = md.Upsert(ctx, &parentMarket) 1371 require.NoError(t, err) 1372 1373 var marketID, parentMarketID, rootID entities.MarketID 1374 err = connectionSource.QueryRow(ctx, 1375 `select market_id, parent_market_id, root_id from market_lineage where market_id = $1`, 1376 parentMarket.ID, 1377 ).Scan(&marketID, &parentMarketID, &rootID) 1378 require.NoError(t, err) 1379 assert.Equal(t, parentMarket.ID, marketID) 1380 assert.Equal(t, entities.MarketID(""), parentMarketID) 1381 assert.Equal(t, parentMarket.ID, rootID) 1382 }) 1383 1384 block = source.getNextBlock(t, ctx) 1385 t.Run("successor market should create a market lineage record pointing to the parent market and the root market", func(t *testing.T) { 1386 successorMarketA.VegaTime = block.VegaTime 1387 successorMarketA.State = entities.MarketStateProposed 1388 err := md.Upsert(ctx, &successorMarketA) 1389 require.NoError(t, err) 1390 // proposed market successor only, so it should not create a lineage record yet 1391 err = connectionSource.QueryRow(ctx, `select count(*) from market_lineage where market_id = $1`, successorMarketA.ID).Scan(&rowCount) 1392 require.NoError(t, err) 1393 assert.Equal(t, int64(0), rowCount) 1394 1395 block = source.getNextBlock(t, ctx) 1396 successorMarketA.State = entities.MarketStatePending 1397 successorMarketA.TradingMode = entities.MarketTradingModeOpeningAuction 1398 successorMarketA.VegaTime = block.VegaTime 1399 err = md.Upsert(ctx, &successorMarketA) 1400 require.NoError(t, err) 1401 1402 block = source.getNextBlock(t, ctx) 1403 successorMarketA.State = entities.MarketStateActive 1404 successorMarketA.TradingMode = entities.MarketTradingModeContinuous 1405 successorMarketA.VegaTime = block.VegaTime 1406 err = md.Upsert(ctx, &successorMarketA) 1407 require.NoError(t, err) 1408 // proposed market successor has been accepted and is pending, so we should now have a lineage record pointing to the parent 1409 var marketID, parentMarketID, rootID entities.MarketID 1410 err = connectionSource.QueryRow(ctx, 1411 `select market_id, parent_market_id, root_id from market_lineage where market_id = $1`, 1412 successorMarketA.ID, 1413 ).Scan(&marketID, &parentMarketID, &rootID) 1414 require.NoError(t, err) 1415 assert.Equal(t, successorMarketA.ID, marketID) 1416 assert.Equal(t, parentMarket.ID, parentMarketID) 1417 assert.Equal(t, parentMarket.ID, rootID) 1418 }) 1419 1420 block = source.getNextBlock(t, ctx) 1421 t.Run("second successor market should create a lineage record pointing to the parent market and the root market", func(t *testing.T) { 1422 successorMarketB.VegaTime = block.VegaTime 1423 successorMarketB.State = entities.MarketStateProposed 1424 err := md.Upsert(ctx, &successorMarketB) 1425 require.NoError(t, err) 1426 // proposed market successor only, so it should not create a lineage record yet 1427 err = connectionSource.QueryRow(ctx, `select count(*) from market_lineage where market_id = $1`, successorMarketB.ID).Scan(&rowCount) 1428 require.NoError(t, err) 1429 assert.Equal(t, int64(0), rowCount) 1430 1431 block = source.getNextBlock(t, ctx) 1432 successorMarketB.State = entities.MarketStatePending 1433 successorMarketB.TradingMode = entities.MarketTradingModeOpeningAuction 1434 successorMarketB.VegaTime = block.VegaTime 1435 err = md.Upsert(ctx, &successorMarketB) 1436 require.NoError(t, err) 1437 // proposed market successor has been accepted and is pending, so we should now have a lineage record pointing to the parent 1438 block = source.getNextBlock(t, ctx) 1439 successorMarketB.State = entities.MarketStateActive 1440 successorMarketB.TradingMode = entities.MarketTradingModeContinuous 1441 successorMarketB.VegaTime = block.VegaTime 1442 err = md.Upsert(ctx, &successorMarketB) 1443 require.NoError(t, err) 1444 var marketID, parentMarketID, rootID entities.MarketID 1445 err = connectionSource.QueryRow(ctx, 1446 `select market_id, parent_market_id, root_id from market_lineage where market_id = $1`, 1447 successorMarketB.ID, 1448 ).Scan(&marketID, &parentMarketID, &rootID) 1449 require.NoError(t, err) 1450 assert.Equal(t, successorMarketB.ID, marketID) 1451 assert.Equal(t, successorMarketA.ID, parentMarketID) 1452 assert.Equal(t, parentMarket.ID, rootID) 1453 }) 1454 } 1455 1456 func testListSuccessorMarkets(t *testing.T) { 1457 ctx := tempTransaction(t) 1458 1459 md, markets, proposals := setupSuccessorMarkets(t, ctx) 1460 1461 successors := []entities.SuccessorMarket{ 1462 { 1463 Market: markets[5], 1464 Proposals: []*entities.Proposal{ 1465 &proposals[1], 1466 &proposals[2], 1467 }, 1468 }, 1469 { 1470 Market: markets[6], 1471 Proposals: []*entities.Proposal{ 1472 &proposals[3], 1473 &proposals[4], 1474 }, 1475 }, 1476 { 1477 Market: markets[9], 1478 }, 1479 } 1480 1481 t.Run("should list the full history if children only is false", func(t *testing.T) { 1482 got, _, err := md.ListSuccessorMarkets(ctx, "deadbeef02", true, entities.CursorPagination{}) 1483 require.NoError(t, err) 1484 want := successors[:] 1485 assert.Equal(t, want, got) 1486 }) 1487 1488 t.Run("should list only the successor markets if children only is true", func(t *testing.T) { 1489 got, _, err := md.ListSuccessorMarkets(ctx, "deadbeef02", false, entities.CursorPagination{}) 1490 require.NoError(t, err) 1491 want := successors[1:] 1492 1493 assert.Equal(t, want, got) 1494 }) 1495 1496 t.Run("should paginate results if pagination is provided", func(t *testing.T) { 1497 first := int32(2) 1498 after := entities.NewCursor( 1499 entities.MarketCursor{ 1500 VegaTime: markets[5].VegaTime, 1501 ID: markets[5].ID, 1502 }.String(), 1503 ).Encode() 1504 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 1505 require.NoError(t, err) 1506 got, pageInfo, err := md.ListSuccessorMarkets(ctx, "deadbeef01", true, pagination) 1507 require.NoError(t, err) 1508 want := successors[1:] 1509 1510 assert.Equal(t, want, got, "paged successor markets do not match") 1511 wantStartCursor := entities.NewCursor( 1512 entities.MarketCursor{ 1513 VegaTime: markets[6].VegaTime, 1514 ID: markets[6].ID, 1515 }.String(), 1516 ).Encode() 1517 wantEndCursor := entities.NewCursor( 1518 entities.MarketCursor{ 1519 VegaTime: markets[9].VegaTime, 1520 ID: markets[9].ID, 1521 }.String(), 1522 ).Encode() 1523 assert.Equal(t, entities.PageInfo{ 1524 HasNextPage: false, 1525 HasPreviousPage: true, 1526 StartCursor: wantStartCursor, 1527 EndCursor: wantEndCursor, 1528 }, pageInfo) 1529 }) 1530 1531 t.Run("should list the parent market even if it has not entered continuous trading and has no successors", func(t *testing.T) { 1532 got, _, err := md.ListSuccessorMarkets(ctx, "deadbeef04", false, entities.CursorPagination{}) 1533 require.NoError(t, err) 1534 want := []entities.SuccessorMarket{ 1535 { 1536 Market: markets[10], 1537 }, 1538 } 1539 assert.Equal(t, want, got) 1540 }) 1541 } 1542 1543 func testGetMarketWithParentAndSuccessor(t *testing.T) { 1544 ctx := tempTransaction(t) 1545 1546 md, _, _ := setupSuccessorMarkets(t, ctx) 1547 1548 t.Run("should return successor market id only if the first market in a succession line", func(t *testing.T) { 1549 got, err := md.GetByID(ctx, "deadbeef01") 1550 require.NoError(t, err) 1551 assert.Equal(t, "", got.ParentMarketID.String()) 1552 assert.Equal(t, "deadbeef02", got.SuccessorMarketID.String()) 1553 }) 1554 1555 t.Run("should return parent and successor market id if the market is within a succession line", func(t *testing.T) { 1556 got, err := md.GetByID(ctx, "deadbeef02") 1557 require.NoError(t, err) 1558 assert.Equal(t, "deadbeef01", got.ParentMarketID.String()) 1559 assert.Equal(t, "deadbeef03", got.SuccessorMarketID.String()) 1560 }) 1561 1562 t.Run("should return parent market id only if the last market in a succession line", func(t *testing.T) { 1563 got, err := md.GetByID(ctx, "deadbeef03") 1564 require.NoError(t, err) 1565 assert.Equal(t, "deadbeef02", got.ParentMarketID.String()) 1566 assert.Equal(t, "", got.SuccessorMarketID.String()) 1567 }) 1568 } 1569 1570 func setupSuccessorMarkets(t *testing.T, ctx context.Context) (*sqlstore.Markets, []entities.Market, []entities.Proposal) { 1571 t.Helper() 1572 1573 bs, md := setupMarketsTest(t) 1574 ps := sqlstore.NewProposals(connectionSource) 1575 ts := sqlstore.NewParties(connectionSource) 1576 1577 emptyLS := &vega.LiquidationStrategy{ 1578 DisposalTimeStep: 0, 1579 DisposalFraction: "0", 1580 FullDisposalSize: 0, 1581 MaxFractionConsumed: "0", 1582 DisposalSlippageRange: "0", 1583 } 1584 liquidationStrat := entities.LiquidationStrategyFromProto(emptyLS) 1585 parentMarket := entities.Market{ 1586 ID: entities.MarketID("deadbeef01"), 1587 InstrumentID: "deadbeef01", 1588 TradableInstrument: entities.TradableInstrument{ 1589 TradableInstrument: &vega.TradableInstrument{}, 1590 }, 1591 LiquiditySLAParameters: entities.LiquiditySLAParameters{ 1592 PriceRange: num.NewDecimalFromFloat(0), 1593 CommitmentMinTimeFraction: num.NewDecimalFromFloat(0), 1594 PerformanceHysteresisEpochs: 0, 1595 SlaCompetitionFactor: num.NewDecimalFromFloat(0), 1596 }, 1597 LiquidationStrategy: liquidationStrat, 1598 } 1599 1600 successorMarketA := entities.Market{ 1601 ID: entities.MarketID("deadbeef02"), 1602 InstrumentID: "deadbeef02", 1603 TradableInstrument: entities.TradableInstrument{ 1604 TradableInstrument: &vega.TradableInstrument{}, 1605 }, 1606 ParentMarketID: parentMarket.ID, 1607 LiquiditySLAParameters: entities.LiquiditySLAParameters{ 1608 PriceRange: num.NewDecimalFromFloat(0), 1609 CommitmentMinTimeFraction: num.NewDecimalFromFloat(0), 1610 PerformanceHysteresisEpochs: 0, 1611 SlaCompetitionFactor: num.NewDecimalFromFloat(0), 1612 }, 1613 LiquidationStrategy: liquidationStrat, 1614 } 1615 1616 parentMarket.SuccessorMarketID = successorMarketA.ID 1617 1618 successorMarketB := entities.Market{ 1619 ID: entities.MarketID("deadbeef03"), 1620 InstrumentID: "deadbeef03", 1621 TradableInstrument: entities.TradableInstrument{ 1622 TradableInstrument: &vega.TradableInstrument{}, 1623 }, 1624 ParentMarketID: successorMarketA.ID, 1625 LiquiditySLAParameters: entities.LiquiditySLAParameters{ 1626 PriceRange: num.NewDecimalFromFloat(0), 1627 CommitmentMinTimeFraction: num.NewDecimalFromFloat(0), 1628 PerformanceHysteresisEpochs: 0, 1629 SlaCompetitionFactor: num.NewDecimalFromFloat(0), 1630 }, 1631 LiquidationStrategy: liquidationStrat, 1632 } 1633 1634 parentMarket2 := entities.Market{ 1635 ID: entities.MarketID("deadbeef04"), 1636 InstrumentID: "deadbeef04", 1637 TradableInstrument: entities.TradableInstrument{ 1638 TradableInstrument: &vega.TradableInstrument{}, 1639 }, 1640 LiquiditySLAParameters: entities.LiquiditySLAParameters{ 1641 PriceRange: num.NewDecimalFromFloat(0), 1642 CommitmentMinTimeFraction: num.NewDecimalFromFloat(0), 1643 PerformanceHysteresisEpochs: 0, 1644 SlaCompetitionFactor: num.NewDecimalFromFloat(0), 1645 }, 1646 LiquidationStrategy: liquidationStrat, 1647 } 1648 1649 successorMarketA.SuccessorMarketID = successorMarketB.ID 1650 1651 source := &testBlockSource{bs, time.Now()} 1652 1653 block := source.getNextBlock(t, ctx) 1654 1655 pt1 := addTestParty(t, ctx, ts, block) 1656 pt2 := addTestParty(t, ctx, ts, block) 1657 1658 proposals := []struct { 1659 id string 1660 party entities.Party 1661 reference string 1662 block entities.Block 1663 state entities.ProposalState 1664 rationale entities.ProposalRationale 1665 terms entities.ProposalTerms 1666 reason entities.ProposalError 1667 }{ 1668 { 1669 id: "deadbeef01", 1670 party: pt1, 1671 reference: "deadbeef01", 1672 block: source.getNextBlock(t, ctx), 1673 state: entities.ProposalStateEnacted, 1674 rationale: entities.ProposalRationale{ProposalRationale: &vega.ProposalRationale{Title: "myurl1.com", Description: "mydescription1"}}, 1675 terms: entities.ProposalTerms{ProposalTerms: &vega.ProposalTerms{Change: &vega.ProposalTerms_NewMarket{NewMarket: &vega.NewMarket{ 1676 Changes: &vega.NewMarketConfiguration{ 1677 LiquidationStrategy: emptyLS, 1678 }, 1679 }}}}, 1680 reason: entities.ProposalErrorUnspecified, 1681 }, 1682 { 1683 id: "deadbeef02", 1684 party: pt1, 1685 reference: "deadbeef02", 1686 block: source.getNextBlock(t, ctx), 1687 state: entities.ProposalStateEnacted, 1688 rationale: entities.ProposalRationale{ProposalRationale: &vega.ProposalRationale{Title: "myurl1.com", Description: "mydescription1"}}, 1689 terms: entities.ProposalTerms{ProposalTerms: &vega.ProposalTerms{Change: &vega.ProposalTerms_NewMarket{NewMarket: &vega.NewMarket{ 1690 Changes: &vega.NewMarketConfiguration{ 1691 Successor: &vega.SuccessorConfiguration{ 1692 ParentMarketId: "deadbeef01", 1693 InsurancePoolFraction: "1.0", 1694 }, 1695 LiquidationStrategy: emptyLS, 1696 }, 1697 }}}}, 1698 reason: entities.ProposalErrorUnspecified, 1699 }, 1700 { 1701 id: "deadbeefaa", 1702 party: pt2, 1703 reference: "deadbeefaa", 1704 block: source.getNextBlock(t, ctx), 1705 state: entities.ProposalStateEnacted, 1706 rationale: entities.ProposalRationale{ProposalRationale: &vega.ProposalRationale{Title: "myurl1.com", Description: "mydescription1"}}, 1707 terms: entities.ProposalTerms{ProposalTerms: &vega.ProposalTerms{Change: &vega.ProposalTerms_NewMarket{NewMarket: &vega.NewMarket{ 1708 Changes: &vega.NewMarketConfiguration{ 1709 Successor: &vega.SuccessorConfiguration{ 1710 ParentMarketId: "deadbeef01", 1711 InsurancePoolFraction: "1.0", 1712 }, 1713 LiquidationStrategy: emptyLS, 1714 }, 1715 }}}}, 1716 reason: entities.ProposalErrorParticipationThresholdNotReached, 1717 }, 1718 { 1719 id: "deadbeef03", 1720 party: pt1, 1721 reference: "deadbeef03", 1722 block: source.getNextBlock(t, ctx), 1723 state: entities.ProposalStateEnacted, 1724 rationale: entities.ProposalRationale{ProposalRationale: &vega.ProposalRationale{Title: "myurl1.com", Description: "mydescription1"}}, 1725 terms: entities.ProposalTerms{ProposalTerms: &vega.ProposalTerms{Change: &vega.ProposalTerms_NewMarket{NewMarket: &vega.NewMarket{ 1726 Changes: &vega.NewMarketConfiguration{ 1727 Successor: &vega.SuccessorConfiguration{ 1728 ParentMarketId: "deadbeef02", 1729 InsurancePoolFraction: "1.0", 1730 }, 1731 LiquidationStrategy: emptyLS, 1732 }, 1733 }}}}, 1734 reason: entities.ProposalErrorUnspecified, 1735 }, 1736 { 1737 id: "deadbeefbb", 1738 party: pt2, 1739 reference: "deadbeefbb", 1740 block: source.getNextBlock(t, ctx), 1741 state: entities.ProposalStateEnacted, 1742 rationale: entities.ProposalRationale{ProposalRationale: &vega.ProposalRationale{Title: "myurl1.com", Description: "mydescription1"}}, 1743 terms: entities.ProposalTerms{ProposalTerms: &vega.ProposalTerms{Change: &vega.ProposalTerms_NewMarket{NewMarket: &vega.NewMarket{ 1744 Changes: &vega.NewMarketConfiguration{ 1745 Successor: &vega.SuccessorConfiguration{ 1746 ParentMarketId: "deadbeef02", 1747 InsurancePoolFraction: "1.0", 1748 }, 1749 LiquidationStrategy: emptyLS, 1750 }, 1751 }}}}, 1752 reason: entities.ProposalErrorParticipationThresholdNotReached, 1753 }, 1754 } 1755 1756 props := []entities.Proposal{} 1757 for _, p := range proposals { 1758 p := addTestProposal(t, ctx, ps, p.id, p.party, p.reference, p.block, p.state, 1759 p.rationale, p.terms, p.reason, nil, entities.BatchProposalTerms{}) 1760 1761 props = append(props, p) 1762 } 1763 1764 markets := []struct { 1765 market entities.Market 1766 state entities.MarketState 1767 tradingMode entities.MarketTradingMode 1768 }{ 1769 { 1770 market: parentMarket, 1771 state: entities.MarketStateProposed, 1772 tradingMode: entities.MarketTradingModeOpeningAuction, 1773 }, 1774 { 1775 market: parentMarket, 1776 state: entities.MarketStatePending, 1777 tradingMode: entities.MarketTradingModeOpeningAuction, 1778 }, 1779 { 1780 market: parentMarket, 1781 state: entities.MarketStateActive, 1782 tradingMode: entities.MarketTradingModeContinuous, 1783 }, 1784 { 1785 market: successorMarketA, 1786 state: entities.MarketStateProposed, 1787 tradingMode: entities.MarketTradingModeOpeningAuction, 1788 }, 1789 { 1790 market: successorMarketA, 1791 state: entities.MarketStatePending, 1792 tradingMode: entities.MarketTradingModeOpeningAuction, 1793 }, 1794 { 1795 market: parentMarket, 1796 state: entities.MarketStateSettled, 1797 tradingMode: entities.MarketTradingModeNoTrading, 1798 }, 1799 { 1800 market: successorMarketA, 1801 state: entities.MarketStateActive, 1802 tradingMode: entities.MarketTradingModeContinuous, 1803 }, 1804 { 1805 market: successorMarketB, 1806 state: entities.MarketStateProposed, 1807 tradingMode: entities.MarketTradingModeOpeningAuction, 1808 }, 1809 { 1810 market: successorMarketB, 1811 state: entities.MarketStatePending, 1812 tradingMode: entities.MarketTradingModeOpeningAuction, 1813 }, 1814 { 1815 market: successorMarketB, 1816 state: entities.MarketStateActive, 1817 tradingMode: entities.MarketTradingModeContinuous, 1818 }, 1819 { 1820 market: parentMarket2, 1821 state: entities.MarketStatePending, 1822 tradingMode: entities.MarketTradingModeOpeningAuction, 1823 }, 1824 } 1825 1826 entries := make([]entities.Market, 0, len(markets)) 1827 1828 for _, u := range markets { 1829 block := source.getNextBlock(t, ctx) 1830 u.market.VegaTime = block.VegaTime 1831 u.market.State = u.state 1832 u.market.TradingMode = u.tradingMode 1833 err := md.Upsert(ctx, &u.market) 1834 entries = append(entries, u.market) 1835 require.NoError(t, err) 1836 } 1837 1838 return md, entries, props 1839 } 1840 1841 func TestMarketsEnums(t *testing.T) { 1842 t.Run("All proto market states should be supported", testMarketState) 1843 t.Run("All proto market trading modes should be supported", testMarketTradingMode) 1844 } 1845 1846 func testMarketState(t *testing.T) { 1847 var marketState vega.Market_State 1848 states := getEnums(t, marketState) 1849 assert.Len(t, states, 11) 1850 for s, state := range states { 1851 t.Run(state, func(t *testing.T) { 1852 bs, md := setupMarketsTest(t) 1853 1854 ctx := tempTransaction(t) 1855 1856 block := addTestBlock(t, ctx, bs) 1857 1858 marketProto := getTestFutureMarket(true) 1859 marketProto.State = vega.Market_State(s) 1860 1861 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 1862 require.NoError(t, err, "Converting market proto to database entity") 1863 require.NoError(t, md.Upsert(ctx, market)) 1864 got, err := md.GetByID(ctx, market.ID.String()) 1865 require.NoError(t, err) 1866 assert.Equal(t, market.State, got.State) 1867 }) 1868 } 1869 } 1870 1871 func testMarketTradingMode(t *testing.T) { 1872 var marketTradingMode vega.Market_TradingMode 1873 modes := getEnums(t, marketTradingMode) 1874 assert.Len(t, modes, 9) 1875 for m, mode := range modes { 1876 t.Run(mode, func(t *testing.T) { 1877 bs, md := setupMarketsTest(t) 1878 1879 ctx := tempTransaction(t) 1880 1881 block := addTestBlock(t, ctx, bs) 1882 1883 marketProto := getTestFutureMarket(true) 1884 marketProto.TradingMode = vega.Market_TradingMode(m) 1885 1886 market, err := entities.NewMarketFromProto(marketProto, generateTxHash(), block.VegaTime) 1887 require.NoError(t, err, "Converting market proto to database entity") 1888 require.NoError(t, md.Upsert(ctx, market)) 1889 got, err := md.GetByID(ctx, market.ID.String()) 1890 require.NoError(t, err) 1891 assert.Equal(t, market.TradingMode, got.TradingMode) 1892 }) 1893 } 1894 }