# -*- coding: utf-8 -*-
from datetime import date, datetime
import multimethods as mm
from miq_version import ( # noqa
Version, LOWEST, LATEST, UPSTREAM, SPTuple, get_version,
version_stream_product_mapping
)
from fixtures.pytest_store import store
[docs]def get_product_version(ver):
"""Return product version for given Version obj or version string
"""
ver = Version(ver)
if ver.product_version() is not None:
return ver.product_version()
else:
raise LookupError("no matching product version found for version {}".format(ver))
[docs]def get_stream(ver):
"""Return a stream name for given Version obj or version string
"""
ver = Version(ver)
if ver.stream() is not None:
return ver.stream()
else:
raise LookupError("no matching stream found for version {}".format(ver))
[docs]def current_stream():
return get_stream(store.current_appliance.version)
[docs]def current_version():
"""A lazy cached method to return the appliance version.
Do not catch errors, since generally we cannot proceed with
testing, without knowing the server version.
"""
return store.current_appliance.version
[docs]def appliance_build_datetime():
try:
return store.current_appliance.build_datetime
except:
return None
[docs]def appliance_build_date():
try:
return store.current_appliance.build_date
except:
return None
[docs]def appliance_is_downstream():
return store.current_appliance.is_downstream
[docs]def parsedate(o):
if isinstance(o, date):
return o
elif isinstance(o, datetime):
return o.date()
else:
# 1234-12-13
return date(*[int(x) for x in str(o).split("-", 2)])
[docs]def before_date_or_version(date=None, version=None):
"""Function for deciding based on the build date and version.
Usage:
* If both date and version are set, then two things can happen. If the appliance is
downstream, both date and version are checked, otherwise only the date.
* If only date is set, then only date is checked.
* if only version is set, then it checks the version if the appliance is downstream,
otherwise it returns ``False``
The checks are in form ``appliance_build_date() < date`` and ``current_version() < version``.
Therefore when used in ``if`` statement, the truthy value signalizes 'older' version and falsy
signalizes 'newer' version.
"""
if date is not None:
date = parsedate(date)
if date is not None and version is not None:
if not appliance_is_downstream():
return appliance_build_date() < date
else:
return appliance_build_date() < date and current_version() < version
elif date is not None and version is None:
return appliance_build_date() < date
elif date is None and version is not None:
if not appliance_is_downstream():
return False
return current_version() < version
else:
raise TypeError("You have to pass either date or version, or both!")
[docs]def since_date_or_version(*args, **kwargs):
"""Opposite of :py:func:`before_date_or_version`"""
return not before_date_or_version(*args, **kwargs)
[docs]def appliance_has_netapp():
try:
return store.current_appliance.has_netapp()
except:
return None
[docs]def product_version_dispatch(*_args, **_kwargs):
"""Dispatch function for use in multimethods that just ignores
arguments and dispatches on the current product version."""
return current_version()
[docs]def dependent(default_function):
m = mm.MultiMethod(default_function.__name__, product_version_dispatch)
m.add_method(mm.Default, default_function)
mm._copy_attrs(default_function, m)
return m
[docs]def pick(v_dict):
"""
Collapses an ambiguous series of objects bound to specific versions
by interrogating the CFME Version and returning the correct item.
"""
# convert keys to Versions
v_dict = {get_version(k): v for (k, v) in v_dict.items()}
versions = v_dict.keys()
sorted_matching_versions = sorted(filter(lambda v: v <= current_version(), versions),
reverse=True)
return v_dict.get(sorted_matching_versions[0]) if sorted_matching_versions else None
# Compare Versions using > for dispatch
@mm.is_a.method((Version, Version))
def _is_a_loose(x, y):
return x >= y
@mm.is_a.method((str, Version))
def _is_a_slv(x, y):
return mm.is_a(Version(x), y)
@mm.is_a.method((Version, str))
def _is_a_lvs(x, y):
return mm.is_a(x, Version(y))