Merge ~chad.smith/cloud-init:bug/ec2-tests-unmocked-metadata into cloud-init:master

Proposed by Chad Smith
Status: Merged
Merged at revision: 1770a1eb647d24e14732194e72210ea494986ad2
Proposed branch: ~chad.smith/cloud-init:bug/ec2-tests-unmocked-metadata
Merge into: cloud-init:master
Diff against target: 102 lines (+30/-16)
1 file modified
tests/unittests/test_datasource/test_ec2.py (+30/-16)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Joshua Powers (community) Approve
cloud-init Commiters Pending
Review via email: mp+330040@code.launchpad.net

Commit message

ec2 tests: Stop leaking calls through unmocked metadata addresses

DataSourceEc2 behavior changed to first check a minimum acceptable
metadata version uri http://169.154.169.254/<min_version>/instance-id,
retrying on 404, until the metadata service is available. After the
metadata service is up, the datasource inspects preferred
extended_metadata_versions for availability. Unit tests only mocked the
preferred extended_metadata_version so all Ec2 tests were retrying
attempts against
http://169.254.169.254/meta-data/<min-version>/instance-id adding a lot of
time cost to the unit test runs.

This branch uses httpretty to properly mock the following:
  - 404s from metadata on undesired extended_metadata_version test routes
    - https://169.254.169.254/meta-data/2016-09-02/instance-id
  - full metadata dictionary represented on min_metadata_version
    - https://169.254.169.254/meta-data/2016-09-02/*

The branch also tightens httpretty to raise a MockError for any URL
which isn't mocked via httpretty.HTTPretty.allow_net_connect=False.

LP: #1714117

Description of the change

ec2 tests: Stop leaking calls through unmocked metadata addresses

DataSourceEc2 behavior changed to first check a minimum acceptable
metadata version uri http://169.154.169.254/<min_version>/instance-id,
retrying on 404, until the metadata service is available. After the
metadata service is up, the datasource inspects preferred
extended_metadata_versions for availability. Unit tests only mocked the
preferred extended_metadata_version so all Ec2 tests were retrying
attempts against
http://169.254.169.254/meta-data/<min-version>/instance-id adding a lot of
time cost to the unit test runs.

This branch uses httpretty to properly mock the following:
  - 404s from metadata on undesired extended_metadata_version test routes
    - https://169.254.169.254/meta-data/2016-09-02/instance-id
  - full metadata dictionary represented on min_metadata_version
    - https://169.254.169.254/meta-data/2016-09-02/*

The branch also tightens httpretty to raise a MockError for any URL
which isn't mocked via httpretty.HTTPretty.allow_net_connect=False.

LP: #1714117

To post a comment you must log in.
Revision history for this message
Joshua Powers (powersj) wrote :

Ran on the test system and was back to under 20 seconds for each environment. Add link to bug (LP: 1714117), fix style tests, and this is good to go!

tests/unittests/test_datasource/test_ec2.py:6:1: F401 're' imported but unused
tests/unittests/test_datasource/test_ec2.py:203:24: E114 indentation is not a multiple of four (comment)
tests/unittests/test_datasource/test_ec2.py:207:24: E114 indentation is not a multiple of four (comment)
tests/unittests/test_datasource/test_ec2.py:208:24: E111 indentation is not a multiple of four

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:d817633406d69224ae24924244e10a039a84bdbb
https://jenkins.ubuntu.com/server/job/cloud-init-ci/243/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/243/rebuild

review: Needs Fixing (continuous-integration)
53e97d2... by Chad Smith

