Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions coriolisclient/cli/licensing.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from cliff import show

from coriolisclient.cli import formatter
from coriolisclient import constants


class LicensingStatusFormatter(formatter.EntityFormatter):
Expand All @@ -29,29 +30,26 @@ def __init__(self):
"appliance_id",
"earliest_licence_expiry_time",
"latest_licence_expiry_time",
"current_performed_migrations",
"current_performed_replicas",
"current_available_migrations",
"current_available_replicas",
"lifetime_performed_migrations",
"lifetime_performed_replicas",
"lifetime_available_migrations",
"lifetime_available_replicas",
]
self.columns.extend(
"standard_%s" % field
for field in constants.LICENCE_STATS_FIELDS)
self.columns.extend(
"sap_%s" % field for field in constants.LICENCE_STATS_FIELDS)

def _get_formatted_data(self, obj):
standard_stats = getattr(obj, constants.LICENCE_STATS_KEY_STANDARD)
sap_stats = getattr(obj, constants.LICENCE_STATS_KEY_SAP)

data = [obj.appliance_id,
obj.earliest_licence_expiry_time,
obj.latest_licence_expiry_time,
obj.current_performed_migrations,
obj.current_performed_replicas,
obj.current_available_migrations,
obj.current_available_replicas,
obj.lifetime_performed_migrations,
obj.lifetime_performed_replicas,
obj.lifetime_available_migrations,
obj.lifetime_available_replicas,
]
data.extend(
standard_stats[field]
for field in constants.LICENCE_STATS_FIELDS)
data.extend(
sap_stats[field] for field in constants.LICENCE_STATS_FIELDS)

return data

Expand All @@ -65,6 +63,7 @@ class LicenceFormatter(formatter.EntityFormatter):
"Period End",
"Period Duration",
"Licence Version",
"Licence Edition",
)

def _get_sorted_list(self, obj_list):
Expand All @@ -79,6 +78,8 @@ def _get_formatted_data(self, obj):
obj.period_end,
obj.period_duration,
obj.licence_version,
constants.LICENCE_TYPE_EDITION_MAP.get(
obj.licence_version),
)

return data
Expand Down
3 changes: 3 additions & 0 deletions coriolisclient/cli/licensing_reservations.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
from cliff import show

from coriolisclient.cli import formatter
from coriolisclient import constants


class ReservationFormatter(formatter.EntityFormatter):
columns = ("ID",
"Appliance ID",
"Licence ID",
"Type",
"Licence Edition",
"Count",
"Created At",
)
Expand All @@ -36,6 +38,7 @@ def _get_formatted_data(self, obj):
obj.appliance_id,
obj.licence_id,
obj.type,
constants.RESERVATION_TYPE_EDITION_MAP.get(obj.type),
obj.count,
obj.created_at,
)
Expand Down
40 changes: 40 additions & 0 deletions coriolisclient/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,46 @@
# See the License for the specific language governing permissions and
# limitations under the License.

LICENCE_VERSION_V1 = "v1"
LICENCE_VERSION_V2 = "v2"
LICENCE_VERSION_V2_SAP = "v2-sap"

LICENCE_EDITION_STANDARD = "Standard"
LICENCE_EDITION_SAP = "SAP"

LICENCE_TYPE_EDITION_MAP = {
LICENCE_VERSION_V1: LICENCE_EDITION_STANDARD,
LICENCE_VERSION_V2: LICENCE_EDITION_STANDARD,
LICENCE_VERSION_V2_SAP: LICENCE_EDITION_SAP,
}

RESERVATION_TYPE_REPLICA = "replica"
RESERVATION_TYPE_MIGRATION = "migration"
RESERVATION_TYPE_SAP_REPLICA = "sap_replica"
RESERVATION_TYPE_SAP_MIGRATION = "sap_migration"

RESERVATION_TYPE_EDITION_MAP = {
RESERVATION_TYPE_REPLICA: LICENCE_EDITION_STANDARD,
RESERVATION_TYPE_MIGRATION: LICENCE_EDITION_STANDARD,
RESERVATION_TYPE_SAP_REPLICA: LICENCE_EDITION_SAP,
RESERVATION_TYPE_SAP_MIGRATION: LICENCE_EDITION_SAP,
}

