diff --git a/src/galaxy/api/consts.py b/src/galaxy/api/consts.py index 8e224a7..4902603 100644 --- a/src/galaxy/api/consts.py +++ b/src/galaxy/api/consts.py @@ -116,6 +116,7 @@ class Feature(Enum): ImportUserPresence = "ImportUserPresence" ImportLocalSize = "ImportLocalSize" ImportSubscriptions = "ImportSubscriptions" + ImportSubscriptionGames = "ImportSubscriptionGames" class LicenseType(Enum): diff --git a/src/galaxy/api/plugin.py b/src/galaxy/api/plugin.py index b2704e8..b97072e 100644 --- a/src/galaxy/api/plugin.py +++ b/src/galaxy/api/plugin.py @@ -62,6 +62,9 @@ class Importer: if self._yielding: async for element in self._get(id_, context_): self._notification_success(id_, element) + if element is None: + logger.debug("None element yielded, import finished") + break else: element = await self._get(id_, context_) self._notification_success(id_, element) @@ -265,8 +268,10 @@ class Plugin: self._detect_feature(Feature.ImportLocalSize, ["get_local_size"]) self._register_method("import_subscriptions", self.get_subscriptions, result_name="subscriptions") + self._detect_feature(Feature.ImportSubscriptions, ["get_subscriptions"]) + self._register_method("start_subscription_games_import", self._start_subscription_games_import) - self._detect_feature(Feature.ImportSubscriptions, ["get_subscriptions", "get_subscription_games"]) + self._detect_feature(Feature.ImportSubscriptionGames, ["get_subscription_games"]) async def __aenter__(self): return self @@ -1099,9 +1104,6 @@ class Plugin: Subscriptions available on platform. This method is called by the GOG Galaxy Client. - Both this method and get_subscription_games are required to be overridden - for the Subscriptions feature to be recognized - Example of possible override of the method: .. code-block:: python @@ -1133,6 +1135,9 @@ class Plugin: """Override this method to return SubscriptionGames for a given subscription. This method should `yield` results from a list of SubscriptionGames + Both this method and get_subscriptions are required to be overridden + for the ImportSubscriptionGames feature to be recognized + :param context: the value returned from :meth:`prepare_subscription_games_context` :return yield List of subscription games. diff --git a/tests/test_features.py b/tests/test_features.py index c06a1a7..e1587a7 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -19,7 +19,8 @@ def test_base_class(): Feature.ImportOSCompatibility, Feature.ImportUserPresence, Feature.ImportLocalSize, - Feature.ImportSubscriptions + Feature.ImportSubscriptions, + Feature.ImportSubscriptionGames } diff --git a/tests/test_subscriptions.py b/tests/test_subscriptions.py index 1083816..dd5d5ab 100644 --- a/tests/test_subscriptions.py +++ b/tests/test_subscriptions.py @@ -96,12 +96,17 @@ async def test_get_subscription_games_success(plugin, read, write): } } read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)] - plugin.get_subscription_games.return_value = async_return_value([ + + async def sub_games(): + games = [ SubscriptionGame(game_title="game A", game_id="game_A"), SubscriptionGame(game_title="game B", game_id="game_B", start_time=1548495632), SubscriptionGame(game_title="game C", game_id="game_C", end_time=1548495633), SubscriptionGame(game_title="game D", game_id="game_D", start_time=1548495632, end_time=1548495633), - ]) + ] + yield [game for game in games] + + plugin.get_subscription_games.return_value = sub_games() await plugin.run() plugin.prepare_subscription_games_context.assert_called_with(["sub_a"]) plugin.get_subscription_games.assert_called_with("sub_a", 5) @@ -149,6 +154,108 @@ async def test_get_subscription_games_success(plugin, read, write): } ] +@pytest.mark.asyncio +async def test_get_subscription_games_success_none_yield(plugin, read, write): + plugin.prepare_subscription_games_context.return_value = async_return_value(5) + request = { + "jsonrpc": "2.0", + "id": "3", + "method": "start_subscription_games_import", + "params": { + "subscription_names": ["sub_a"] + } + } + read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)] + + async def sub_games(): + yield None + + plugin.get_subscription_games.return_value = sub_games() + await plugin.run() + plugin.prepare_subscription_games_context.assert_called_with(["sub_a"]) + plugin.get_subscription_games.assert_called_with("sub_a", 5) + plugin.subscription_games_import_complete.asert_called_with() + + assert get_messages(write) == [ + { + "jsonrpc": "2.0", + "id": "3", + "result": None + }, + { + "jsonrpc": "2.0", + "method": "subscription_games_import_success", + "params": { + "subscription_name": "sub_a", + "subscription_games": None + } + }, + { + "jsonrpc": "2.0", + "method": "subscription_games_import_finished", + "params": None + } + ] + +@pytest.mark.asyncio +async def test_get_subscription_games_success_yield_mix(plugin, read, write): + plugin.prepare_subscription_games_context.return_value = async_return_value(5) + request = { + "jsonrpc": "2.0", + "id": "3", + "method": "start_subscription_games_import", + "params": { + "subscription_names": ["sub_a"] + } + } + read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)] + + async def sub_games(): + games = [ + SubscriptionGame(game_title="game A", game_id="game_A")] + yield games + yield None + + plugin.get_subscription_games.return_value = sub_games() + await plugin.run() + plugin.prepare_subscription_games_context.assert_called_with(["sub_a"]) + plugin.get_subscription_games.assert_called_with("sub_a", 5) + plugin.subscription_games_import_complete.asert_called_with() + + assert get_messages(write) == [ + { + "jsonrpc": "2.0", + "id": "3", + "result": None + }, + { + "jsonrpc": "2.0", + "method": "subscription_games_import_success", + "params": { + "subscription_name": "sub_a", + "subscription_games": [ + { + "game_title": "game A", + "game_id": "game_A" + }, + ] + } + }, + { + "jsonrpc": "2.0", + "method": "subscription_games_import_success", + "params": { + "subscription_name": "sub_a", + "subscription_games": None + } + }, + { + "jsonrpc": "2.0", + "method": "subscription_games_import_finished", + "params": None + } + ] + @pytest.mark.asyncio @pytest.mark.parametrize("exception,code,message", [