code.vegaprotocol.io/vega@v0.79.0/core/datasource/spec/engine_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 spec_test 17 18 import ( 19 "context" 20 "fmt" 21 "strconv" 22 "testing" 23 "time" 24 25 bmok "code.vegaprotocol.io/vega/core/broker/mocks" 26 "code.vegaprotocol.io/vega/core/datasource" 27 "code.vegaprotocol.io/vega/core/datasource/common" 28 "code.vegaprotocol.io/vega/core/datasource/definition" 29 "code.vegaprotocol.io/vega/core/datasource/internal/timetrigger" 30 dsspec "code.vegaprotocol.io/vega/core/datasource/spec" 31 "code.vegaprotocol.io/vega/core/datasource/spec/mocks" 32 "code.vegaprotocol.io/vega/core/events" 33 "code.vegaprotocol.io/vega/logging" 34 vegapb "code.vegaprotocol.io/vega/protos/vega" 35 datapb "code.vegaprotocol.io/vega/protos/vega/data/v1" 36 37 "github.com/golang/mock/gomock" 38 "github.com/stretchr/testify/assert" 39 "github.com/stretchr/testify/require" 40 ) 41 42 func TestOracleEngine(t *testing.T) { 43 t.Run("Oracle listens to given public keys succeeds", testOracleEngineListensToSignersSucceeds) 44 t.Run("Oracle listens to given public keys fails", testOracleEngineListensToSignersFails) 45 t.Run("Subscribing to oracle engine succeeds", testOracleEngineSubscribingSucceeds) 46 t.Run("Subscribing to oracle engine with without callback fails", testOracleEngineSubscribingWithoutCallbackFails) 47 t.Run("Broadcasting to matching data succeeds", testOracleEngineBroadcastingMatchingDataSucceeds) 48 t.Run("Unsubscribing known ID from oracle engine succeeds", testOracleEngineUnsubscribingKnownIDSucceeds) 49 t.Run("Unsubscribing unknown ID from oracle engine panics", testOracleEngineUnsubscribingUnknownIDPanics) 50 t.Run("Updating current time succeeds", testOracleEngineUpdatingCurrentTimeSucceeds) 51 t.Run("Subscribing to oracle spec activation succeeds", testOracleEngineSubscribingToSpecActivationSucceeds) 52 t.Run("Builtin time trigger succeeds", testBuiltinTimeTriggerSucceeds) 53 } 54 55 func testOracleEngineListensToSignersSucceeds(t *testing.T) { 56 // test conditions 57 ctx := context.Background() 58 currentTime := time.Now() 59 engine := newEngine(ctx, t, currentTime) 60 61 // test oracle engine with 1 subscriber and 1 key provided 62 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 63 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 64 _, _, _ = engine.Subscribe(ctx, btcEquals42.spec, btcEquals42.subscriber.Cb) 65 66 // test oracle data with single PubKey 67 data := common.Data{ 68 Signers: []*common.Signer{ 69 common.CreateSignerFromString("0xCAFED00D", common.SignerTypePubKey), 70 }, 71 Data: map[string]string{ 72 "my_key": "not an integer", 73 }, 74 } 75 76 result := engine.ListensToSigners(data) 77 assert.True(t, result) 78 79 // test oracle engine with 2 subscribers and multiple keys provided for one of them 80 ethEquals42 := spec(t, "ETH", datapb.Condition_OPERATOR_LESS_THAN, "84", "0xCAFED00X", "0xCAFED00D", "0xBEARISH7", "0xBULLISH5") 81 engine.broker.expectNewSpecSubscription(currentTime, ethEquals42.spec.OriginalSpec) 82 _, _, _ = engine.Subscribe(ctx, ethEquals42.spec, ethEquals42.subscriber.Cb) 83 84 signersAppend := []*common.Signer{ 85 common.CreateSignerFromString("0xBEARISH7", common.SignerTypePubKey), 86 common.CreateSignerFromString("0xBULLISH5", common.SignerTypePubKey), 87 } 88 89 data.Signers = append(data.Signers, signersAppend...) 90 result = engine.ListensToSigners(data) 91 assert.True(t, result) 92 93 // test oracle data with 3 subscribers and multiple keys for some of them 94 btcGreater21 := spec(t, "BTC", datapb.Condition_OPERATOR_GREATER_THAN, "21", "0xCAFED00D", "0xBEARISH7", "0xBULLISH5", "0xMILK123", "OxMILK456") 95 engine.broker.expectNewSpecSubscription(currentTime, btcGreater21.spec.OriginalSpec) 96 _, _, _ = engine.Subscribe(ctx, btcGreater21.spec, btcGreater21.subscriber.Cb) 97 98 data.Signers = append(data.Signers, common.CreateSignerFromString("0xMILK123", common.SignerTypePubKey)) 99 result = engine.ListensToSigners(data) 100 assert.True(t, result) 101 } 102 103 func testOracleEngineListensToSignersFails(t *testing.T) { 104 // test conditions 105 ctx := context.Background() 106 currentTime := time.Now() 107 engine := newEngine(ctx, t, currentTime) 108 109 // test oracle engine with single subscriber and wrong key 110 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42", "0xWRONGKEY") 111 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 112 _, _, _ = engine.Subscribe(ctx, btcEquals42.spec, btcEquals42.subscriber.Cb) 113 114 data := common.Data{ 115 Signers: []*common.Signer{ 116 common.CreateSignerFromString("0xCAFED00D", common.SignerTypePubKey), 117 common.CreateSignerFromString("0xBEARISH17", common.SignerTypePubKey), 118 }, 119 Data: map[string]string{ 120 "my_key": "not an integer", 121 }, 122 MetaData: map[string]string{}, 123 } 124 125 result := engine.ListensToSigners(data) 126 assert.False(t, result) 127 128 // test oracle engine with 2 subscribers and multiple missing keys 129 ethEquals42 := spec(t, "ETH", datapb.Condition_OPERATOR_LESS_THAN, "84", "0xBEARISH7", "0xBULLISH5") 130 engine.broker.expectNewSpecSubscription(currentTime, ethEquals42.spec.OriginalSpec) 131 _, _, _ = engine.Subscribe(ctx, ethEquals42.spec, ethEquals42.subscriber.Cb) 132 133 signersAppend := []*common.Signer{ 134 common.CreateSignerFromString("0xMILK123", common.SignerTypePubKey), 135 common.CreateSignerFromString("OxMILK456", common.SignerTypePubKey), 136 } 137 data.Signers = append(data.Signers, signersAppend...) 138 result = engine.ListensToSigners(data) 139 assert.False(t, result) 140 } 141 142 func testOracleEngineSubscribingSucceeds(t *testing.T) { 143 // given 144 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 145 ethLess84 := spec(t, "ETH", datapb.Condition_OPERATOR_LESS_THAN, "84") 146 147 // setup 148 ctx := context.Background() 149 currentTime := time.Now() 150 151 engine := newEngine(ctx, t, currentTime) 152 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 153 engine.broker.expectNewSpecSubscription(currentTime, ethLess84.spec.OriginalSpec) 154 155 // when 156 id1, _, _ := engine.Subscribe(ctx, btcEquals42.spec, btcEquals42.subscriber.Cb) 157 id2, _, _ := engine.Subscribe(ctx, ethLess84.spec, ethLess84.subscriber.Cb) 158 159 // then 160 assert.Equal(t, dsspec.SubscriptionID(1), id1) 161 assert.Equal(t, dsspec.SubscriptionID(2), id2) 162 } 163 164 func testOracleEngineSubscribingToSpecActivationSucceeds(t *testing.T) { 165 // given 166 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 167 ethLess84 := spec(t, "ETH", datapb.Condition_OPERATOR_LESS_THAN, "84") 168 169 subscriber1 := dummySubscriber{} 170 subscriber2 := dummySubscriber{} 171 172 // setup 173 ctx := context.Background() 174 currentTime := time.Now() 175 176 subscriber := newTestActivationSubscriber() 177 178 engine := newEngine(ctx, t, currentTime) 179 engine.AddSpecActivationListener(subscriber) 180 181 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 182 183 id1, _, _ := engine.Subscribe(ctx, btcEquals42.spec, subscriber1.Cb) 184 185 engine.broker.expectNewSpecSubscription(currentTime, ethLess84.spec.OriginalSpec) 186 id2, _, _ := engine.Subscribe(ctx, ethLess84.spec, subscriber1.Cb) 187 188 engine.broker.expectNewSpecSubscription(currentTime, ethLess84.spec.OriginalSpec) 189 id3, _, _ := engine.Subscribe(ctx, ethLess84.spec, subscriber2.Cb) 190 191 assert.Equal(t, 2, len(subscriber.activeSpecs)) 192 193 engine.Unsubscribe(ctx, id3) 194 195 assert.Equal(t, 2, len(subscriber.activeSpecs)) 196 197 engine.broker.expectSpecSubscriptionDeactivation(currentTime, ethLess84.spec.OriginalSpec) 198 engine.Unsubscribe(ctx, id2) 199 assert.Equal(t, 1, len(subscriber.activeSpecs)) 200 201 engine.broker.expectSpecSubscriptionDeactivation(currentTime, btcEquals42.spec.OriginalSpec) 202 engine.Unsubscribe(ctx, id1) 203 assert.Equal(t, 0, len(subscriber.activeSpecs)) 204 } 205 206 type testActivationSubscriber struct { 207 activeSpecs map[string]datasource.Spec 208 } 209 210 func newTestActivationSubscriber() testActivationSubscriber { 211 return testActivationSubscriber{activeSpecs: make(map[string]datasource.Spec)} 212 } 213 214 func (t testActivationSubscriber) OnSpecActivated(ctx context.Context, oracleSpec datasource.Spec) error { 215 t.activeSpecs[oracleSpec.ID] = oracleSpec 216 return nil 217 } 218 219 func (t testActivationSubscriber) OnSpecDeactivated(ctx context.Context, oracleSpec datasource.Spec) { 220 delete(t.activeSpecs, oracleSpec.ID) 221 } 222 223 func testOracleEngineSubscribingWithoutCallbackFails(t *testing.T) { 224 // given 225 s := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 226 227 // setup 228 ctx := context.Background() 229 currentTime := time.Now() 230 engine := newEngine(ctx, t, currentTime) 231 232 // when 233 subscribe := func() { 234 engine.Subscribe(ctx, s.spec, nil) 235 } 236 237 // then 238 assert.Panics(t, subscribe) 239 } 240 241 func testOracleEngineBroadcastingMatchingDataSucceeds(t *testing.T) { 242 // given 243 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 244 btcGreater21 := spec(t, "BTC", datapb.Condition_OPERATOR_GREATER_THAN, "21") 245 ethEquals42 := spec(t, "ETH", datapb.Condition_OPERATOR_EQUALS, "42") 246 ethLess84 := spec(t, "ETH", datapb.Condition_OPERATOR_LESS_THAN, "84") 247 btcGreater100 := spec(t, "BTC", datapb.Condition_OPERATOR_GREATER_THAN, "100") 248 dataBTC42 := dataWithPrice("BTC", "42") 249 250 // setup 251 ctx := context.Background() 252 currentTime := time.Now() 253 engine := newEngine(ctx, t, currentTime) 254 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 255 engine.broker.expectNewSpecSubscription(currentTime, btcGreater21.spec.OriginalSpec) 256 engine.broker.expectNewSpecSubscription(currentTime, ethEquals42.spec.OriginalSpec) 257 engine.broker.expectNewSpecSubscription(currentTime, ethLess84.spec.OriginalSpec) 258 engine.broker.expectNewSpecSubscription(currentTime, btcGreater100.spec.OriginalSpec) 259 engine.broker.expectMatchedDataEvent(currentTime, &dataBTC42.proto, []string{ 260 btcEquals42.spec.OriginalSpec.ID, 261 btcGreater21.spec.OriginalSpec.ID, 262 }) 263 264 // when 265 engine.Subscribe(ctx, btcEquals42.spec, btcEquals42.subscriber.Cb) 266 engine.Subscribe(ctx, ethEquals42.spec, ethEquals42.subscriber.Cb) 267 engine.Subscribe(ctx, btcGreater21.spec, btcGreater21.subscriber.Cb) 268 engine.Subscribe(ctx, ethLess84.spec, ethLess84.subscriber.Cb) 269 engine.Subscribe(ctx, btcGreater100.spec, btcGreater100.subscriber.Cb) 270 errB := engine.BroadcastData(context.Background(), dataBTC42.data) 271 272 // ensure vega-time is set 273 dataBTC42.data.MetaData = map[string]string{ 274 "vega-time": strconv.FormatInt(currentTime.Unix(), 10), 275 } 276 // then 277 require.NoError(t, errB) 278 assert.Equal(t, &dataBTC42.data, btcEquals42.subscriber.ReceivedData) 279 assert.Equal(t, &dataBTC42.data, btcGreater21.subscriber.ReceivedData) 280 assert.Nil(t, ethEquals42.subscriber.ReceivedData) 281 assert.Nil(t, ethLess84.subscriber.ReceivedData) 282 assert.Nil(t, btcGreater100.subscriber.ReceivedData) 283 } 284 285 func testOracleEngineUnsubscribingUnknownIDPanics(t *testing.T) { 286 // setup 287 ctx := context.Background() 288 currentTime := time.Now() 289 engine := newEngine(ctx, t, currentTime) 290 291 // when 292 unsubscribe := func() { 293 engine.Unsubscribe(ctx, dsspec.SubscriptionID(1)) 294 } 295 296 // then 297 assert.Panics(t, unsubscribe) 298 } 299 300 func testOracleEngineUnsubscribingKnownIDSucceeds(t *testing.T) { 301 // given 302 btcEquals42 := spec(t, "BTC", datapb.Condition_OPERATOR_EQUALS, "42") 303 ethEquals42 := spec(t, "ETH", datapb.Condition_OPERATOR_EQUALS, "42") 304 ctx := context.Background() 305 currentTime := time.Now() 306 engine := newEngine(ctx, t, currentTime) 307 308 // expect 309 engine.broker.expectNewSpecSubscription(currentTime, btcEquals42.spec.OriginalSpec) 310 311 // when 312 idS1, _, _ := engine.Subscribe(ctx, btcEquals42.spec, btcEquals42.subscriber.Cb) 313 314 // expect 315 engine.broker.expectNewSpecSubscription(currentTime, ethEquals42.spec.OriginalSpec) 316 317 // when 318 _, _, _ = engine.Subscribe(ctx, ethEquals42.spec, ethEquals42.subscriber.Cb) 319 320 // expect 321 engine.broker.expectSpecSubscriptionDeactivation(currentTime, btcEquals42.spec.OriginalSpec) 322 323 // when 324 engine.Unsubscribe(ctx, idS1) 325 326 // given 327 dataETH42 := dataWithPrice("ETH", "42") 328 329 // expect 330 engine.broker.expectMatchedDataEvent(currentTime, &dataETH42.proto, []string{ 331 ethEquals42.spec.OriginalSpec.ID, 332 }) 333 // vega-time will be set 334 dataETH42.data.MetaData = map[string]string{ 335 "vega-time": strconv.FormatInt(currentTime.Unix(), 10), 336 } 337 338 // when 339 err := engine.BroadcastData(context.Background(), dataETH42.data) 340 341 // then 342 require.NoError(t, err) 343 assert.Equal(t, &dataETH42.data, ethEquals42.subscriber.ReceivedData) 344 } 345 346 func testOracleEngineUpdatingCurrentTimeSucceeds(t *testing.T) { 347 // setup 348 ctx := context.Background() 349 time30 := time.Unix(30, 0) 350 time60 := time.Unix(60, 0) 351 engine := newEngine(ctx, t, time30) 352 assert.Equal(t, time30, engine.ts.GetTimeNow()) 353 354 engine2 := newEngine(ctx, t, time60) 355 assert.Equal(t, time60, engine2.ts.GetTimeNow()) 356 } 357 358 func testBuiltinTimeTriggerSucceeds(t *testing.T) { 359 // given 360 trigger := triggerSpec(t, time.Now(), 5) 361 362 // setup 363 ctx := context.Background() 364 currentTime := time.Now() 365 engine := newEngine(ctx, t, currentTime) 366 367 engine.broker.EXPECT().Send(gomock.Any()).Times(1) 368 engine.Subscribe(ctx, trigger.spec, trigger.subscriber.Cb) 369 370 // broadcast a time that will not trigger 371 data := common.Data{ 372 Data: map[string]string{ 373 dsspec.BuiltinTimeTrigger: strconv.FormatInt(currentTime.Add(-time.Minute).Unix(), 10), 374 }, 375 } 376 engine.BroadcastData(ctx, data) 377 378 // now broadcast one that will 379 engine.broker.EXPECT().Send(gomock.Any()).Times(1) 380 data = common.Data{ 381 Data: map[string]string{ 382 dsspec.BuiltinTimeTrigger: strconv.FormatInt(currentTime.Add(time.Minute).Unix(), 10), 383 }, 384 } 385 engine.BroadcastData(ctx, data) 386 } 387 388 type testEngine struct { 389 *dsspec.Engine 390 ts *testTimeService 391 broker *testBroker 392 } 393 394 // newEngine returns new Oracle test engine, but with preset time, so we can test against its value. 395 func newEngine(ctx context.Context, t *testing.T, tm time.Time) *testEngine { 396 t.Helper() 397 broker := newBroker(ctx, t) 398 399 ts := newTimeService(ctx, t) 400 ts.EXPECT().GetTimeNow().DoAndReturn( 401 func() time.Time { 402 return tm 403 }).AnyTimes() 404 405 te := &testEngine{ 406 Engine: dsspec.NewEngine( 407 logging.NewTestLogger(), 408 dsspec.NewDefaultConfig(), 409 ts, 410 broker, 411 ), 412 ts: ts, 413 broker: broker, 414 } 415 416 return te 417 } 418 419 type dataBundle struct { 420 data common.Data 421 proto vegapb.OracleData 422 } 423 424 func dataWithPrice(currency, price string) dataBundle { 425 priceName := fmt.Sprintf("prices.%s.value", currency) 426 signers := []*common.Signer{ 427 common.CreateSignerFromString("0xCAFED00D", common.SignerTypePubKey), 428 } 429 430 return dataBundle{ 431 data: common.Data{ 432 Data: map[string]string{ 433 priceName: price, 434 }, 435 Signers: signers, 436 }, 437 proto: vegapb.OracleData{ 438 ExternalData: &datapb.ExternalData{ 439 Data: &datapb.Data{ 440 Data: []*datapb.Property{ 441 { 442 Name: priceName, 443 Value: price, 444 }, 445 }, 446 MetaData: []*datapb.Property{}, 447 Signers: common.SignersIntoProto(signers), 448 }, 449 }, 450 }, 451 } 452 } 453 454 type specBundle struct { 455 spec dsspec.Spec 456 subscriber dummySubscriber 457 } 458 459 func triggerSpec(t *testing.T, initial time.Time, every int64) specBundle { 460 t.Helper() 461 462 cfg := &timetrigger.SpecConfiguration{ 463 Conditions: []*common.SpecCondition{ 464 { 465 Operator: common.SpecConditionOperator(2), 466 Value: "12", 467 }, 468 { 469 Operator: common.SpecConditionOperator(2), 470 Value: "17", 471 }, 472 }, 473 Triggers: common.InternalTimeTriggers{ 474 { 475 Initial: &initial, 476 Every: every, 477 }, 478 }, 479 } 480 481 testSpec := vegapb.NewDataSourceSpec(definition.NewWith(cfg).IntoProto()) 482 typedOracleSpec := datasource.SpecFromProto(testSpec) 483 484 // Initialise trigger 485 balh := typedOracleSpec.Data.Content().(timetrigger.SpecConfiguration) 486 balh.SetNextTrigger(initial) 487 488 spec, err := dsspec.New(*typedOracleSpec) 489 if err != nil { 490 t.Fatalf("Couldn't create oracle spec: %v", err) 491 } 492 return specBundle{ 493 spec: *spec, 494 subscriber: dummySubscriber{}, 495 } 496 } 497 498 func spec(t *testing.T, currency string, op datapb.Condition_Operator, price string, keys ...string) specBundle { 499 t.Helper() 500 var signers []*datapb.Signer 501 if len(keys) > 0 { 502 signers = make([]*datapb.Signer, len(keys)) 503 for i, k := range keys { 504 signers[i] = &datapb.Signer{ 505 Signer: &datapb.Signer_PubKey{ 506 PubKey: &datapb.PubKey{ 507 Key: k, 508 }, 509 }, 510 } 511 } 512 } 513 if len(keys) == 0 { 514 signers = []*datapb.Signer{ 515 { 516 Signer: &datapb.Signer_PubKey{ 517 PubKey: &datapb.PubKey{ 518 Key: "0xCAFED00D", 519 }, 520 }, 521 }, 522 } 523 } 524 525 testSpec := vegapb.NewDataSourceSpec( 526 vegapb.NewDataSourceDefinition( 527 vegapb.DataSourceContentTypeOracle, 528 ).SetOracleConfig( 529 &vegapb.DataSourceDefinitionExternal_Oracle{ 530 Oracle: &vegapb.DataSourceSpecConfiguration{ 531 Signers: signers, 532 Filters: []*datapb.Filter{ 533 { 534 Key: &datapb.PropertyKey{ 535 Name: fmt.Sprintf("prices.%s.value", currency), 536 Type: datapb.PropertyKey_TYPE_INTEGER, 537 }, 538 Conditions: []*datapb.Condition{ 539 { 540 Value: price, 541 Operator: op, 542 }, 543 }, 544 }, 545 }, 546 }, 547 }, 548 ), 549 ) 550 551 typedOracleSpec := datasource.SpecFromProto(testSpec) 552 553 spec, err := dsspec.New(*typedOracleSpec) 554 if err != nil { 555 t.Fatalf("Couldn't create oracle spec: %v", err) 556 } 557 return specBundle{ 558 spec: *spec, 559 subscriber: dummySubscriber{}, 560 } 561 } 562 563 type dummySubscriber struct { 564 ReceivedData *common.Data 565 } 566 567 func (d *dummySubscriber) Cb(_ context.Context, data common.Data) error { 568 d.ReceivedData = &data 569 return nil 570 } 571 572 type testBroker struct { 573 *bmok.MockBroker 574 ctx context.Context 575 } 576 577 type testTimeService struct { 578 *mocks.MockTimeService 579 ctx context.Context 580 } 581 582 func newBroker(ctx context.Context, t *testing.T) *testBroker { 583 t.Helper() 584 ctrl := gomock.NewController(t) 585 return &testBroker{ 586 MockBroker: bmok.NewMockBroker(ctrl), 587 ctx: ctx, 588 } 589 } 590 591 func newTimeService(ctx context.Context, t *testing.T) *testTimeService { 592 t.Helper() 593 ctrl := gomock.NewController(t) 594 return &testTimeService{ 595 MockTimeService: mocks.NewMockTimeService(ctrl), 596 ctx: ctx, 597 } 598 } 599 600 func (b *testBroker) expectNewSpecSubscription(currentTime time.Time, spec *datasource.Spec) { 601 proto := spec.IntoProto() 602 proto.CreatedAt = currentTime.UnixNano() 603 proto.Status = vegapb.DataSourceSpec_STATUS_ACTIVE 604 b.EXPECT().Send(events.NewOracleSpecEvent(b.ctx, &vegapb.OracleSpec{ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{Spec: proto}})).Times(1) 605 } 606 607 func (b *testBroker) expectSpecSubscriptionDeactivation(currentTime time.Time, spec *datasource.Spec) { 608 proto := spec.IntoProto() 609 proto.CreatedAt = currentTime.UnixNano() 610 proto.Status = vegapb.DataSourceSpec_STATUS_DEACTIVATED 611 b.EXPECT().Send(events.NewOracleSpecEvent(b.ctx, &vegapb.OracleSpec{ExternalDataSourceSpec: &vegapb.ExternalDataSourceSpec{Spec: proto}})).Times(1) 612 } 613 614 func (b *testBroker) expectMatchedDataEvent(currentTime time.Time, data *vegapb.OracleData, specIDs []string) { 615 data.ExternalData.Data.MatchedSpecIds = specIDs 616 data.ExternalData.Data.BroadcastAt = currentTime.UnixNano() 617 data.ExternalData.Data.MetaData = []*datapb.Property{ 618 { 619 Name: "vega-time", 620 Value: strconv.FormatInt(currentTime.Unix(), 10), 621 }, 622 } 623 b.EXPECT().Send(events.NewOracleDataEvent(b.ctx, *data)).Times(1) 624 }