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)
示例#2
0
 def subscription_json_parsing_test(self):
     """Test the subscription JSON parsing method of ParseAttachedSubscriptionsTask."""
     parse_method = ParseAttachedSubscriptionsTask._parse_subscription_json
     # the method should be able to survive the RHSM DBus API returning an empty string,
     # as empty list of subscriptions is a lesser issue than crashed installation
     self.assertEqual(parse_method(""), [])
     # try parsing a json file containing two subscriptions
     # - to make this look sane, we write it as a dict that we then convert to JSON
     subscription_dict = {
         "consumed": [{
             "subscription_name": "Foo Bar Beta",
             "service_level": "very good",
             "sku": "ABC1234",
             "contract": "12345678",
             "starts": "05/12/20",
             "ends": "05/12/21",
             "quantity_used": "1"
         }, {
             "subscription_name": "Foo Bar Beta NG",
             "service_level": "even better",
             "sku": "ABC4321",
             "contract": "87654321",
             "starts": "now",
             "ends": "never",
             "quantity_used": "1000"
         }]
     }
     subscription_json = json.dumps(subscription_dict)
     expected_structs = [{
         "name": "Foo Bar Beta",
         "service-level": "very good",
         "sku": "ABC1234",
         "contract": "12345678",
         "start-date": "May 12, 2020",
         "end-date": "May 12, 2021",
         "consumed-entitlement-count": 1
     }, {
         "name": "Foo Bar Beta NG",
         "service-level": "even better",
         "sku": "ABC4321",
         "contract": "87654321",
         "start-date": "now",
         "end-date": "never",
         "consumed-entitlement-count": 1000
     }]
     structs = get_native(
         AttachedSubscription.to_structure_list(
             parse_method(subscription_json)))
     # check the content of the AttachedSubscription corresponds to the input JSON,
     # including date formatting
     self.assertEqual(structs, expected_structs)
示例#3
0
    def _update_subscription_state(self):
        """Update state of the subscription related part of the spoke.

        Update state of the part of the spoke, that shows data about the
        currently attached subscriptions.
        """
        # authentication method
        if self.authentication_method == AuthenticationMethod.USERNAME_PASSWORD:
            method_string = _("Registered with account {}").format(
                self.subscription_request.account_username)
        else:  # org + key
            method_string = _("Registered with organization {}").format(
                self.subscription_request.organization)
        self._method_status_label.set_text(method_string)

        # final syspurpose data

        # role
        final_role_string = _("Role: {}").format(self.system_purpose_data.role)
        self._role_status_label.set_text(final_role_string)

        # SLA
        final_sla_string = _("SLA: {}").format(self.system_purpose_data.sla)
        self._sla_status_label.set_text(final_sla_string)

        # usage
        final_usage_string = _("Usage: {}").format(
            self.system_purpose_data.usage)
        self._usage_status_label.set_text(final_usage_string)

        # Insights
        # - this strings are referring to the desired target system state,
        #   the installation environment itself is not expected to be
        #   connected to Insights
        if self._subscription_module.InsightsEnabled:
            insights_string = _("Connected to Red Hat Insights")
        else:
            insights_string = _("Not connected to Red Hat Insights")
        self._insights_status_label.set_text(insights_string)

        # get attached subscriptions as a list of structs
        attached_subscriptions = self._subscription_module.AttachedSubscriptions
        # turn the structs to more useful AttachedSubscription instances
        attached_subscriptions = AttachedSubscription.from_structure_list(
            attached_subscriptions)

        # check how many we have & set the subscription status string accordingly
        subscription_count = len(attached_subscriptions)
        if subscription_count == 0:
            subscription_string = _(
                "No subscriptions are attached to the system")
        elif subscription_count == 1:
            subscription_string = _("1 subscription attached to the system")
        else:
            subscription_string = _("{} subscriptions attached to the system"
                                    ).format(subscription_count)

        self._attached_subscriptions_label.set_text(subscription_string)

        # populate the attached subscriptions listbox
        populate_attached_subscriptions_listbox(self._subscriptions_listbox,
                                                attached_subscriptions)
示例#4
0
    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
示例#5
0
 def AttachedSubscriptions(self) -> List[Structure]:
     """Return a list of DBus structures holding data about attached subscriptions."""
     return AttachedSubscription.to_structure_list(
         self.implementation.attached_subscriptions)