flakes

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:53e97d2da7fd9f080d6774bfa7394e139a457c0d
https://jenkins.ubuntu.com/server/job/cloud-init-ci/244/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/244/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
2index e1ce644..b7a84e2 100644
3--- a/tests/unittests/test_datasource/test_ec2.py
4+++ b/tests/unittests/test_datasource/test_ec2.py
5@@ -116,6 +116,9 @@ def register_mock_metaserver(base_url, data):
6 In the index, references to lists or dictionaries have a trailing /.
7 """
8 def register_helper(register, base_url, body):
9+ if not isinstance(base_url, str):
10+ register(base_url, body)
11+ return
12 base_url = base_url.rstrip("/")
13 if isinstance(body, str):
14 register(base_url, body)
15@@ -138,7 +141,7 @@ def register_mock_metaserver(base_url, data):
16 register(base_url, '\n'.join(vals) + '\n')
17 register(base_url + '/', '\n'.join(vals) + '\n')
18 elif body is None:
19- register(base_url, 'not found', status_code=404)
20+ register(base_url, 'not found', status=404)
21
22 def myreg(*argc, **kwargs):
23 # print("register_url(%s, %s)" % (argc, kwargs))
24@@ -161,38 +164,47 @@ class TestEc2(test_helpers.HttprettyTestCase):
25 self.datasource = ec2.DataSourceEc2
26 self.metadata_addr = self.datasource.metadata_urls[0]
27
28- @property
29- def metadata_url(self):
30- return '/'.join([
31- self.metadata_addr,
32- self.datasource.min_metadata_version, 'meta-data', ''])
33-
34- @property
35- def userdata_url(self):
36- return '/'.join([
37- self.metadata_addr,
38- self.datasource.min_metadata_version, 'user-data'])
39+ def data_url(self, version):
40+ """Return a metadata url based on the version provided."""
41+ return '/'.join([self.metadata_addr, version, 'meta-data', ''])
42
43 def _patch_add_cleanup(self, mpath, *args, **kwargs):
44 p = mock.patch(mpath, *args, **kwargs)
45 p.start()
46 self.addCleanup(p.stop)
47
48- def _setup_ds(self, sys_cfg, platform_data, md, ud=None):
49+ def _setup_ds(self, sys_cfg, platform_data, md, md_version=None):
50+ self.uris = []
51 distro = {}
52 paths = helpers.Paths({})
53 if sys_cfg is None:
54 sys_cfg = {}
55 ds = self.datasource(sys_cfg=sys_cfg, distro=distro, paths=paths)
56+ if not md_version:
57+ md_version = ds.min_metadata_version
58 if platform_data is not None:
59 self._patch_add_cleanup(
60 "cloudinit.sources.DataSourceEc2._collect_platform_data",
61 return_value=platform_data)
62
63 if md:
64- register_mock_metaserver(self.metadata_url, md)
65- register_mock_metaserver(self.userdata_url, ud)
66-
67+ httpretty.HTTPretty.allow_net_connect = False
68+ all_versions = (
69+ [ds.min_metadata_version] + ds.extended_metadata_versions)
70+ for version in all_versions:
71+ metadata_url = self.data_url(version)
72+ if version == md_version:
73+ # Register all metadata for desired version
74+ register_mock_metaserver(metadata_url, md)
75+ else:
76+ instance_id_url = metadata_url + 'instance-id'
77+ if version == ds.min_metadata_version:
78+ # Add min_metadata_version service availability check
79+ register_mock_metaserver(
80+ instance_id_url, DEFAULT_METADATA['instance-id'])
81+ else:
82+ # Register 404s for all unrequested extended versions
83+ register_mock_metaserver(instance_id_url, None)
84 return ds
85
86 @httpretty.activate
87@@ -297,6 +309,7 @@ class TestEc2(test_helpers.HttprettyTestCase):
88 Then the metadata services is crawled for more network config info.
89 When the platform data is valid, return True.
90 """
91+
92 m_is_bsd.return_value = False
93 m_dhcp.return_value = [{
94 'interface': 'eth9', 'fixed-address': '192.168.2.9',
95@@ -307,6 +320,7 @@ class TestEc2(test_helpers.HttprettyTestCase):
96 platform_data=self.valid_platform_data,
97 sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
98 md=DEFAULT_METADATA)
99+
100 ret = ds.get_data()
101 self.assertTrue(ret)
102 m_dhcp.assert_called_once_with()

Subscribers

People subscribed via source and target branches