def test_attach_subscription_task_success(self, environ_get): """Test the ParseAttachedSubscriptionsTask.""" # prepare mock proxies the task is expected to interact with rhsm_entitlement_proxy = Mock() rhsm_entitlement_proxy.GetPools.return_value = "foo" rhsm_syspurpose_proxy = Mock() rhsm_syspurpose_proxy.GetSyspurpose.return_value = "bar" task = ParseAttachedSubscriptionsTask( rhsm_entitlement_proxy=rhsm_entitlement_proxy, rhsm_syspurpose_proxy=rhsm_syspurpose_proxy) # mock the parsing methods subscription1 = AttachedSubscription() subscription2 = AttachedSubscription() task._parse_subscription_json = Mock() task._parse_subscription_json.return_value = [ subscription1, subscription2 ] system_purpose_data = SystemPurposeData() task._parse_system_purpose_json = Mock() task._parse_system_purpose_json.return_value = system_purpose_data # run the task result = task.run() # check DBus proxies were called as expected rhsm_entitlement_proxy.GetPools.assert_called_once_with( {'pool_subsets': get_variant(Str, "consumed")}, {}, "en_US.UTF-8") rhsm_syspurpose_proxy.GetSyspurpose.assert_called_once_with( "en_US.UTF-8") # check the parsing methods were called task._parse_subscription_json.assert_called_once_with("foo") task._parse_system_purpose_json.assert_called_once_with("bar") # check the result that has been returned is as expected self.assertEqual(result.attached_subscriptions, [subscription1, subscription2]) self.assertEqual(result.system_purpose_data, system_purpose_data)
def _parse_subscription_json(cls, subscription_json): """Parse the JSON into list of AttachedSubscription instances. The expected JSON is at top level a list of rather complex dictionaries, with each dictionary describing a single subscription that has been attached to the system. :param str subscription_json: JSON describing what subscriptions have been attached :return: list of attached subscriptions :rtype: list of AttachedSubscription instances """ attached_subscriptions = [] try: subscriptions = json.loads(subscription_json) except json.decoder.JSONDecodeError: log.warning("subscription: failed to parse GetPools() JSON output") # empty attached subscription list is better than an installation # ending crash return [] # find the list of subscriptions consumed_subscriptions = subscriptions.get("consumed", []) log.debug("subscription: parsing %d attached subscriptions", len(consumed_subscriptions)) # split the list of subscriptions into separate subscription dictionaries for subscription_info in consumed_subscriptions: attached_subscription = AttachedSubscription() # user visible product name attached_subscription.name = subscription_info.get( "subscription_name", _("product name unknown")) # subscription support level # - this does *not* seem to directly correlate to system purpose SLA attribute attached_subscription.service_level = subscription_info.get( "service_level", _("unknown")) # SKU # - looks like productId == SKU in this JSON output attached_subscription.sku = subscription_info.get( "sku", _("unknown")) # contract number attached_subscription.contract = subscription_info.get( "contract", _("not available")) # subscription start date # - convert the raw date data from JSON to something more readable start_date = subscription_info.get("starts", _("unknown")) attached_subscription.start_date = cls._pretty_date(start_date) # subscription end date # - convert the raw date data from JSON to something more readable end_date = subscription_info.get("ends", _("unknown")) attached_subscription.end_date = cls._pretty_date(end_date) # consumed entitlements # - this seems to correspond to the toplevel "quantity" key, # not to the pool-level "consumed" key for some reason # *or* the pool-level "quantity" key quantity_string = int(subscription_info.get("quantity_used", 1)) attached_subscription.consumed_entitlement_count = quantity_string # add attached subscription to the list attached_subscriptions.append(attached_subscription) # return the list of attached subscriptions return attached_subscriptions