code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/market_data_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 "bufio" 20 "context" 21 "encoding/csv" 22 "encoding/hex" 23 "encoding/json" 24 "io" 25 "os" 26 "path/filepath" 27 "strconv" 28 "strings" 29 "testing" 30 "time" 31 32 "code.vegaprotocol.io/vega/datanode/entities" 33 "code.vegaprotocol.io/vega/datanode/sqlstore" 34 "code.vegaprotocol.io/vega/libs/num" 35 "code.vegaprotocol.io/vega/libs/ptr" 36 "code.vegaprotocol.io/vega/protos/vega" 37 vegapb "code.vegaprotocol.io/vega/protos/vega" 38 39 "github.com/shopspring/decimal" 40 "github.com/stretchr/testify/assert" 41 "github.com/stretchr/testify/require" 42 ) 43 44 const ( 45 csvColumnMarket = iota 46 _ 47 csvColumnVegaTime 48 csvColumnMarkPrice 49 csvColumnBestBidPrice 50 csvColumnBestBidVolume 51 csvColumnBestOfferPrice 52 csvColumnBestOfferVolume 53 csvColumnBestStaticBidPrice 54 csvColumnBestStaticBidVolume 55 csvColumnBestStaticOfferPrice 56 csvColumnBestStaticOfferVolume 57 csvColumnMidPrice 58 csvColumnStaticMidPrice 59 csvColumnOpenInterest 60 csvColumnAuctionEnd 61 csvColumnAuctionStart 62 csvColumnIndicativePrice 63 csvColumnIndicativeVolume 64 csvColumnMarketTradingMode 65 csvColumnAuctionTrigger 66 csvColumnExtensionTrigger 67 csvColumnTargetStake 68 csvColumnSuppliedStake 69 csvColumnPriceMonitoringBounds 70 csvColumnMarketValueProxy 71 csvColumnLiquidityProviderFeeShares 72 csvColumnMarketState 73 csvColumnMarketGrowth 74 csvColumnLastTradedPrice 75 ) 76 77 func Test_MarketData(t *testing.T) { 78 t.Run("Add should insert a valid market data record", shouldInsertAValidMarketDataRecord) 79 t.Run("Get should return the latest market data record for a given market", getLatestMarketData) 80 t.Run("GetHistoricMarketData should return the all the market data between dates given for the specified market", getAllForMarketBetweenDates) 81 t.Run("GetHistoricMarketData should return all market data for a given market with date greater than or equal to the given date", getForMarketFromDate) 82 t.Run("GetHistoricMarketData should return all market data for a given market with date less than or equal to the given date", getForMarketToDate) 83 t.Run("GetHistoricMarketData should return all market data when no start or end is provided", TestGetAllMarketData) 84 t.Run("Add should work for all valid enumerations values of auction trigger", shouldWorkForAllValuesOfAuctionTrigger) 85 t.Run("Add should work for all valid enumerations values of composite price type", shouldWorkForAllValuesOfCompositePriceType) 86 } 87 88 func shouldWorkForAllValuesOfCompositePriceType(t *testing.T) { 89 var priceType vegapb.CompositePriceType 90 enums := getEnums(t, priceType) 91 assert.Len(t, enums, 4) 92 93 for e, pt := range enums { 94 t.Run(pt, func(t *testing.T) { 95 ctx := tempTransaction(t) 96 97 addMarketData(t, ctx, "AUCTION_TRIGGER_LIQUIDITY", pt) 98 var got entities.MarketData 99 100 err := connectionSource.QueryRow(ctx, `select mark_price_type from market_data`).Scan(&got.MarkPriceType) 101 require.NoError(t, err) 102 103 mdProto := got.ToProto() 104 105 assert.Equal(t, vegapb.CompositePriceType(e), mdProto.MarkPriceType) 106 }) 107 } 108 } 109 110 func TestGetPAPState(t *testing.T) { 111 ctx := tempTransaction(t) 112 113 addMarketData(t, ctx, "AUCTION_TRIGGER_LIQUIDITY", "COMPOSITE_PRICE_TYPE_LAST_TRADE") 114 var got entities.MarketData 115 116 err := connectionSource.QueryRow(ctx, `select active_protocol_automated_purchase from market_data`).Scan(&got.ActiveProtocolAutomatedPurchase) 117 require.NoError(t, err) 118 119 require.Equal(t, "1", got.ActiveProtocolAutomatedPurchase.Id) 120 require.Equal(t, "2", *got.ActiveProtocolAutomatedPurchase.OrderId) 121 } 122 123 func addMarketData(t *testing.T, ctx context.Context, trigger, priceType string) { 124 t.Helper() 125 bs := sqlstore.NewBlocks(connectionSource) 126 block := addTestBlock(t, ctx, bs) 127 128 md := sqlstore.NewMarketData(connectionSource) 129 orderID := "2" 130 err := md.Add(&entities.MarketData{ 131 Market: entities.MarketID("deadbeef"), 132 MarketTradingMode: "TRADING_MODE_MONITORING_AUCTION", 133 MarketState: "STATE_ACTIVE", 134 AuctionTrigger: trigger, 135 ExtensionTrigger: trigger, 136 MarkPriceType: priceType, 137 PriceMonitoringBounds: []*vega.PriceMonitoringBounds{ 138 { 139 MinValidPrice: "1", 140 MaxValidPrice: "2", 141 Trigger: &vega.PriceMonitoringTrigger{ 142 Horizon: 100, 143 Probability: "0.5", 144 AuctionExtension: 200, 145 }, 146 ReferencePrice: "3", 147 }, 148 }, 149 VegaTime: block.VegaTime, 150 ActiveProtocolAutomatedPurchase: &vegapb.ProtocolAutomatedPurchaseData{ 151 Id: "1", 152 OrderId: &orderID, 153 }, 154 }) 155 require.NoError(t, err) 156 157 _, err = md.Flush(ctx) 158 require.NoError(t, err) 159 } 160 161 func shouldWorkForAllValuesOfAuctionTrigger(t *testing.T) { 162 var auctionTrigger vegapb.AuctionTrigger 163 enums := getEnums(t, auctionTrigger) 164 require.Len(t, enums, 10) 165 166 for e, trigger := range enums { 167 t.Run(trigger, func(t *testing.T) { 168 ctx := tempTransaction(t) 169 170 addMarketData(t, ctx, trigger, "COMPOSITE_PRICE_TYPE_LAST_TRADE") 171 var got entities.MarketData 172 173 err := connectionSource.QueryRow(ctx, `select auction_trigger from market_data`).Scan(&got.AuctionTrigger) 174 require.NoError(t, err) 175 176 mdProto := got.ToProto() 177 178 assert.Equal(t, vegapb.AuctionTrigger(e), mdProto.Trigger) 179 }) 180 } 181 } 182 183 func shouldInsertAValidMarketDataRecord(t *testing.T) { 184 ctx := tempTransaction(t) 185 186 bs := sqlstore.NewBlocks(connectionSource) 187 md := sqlstore.NewMarketData(connectionSource) 188 189 var rowCount int 190 191 err := connectionSource.QueryRow(ctx, `select count(*) from market_data`).Scan(&rowCount) 192 require.NoError(t, err) 193 assert.Equal(t, 0, rowCount) 194 195 block := addTestBlock(t, ctx, bs) 196 197 err = md.Add(&entities.MarketData{ 198 Market: entities.MarketID("deadbeef"), 199 MarketTradingMode: "TRADING_MODE_MONITORING_AUCTION", 200 MarketState: "STATE_ACTIVE", 201 AuctionTrigger: "AUCTION_TRIGGER_LIQUIDITY", 202 ExtensionTrigger: "AUCTION_TRIGGER_UNSPECIFIED", 203 MarkPriceType: "COMPOSITE_PRICE_TYPE_UNSPECIFIED", 204 PriceMonitoringBounds: []*vega.PriceMonitoringBounds{ 205 { 206 MinValidPrice: "1", 207 MaxValidPrice: "2", 208 Trigger: &vega.PriceMonitoringTrigger{ 209 Horizon: 100, 210 Probability: "0.5", 211 AuctionExtension: 200, 212 }, 213 ReferencePrice: "3", 214 }, 215 }, 216 VegaTime: block.VegaTime, 217 }) 218 require.NoError(t, err) 219 220 _, err = md.Flush(ctx) 221 require.NoError(t, err) 222 223 err = connectionSource.QueryRow(ctx, `select count(*) from market_data`).Scan(&rowCount) 224 assert.NoError(t, err) 225 assert.Equal(t, 1, rowCount) 226 } 227 228 func getLatestMarketData(t *testing.T) { 229 ctx := tempTransaction(t) 230 231 store, err := setupMarketData(t, ctx) 232 if err != nil { 233 t.Fatalf("could not set up test: %s", err) 234 } 235 236 marketID := entities.MarketID("8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8") 237 238 want := entities.MarketData{ 239 MarkPrice: mustParseDecimal(t, "999992587"), 240 BestBidPrice: mustParseDecimal(t, "1000056152"), 241 BestBidVolume: 3, 242 BestOfferPrice: mustParseDecimal(t, "999945379"), 243 BestOfferVolume: 1, 244 BestStaticBidPrice: mustParseDecimal(t, "1000056152"), 245 BestStaticBidVolume: 3, 246 BestStaticOfferPrice: mustParseDecimal(t, "999945379"), 247 BestStaticOfferVolume: 1, 248 MidPrice: mustParseDecimal(t, "1000000765"), 249 StaticMidPrice: mustParseDecimal(t, "1000000765"), 250 Market: marketID, 251 OpenInterest: 27, 252 AuctionEnd: 1644573937314794695, 253 AuctionStart: 1644573911314794695, 254 IndicativePrice: mustParseDecimal(t, "1000026624"), 255 IndicativeVolume: 3, 256 MarketTradingMode: "TRADING_MODE_MONITORING_AUCTION", 257 MarketState: "STATE_ACTIVE", 258 AuctionTrigger: "AUCTION_TRIGGER_LIQUIDITY", 259 ExtensionTrigger: "AUCTION_TRIGGER_UNSPECIFIED", 260 MarkPriceType: "COMPOSITE_PRICE_TYPE_LAST_TRADE", 261 TargetStake: mustParseDecimal(t, "67499499622"), 262 SuppliedStake: mustParseDecimal(t, "50000000000"), 263 PriceMonitoringBounds: []*vega.PriceMonitoringBounds{ 264 { 265 MinValidPrice: "1", 266 MaxValidPrice: "2", 267 Trigger: &vega.PriceMonitoringTrigger{ 268 Horizon: 100, 269 Probability: "0.5", 270 AuctionExtension: 200, 271 }, 272 ReferencePrice: "3", 273 }, 274 }, 275 MarketValueProxy: "194290093211464.7413030152957024", 276 LiquidityProviderFeeShares: []*vega.LiquidityProviderFeeShare{ 277 { 278 Party: "af2bb48edd738353fcd7a2b6cea4821dd2382ec95497954535278dfbfff7b5b5", 279 EquityLikeShare: "1", 280 AverageEntryValuation: "50000000000", 281 AverageScore: "123", 282 }, 283 }, 284 MarketGrowth: num.DecimalZero(), 285 LastTradedPrice: mustParseDecimal(t, "999992588"), 286 ProductData: &entities.ProductData{ 287 ProductData: &vega.ProductData{ 288 Data: &vega.ProductData_PerpetualData{ 289 PerpetualData: &vega.PerpetualData{ 290 InternalCompositePrice: "100", 291 NextInternalCompositePriceCalc: 200, 292 InternalCompositePriceType: vega.CompositePriceType_COMPOSITE_PRICE_TYPE_LAST_TRADE, 293 }, 294 }, 295 }, 296 }, 297 } 298 got, err := store.GetMarketDataByID(ctx, "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8") 299 require.NoError(t, err) 300 301 require.Truef(t, want.Equal(got), "want: %#v\ngot: %#v\n", want, got) 302 } 303 304 func getAllForMarketBetweenDates(t *testing.T) { 305 ctx := tempTransaction(t) 306 307 store, err := setupMarketData(t, ctx) 308 if err != nil { 309 t.Fatalf("could not set up test: %s", err) 310 } 311 312 market := "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8" 313 314 startDate := ptr.From(time.Date(2022, 2, 11, 10, 5, 30, 0, time.UTC)) 315 endDate := ptr.From(time.Date(2022, 2, 11, 10, 6, 0, 0, time.UTC)) 316 317 t.Run("should return all results if no cursor pagination is provided", func(t *testing.T) { 318 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, entities.CursorPagination{}) 319 assert.NoError(t, err) 320 assert.Equal(t, 9, len(got)) 321 assert.Equal(t, entities.PageInfo{ 322 HasNextPage: false, 323 HasPreviousPage: false, 324 StartCursor: entities.NewCursor( 325 entities.MarketDataCursor{ 326 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 31, 175000, time.UTC).Local(), 327 }.String()).Encode(), 328 EndCursor: entities.NewCursor( 329 entities.MarketDataCursor{ 330 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 331 }.String()).Encode(), 332 }, pageInfo) 333 }) 334 335 t.Run("should return all results if no cursor pagination is provided - newest first", func(t *testing.T) { 336 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, entities.CursorPagination{NewestFirst: true}) 337 assert.NoError(t, err) 338 assert.Equal(t, 9, len(got)) 339 assert.Equal(t, entities.PageInfo{ 340 HasNextPage: false, 341 HasPreviousPage: false, 342 StartCursor: entities.NewCursor( 343 entities.MarketDataCursor{ 344 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 345 }.String()).Encode(), 346 EndCursor: entities.NewCursor( 347 entities.MarketDataCursor{ 348 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 31, 175000, time.UTC).Local(), 349 }.String()).Encode(), 350 }, pageInfo) 351 }) 352 353 t.Run("should return page of results if cursor pagination is provided with first", func(t *testing.T) { 354 first := int32(5) 355 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 356 require.NoError(t, err) 357 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 358 require.NoError(t, err) 359 assert.Equal(t, 5, len(got)) 360 assert.Equal(t, entities.PageInfo{ 361 HasNextPage: true, 362 HasPreviousPage: false, 363 StartCursor: entities.NewCursor( 364 entities.MarketDataCursor{ 365 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 31, 175000, time.UTC).Local(), 366 }.String()).Encode(), 367 EndCursor: entities.NewCursor( 368 entities.MarketDataCursor{ 369 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 370 }.String()).Encode(), 371 }, pageInfo) 372 }) 373 374 t.Run("should return page of results if cursor pagination is provided with first - newest first", func(t *testing.T) { 375 first := int32(5) 376 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 377 require.NoError(t, err) 378 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 379 require.NoError(t, err) 380 assert.Equal(t, 5, len(got)) 381 assert.Equal(t, entities.PageInfo{ 382 HasNextPage: true, 383 HasPreviousPage: false, 384 StartCursor: entities.NewCursor( 385 entities.MarketDataCursor{ 386 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 387 }.String()).Encode(), 388 EndCursor: entities.NewCursor( 389 entities.MarketDataCursor{ 390 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 391 }.String()).Encode(), 392 }, pageInfo) 393 }) 394 395 t.Run("should return page of results if forward cursor pagination is provided with first and after parameter", func(t *testing.T) { 396 first := int32(5) 397 after := entities.NewCursor(entities.MarketDataCursor{ 398 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 32, 176000, time.UTC).Local(), 399 }.String()).Encode() 400 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 401 require.NoError(t, err) 402 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 403 require.NoError(t, err) 404 assert.Equal(t, 5, len(got)) 405 assert.Equal(t, entities.PageInfo{ 406 HasNextPage: true, 407 HasPreviousPage: true, 408 StartCursor: entities.NewCursor( 409 entities.MarketDataCursor{ 410 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 33, 177000, time.UTC).Local(), 411 }.String()).Encode(), 412 EndCursor: entities.NewCursor( 413 entities.MarketDataCursor{ 414 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 39, 181000, time.UTC).Local(), 415 }.String()).Encode(), 416 }, pageInfo) 417 }) 418 419 t.Run("should return page of results if forward cursor pagination is provided with first and after parameter - newest first", func(t *testing.T) { 420 first := int32(5) 421 after := entities.NewCursor(entities.MarketDataCursor{ 422 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 40, 182000, time.UTC).Local(), 423 }.String()).Encode() 424 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 425 require.NoError(t, err) 426 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 427 require.NoError(t, err) 428 assert.Equal(t, 5, len(got)) 429 assert.Equal(t, entities.PageInfo{ 430 HasNextPage: true, 431 HasPreviousPage: true, 432 StartCursor: entities.NewCursor( 433 entities.MarketDataCursor{ 434 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 39, 181000, time.UTC).Local(), 435 }.String()).Encode(), 436 EndCursor: entities.NewCursor( 437 entities.MarketDataCursor{ 438 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 33, 177000, time.UTC).Local(), 439 }.String()).Encode(), 440 }, pageInfo) 441 }) 442 443 t.Run("should return page of results if cursor pagination is provided with last", func(t *testing.T) { 444 last := int32(5) 445 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 446 require.NoError(t, err) 447 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 448 require.NoError(t, err) 449 assert.Equal(t, 5, len(got)) 450 assert.Equal(t, entities.PageInfo{ 451 HasNextPage: false, 452 HasPreviousPage: true, 453 StartCursor: entities.NewCursor( 454 entities.MarketDataCursor{ 455 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 456 }.String()).Encode(), 457 EndCursor: entities.NewCursor( 458 entities.MarketDataCursor{ 459 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 460 }.String()).Encode(), 461 }, pageInfo) 462 }) 463 464 t.Run("should return page of results if cursor pagination is provided with last - newest first", func(t *testing.T) { 465 last := int32(5) 466 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 467 require.NoError(t, err) 468 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 469 require.NoError(t, err) 470 assert.Equal(t, 5, len(got)) 471 assert.Equal(t, entities.PageInfo{ 472 HasNextPage: false, 473 HasPreviousPage: true, 474 StartCursor: entities.NewCursor( 475 entities.MarketDataCursor{ 476 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 477 }.String()).Encode(), 478 EndCursor: entities.NewCursor( 479 entities.MarketDataCursor{ 480 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 31, 175000, time.UTC).Local(), 481 }.String()).Encode(), 482 }, pageInfo) 483 }) 484 485 t.Run("should return page of results if forward cursor pagination is provided with last and before parameter", func(t *testing.T) { 486 last := int32(5) 487 before := entities.NewCursor( 488 entities.MarketDataCursor{ 489 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 40, 182000, time.UTC).Local(), 490 }.String()).Encode() 491 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 492 require.NoError(t, err) 493 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 494 require.NoError(t, err) 495 assert.Equal(t, 5, len(got)) 496 assert.Equal(t, entities.PageInfo{ 497 HasNextPage: true, 498 HasPreviousPage: true, 499 StartCursor: entities.NewCursor( 500 entities.MarketDataCursor{ 501 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 33, 177000, time.UTC).Local(), 502 }.String()).Encode(), 503 EndCursor: entities.NewCursor( 504 entities.MarketDataCursor{ 505 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 39, 181000, time.UTC).Local(), 506 }.String()).Encode(), 507 }, pageInfo) 508 }) 509 510 t.Run("should return page of results if forward cursor pagination is provided with last and before parameter - newest first", func(t *testing.T) { 511 last := int32(5) 512 before := entities.NewCursor( 513 entities.MarketDataCursor{ 514 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 32, 176000, time.UTC).Local(), 515 }.String()).Encode() 516 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 517 require.NoError(t, err) 518 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, endDate, pagination) 519 require.NoError(t, err) 520 assert.Equal(t, 5, len(got)) 521 assert.Equal(t, entities.PageInfo{ 522 HasNextPage: true, 523 HasPreviousPage: true, 524 StartCursor: entities.NewCursor( 525 entities.MarketDataCursor{ 526 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 39, 181000, time.UTC).Local(), 527 }.String()).Encode(), 528 EndCursor: entities.NewCursor( 529 entities.MarketDataCursor{ 530 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 33, 177000, time.UTC).Local(), 531 }.String()).Encode(), 532 }, pageInfo) 533 }) 534 } 535 536 func getForMarketFromDate(t *testing.T) { 537 ctx := tempTransaction(t) 538 539 store, err := setupMarketData(t, ctx) 540 require.NoError(t, err) 541 542 startDate := ptr.From(time.Date(2022, 2, 11, 10, 5, 0, 0, time.UTC)) 543 544 market := "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8" 545 546 t.Run("should return all results if no cursor pagination is provided", func(t *testing.T) { 547 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, entities.CursorPagination{}) 548 assert.NoError(t, err) 549 assert.Equal(t, 32, len(got)) 550 assert.Equal(t, entities.PageInfo{ 551 HasNextPage: false, 552 HasPreviousPage: false, 553 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 554 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o0, 152000, time.UTC).Local(), 555 }.String()).Encode(), 556 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 557 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 558 }.String()).Encode(), 559 }, pageInfo) 560 }) 561 562 t.Run("should return all results if no cursor pagination is provided - newest first", func(t *testing.T) { 563 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, entities.CursorPagination{NewestFirst: true}) 564 assert.NoError(t, err) 565 assert.Equal(t, 32, len(got)) 566 assert.Equal(t, entities.PageInfo{ 567 HasNextPage: false, 568 HasPreviousPage: false, 569 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 570 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 571 }.String()).Encode(), 572 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 573 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o0, 152000, time.UTC).Local(), 574 }.String()).Encode(), 575 }, pageInfo) 576 }) 577 578 t.Run("should return a page of results if cursor pagination is provided with first", func(t *testing.T) { 579 first := int32(5) 580 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 581 require.NoError(t, err) 582 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 583 assert.NoError(t, err) 584 assert.Equal(t, 5, len(got)) 585 assert.Equal(t, entities.PageInfo{ 586 HasNextPage: true, 587 HasPreviousPage: false, 588 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 589 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o0, 152000, time.UTC).Local(), 590 }.String()).Encode(), 591 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 592 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o5, 156000, time.UTC).Local(), 593 }.String()).Encode(), 594 }, pageInfo) 595 }) 596 597 t.Run("should return a page of results if cursor pagination is provided with first - newest first", func(t *testing.T) { 598 first := int32(5) 599 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 600 require.NoError(t, err) 601 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 602 assert.NoError(t, err) 603 assert.Equal(t, 5, len(got)) 604 assert.Equal(t, entities.PageInfo{ 605 HasNextPage: true, 606 HasPreviousPage: false, 607 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 608 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 41, 183000, time.UTC).Local(), 609 }.String()).Encode(), 610 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 611 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 36, 179000, time.UTC).Local(), 612 }.String()).Encode(), 613 }, pageInfo) 614 }) 615 616 t.Run("should return a page of results if cursor pagination is provided with first and after", func(t *testing.T) { 617 first := int32(5) 618 after := entities.NewCursor(entities.MarketDataCursor{ 619 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 9, 159000, time.UTC).Local(), 620 }.String()).Encode() 621 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 622 require.NoError(t, err) 623 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 624 assert.NoError(t, err) 625 assert.Equal(t, 5, len(got)) 626 assert.Equal(t, entities.PageInfo{ 627 HasNextPage: true, 628 HasPreviousPage: true, 629 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 630 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 11, 160000, time.UTC).Local(), 631 }.String()).Encode(), 632 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 633 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 16, 164000, time.UTC).Local(), 634 }.String()).Encode(), 635 }, pageInfo) 636 }) 637 638 t.Run("should return a page of results if cursor pagination is provided with first and after", func(t *testing.T) { 639 first := int32(5) 640 after := entities.NewCursor(entities.MarketDataCursor{ 641 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 9, 159000, time.UTC).Local(), 642 }.String()).Encode() 643 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 644 require.NoError(t, err) 645 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 646 assert.NoError(t, err) 647 assert.Equal(t, 5, len(got)) 648 assert.Equal(t, entities.PageInfo{ 649 HasNextPage: true, 650 HasPreviousPage: true, 651 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 652 SyntheticTime: time.Date(2022, 2, 11, 10, 5, 8, 158000, time.UTC).Local(), 653 }.String()).Encode(), 654 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 655 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o3, 154000, time.UTC).Local(), 656 }.String()).Encode(), 657 }, pageInfo) 658 }) 659 660 t.Run("should return a page of results if cursor pagination is provided with last", func(t *testing.T) { 661 last := int32(5) 662 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 663 require.NoError(t, err) 664 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 665 assert.NoError(t, err) 666 assert.Equal(t, 5, len(got)) 667 assert.Equal(t, entities.PageInfo{ 668 HasNextPage: false, 669 HasPreviousPage: true, 670 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 671 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 672 }.String()).Encode(), 673 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 674 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 675 }.String()).Encode(), 676 }, pageInfo) 677 }) 678 679 t.Run("should return a page of results if cursor pagination is provided with last - newest first", func(t *testing.T) { 680 last := int32(5) 681 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 682 require.NoError(t, err) 683 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 684 assert.NoError(t, err) 685 assert.Equal(t, 5, len(got)) 686 assert.Equal(t, entities.PageInfo{ 687 HasNextPage: false, 688 HasPreviousPage: true, 689 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 690 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o5, 156000, time.UTC).Local(), 691 }.String()).Encode(), 692 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 693 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 0o0, 152000, time.UTC).Local(), 694 }.String()).Encode(), 695 }, pageInfo) 696 }) 697 698 t.Run("should return a page of results if cursor pagination is provided with last and before", func(t *testing.T) { 699 last := int32(5) 700 before := entities.NewCursor(entities.MarketDataCursor{ 701 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 37, 180000, time.UTC).Local(), 702 }.String()).Encode() 703 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 704 require.NoError(t, err) 705 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 706 assert.NoError(t, err) 707 assert.Equal(t, 5, len(got)) 708 assert.Equal(t, entities.PageInfo{ 709 HasNextPage: true, 710 HasPreviousPage: true, 711 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 712 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 31, 175000, time.UTC).Local(), 713 }.String()).Encode(), 714 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 715 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 36, 179000, time.UTC).Local(), 716 }.String()).Encode(), 717 }, pageInfo) 718 }) 719 720 t.Run("should return a page of results if cursor pagination is provided with last and before - newest first", func(t *testing.T) { 721 last := int32(5) 722 before := entities.NewCursor(entities.MarketDataCursor{ 723 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 20, 167000, time.UTC).Local(), 724 }.String()).Encode() 725 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 726 require.NoError(t, err) 727 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, startDate, nil, pagination) 728 assert.NoError(t, err) 729 assert.Equal(t, 5, len(got)) 730 assert.Equal(t, entities.PageInfo{ 731 HasNextPage: true, 732 HasPreviousPage: true, 733 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 734 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 27, 172000, time.UTC).Local(), 735 }.String()).Encode(), 736 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 737 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 22, 168000, time.UTC).Local(), 738 }.String()).Encode(), 739 }, pageInfo) 740 }) 741 } 742 743 func getForMarketToDate(t *testing.T) { 744 ctx := tempTransaction(t) 745 746 store, err := setupMarketData(t, ctx) 747 require.NoError(t, err) 748 749 endDate := ptr.From(time.Date(2022, 2, 11, 10, 2, 0, 0, time.UTC)) 750 751 market := "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8" 752 753 t.Run("should return all results if no cursor pagination is provided", func(t *testing.T) { 754 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, entities.CursorPagination{}) 755 assert.NoError(t, err) 756 assert.Equal(t, 18, len(got)) 757 wantStartCursor := entities.NewCursor(entities.MarketDataCursor{ 758 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 759 }.String()).Encode() 760 wantEndCursor := entities.NewCursor(entities.MarketDataCursor{ 761 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 762 }.String()).Encode() 763 assert.Equal(t, entities.PageInfo{ 764 HasNextPage: false, 765 HasPreviousPage: false, 766 StartCursor: wantStartCursor, 767 EndCursor: wantEndCursor, 768 }, pageInfo) 769 }) 770 771 t.Run("should return all results if no cursor pagination is provided - newest first", func(t *testing.T) { 772 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, entities.CursorPagination{NewestFirst: true}) 773 assert.NoError(t, err) 774 assert.Equal(t, 18, len(got)) 775 wantStartCursor := entities.NewCursor(entities.MarketDataCursor{ 776 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 777 }.String()).Encode() 778 wantEndCursor := entities.NewCursor(entities.MarketDataCursor{ 779 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 780 }.String()).Encode() 781 assert.Equal(t, entities.PageInfo{ 782 HasNextPage: false, 783 HasPreviousPage: false, 784 StartCursor: wantStartCursor, 785 EndCursor: wantEndCursor, 786 }, pageInfo) 787 }) 788 789 t.Run("should return a page of results if cursor pagination is provided with first", func(t *testing.T) { 790 first := int32(10) 791 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 792 require.NoError(t, err) 793 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 794 assert.NoError(t, err) 795 assert.Equal(t, 10, len(got)) 796 assert.Equal(t, entities.PageInfo{ 797 HasNextPage: true, 798 HasPreviousPage: false, 799 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 800 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 801 }.String()).Encode(), 802 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 803 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 804 }.String()).Encode(), 805 }, pageInfo) 806 }) 807 808 t.Run("should return a page of results if cursor pagination is provided with first - newest first", func(t *testing.T) { 809 first := int32(10) 810 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 811 require.NoError(t, err) 812 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 813 assert.NoError(t, err) 814 assert.Equal(t, 10, len(got)) 815 assert.Equal(t, entities.PageInfo{ 816 HasNextPage: true, 817 HasPreviousPage: false, 818 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 819 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 820 }.String()).Encode(), 821 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 822 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 47, 8000, time.UTC).Local(), 823 }.String()).Encode(), 824 }, pageInfo) 825 }) 826 827 t.Run("should return a page of results if cursor pagination is provided with first and after", func(t *testing.T) { 828 first := int32(10) 829 after := entities.NewCursor(entities.MarketDataCursor{ 830 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 831 }.String()).Encode() 832 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 833 require.NoError(t, err) 834 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 835 assert.NoError(t, err) 836 assert.Equal(t, 8, len(got)) 837 assert.Equal(t, entities.PageInfo{ 838 HasNextPage: false, 839 HasPreviousPage: true, 840 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 841 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 50, 10000, time.UTC).Local(), 842 }.String()).Encode(), 843 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 844 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 845 }.String()).Encode(), 846 }, pageInfo) 847 }) 848 849 t.Run("should return a page of results if cursor pagination is provided with first and after - newest first", func(t *testing.T) { 850 first := int32(10) 851 after := entities.NewCursor(entities.MarketDataCursor{ 852 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 47, 8000, time.UTC).Local(), 853 }.String()).Encode() 854 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 855 require.NoError(t, err) 856 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 857 assert.NoError(t, err) 858 assert.Equal(t, 8, len(got)) 859 assert.Equal(t, entities.PageInfo{ 860 HasNextPage: false, 861 HasPreviousPage: true, 862 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 863 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 46, 7000, time.UTC).Local(), 864 }.String()).Encode(), 865 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 866 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 867 }.String()).Encode(), 868 }, pageInfo) 869 }) 870 871 t.Run("should return a page of results if cursor pagination is provided with last", func(t *testing.T) { 872 last := int32(10) 873 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 874 require.NoError(t, err) 875 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 876 assert.NoError(t, err) 877 assert.Equal(t, 10, len(got)) 878 assert.Equal(t, entities.PageInfo{ 879 HasNextPage: false, 880 HasPreviousPage: true, 881 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 882 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 47, 8000, time.UTC).Local(), 883 }.String()).Encode(), 884 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 885 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 886 }.String()).Encode(), 887 }, pageInfo) 888 }) 889 890 t.Run("should return a page of results if cursor pagination is provided with last - newest first", func(t *testing.T) { 891 last := int32(10) 892 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 893 require.NoError(t, err) 894 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 895 assert.NoError(t, err) 896 assert.Equal(t, 10, len(got)) 897 assert.Equal(t, entities.PageInfo{ 898 HasNextPage: false, 899 HasPreviousPage: true, 900 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 901 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 902 }.String()).Encode(), 903 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 904 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 905 }.String()).Encode(), 906 }, pageInfo) 907 }) 908 909 t.Run("should return a page of results if cursor pagination is provided with last and before", func(t *testing.T) { 910 last := int32(10) 911 before := entities.NewCursor(entities.MarketDataCursor{ 912 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 913 }.String()).Encode() 914 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 915 require.NoError(t, err) 916 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 917 assert.NoError(t, err) 918 assert.Equal(t, 9, len(got)) 919 assert.Equal(t, entities.PageInfo{ 920 HasNextPage: true, 921 HasPreviousPage: false, 922 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 923 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 924 }.String()).Encode(), 925 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 926 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 47, 8000, time.UTC).Local(), 927 }.String()).Encode(), 928 }, pageInfo) 929 }) 930 931 t.Run("should return a page of results if cursor pagination is provided with last and before - newest first", func(t *testing.T) { 932 last := int32(10) 933 before := entities.NewCursor(entities.MarketDataCursor{ 934 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 47, 8000, time.UTC).Local(), 935 }.String()).Encode() 936 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 937 require.NoError(t, err) 938 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, endDate, pagination) 939 assert.NoError(t, err) 940 assert.Equal(t, 9, len(got)) 941 assert.Equal(t, entities.PageInfo{ 942 HasNextPage: true, 943 HasPreviousPage: false, 944 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 945 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o2, 0o0, 17000, time.UTC).Local(), 946 }.String()).Encode(), 947 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 948 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 949 }.String()).Encode(), 950 }, pageInfo) 951 }) 952 } 953 954 func TestGetAllMarketData(t *testing.T) { 955 ctx := tempTransaction(t) 956 957 store, err := setupMarketData(t, ctx) 958 require.NoError(t, err) 959 market := "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8" 960 startDate := time.Date(2022, 2, 11, 0, 0, 0, 0, time.UTC) 961 962 t.Run("should return all results if no cursor pagination is provided", func(t *testing.T) { 963 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, &startDate, nil, entities.CursorPagination{}) 964 assert.NoError(t, err) 965 assert.Equal(t, 184, len(got)) 966 wantStartCursor := entities.NewCursor(entities.MarketDataCursor{ 967 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 968 }.String()).Encode() 969 wantEndCursor := entities.NewCursor(entities.MarketDataCursor{ 970 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 971 }.String()).Encode() 972 assert.Equal(t, entities.PageInfo{ 973 HasNextPage: false, 974 HasPreviousPage: false, 975 StartCursor: wantStartCursor, 976 EndCursor: wantEndCursor, 977 }, pageInfo) 978 }) 979 980 t.Run("should return a page of results if cursor pagination is provided with first", func(t *testing.T) { 981 first := int32(10) 982 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 983 require.NoError(t, err) 984 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, &startDate, nil, pagination) 985 assert.NoError(t, err) 986 assert.Equal(t, 10, len(got)) 987 assert.Equal(t, entities.PageInfo{ 988 HasNextPage: true, 989 HasPreviousPage: false, 990 StartCursor: entities.NewCursor(entities.MarketDataCursor{ 991 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 35, 0, time.UTC).Local(), 992 }.String()).Encode(), 993 EndCursor: entities.NewCursor(entities.MarketDataCursor{ 994 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o1, 49, 9000, time.UTC).Local(), 995 }.String()).Encode(), 996 }, pageInfo) 997 }) 998 999 t.Run("should return the most recent record if no dates and no cursor pagination is provided", func(t *testing.T) { 1000 got, pageInfo, err := store.GetHistoricMarketData(ctx, market, nil, nil, entities.CursorPagination{}) 1001 assert.NoError(t, err) 1002 assert.Equal(t, 1, len(got)) 1003 wantStartCursor := entities.NewCursor(entities.MarketDataCursor{ 1004 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 1005 }.String()).Encode() 1006 wantEndCursor := entities.NewCursor(entities.MarketDataCursor{ 1007 SyntheticTime: time.Date(2022, 0o2, 11, 10, 0o5, 41, 183000, time.UTC).Local(), 1008 }.String()).Encode() 1009 assert.Equal(t, entities.PageInfo{ 1010 HasNextPage: true, 1011 HasPreviousPage: false, 1012 StartCursor: wantStartCursor, 1013 EndCursor: wantEndCursor, 1014 }, pageInfo) 1015 }) 1016 } 1017 1018 func setupMarketData(t *testing.T, ctx context.Context) (*sqlstore.MarketData, error) { 1019 t.Helper() 1020 1021 bs := sqlstore.NewBlocks(connectionSource) 1022 md := sqlstore.NewMarketData(connectionSource) 1023 1024 f, err := os.Open(filepath.Join("testdata", "marketdata.csv")) 1025 if err != nil { 1026 return nil, err 1027 } 1028 1029 defer f.Close() 1030 1031 reader := csv.NewReader(bufio.NewReader(f)) 1032 1033 var hash []byte 1034 hash, err = hex.DecodeString("deadbeef") 1035 assert.NoError(t, err) 1036 1037 addedBlocksAt := make(map[int64]struct{}) 1038 seqNum := 0 1039 for { 1040 line, err := reader.Read() 1041 if err != nil { 1042 if err == io.EOF { 1043 break 1044 } 1045 return nil, err 1046 } 1047 if len(line) == 0 { 1048 continue 1049 } 1050 1051 marketData := csvToMarketData(t, line, seqNum) 1052 seqNum++ 1053 1054 if _, alreadyAdded := addedBlocksAt[marketData.VegaTime.UnixNano()]; !alreadyAdded { 1055 // Postgres only stores timestamps in microsecond resolution 1056 block := entities.Block{ 1057 VegaTime: marketData.VegaTime, 1058 Height: 2, 1059 Hash: hash, 1060 } 1061 1062 // Add it to the database 1063 err = bs.Add(ctx, block) 1064 require.NoError(t, err) 1065 addedBlocksAt[marketData.VegaTime.UnixNano()] = struct{}{} 1066 } 1067 1068 err = md.Add(marketData) 1069 require.NoError(t, err) 1070 } 1071 _, err = md.Flush(ctx) 1072 require.NoError(t, err) 1073 1074 return md, nil 1075 } 1076 1077 func mustParseDecimal(t *testing.T, value string) decimal.Decimal { 1078 t.Helper() 1079 d, err := decimal.NewFromString(value) 1080 if err != nil { 1081 t.Fatalf("could not parse decimal value: %s", err) 1082 } 1083 1084 return d 1085 } 1086 1087 func mustParseTimestamp(t *testing.T, value string) time.Time { 1088 t.Helper() 1089 const dbDateFormat = "2006-01-02 15:04:05.999999 -07:00" 1090 ts, err := time.Parse(dbDateFormat, value) 1091 if err != nil { 1092 t.Fatalf("could not parse time: %s", err) 1093 } 1094 1095 return ts 1096 } 1097 1098 func mustParseUInt64(t *testing.T, value string) uint64 { 1099 t.Helper() 1100 i, err := strconv.ParseUint(value, 10, 64) 1101 if err != nil { 1102 t.Fatalf("could not parse int64: %s", err) 1103 } 1104 1105 return i 1106 } 1107 1108 func mustParseInt64(t *testing.T, value string) int64 { 1109 t.Helper() 1110 i, err := strconv.ParseInt(value, 10, 64) 1111 if err != nil { 1112 t.Fatalf("could not parse int64: %s", err) 1113 } 1114 1115 return i 1116 } 1117 1118 func mustParsePriceMonitoringBounds(t *testing.T, value string) []*vega.PriceMonitoringBounds { 1119 t.Helper() 1120 if strings.ToLower(value) == "null" { 1121 return nil 1122 } 1123 1124 var bounds []*vega.PriceMonitoringBounds 1125 1126 err := json.Unmarshal([]byte(value), &bounds) 1127 if err != nil { 1128 t.Fatalf("could not parse Price Monitoring Bounds: %s", err) 1129 } 1130 1131 return bounds 1132 } 1133 1134 func mustParseLiquidity(t *testing.T, value string) []*vega.LiquidityProviderFeeShare { 1135 t.Helper() 1136 if strings.ToLower(value) == "null" { 1137 return nil 1138 } 1139 1140 var liquidity []*vega.LiquidityProviderFeeShare 1141 1142 err := json.Unmarshal([]byte(value), &liquidity) 1143 if err != nil { 1144 t.Fatalf("could not parse Liquidity Provider Fee Share: %s", err) 1145 } 1146 1147 return liquidity 1148 } 1149 1150 func csvToMarketData(t *testing.T, line []string, seqNum int) *entities.MarketData { 1151 t.Helper() 1152 1153 vegaTime := mustParseTimestamp(t, line[csvColumnVegaTime]) 1154 syntheticTime := vegaTime.Add(time.Duration(seqNum) * time.Microsecond) 1155 1156 return &entities.MarketData{ 1157 MarkPrice: mustParseDecimal(t, line[csvColumnMarkPrice]), 1158 BestBidPrice: mustParseDecimal(t, line[csvColumnBestBidPrice]), 1159 BestBidVolume: mustParseUInt64(t, line[csvColumnBestBidVolume]), 1160 BestOfferPrice: mustParseDecimal(t, line[csvColumnBestOfferPrice]), 1161 BestOfferVolume: mustParseUInt64(t, line[csvColumnBestOfferVolume]), 1162 BestStaticBidPrice: mustParseDecimal(t, line[csvColumnBestStaticBidPrice]), 1163 BestStaticBidVolume: mustParseUInt64(t, line[csvColumnBestStaticBidVolume]), 1164 BestStaticOfferPrice: mustParseDecimal(t, line[csvColumnBestStaticOfferPrice]), 1165 BestStaticOfferVolume: mustParseUInt64(t, line[csvColumnBestStaticOfferVolume]), 1166 MidPrice: mustParseDecimal(t, line[csvColumnMidPrice]), 1167 StaticMidPrice: mustParseDecimal(t, line[csvColumnStaticMidPrice]), 1168 Market: entities.MarketID(line[csvColumnMarket]), 1169 OpenInterest: mustParseUInt64(t, line[csvColumnOpenInterest]), 1170 AuctionEnd: mustParseInt64(t, line[csvColumnAuctionEnd]), 1171 AuctionStart: mustParseInt64(t, line[csvColumnAuctionStart]), 1172 IndicativePrice: mustParseDecimal(t, line[csvColumnIndicativePrice]), 1173 IndicativeVolume: mustParseUInt64(t, line[csvColumnIndicativeVolume]), 1174 MarketTradingMode: line[csvColumnMarketTradingMode], 1175 AuctionTrigger: line[csvColumnAuctionTrigger], 1176 ExtensionTrigger: line[csvColumnExtensionTrigger], 1177 TargetStake: mustParseDecimal(t, line[csvColumnTargetStake]), 1178 SuppliedStake: mustParseDecimal(t, line[csvColumnSuppliedStake]), 1179 PriceMonitoringBounds: mustParsePriceMonitoringBounds(t, line[csvColumnPriceMonitoringBounds]), 1180 MarketValueProxy: line[csvColumnMarketValueProxy], 1181 LiquidityProviderFeeShares: mustParseLiquidity(t, line[csvColumnLiquidityProviderFeeShares]), 1182 MarketState: line[csvColumnMarketState], 1183 VegaTime: vegaTime, 1184 SeqNum: uint64(seqNum), 1185 SyntheticTime: syntheticTime, 1186 MarketGrowth: mustParseDecimal(t, line[csvColumnMarketGrowth]), 1187 LastTradedPrice: mustParseDecimal(t, line[csvColumnLastTradedPrice]), 1188 ProductData: &entities.ProductData{ 1189 ProductData: &vega.ProductData{ 1190 Data: &vega.ProductData_PerpetualData{ 1191 PerpetualData: &vega.PerpetualData{ 1192 InternalCompositePrice: "100", 1193 NextInternalCompositePriceCalc: 200, 1194 InternalCompositePriceType: vega.CompositePriceType_COMPOSITE_PRICE_TYPE_LAST_TRADE, 1195 }, 1196 }, 1197 }, 1198 }, 1199 MarkPriceType: "COMPOSITE_PRICE_TYPE_LAST_TRADE", 1200 } 1201 }