def test_schedule_handler(): GIVEN("a schedule handler connected to the dev environment") dev_schedule_handler = ExternalAPIScheduleHandler(environment="Dev") WHEN("we get the schedule for market which start in the next 5 minutes") schedule = dev_schedule_handler.get_schedule("7", DateTime.utc_5_minutes_from_now()) THEN("a list is returned") assert isinstance(schedule, list) THEN("each item in the list is a dict refering to a market") for market in schedule: assert isinstance(market, dict) THEN("each market has an id which is a string") market_id = market.get("marketId") assert isinstance(market_id, str) THEN("each market has a name") assert isinstance(market.get("marketName"), str) THEN("each market is associated with an event which is stored as a dict") event = market.get("event") assert isinstance(event, dict) THEN("the event has an id which is a string") assert isinstance(event.get("id"), str) THEN("the event has a name which is a string") assert isinstance(event.get("name"), str) THEN("the event has a country code which is a string") assert isinstance(event.get("countryCode"), str)
def test_handler(): GIVEN("a directory, an historical external api file and a handler") directory = "./data/29220705" file_name = "1.157190397.txt" file = HistoricalExternalAPIFileHander(directory=directory, file=file_name) WHEN("we get the file as a list") file_data = file.get_file_as_list() THEN("the data is a list") assert isinstance(file_data, list) THEN("the file has a record for every 5 seconds in the" + "4 minutes 27 seconds leading up to 33 seconds before the race") assert len(file_data) == round_down(((5 * 60) - 33) / 5) for record in file_data: THEN("each record in the file data has a process time") assert isinstance(record.get("process_time"), str) THEN("none of the records have marketInfo") assert record.get("marketInfo") is None WHEN("we get the market start time") market_start_time = file.get_market_start_time() THEN("the market_start_time is a string") assert isinstance(market_start_time, str) THEN("the market start time can be converted to an epoch") epoch = DateTime(market_start_time).get_epoch() assert epoch > 0
def test_datetime_helpers(): GIVEN("the time has been overridden") WHEN("we call get_utc_now") now = DateTime.get_utc_now() THEN("the correct string is returned") assert now == "1984-11-07T12:45:00Z" WHEN("we call utc_5_minutes_from_now and add 5 minutes") five_minutes_from_now = DateTime.utc_5_minutes_from_now() THEN("the correct string is returned") assert five_minutes_from_now == "1984-11-07T12:50:00Z" WHEN("we call utc_15_minutes_from_now and add 5 minutes") five_minutes_from_now = DateTime.utc_15_minutes_from_now() THEN("the correct string is returned") assert five_minutes_from_now == "1984-11-07T13:00:00Z" WHEN( "we call is_datetime_more_than_33_seconds_from_now with a time in the distant future" ) is_future = DateTime( "2019-01-01T00:00:00.000Z").is_more_than_33_seconds_from_now() THEN("the date time is far enough in the future to return true") assert is_future is True WHEN( "we call is_datetime_more_than_33_seconds_from_now with a time 34 seconds in the future" ) is_not_future = DateTime( "1984-11-07T12:45:34.000Z").is_more_than_33_seconds_from_now() THEN("the date time is far enough in the future to return true") assert is_not_future is True WHEN( "we call is_datetime_more_than_33_seconds_from_now with a time 33 seconds in the future" ) is_not_future = DateTime( "1984-11-07T12:44:33.000Z").is_more_than_33_seconds_from_now() THEN("the date time is not far enough in the future to return true") assert is_not_future is False WHEN( "we call is_datetime_more_than_33_seconds_from_now with a time that matches our override" ) is_not_future = DateTime( "1984-11-07T12:45:00.000Z").is_more_than_33_seconds_from_now() THEN("the date time is not far enough in the future to return true") assert is_not_future is False WHEN( "we call is_datetime_more_than_33_seconds_from_now with a time from the past" ) is_not_future = DateTime( "1984-11-07T12:44:00.000Z").is_more_than_33_seconds_from_now() THEN("the date time is not far enough in the future to return true") assert is_not_future is False
def test_date_time_epoch(): GIVEN("a UTC date time string with milliseconds") utc_date_time_str = "2019-01-01T00:00:00.000Z" WHEN("we get the epoch representation") epoch = DateTime(utc_date_time_str).get_epoch() THEN("the correct epoch is returned") local_epoch = 1546261200 assert epoch == local_epoch GIVEN("a UTC date time string and another that is 60 seconds afterwards") first_date_time_str = "2019-01-01T00:00:00.000Z" second_date_time_str = "2019-01-01T00:01:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_date_time_str).get_epoch() - DateTime(second_date_time_str).get_epoch()) THEN("the difference is as expected") assert seconds_difference == -60 GIVEN("a UTC date time strings") utc_date_time_str = "2019-01-01T00:00:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(utc_date_time_str).get_epoch() - DateTime(utc_date_time_str).get_epoch()) THEN("there is no difference") assert seconds_difference == 0 GIVEN("two UTC date time strings 60 seconds apart") first_date_time_str = "2019-01-01T00:01:00.000Z" second_date_time_str = "2019-01-01T00:00:00.000Z" WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_date_time_str).get_epoch() - DateTime(second_date_time_str).get_epoch()) THEN("the difference is as expected") assert seconds_difference == 60 GIVEN("two milliseconds since epoch 1 second apart") first_epoch = 1569876588922 second_epoch = 1569876587922 WHEN( "we create instances of DateTime and subtract the epochs from one another" ) seconds_difference = (DateTime(first_epoch).get_epoch() - DateTime(second_epoch).get_epoch()) THEN("the difference is as expected") assert seconds_difference == 1
def test_date_time_str_converters(): GIVEN("a UTC date time string with milliseconds") utc_date_time_str = "2019-01-01T00:00:00.000Z" WHEN("we call local_hms_45_seconds_before") hour_minutes_seconds_str = DateTime( utc_date_time_str).local_hms_45_seconds_before() THEN( "a string in the correct format corresponding to the local date time is returned" ) assert hour_minutes_seconds_str == "10:59:15" WHEN("we call utc_30_seconds_before") hour_minutes_seconds_str = DateTime( utc_date_time_str).local_hms_30_seconds_before() THEN( "a string in the correct format corresponding to the local date time is returned" ) assert hour_minutes_seconds_str == "10:59:30" GIVEN("a UTC date time string without milliseconds") utc_date_time_str = "2019-01-01T12:00:00Z" WHEN("we call local_hms_45_seconds_before") hour_minutes_seconds_str = DateTime( utc_date_time_str).local_hms_45_seconds_before() THEN( "a string in the correct format corresponding to the local date time is returned" ) assert hour_minutes_seconds_str == "22:59:15" WHEN("we call utc_30_seconds_before") hour_minutes_seconds_str = DateTime( utc_date_time_str).local_hms_30_seconds_before() THEN( "a string in the correct format corresponding to the local date time is returned" ) assert hour_minutes_seconds_str == "22:59:30"
def test_error_handling(mock_urlopen, mock_set_headers): GIVEN("a mocked instance of the ExternalAPIScheduleHandler") mock_set_headers.side_effect = setattr(ExternalAPIScheduleHandler, "_headers", {}) dev_schedule_handler = ExternalAPIScheduleHandler(environment="Dev") WHEN( "we try to get the for all markets which start" + " in the next 5 minutes but no payload is returned" ) mock_urlopen.return_value = {} schedule = dev_schedule_handler.get_schedule("7", DateTime.utc_5_minutes_from_now()) THEN("no information is returned from the handler") assert schedule is None WHEN( "we try to get the markets which start in the next 5 minutes but it throws an error" ) mock_urlopen.return_value = None schedule = dev_schedule_handler.get_schedule("7", DateTime.utc_5_minutes_from_now()) THEN("no information is returned from the handler") assert schedule is None
def get_market(self): request = ( '{"jsonrpc": "2.0", "method": "%s",' '"params":{"marketIds":[%s],' '"priceProjection":{"priceData":["EX_BEST_OFFERS","SP_AVAILABLE","SP_TRADED","EX_TRADED"]},' # pylint: disable=line-too-long '"marketProjection":["MARKET_START_TIME"]}, "id": 1}') % ( get_market_str(), self.__market_id) process_time = DateTime.get_utc_now() market = self._call_exchange(request=request) data = market[0] if market else {} data["process_time"] = process_time return self._mediator.notify(event="external data fetched", data=data)
def __init__(self, items, market_start_time): self._items = { item.get("id"): { "ex": {"atb": {}, "trd": {}, "atl": {}}, "sp": { "spn": None, "spb": {}, "spl": {}, }, } for item in items } self._market_start_time = DateTime(market_start_time).get_epoch() self._existing_times = [] self._record = {} self._closed_indicator = False self.__market_definition_change = None
def test_handler_download_file(): GIVEN("a file and a directory with the correct market type") directory = "./dev" file = "1.163093692.bz2" WHEN("we instantiate the handler") file_data = FileHandler(directory=directory, file=file).get_file_as_list() THEN("it has loaded the file as a list") assert isinstance(file_data, list) THEN("the list has hundreds of records") assert len(file_data) > 200 THEN("the list's first record has all of the items") first_record = file_data[0] items = first_record.get("mc")[0].get("marketDefinition").get("runners") assert isinstance(items, list) THEN("the list's first record has the market time") market_time = DateTime( first_record.get("mc")[0].get("marketDefinition").get("marketTime") ).get_epoch() assert market_time == 1569840120.0 THEN("the first record has a process time which can be converted to an epoch") process_time = __get_record_process_time(first_record) assert isinstance(process_time, float) THEN("the process time is within 24 hours of the market_time") assert (market_time - process_time) < (60 * 60 * 24) THEN("the handler's file data has a last record") last_record = file_data[-1] THEN("the process time is after the market time but within 20 minutes") process_time = __get_record_process_time(last_record) assert (20 * 60) > -(market_time - process_time) > 0
def test_get_data(mock_notify): GIVEN( "a schedule handler and a market handler connected to the dev environment" ) schedule_handler = ExternalAPIScheduleHandler(environment="Dev") headers = schedule_handler.get_headers() markets = schedule_handler.get_schedule("7", DateTime.utc_5_minutes_from_now()) WHEN( "we create an instance of the market handler for each market and ask for data" ) for market in markets: market_id = market.get("marketId") market_handler = ExternalAPIMarketHandler( mediator=MockMediator(), environment="Dev", headers=headers, market_id=market_id, ) market_info = market_handler.get_market() THEN("the notify method was called with the correct parameters") args, kwargs = mock_notify.call_args assert args == () assert kwargs.get("event") == "external data fetched" market_info = kwargs.get("data") assert isinstance(market_info, dict) if market_info: THEN("the dict contains a list of items") items = market_info.get("runners") assert isinstance(items, list) THEN("the dict has an extract time") process_time = market_info.get("process_time") assert isinstance(process_time, str)
def __get_process_time(self): return DateTime(self._record.get("pt")).get_epoch()
def __init__(self, market_start_time): self.__market_start_time = DateTime(market_start_time).get_epoch() self.__data = None
def _get_time_difference(self): extract_time = DateTime(self.__data.get("process_time")).get_epoch() return extract_time - self.__market_start_time
def get_schedule(self): return self.external_api.get_schedule( "7", DateTime.utc_5_minutes_from_now())
def __get_record_process_time(record): return DateTime(record.get("pt")).get_epoch()
def __get_removal_date(self): raw_removal_date = self.__record.get("removalDate") removal_date = (DateTime(raw_removal_date).get_epoch() if raw_removal_date else not_a_number()) return removal_date