LICENCE_STATS_KEY_STANDARD = "standard_licence_stats"
LICENCE_STATS_KEY_SAP = "sap_licence_stats"

LICENCE_STATS_FIELDS = (
"current_performed_migrations",
"current_performed_replicas",
"current_available_migrations",
"current_available_replicas",
"lifetime_performed_migrations",
"lifetime_performed_replicas",
"lifetime_available_migrations",
"lifetime_available_replicas",
)


MIGRATION_STATUS_RUNNING = "RUNNING"
MIGRATION_STATUS_COMPLETED = "COMPLETED"
MIGRATION_STATUS_ERROR = "ERROR"
Expand Down
103 changes: 72 additions & 31 deletions coriolisclient/tests/cli/test_licensing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from cliff import show

from coriolisclient.cli import licensing
from coriolisclient import constants
from coriolisclient.tests import test_base


Expand All @@ -18,29 +19,42 @@ def setUp(self):
super(LicensingStatusFormatterTestCase, self).setUp()
self.licence = licensing.LicensingStatusFormatter()

def test_get_formatted_data(self):
@staticmethod
def _make_stats(offset):
"""Builds a stats body whose counters are all distinguishable."""
return {
field: offset + i
for i, field in enumerate(constants.LICENCE_STATS_FIELDS)}

def _make_status(self, standard_stats, sap_stats):
obj = mock.Mock()
obj.appliance_id = mock.sentinel.appliance_id
obj.earliest_licence_expiry_time = \
mock.sentinel.earliest_licence_expiry_time
obj.latest_licence_expiry_time = \
mock.sentinel.latest_licence_expiry_time
obj.current_performed_migrations = \
mock.sentinel.current_performed_migrations
obj.current_performed_replicas = \
mock.sentinel.current_performed_replicas
obj.current_available_migrations = \
mock.sentinel.current_available_migrations
obj.current_available_replicas = \
mock.sentinel.current_available_replicas
obj.lifetime_performed_migrations = \
mock.sentinel.lifetime_performed_migrations
obj.lifetime_performed_replicas = \
mock.sentinel.lifetime_performed_replicas
obj.lifetime_available_migrations = \
mock.sentinel.lifetime_available_migrations
obj.lifetime_available_replicas = \
mock.sentinel.lifetime_available_replicas
setattr(obj, constants.LICENCE_STATS_KEY_STANDARD, standard_stats)
setattr(obj, constants.LICENCE_STATS_KEY_SAP, sap_stats)
return obj

def test_columns(self):
self.assertEqual(
[
"appliance_id",
"earliest_licence_expiry_time",
"latest_licence_expiry_time",
] + [
"standard_%s" % f for f in constants.LICENCE_STATS_FIELDS
] + [
"sap_%s" % f for f in constants.LICENCE_STATS_FIELDS
],
self.licence.columns
)

def test_get_formatted_data(self):
standard_stats = self._make_stats(0)
sap_stats = self._make_stats(100)
obj = self._make_status(standard_stats, sap_stats)

result = self.licence._get_formatted_data(obj)

Expand All @@ -49,17 +63,30 @@ def test_get_formatted_data(self):
mock.sentinel.appliance_id,
mock.sentinel.earliest_licence_expiry_time,
mock.sentinel.latest_licence_expiry_time,
mock.sentinel.current_performed_migrations,
mock.sentinel.current_performed_replicas,
mock.sentinel.current_available_migrations,
mock.sentinel.current_available_replicas,
mock.sentinel.lifetime_performed_migrations,
mock.sentinel.lifetime_performed_replicas,
mock.sentinel.lifetime_available_migrations,
mock.sentinel.lifetime_available_replicas
] + [
standard_stats[f] for f in constants.LICENCE_STATS_FIELDS
] + [
sap_stats[f] for f in constants.LICENCE_STATS_FIELDS
],
result
)
self.assertEqual(len(self.licence.columns), len(result))

def test_get_formatted_data_standard_only(self):
standard_stats = self._make_stats(0)
sap_stats = dict.fromkeys(constants.LICENCE_STATS_FIELDS, 0)
obj = self._make_status(standard_stats, sap_stats)

