diff options
| author | Brett Holman <bholman.devel@gmail.com> | 2021-12-03 13:11:46 -0700 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-03 13:11:46 -0700 | 
| commit | 039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51 (patch) | |
| tree | 5f1b09486ccaf98ee8159de58d9a2a1ef0af5dc1 /tests/unittests/sources/test_aliyun.py | |
| parent | ffa6fc88249aa080aa31811a45569a45e567418a (diff) | |
| download | vyos-cloud-init-039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51.tar.gz vyos-cloud-init-039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51.zip | |
Reorganize unit test locations under tests/unittests (#1126)
This attempts to standardize unit test file location under test/unittests/
such that any source file located at cloudinit/path/to/file.py may have a
corresponding unit test file at test/unittests/path/to/test_file.py.
Noteworthy Comments:
====================
Four different duplicate test files existed:
test_{gpg,util,cc_mounts,cc_resolv_conf}.py
Each of these duplicate file pairs has been merged together. This is a
break in git history for these files.
The test suite appears to have a dependency on test order. Changing test
order causes some tests to fail. This should be rectified, but for now
some tests have been modified in
tests/unittests/config/test_set_passwords.py.
A helper class name starts with "Test" which causes pytest to try
executing it as a test case, which then throws warnings "due to Class
having __init__()".  Silence by changing the name of the class.
# helpers.py is imported in many test files, import paths change
cloudinit/tests/helpers.py -> tests/unittests/helpers.py
# Move directories:
cloudinit/distros/tests -> tests/unittests/distros
cloudinit/cmd/devel/tests -> tests/unittests/cmd/devel
cloudinit/cmd/tests -> tests/unittests/cmd/
cloudinit/sources/helpers/tests -> tests/unittests/sources/helpers
cloudinit/sources/tests -> tests/unittests/sources
cloudinit/net/tests -> tests/unittests/net
cloudinit/config/tests -> tests/unittests/config
cloudinit/analyze/tests/ -> tests/unittests/analyze/
# Standardize tests already in tests/unittests/
test_datasource -> sources
test_distros -> distros
test_vmware -> sources/vmware
test_handler -> config        # this contains cloudconfig module tests
test_runs -> runs
Diffstat (limited to 'tests/unittests/sources/test_aliyun.py')
| -rw-r--r-- | tests/unittests/sources/test_aliyun.py | 248 | 
1 files changed, 248 insertions, 0 deletions
| diff --git a/tests/unittests/sources/test_aliyun.py b/tests/unittests/sources/test_aliyun.py new file mode 100644 index 00000000..00209913 --- /dev/null +++ b/tests/unittests/sources/test_aliyun.py @@ -0,0 +1,248 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import functools +import httpretty +import os +from unittest import mock + +from cloudinit import helpers +from cloudinit.sources import DataSourceAliYun as ay +from cloudinit.sources.DataSourceEc2 import convert_ec2_metadata_network_config +from tests.unittests import helpers as test_helpers + +DEFAULT_METADATA = { +    'instance-id': 'aliyun-test-vm-00', +    'eipv4': '10.0.0.1', +    'hostname': 'test-hostname', +    'image-id': 'm-test', +    'launch-index': '0', +    'mac': '00:16:3e:00:00:00', +    'network-type': 'vpc', +    'private-ipv4': '192.168.0.1', +    'serial-number': 'test-string', +    'vpc-cidr-block': '192.168.0.0/16', +    'vpc-id': 'test-vpc', +    'vswitch-id': 'test-vpc', +    'vswitch-cidr-block': '192.168.0.0/16', +    'zone-id': 'test-zone-1', +    'ntp-conf': {'ntp_servers': [ +                 'ntp1.aliyun.com', +                 'ntp2.aliyun.com', +                 'ntp3.aliyun.com']}, +    'source-address': ['http://mirrors.aliyun.com', +                       'http://mirrors.aliyuncs.com'], +    'public-keys': {'key-pair-1': {'openssh-key': 'ssh-rsa AAAAB3...'}, +                    'key-pair-2': {'openssh-key': 'ssh-rsa AAAAB3...'}} +} + +DEFAULT_USERDATA = """\ +#cloud-config + +hostname: localhost""" + + +def register_mock_metaserver(base_url, data): +    def register_helper(register, base_url, body): +        if isinstance(body, str): +            register(base_url, body) +        elif isinstance(body, list): +            register(base_url.rstrip('/'), '\n'.join(body) + '\n') +        elif isinstance(body, dict): +            if not body: +                register(base_url.rstrip('/') + '/', 'not found', +                         status_code=404) +            vals = [] +            for k, v in body.items(): +                if isinstance(v, (str, list)): +                    suffix = k.rstrip('/') +                else: +                    suffix = k.rstrip('/') + '/' +                vals.append(suffix) +                url = base_url.rstrip('/') + '/' + suffix +                register_helper(register, url, v) +            register(base_url, '\n'.join(vals) + '\n') + +    register = functools.partial(httpretty.register_uri, httpretty.GET) +    register_helper(register, base_url, data) + + +class TestAliYunDatasource(test_helpers.HttprettyTestCase): +    def setUp(self): +        super(TestAliYunDatasource, self).setUp() +        cfg = {'datasource': {'AliYun': {'timeout': '1', 'max_wait': '1'}}} +        distro = {} +        paths = helpers.Paths({'run_dir': self.tmp_dir()}) +        self.ds = ay.DataSourceAliYun(cfg, distro, paths) +        self.metadata_address = self.ds.metadata_urls[0] + +    @property +    def default_metadata(self): +        return DEFAULT_METADATA + +    @property +    def default_userdata(self): +        return DEFAULT_USERDATA + +    @property +    def metadata_url(self): +        return os.path.join( +            self.metadata_address, +            self.ds.min_metadata_version, 'meta-data') + '/' + +    @property +    def userdata_url(self): +        return os.path.join( +            self.metadata_address, +            self.ds.min_metadata_version, 'user-data') + +    # EC2 provides an instance-identity document which must return 404 here +    # for this test to pass. +    @property +    def default_identity(self): +        return {} + +    @property +    def identity_url(self): +        return os.path.join(self.metadata_address, +                            self.ds.min_metadata_version, +                            'dynamic', 'instance-identity') + +    def regist_default_server(self): +        register_mock_metaserver(self.metadata_url, self.default_metadata) +        register_mock_metaserver(self.userdata_url, self.default_userdata) +        register_mock_metaserver(self.identity_url, self.default_identity) + +    def _test_get_data(self): +        self.assertEqual(self.ds.metadata, self.default_metadata) +        self.assertEqual(self.ds.userdata_raw, +                         self.default_userdata.encode('utf8')) + +    def _test_get_sshkey(self): +        pub_keys = [v['openssh-key'] for (_, v) in +                    self.default_metadata['public-keys'].items()] +        self.assertEqual(self.ds.get_public_ssh_keys(), pub_keys) + +    def _test_get_iid(self): +        self.assertEqual(self.default_metadata['instance-id'], +                         self.ds.get_instance_id()) + +    def _test_host_name(self): +        self.assertEqual(self.default_metadata['hostname'], +                         self.ds.get_hostname()) + +    @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun") +    def test_with_mock_server(self, m_is_aliyun): +        m_is_aliyun.return_value = True +        self.regist_default_server() +        ret = self.ds.get_data() +        self.assertEqual(True, ret) +        self.assertEqual(1, m_is_aliyun.call_count) +        self._test_get_data() +        self._test_get_sshkey() +        self._test_get_iid() +        self._test_host_name() +        self.assertEqual('aliyun', self.ds.cloud_name) +        self.assertEqual('ec2', self.ds.platform) +        self.assertEqual( +            'metadata (http://100.100.100.200)', self.ds.subplatform) + +    @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun") +    def test_returns_false_when_not_on_aliyun(self, m_is_aliyun): +        """If is_aliyun returns false, then get_data should return False.""" +        m_is_aliyun.return_value = False +        self.regist_default_server() +        ret = self.ds.get_data() +        self.assertEqual(1, m_is_aliyun.call_count) +        self.assertEqual(False, ret) + +    def test_parse_public_keys(self): +        public_keys = {} +        self.assertEqual(ay.parse_public_keys(public_keys), []) + +        public_keys = {'key-pair-0': 'ssh-key-0'} +        self.assertEqual(ay.parse_public_keys(public_keys), +                         [public_keys['key-pair-0']]) + +        public_keys = {'key-pair-0': 'ssh-key-0', 'key-pair-1': 'ssh-key-1'} +        self.assertEqual(set(ay.parse_public_keys(public_keys)), +                         set([public_keys['key-pair-0'], +                             public_keys['key-pair-1']])) + +        public_keys = {'key-pair-0': ['ssh-key-0', 'ssh-key-1']} +        self.assertEqual(ay.parse_public_keys(public_keys), +                         public_keys['key-pair-0']) + +        public_keys = {'key-pair-0': {'openssh-key': []}} +        self.assertEqual(ay.parse_public_keys(public_keys), []) + +        public_keys = {'key-pair-0': {'openssh-key': 'ssh-key-0'}} +        self.assertEqual(ay.parse_public_keys(public_keys), +                         [public_keys['key-pair-0']['openssh-key']]) + +        public_keys = {'key-pair-0': {'openssh-key': ['ssh-key-0', +                                                      'ssh-key-1']}} +        self.assertEqual(ay.parse_public_keys(public_keys), +                         public_keys['key-pair-0']['openssh-key']) + +    def test_route_metric_calculated_without_device_number(self): +        """Test that route-metric code works without `device-number` + +        `device-number` is part of EC2 metadata, but not supported on aliyun. +        Attempting to access it will raise a KeyError. + +        LP: #1917875 +        """ +        netcfg = convert_ec2_metadata_network_config( +            {"interfaces": {"macs": { +                "06:17:04:d7:26:09": { +                    "interface-id": "eni-e44ef49e", +                }, +                "06:17:04:d7:26:08": { +                    "interface-id": "eni-e44ef49f", +                } +            }}}, +            macs_to_nics={ +                '06:17:04:d7:26:09': 'eth0', +                '06:17:04:d7:26:08': 'eth1', +            } +        ) + +        met0 = netcfg['ethernets']['eth0']['dhcp4-overrides']['route-metric'] +        met1 = netcfg['ethernets']['eth1']['dhcp4-overrides']['route-metric'] + +        # route-metric numbers should be 100 apart +        assert 100 == abs(met0 - met1) + + +class TestIsAliYun(test_helpers.CiTestCase): +    ALIYUN_PRODUCT = 'Alibaba Cloud ECS' +    read_dmi_data_expected = [mock.call('system-product-name')] + +    @mock.patch("cloudinit.sources.DataSourceAliYun.dmi.read_dmi_data") +    def test_true_on_aliyun_product(self, m_read_dmi_data): +        """Should return true if the dmi product data has expected value.""" +        m_read_dmi_data.return_value = self.ALIYUN_PRODUCT +        ret = ay._is_aliyun() +        self.assertEqual(self.read_dmi_data_expected, +                         m_read_dmi_data.call_args_list) +        self.assertEqual(True, ret) + +    @mock.patch("cloudinit.sources.DataSourceAliYun.dmi.read_dmi_data") +    def test_false_on_empty_string(self, m_read_dmi_data): +        """Should return false on empty value returned.""" +        m_read_dmi_data.return_value = "" +        ret = ay._is_aliyun() +        self.assertEqual(self.read_dmi_data_expected, +                         m_read_dmi_data.call_args_list) +        self.assertEqual(False, ret) + +    @mock.patch("cloudinit.sources.DataSourceAliYun.dmi.read_dmi_data") +    def test_false_on_unknown_string(self, m_read_dmi_data): +        """Should return false on an unrelated string.""" +        m_read_dmi_data.return_value = "cubs win" +        ret = ay._is_aliyun() +        self.assertEqual(self.read_dmi_data_expected, +                         m_read_dmi_data.call_args_list) +        self.assertEqual(False, ret) + +# vi: ts=4 expandtab | 
