mirror of https://github.com/ansible/ansible.git
Cleanups to the common.sys_info API
* Move get_all_subclasses out of sys_info as it is unrelated to system information. * get_all_subclasses now returns a set() instead of a list. * Don't port get_platform to sys_info as it is deprecated. Code using the common API should just use platform.system() directly. * Rename load_platform_subclass() to get_platform_subclass and do not instantiate the rturned class. * Test the compat shims in module_utils/basic.py separately from the new API in module_utils/common/sys_info.py and module_utils/common/_utils.pypull/50537/head
parent
79dc9a75c3
commit
5844c8c7f0
@ -0,0 +1,40 @@
|
|||||||
|
# Copyright (c) 2018, Ansible Project
|
||||||
|
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Modules in _utils are waiting to find a better home. If you need to use them, be prepared for them
|
||||||
|
to move to a different location in the future.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_subclasses(cls):
|
||||||
|
'''
|
||||||
|
Recursively search and find all subclasses of a given class
|
||||||
|
|
||||||
|
:arg cls: A python class
|
||||||
|
:rtype: set
|
||||||
|
:returns: The set of python classes which are the subclasses of `cls`.
|
||||||
|
|
||||||
|
In python, you can use a class's :py:meth:`__subclasses__` method to determine what subclasses
|
||||||
|
of a class exist. However, `__subclasses__` only goes one level deep. This function searches
|
||||||
|
each child class's `__subclasses__` method to find all of the descendent classes. It then
|
||||||
|
returns an iterable of the descendent classes.
|
||||||
|
'''
|
||||||
|
# Retrieve direct subclasses
|
||||||
|
subclasses = set(cls.__subclasses__())
|
||||||
|
to_visit = list(subclasses)
|
||||||
|
# Then visit all subclasses
|
||||||
|
while to_visit:
|
||||||
|
for sc in to_visit:
|
||||||
|
# The current class is now visited, so remove it from list
|
||||||
|
to_visit.remove(sc)
|
||||||
|
# Appending all subclasses to visit and keep a reference of available class
|
||||||
|
for ssc in sc.__subclasses__():
|
||||||
|
if ssc not in subclasses:
|
||||||
|
to_visit.append(ssc)
|
||||||
|
subclasses.add(ssc)
|
||||||
|
return subclasses
|
@ -0,0 +1,108 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||||
|
# (c) 2016 Toshio Kuratomi <tkuratomi@ansible.com>
|
||||||
|
# (c) 2017-2018 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from units.compat.mock import patch
|
||||||
|
|
||||||
|
from ansible.module_utils.six.moves import builtins
|
||||||
|
|
||||||
|
# Functions being tested
|
||||||
|
from ansible.module_utils.common.sys_info import get_distribution
|
||||||
|
from ansible.module_utils.common.sys_info import get_distribution_version
|
||||||
|
from ansible.module_utils.common.sys_info import get_platform_subclass
|
||||||
|
|
||||||
|
|
||||||
|
realimport = builtins.__import__
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def platform_linux(mocker):
|
||||||
|
mocker.patch('platform.system', return_value='Linux')
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# get_distribution tests
|
||||||
|
#
|
||||||
|
|
||||||
|
def test_get_distribution_not_linux():
|
||||||
|
"""If it's not Linux, then it has no distribution"""
|
||||||
|
with patch('platform.system', return_value='Foo'):
|
||||||
|
assert get_distribution() is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("platform_linux")
|
||||||
|
class TestGetDistribution:
|
||||||
|
""" Tests for get_distribution that have to find somethine"""
|
||||||
|
def test_distro_known(self):
|
||||||
|
with patch('ansible.module_utils.distro.name', return_value="foo"):
|
||||||
|
assert get_distribution() == "Foo"
|
||||||
|
|
||||||
|
def test_distro_unknown(self):
|
||||||
|
with patch('ansible.module_utils.distro.name', return_value=""):
|
||||||
|
assert get_distribution() == "OtherLinux"
|
||||||
|
|
||||||
|
def test_distro_amazon_part_of_another_name(self):
|
||||||
|
with patch('ansible.module_utils.distro.name', return_value="AmazonFooBar"):
|
||||||
|
assert get_distribution() == "Amazonfoobar"
|
||||||
|
|
||||||
|
def test_distro_amazon_linux(self):
|
||||||
|
with patch('ansible.module_utils.distro.name', return_value="Amazon Linux AMI"):
|
||||||
|
assert get_distribution() == "Amazon"
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# get_distribution_version tests
|
||||||
|
#
|
||||||
|
|
||||||
|
def test_get_distribution_version_not_linux():
|
||||||
|
"""If it's not Linux, then it has no distribution"""
|
||||||
|
with patch('platform.system', return_value='Foo'):
|
||||||
|
assert get_distribution_version() is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("platform_linux")
|
||||||
|
def test_distro_found():
|
||||||
|
with patch('ansible.module_utils.distro.version', return_value="1"):
|
||||||
|
assert get_distribution_version() == "1"
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests for get_platform_subclass
|
||||||
|
#
|
||||||
|
|
||||||
|
class TestGetPlatformSubclass:
|
||||||
|
class LinuxTest:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Foo(LinuxTest):
|
||||||
|
platform = "Linux"
|
||||||
|
distribution = None
|
||||||
|
|
||||||
|
class Bar(LinuxTest):
|
||||||
|
platform = "Linux"
|
||||||
|
distribution = "Bar"
|
||||||
|
|
||||||
|
def test_not_linux(self):
|
||||||
|
# if neither match, the fallback should be the top-level class
|
||||||
|
with patch('platform.system', return_value="Foo"):
|
||||||
|
with patch('ansible.module_utils.common.sys_info.get_distribution', return_value=None):
|
||||||
|
assert get_platform_subclass(self.LinuxTest) is self.LinuxTest
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("platform_linux")
|
||||||
|
def test_get_distribution_none(self):
|
||||||
|
# match just the platform class, not a specific distribution
|
||||||
|
with patch('ansible.module_utils.common.sys_info.get_distribution', return_value=None):
|
||||||
|
assert get_platform_subclass(self.LinuxTest) is self.Foo
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("platform_linux")
|
||||||
|
def test_get_distribution_found(self):
|
||||||
|
# match both the distribution and platform class
|
||||||
|
with patch('ansible.module_utils.common.sys_info.get_distribution', return_value="Bar"):
|
||||||
|
assert get_platform_subclass(self.LinuxTest) is self.Bar
|
@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# (c) 2018 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from ansible.module_utils.common.sys_info import get_all_subclasses
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests for get_all_subclasses
|
||||||
|
#
|
||||||
|
|
||||||
|
class TestGetAllSubclasses:
|
||||||
|
class Base:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchI(Base):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchII(Base):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchIA(BranchI):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchIB(BranchI):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchIIA(BranchII):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BranchIIB(BranchII):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_bottom_level(self):
|
||||||
|
assert get_all_subclasses(self.BranchIIB) == set()
|
||||||
|
|
||||||
|
def test_one_inheritance(self):
|
||||||
|
assert set(get_all_subclasses(self.BranchII)) == set([self.BranchIIA, self.BranchIIB])
|
||||||
|
|
||||||
|
def test_toplevel(self):
|
||||||
|
assert set(get_all_subclasses(self.Base)) == set([self.BranchI, self.BranchII,
|
||||||
|
self.BranchIA, self.BranchIB,
|
||||||
|
self.BranchIIA, self.BranchIIB])
|
Loading…
Reference in New Issue