def instrument_list(mock_load_markets_metadata,
                    loop: asyncio.AbstractEventLoop):
    """Prefill `INSTRUMENTS` cache for tests"""
    global INSTRUMENTS

    # Setup
    logger = LiveLogger(loop=loop,
                        clock=LiveClock(),
                        level_stdout=LogLevel.ERROR)
    client = BetfairTestStubs.betfair_client(loop=loop, logger=logger)
    logger = LiveLogger(loop=loop,
                        clock=LiveClock(),
                        level_stdout=LogLevel.DEBUG)
    instrument_provider = BetfairInstrumentProvider(client=client,
                                                    logger=logger,
                                                    market_filter={})

    # Load instruments
    market_ids = BetfairDataProvider.market_ids()
    catalog = {
        r["marketId"]: r
        for r in BetfairResponses.betting_list_market_catalogue()["result"]
        if r["marketId"] in market_ids
    }
    mock_load_markets_metadata.return_value = catalog
    t = loop.create_task(
        instrument_provider.load_all_async(
            market_filter={"market_id": market_ids}))
    loop.run_until_complete(t)

    # Fill INSTRUMENTS global cache
    INSTRUMENTS.extend(instrument_provider.list_all())
    assert INSTRUMENTS
class TestBetfairInstrumentProvider:
    def setup(self):
        # Fixture Setup
        self.loop = asyncio.get_event_loop()
        self.clock = LiveClock()
        self.logger = LiveLogger(loop=self.loop, clock=self.clock)
        self.client = BetfairTestStubs.betfair_client(loop=self.loop,
                                                      logger=self.logger)
        self.provider = BetfairInstrumentProvider(
            client=self.client,
            logger=TestComponentStubs.logger(),
        )

    @pytest.mark.asyncio
    async def test_load_markets(self):
        markets = await load_markets(self.client, market_filter={})
        assert len(markets) == 13227

        markets = await load_markets(
            self.client, market_filter={"event_type_name": "Basketball"})
        assert len(markets) == 302

        markets = await load_markets(
            self.client, market_filter={"event_type_name": "Tennis"})
        assert len(markets) == 1958

        markets = await load_markets(
            self.client, market_filter={"market_id": "1.177125728"})
        assert len(markets) == 1

    @pytest.mark.asyncio
    async def test_load_markets_metadata(self):
        markets = await load_markets(
            self.client, market_filter={"event_type_name": "Basketball"})
        market_metadata = await load_markets_metadata(client=self.client,
                                                      markets=markets)
        assert isinstance(market_metadata, dict)
        assert len(market_metadata) == 169

    @pytest.mark.asyncio
    async def test_make_instruments(self):
        # Arrange
        list_market_catalogue_data = {
            m["marketId"]: m
            for m in BetfairResponses.betting_list_market_catalogue()["result"]
            if m["eventType"]["name"] == "Basketball"
        }

        # Act
        instruments = [
            instrument for metadata in list_market_catalogue_data.values()
            for instrument in make_instruments(metadata, currency="GBP")
        ]

        # Assert
        assert len(instruments) == 30412

    @pytest.mark.asyncio
    async def test_load_all(self):
        await self.provider.load_all_async({"event_type_name": "Tennis"})
        assert len(self.provider.list_all()) == 4711

    @pytest.mark.asyncio
    async def test_list_all(self):
        await self.provider.load_all_async(
            market_filter={"event_type_name": "Basketball"})
        instruments = self.provider.list_all()
        assert len(instruments) == 23908

    @pytest.mark.asyncio
    async def test_search_instruments(self):
        await self.provider.load_all_async(
            market_filter={"event_type_name": "Basketball"})
        instruments = self.provider.search_instruments(
            instrument_filter={"market_type": "MATCH_ODDS"})
        assert len(instruments) == 104

    @pytest.mark.asyncio
    async def test_get_betting_instrument(self):
        await self.provider.load_all_async(
            market_filter={"market_id": ["1.180678317"]})
        kw = dict(
            market_id="1.180678317",
            selection_id="11313157",
            handicap="0.0",
        )
        instrument = self.provider.get_betting_instrument(**kw)
        assert instrument.market_id == "1.180678317"

        # Test throwing warning
        kw["handicap"] = "-1000"
        instrument = self.provider.get_betting_instrument(**kw)
        assert instrument is None

        # Test already in self._subscribed_instruments
        instrument = self.provider.get_betting_instrument(**kw)
        assert instrument is None

    def test_market_update_runner_removed(self):
        update = BetfairStreaming.market_definition_runner_removed()

        # Setup
        market_def = update["mc"][0]["marketDefinition"]
        market_def["marketId"] = update["mc"][0]["id"]
        instruments = make_instruments(
            market_definition=update["mc"][0]["marketDefinition"],
            currency="GBP")
        self.provider.add_bulk(instruments)

        results = []
        for data in on_market_update(instrument_provider=self.provider,
                                     update=update):
            results.append(data)
        result = [r.status for r in results[:8]]
        expected = [InstrumentStatus.PRE_OPEN] * 7 + [InstrumentStatus.CLOSED]
        assert result == expected