result = self.licence._get_formatted_data(obj)

self.assertEqual(
[standard_stats[f] for f in constants.LICENCE_STATS_FIELDS],
result[3:3 + len(constants.LICENCE_STATS_FIELDS)]
)
self.assertEqual(
[0] * len(constants.LICENCE_STATS_FIELDS),
result[-len(constants.LICENCE_STATS_FIELDS):]
)


class LicenceFormatterTestCase(test_base.CoriolisBaseTestCase):
Expand All @@ -85,7 +112,7 @@ def test_get_sorted_list(self):
result
)

def test_get_formatted_data(self):
def _assert_formatted(self, licence_version, licence_edition):
obj = mock.Mock()
obj.id = mock.sentinel.id
obj.issue_date = mock.sentinel.issue_date
Expand All @@ -94,9 +121,7 @@ def test_get_formatted_data(self):
obj.period_start = mock.sentinel.period_start
obj.period_end = mock.sentinel.period_end
obj.period_duration = mock.sentinel.period_duration
obj.licence_version = mock.sentinel.licence_version

result = self.licence._get_formatted_data(obj)
obj.licence_version = licence_version

self.assertEqual(
(
Expand All @@ -107,11 +132,27 @@ def test_get_formatted_data(self):
mock.sentinel.period_start,
mock.sentinel.period_end,
mock.sentinel.period_duration,
mock.sentinel.licence_version
licence_version,
licence_edition,
),
result
self.licence._get_formatted_data(obj)
)

def test_get_formatted_data(self):
self._assert_formatted(
constants.LICENCE_VERSION_V2, constants.LICENCE_EDITION_STANDARD)

def test_get_formatted_data_sap(self):
self._assert_formatted(
constants.LICENCE_VERSION_V2_SAP, constants.LICENCE_EDITION_SAP)

def test_get_formatted_data_v1(self):
self._assert_formatted(
constants.LICENCE_VERSION_V1, constants.LICENCE_EDITION_STANDARD)

def test_get_formatted_data_unknown_version(self):
self._assert_formatted("v3-something", None)


class LicensingApplianceStatusTestCase(test_base.CoriolisBaseTestCase):
"""Test suite for the Coriolis Client Licensing Appliance Status."""
Expand Down
23 changes: 20 additions & 3 deletions coriolisclient/tests/cli/test_licensing_reservations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from cliff import show

from coriolisclient.cli import licensing_reservations
from coriolisclient import constants
from coriolisclient.tests import test_base


Expand All @@ -33,12 +34,12 @@ def test_get_sorted_list(self):
result
)

def test_get_formatted_data(self):
def _assert_formatted(self, reservation_type, licence_edition):
obj = mock.Mock()
obj.id = mock.sentinel.id
obj.appliance_id = mock.sentinel.appliance_id
obj.licence_id = mock.sentinel.licence_id
obj.type = mock.sentinel.type
obj.type = reservation_type
obj.count = mock.sentinel.count
obj.created_at = mock.sentinel.created_at

Expand All @@ -49,13 +50,29 @@ def test_get_formatted_data(self):
mock.sentinel.id,
mock.sentinel.appliance_id,
mock.sentinel.licence_id,
mock.sentinel.type,
reservation_type,
licence_edition,
mock.sentinel.count,
mock.sentinel.created_at
),
result
)

def test_get_formatted_data(self):
for reservation_type in [constants.RESERVATION_TYPE_REPLICA,
constants.RESERVATION_TYPE_MIGRATION]:
self._assert_formatted(
reservation_type, constants.LICENCE_EDITION_STANDARD)

def test_get_formatted_data_sap(self):
for reservation_type in [constants.RESERVATION_TYPE_SAP_REPLICA,
constants.RESERVATION_TYPE_SAP_MIGRATION]:
self._assert_formatted(
reservation_type, constants.LICENCE_EDITION_SAP)

def test_get_formatted_data_unknown_type(self):
self._assert_formatted("something", None)


class ReservationListTestCase(test_base.CoriolisBaseTestCase):
"""Test suite for the Coriolis Client Reservation List."""
Expand Down
Loading