diff options
Diffstat (limited to 'tests')
44 files changed, 2793 insertions, 248 deletions
diff --git a/tests/__init__.py b/tests/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/common/__init__.py b/tests/common/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/common/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/common/dhcp/__init__.py b/tests/common/dhcp/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/common/dhcp/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/common/dhcp/test_dhcp.py b/tests/common/dhcp/test_dhcp.py new file mode 100644 index 0000000..c27ffe8 --- /dev/null +++ b/tests/common/dhcp/test_dhcp.py @@ -0,0 +1,107 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +import mock +import azurelinuxagent.common.dhcp as dhcp +import azurelinuxagent.common.osutil.default as osutil +from tests.tools import * + + +class TestDHCP(AgentTestCase): + def test_wireserver_route_exists(self): + # setup + dhcp_handler = dhcp.get_dhcp_handler() + self.assertTrue(dhcp_handler.endpoint is None) + self.assertTrue(dhcp_handler.routes is None) + self.assertTrue(dhcp_handler.gateway is None) + + # execute + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric " \ + "Mask MTU Window IRTT \n\ + eth0 00000000 10813FA8 0003 0 0 5 " \ + "00000000 0 0 0 \n\ + eth0 00345B0A 00000000 0001 0 0 5 " \ + "00000000 0 0 0 \n\ + lo 00000000 01345B0A 0003 0 0 1 " \ + "00FCFFFF 0 0 0 \n" + + with patch("os.path.exists", return_value=True): + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertTrue(dhcp_handler.wireserver_route_exists) + + # test + self.assertTrue(dhcp_handler.endpoint is not None) + self.assertTrue(dhcp_handler.routes is None) + self.assertTrue(dhcp_handler.gateway is None) + + def test_wireserver_route_not_exists(self): + # setup + dhcp_handler = dhcp.get_dhcp_handler() + self.assertTrue(dhcp_handler.endpoint is None) + self.assertTrue(dhcp_handler.routes is None) + self.assertTrue(dhcp_handler.gateway is None) + + # execute + self.assertFalse(dhcp_handler.wireserver_route_exists) + + # test + self.assertTrue(dhcp_handler.endpoint is None) + self.assertTrue(dhcp_handler.routes is None) + self.assertTrue(dhcp_handler.gateway is None) + + def test_dhcp_cache_exists(self): + dhcp_handler = dhcp.get_dhcp_handler() + dhcp_handler.osutil = osutil.DefaultOSUtil() + with patch.object(osutil.DefaultOSUtil, 'get_dhcp_lease_endpoint', + return_value=None): + self.assertFalse(dhcp_handler.dhcp_cache_exists) + self.assertEqual(dhcp_handler.endpoint, None) + with patch.object(osutil.DefaultOSUtil, 'get_dhcp_lease_endpoint', + return_value="foo"): + self.assertTrue(dhcp_handler.dhcp_cache_exists) + self.assertEqual(dhcp_handler.endpoint, "foo") + + def test_dhcp_skip_cache(self): + handler = dhcp.get_dhcp_handler() + handler.osutil = osutil.DefaultOSUtil() + with patch('os.path.exists', return_value=False): + with patch.object(osutil.DefaultOSUtil, 'get_dhcp_lease_endpoint')\ + as patch_dhcp_cache: + with patch.object(dhcp.DhcpHandler, 'send_dhcp_req') \ + as patch_dhcp_send: + + endpoint = 'foo' + patch_dhcp_cache.return_value = endpoint + + # endpoint comes from cache + self.assertFalse(handler.skip_cache) + handler.run() + self.assertTrue(patch_dhcp_cache.call_count == 1) + self.assertTrue(patch_dhcp_send.call_count == 0) + self.assertTrue(handler.endpoint == endpoint) + + # reset + handler.skip_cache = True + handler.endpoint = None + + # endpoint comes from dhcp request + self.assertTrue(handler.skip_cache) + handler.run() + self.assertTrue(patch_dhcp_cache.call_count == 1) + self.assertTrue(patch_dhcp_send.call_count == 1) diff --git a/tests/common/osutil/__init__.py b/tests/common/osutil/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/common/osutil/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/common/osutil/test_default.py b/tests/common/osutil/test_default.py new file mode 100644 index 0000000..d9d00f6 --- /dev/null +++ b/tests/common/osutil/test_default.py @@ -0,0 +1,146 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +import socket +import glob +import mock +import azurelinuxagent.common.osutil.default as osutil +import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.osutil import get_osutil +from tests.tools import * + + +class TestOSUtil(AgentTestCase): + def test_restart(self): + # setup + retries = 3 + ifname = 'dummy' + with patch.object(shellutil, "run") as run_patch: + run_patch.return_value = 1 + + # execute + osutil.DefaultOSUtil.restart_if(osutil.DefaultOSUtil(), ifname=ifname, retries=retries, wait=0) + + # assert + self.assertEqual(run_patch.call_count, retries) + self.assertEqual(run_patch.call_args_list[0][0][0], 'ifdown {0} && ifup {0}'.format(ifname)) + + def test_get_first_if(self): + ifname, ipaddr = osutil.DefaultOSUtil().get_first_if() + self.assertTrue(ifname.startswith('eth')) + self.assertTrue(ipaddr is not None) + try: + socket.inet_aton(ipaddr) + except socket.error: + self.fail("not a valid ip address") + + def test_isloopback(self): + self.assertTrue(osutil.DefaultOSUtil().is_loopback(b'lo')) + self.assertFalse(osutil.DefaultOSUtil().is_loopback(b'eth0')) + + def test_isprimary(self): + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT \n\ + eth0 00000000 01345B0A 0003 0 0 5 00000000 0 0 0 \n\ + eth0 00345B0A 00000000 0001 0 0 5 00000000 0 0 0 \n\ + lo 00000000 01345B0A 0003 0 0 1 00FCFFFF 0 0 0 \n" + + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertFalse(osutil.DefaultOSUtil().is_primary_interface('lo')) + self.assertTrue(osutil.DefaultOSUtil().is_primary_interface('eth0')) + + def test_multiple_default_routes(self): + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT \n\ + high 00000000 01345B0A 0003 0 0 5 00000000 0 0 0 \n\ + low1 00000000 01345B0A 0003 0 0 1 00FCFFFF 0 0 0 \n" + + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertTrue(osutil.DefaultOSUtil().is_primary_interface('low1')) + + def test_multiple_interfaces(self): + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT \n\ + first 00000000 01345B0A 0003 0 0 1 00000000 0 0 0 \n\ + secnd 00000000 01345B0A 0003 0 0 1 00FCFFFF 0 0 0 \n" + + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertTrue(osutil.DefaultOSUtil().is_primary_interface('first')) + + def test_interface_flags(self): + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT \n\ + nflg 00000000 01345B0A 0001 0 0 1 00000000 0 0 0 \n\ + flgs 00000000 01345B0A 0003 0 0 1 00FCFFFF 0 0 0 \n" + + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertTrue(osutil.DefaultOSUtil().is_primary_interface('flgs')) + + def test_no_interface(self): + routing_table = "\ + Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT \n\ + ndst 00000001 01345B0A 0003 0 0 1 00000000 0 0 0 \n\ + nflg 00000000 01345B0A 0001 0 0 1 00FCFFFF 0 0 0 \n" + + mo = mock.mock_open(read_data=routing_table) + with patch(open_patch(), mo): + self.assertFalse(osutil.DefaultOSUtil().is_primary_interface('ndst')) + self.assertFalse(osutil.DefaultOSUtil().is_primary_interface('nflg')) + self.assertFalse(osutil.DefaultOSUtil().is_primary_interface('invalid')) + + def test_no_primary_does_not_throw(self): + with patch.object(osutil.DefaultOSUtil, 'get_primary_interface') \ + as patch_primary: + exception = False + patch_primary.return_value = '' + try: + osutil.DefaultOSUtil().get_first_if()[0] + except Exception as e: + exception = True + self.assertFalse(exception) + + def test_dhcp_lease_default(self): + self.assertTrue(osutil.DefaultOSUtil().get_dhcp_lease_endpoint() is None) + + def test_dhcp_lease_ubuntu(self): + with patch.object(glob, "glob", return_value=['/var/lib/dhcp/dhclient.eth0.leases']): + with patch(open_patch(), mock.mock_open(read_data=load_data("dhcp.leases"))): + endpoint = get_osutil(distro_name='ubuntu', distro_version='12.04').get_dhcp_lease_endpoint() + self.assertTrue(endpoint is not None) + self.assertEqual(endpoint, "168.63.129.16") + + endpoint = get_osutil(distro_name='ubuntu', distro_version='12.04').get_dhcp_lease_endpoint() + self.assertTrue(endpoint is not None) + self.assertEqual(endpoint, "168.63.129.16") + + endpoint = get_osutil(distro_name='ubuntu', distro_version='14.04').get_dhcp_lease_endpoint() + self.assertTrue(endpoint is not None) + self.assertEqual(endpoint, "168.63.129.16") + + def test_dhcp_lease_multi(self): + with patch.object(glob, "glob", return_value=['/var/lib/dhcp/dhclient.eth0.leases']): + with patch(open_patch(), mock.mock_open(read_data=load_data("dhcp.leases.multi"))): + endpoint = get_osutil(distro_name='ubuntu', distro_version='12.04').get_dhcp_lease_endpoint() + self.assertTrue(endpoint is not None) + self.assertEqual(endpoint, "second") + +if __name__ == '__main__': + unittest.main() diff --git a/tests/common/test_version.py b/tests/common/test_version.py new file mode 100644 index 0000000..6a4dc38 --- /dev/null +++ b/tests/common/test_version.py @@ -0,0 +1,65 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from __future__ import print_function + +import copy +import glob +import json +import os +import platform +import random +import subprocess +import sys +import tempfile +import zipfile + +from tests.protocol.mockwiredata import * +from tests.tools import * + +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil + +from azurelinuxagent.common.utils.flexible_version import FlexibleVersion +from azurelinuxagent.common.version import * + + +class TestCurrentAgentName(AgentTestCase): + def setUp(self): + AgentTestCase.setUp(self) + return + + @patch("os.getcwd", return_value="/default/install/directory") + def test_extract_name_finds_installed(self, mock_cwd): + current_agent, current_version = set_current_agent() + self.assertEqual(AGENT_LONG_VERSION, current_agent) + self.assertEqual(AGENT_VERSION, str(current_version)) + return + + @patch("os.getcwd") + def test_extract_name_finds_latest_agent(self, mock_cwd): + path = os.path.join(conf.get_lib_dir(), "{0}-{1}".format( + AGENT_NAME, + "1.2.3")) + mock_cwd.return_value = path + agent = os.path.basename(path) + version = AGENT_NAME_PATTERN.match(agent).group(1) + current_agent, current_version = set_current_agent() + self.assertEqual(agent, current_agent) + self.assertEqual(version, str(current_version)) + return diff --git a/tests/daemon/__init__.py b/tests/daemon/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/daemon/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/distro/test_daemon.py b/tests/daemon/test_daemon.py index 9d3c45b..263af49 100644 --- a/tests/distro/test_daemon.py +++ b/tests/daemon/test_daemon.py @@ -14,14 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.daemon import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.daemon import * class MockDaemonCall(object): def __init__(self, daemon_handler, count): @@ -38,26 +34,30 @@ class MockDaemonCall(object): @patch("time.sleep") class TestDaemon(AgentTestCase): def test_daemon_restart(self, mock_sleep): - distro = get_distro() - mock_daemon = Mock(side_effect=MockDaemonCall(distro.daemon_handler, 2)) - distro.daemon_handler.daemon = mock_daemon - distro.daemon_handler.check_pid = Mock() - distro.daemon_handler.run() + #Mock daemon function + daemon_handler = get_daemon_handler() + mock_daemon = Mock(side_effect=MockDaemonCall(daemon_handler, 2)) + daemon_handler.daemon = mock_daemon + + daemon_handler.check_pid = Mock() + + daemon_handler.run() mock_sleep.assert_any_call(15) - self.assertEquals(2, distro.daemon_handler.daemon.call_count) + self.assertEquals(2, daemon_handler.daemon.call_count) - @patch("azurelinuxagent.distro.default.daemon.conf") - @patch("azurelinuxagent.distro.default.daemon.sys.exit") + @patch("azurelinuxagent.daemon.main.conf") + @patch("azurelinuxagent.daemon.main.sys.exit") def test_check_pid(self, mock_exit, mock_conf, mock_sleep): - distro = get_distro() + daemon_handler = get_daemon_handler() + mock_pid_file = os.path.join(self.tmp_dir, "pid") mock_conf.get_agent_pid_file_path = Mock(return_value=mock_pid_file) - distro.daemon_handler.check_pid() + daemon_handler.check_pid() self.assertTrue(os.path.isfile(mock_pid_file)) - distro.daemon_handler.check_pid() + daemon_handler.check_pid() mock_exit.assert_any_call(0) if __name__ == '__main__': diff --git a/tests/data/dhcp.leases b/tests/data/dhcp.leases new file mode 100644 index 0000000..cb4f396 --- /dev/null +++ b/tests/data/dhcp.leases @@ -0,0 +1,56 @@ +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers invalid; + option dhcp-renewal-time 4294967295; + option rfc3442-classless-static-routes 0,10,0,1,1,32,168,63,129,16,10,0,1,1; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 0 2152/07/23 23:27:10; + rebind 0 2152/07/23 23:27:10; + expire 0 never; +} +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers expired; + option dhcp-renewal-time 4294967295; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 4 2015/06/16 16:58:54; + rebind 4 2015/06/16 16:58:54; + expire 4 2015/06/16 16:58:54; +} +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers 168.63.129.16; + option dhcp-renewal-time 4294967295; + option rfc3442-classless-static-routes 0,10,0,1,1,32,168,63,129,16,10,0,1,1; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 0 2152/07/23 23:27:10; + rebind 0 2152/07/23 23:27:10; + expire 0 2152/07/23 23:27:10; +} diff --git a/tests/data/dhcp.leases.multi b/tests/data/dhcp.leases.multi new file mode 100644 index 0000000..cfe9c67 --- /dev/null +++ b/tests/data/dhcp.leases.multi @@ -0,0 +1,57 @@ +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers first; + option dhcp-renewal-time 4294967295; + option rfc3442-classless-static-routes 0,10,0,1,1,32,168,63,129,16,10,0,1,1; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 0 2152/07/23 23:27:10; + rebind 0 2152/07/23 23:27:10; + expire 0 2152/07/23 23:27:10; +} +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers second; + option dhcp-renewal-time 4294967295; + option rfc3442-classless-static-routes 0,10,0,1,1,32,168,63,129,16,10,0,1,1; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 0 2152/07/23 23:27:10; + rebind 0 2152/07/23 23:27:10; + expire 0 2152/07/23 23:27:10; +} +lease { + interface "eth0"; + fixed-address 10.0.1.4; + server-name "RDE41D2D9BB18C"; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 4294967295; + option routers 10.0.1.1; + option dhcp-message-type 5; + option dhcp-server-identifier 168.63.129.16; + option domain-name-servers expired; + option dhcp-renewal-time 4294967295; + option rfc3442-classless-static-routes 0,10,0,1,1,32,168,63,129,16,10,0,1,1; + option unknown-245 a8:3f:81:10; + option dhcp-rebinding-time 4294967295; + option domain-name "qylsde3bnlhu5dstzf3bav5inc.fx.internal.cloudapp.net"; + renew 0 2152/07/23 23:27:10; + rebind 0 2152/07/23 23:27:10; + expire 0 2012/07/23 23:27:10; +} diff --git a/tests/data/ext/sample_ext/sample.py b/tests/data/ext/sample_ext/sample.py index 7107ac2..74bd839 100755 --- a/tests/data/ext/sample_ext/sample.py +++ b/tests/data/ext/sample_ext/sample.py @@ -2,18 +2,19 @@ import os + def get_seq(): - latest_seq = -1; + latest_seq = -1 config_dir = os.path.join(os.getcwd(), "config") if os.path.isdir(config_dir): for item in os.listdir(config_dir): item_path = os.path.join(config_dir, item) if os.path.isfile(item_path): - seperator = item.rfind(".") - if seperator > 0 and item[seperator + 1:] == "settings": - seq = int(item[0: seperator]) - if seq > latest_seq: - latest_seq = seq + separator = item.rfind(".") + if separator > 0 and item[separator + 1:] == "settings": + sequence = int(item[0: separator]) + if sequence > latest_seq: + latest_seq = sequence return latest_seq @@ -28,6 +29,9 @@ succeed_status = """ if __name__ == "__main__": seq = get_seq() if seq >= 0: - status_file = os.path.join(os.getcwd(), "status", "{0}.status".format(seq)) + status_path = os.path.join(os.getcwd(), "status") + if not os.path.exists(status_path): + os.makedirs(status_path) + status_file = os.path.join(status_path, "{0}.status".format(seq)) with open(status_file, "w+") as status: status.write(succeed_status) diff --git a/tests/data/ga/WALinuxAgent-2.1.5.zip b/tests/data/ga/WALinuxAgent-2.1.5.zip Binary files differnew file mode 100644 index 0000000..b1f2684 --- /dev/null +++ b/tests/data/ga/WALinuxAgent-2.1.5.zip diff --git a/tests/data/wire/ext_conf.xml b/tests/data/wire/ext_conf.xml index 725271d..0b7c528 100644 --- a/tests/data/wire/ext_conf.xml +++ b/tests/data/wire/ext_conf.xml @@ -1,44 +1,24 @@ <Extensions version="1.0.0.0" goalStateIncarnation="9"><GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <GAFamilies> <GAFamily> - <Name>Win8</Name> + <Name>Prod</Name> <Uris> - <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr05.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr06.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr07.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr08.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr09.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr10.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr11.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr12.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> - <Uri>http://zrdfepirv2hk2prdstr01.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + <Uri>http://manifest_of_ga.xml</Uri> </Uris> </GAFamily> <GAFamily> - <Name>Win7</Name> + <Name>Test</Name> <Uris> - <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr05.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr06.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr07.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr08.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr09.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr10.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr11.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://rdfepirv2hknprdstr12.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - <Uri>http://zrdfepirv2hk2prdstr01.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> - </Uris> + <Uri>http://manifest_of_ga.xml</Uri> + </Uris> </GAFamily> </GAFamilies> </GuestAgentExtension> <Plugins> - <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="false" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" /> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="false" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" /> </Plugins> <PluginSettings> - <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0"> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0.0"> <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings> </Plugin> </PluginSettings> diff --git a/tests/data/wire/ext_conf_autoupgrade.xml b/tests/data/wire/ext_conf_autoupgrade.xml new file mode 100644 index 0000000..1d6919e --- /dev/null +++ b/tests/data/wire/ext_conf_autoupgrade.xml @@ -0,0 +1,28 @@ +<Extensions version="1.0.0.0" goalStateIncarnation="9"><GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> + <GAFamilies> + <GAFamily> + <Name>Win8</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + <GAFamily> + <Name>Win7</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + </GAFamilies> +</GuestAgentExtension> +<Plugins> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="true" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" /> +</Plugins> +<PluginSettings> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.0.0"> + <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings> + </Plugin> +</PluginSettings> +<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions> + diff --git a/tests/data/wire/ext_conf_autoupgrade_internalversion.xml b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml new file mode 100644 index 0000000..1e613ea --- /dev/null +++ b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml @@ -0,0 +1,28 @@ +<Extensions version="1.0.0.0" goalStateIncarnation="9"><GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> + <GAFamilies> + <GAFamily> + <Name>Win8</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + <GAFamily> + <Name>Win7</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + </GAFamilies> +</GuestAgentExtension> +<Plugins> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.2.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="true" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" /> +</Plugins> +<PluginSettings> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.2.0"> + <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings> + </Plugin> +</PluginSettings> +<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions> + diff --git a/tests/data/wire/ext_conf_internalversion.xml b/tests/data/wire/ext_conf_internalversion.xml new file mode 100644 index 0000000..1e613ea --- /dev/null +++ b/tests/data/wire/ext_conf_internalversion.xml @@ -0,0 +1,28 @@ +<Extensions version="1.0.0.0" goalStateIncarnation="9"><GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> + <GAFamilies> + <GAFamily> + <Name>Win8</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + <GAFamily> + <Name>Win7</Name> + <Uris> + <Uri>http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + <Uri>http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml</Uri> + </Uris> + </GAFamily> + </GAFamilies> +</GuestAgentExtension> +<Plugins> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.2.0" location="http://rdfepirv2hknprdstr03.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" config="" state="enabled" autoUpgrade="true" failoverlocation="http://rdfepirv2hknprdstr04.blob.core.windows.net/b01058962be54ceca550a390fa5ff064/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml" runAsStartupTask="false" isJson="true" /> +</Plugins> +<PluginSettings> + <Plugin name="OSTCExtensions.ExampleHandlerLinux" version="1.2.0"> + <RuntimeSettings seqNo="0">{"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]}</RuntimeSettings> + </Plugin> +</PluginSettings> +<StatusUploadBlob>https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D</StatusUploadBlob></Extensions> + diff --git a/tests/data/wire/ga_manifest.xml b/tests/data/wire/ga_manifest.xml new file mode 100644 index 0000000..f43daf5 --- /dev/null +++ b/tests/data/wire/ga_manifest.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<PluginVersionManifest xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> + <Plugins> + <Plugin> + <Version>1.0.0</Version> + <Uris> + <Uri>http://foo.bar/zar/OSTCExtensions.WALinuxAgent__1.0.0</Uri> + </Uris> + </Plugin> + <Plugin> + <Version>1.1.0</Version> + <Uris> + <Uri>http://foo.bar/zar/OSTCExtensions.WALinuxAgent__1.1.0</Uri> + </Uris> + </Plugin> + <Plugin> + <Version>2.0.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__2.0.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.1.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__2.1.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.1.1</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__2.1.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.2.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__2.2.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>3.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__3.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>3.1</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__3.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.0.0.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__3.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.0.0.1</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__3.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.1.0.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__3.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>99999.0.0.0</Version><Uris><Uri>http://host/OSTCExtensions.WALinuxAgent__99999.0.0.0</Uri></Uris> + </Plugin> + </Plugins> +</PluginVersionManifest> + diff --git a/tests/data/wire/manifest.xml b/tests/data/wire/manifest.xml index 943755a..ff42b9d 100644 --- a/tests/data/wire/manifest.xml +++ b/tests/data/wire/manifest.xml @@ -2,17 +2,59 @@ <PluginVersionManifest xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Plugins> <Plugin> - <Version>1.0</Version> + <Version>1.0.0</Version> <Uris> - <Uri>http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux</Uri> + <Uri>http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.0.0</Uri> </Uris> </Plugin> <Plugin> - <Version>1.1</Version> + <Version>1.1.0</Version> <Uris> - <Uri>http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux</Uri> + <Uri>http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.1.0</Uri> </Uris> </Plugin> + <Plugin> + <Version>2.0.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.0.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.1.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.1.0</Uri></Uris> + <DisallowMajorVersionUpgrade>True</DisallowMajorVersionUpgrade> + </Plugin> + <Plugin> + <Version>2.1.1</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.1.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.2.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.2.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>3.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__3.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>3.1</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__3.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.0.0.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__3.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.0.0.1</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__3.1</Uri></Uris> + </Plugin> + <Plugin> + <Version>4.1.0.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__3.1</Uri></Uris> + </Plugin> </Plugins> + <InternalPlugins> + <Plugin> + <Version>1.2.0</Version> + <Uris> + <Uri>http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.2.0</Uri> + </Uris> + </Plugin> + <Plugin> + <Version>2.3.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.3.0</Uri></Uris> + </Plugin> + <Plugin> + <Version>2.4.0</Version><Uris><Uri>http://host/OSTCExtensions.ExampleHandlerLinux__2.3.0</Uri></Uris> + </Plugin> + </InternalPlugins> </PluginVersionManifest> diff --git a/tests/distro/__init__.py b/tests/distro/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/distro/__init__.py +++ b/tests/distro/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/distro/test_loader.py b/tests/distro/test_resourceDisk.py index 94ca913..198fd49 100644 --- a/tests/distro/test_loader.py +++ b/tests/distro/test_resourceDisk.py @@ -19,18 +19,24 @@ # http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.distro.default.distro import DefaultDistro +from azurelinuxagent.daemon.resourcedisk import get_resourcedisk_handler -class TestDistroLoader(AgentTestCase): +class TestResourceDisk(AgentTestCase): + def test_mkfile(self): + # setup + test_file = os.path.join(self.tmp_dir, 'test_file') + file_size = 1024 * 128 + if os.path.exists(test_file): + os.remove(test_file) - @distros() - def test_distro_loader(self, *distro_args): - distro = get_distro(*distro_args) - self.assertNotEquals(None, distro) - self.assertNotEquals(DefaultDistro, type(distro)) - + # execute + get_resourcedisk_handler().mkfile(test_file, file_size) + + # assert + assert os.path.exists(test_file) + + # cleanup + os.remove(test_file) if __name__ == '__main__': unittest.main() - diff --git a/tests/distro/test_scvmm.py b/tests/distro/test_scvmm.py new file mode 100644 index 0000000..2437170 --- /dev/null +++ b/tests/distro/test_scvmm.py @@ -0,0 +1,84 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# +# Implements parts of RFC 2131, 1541, 1497 and +# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx +# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx + +import mock +from tests.tools import * + +import azurelinuxagent.daemon.scvmm as scvmm +from azurelinuxagent.daemon.main import * +from azurelinuxagent.common.osutil.default import DefaultOSUtil + +class TestSCVMM(AgentTestCase): + def test_scvmm_detection_with_file(self): + # setup + conf.get_dvd_mount_point = Mock(return_value=self.tmp_dir) + conf.get_detect_scvmm_env = Mock(return_value=True) + scvmm_file = os.path.join(self.tmp_dir, scvmm.VMM_CONF_FILE_NAME) + fileutil.write_file(scvmm_file, "") + + with patch.object(scvmm.ScvmmHandler, 'start_scvmm_agent') as po: + with patch('os.listdir', return_value=["sr0", "sr1", "sr2"]): + with patch('time.sleep', return_value=0): + # execute + failed = False + try: + scvmm.get_scvmm_handler().run() + except: + failed = True + # assert + self.assertTrue(failed) + self.assertTrue(po.call_count == 1) + # cleanup + os.remove(scvmm_file) + + + def test_scvmm_detection_with_multiple_cdroms(self): + # setup + conf.get_dvd_mount_point = Mock(return_value=self.tmp_dir) + conf.get_detect_scvmm_env = Mock(return_value=True) + + # execute + with mock.patch.object(DefaultOSUtil, 'mount_dvd') as patch_mount: + with patch('os.listdir', return_value=["sr0", "sr1", "sr2"]): + scvmm.ScvmmHandler().detect_scvmm_env() + # assert + assert patch_mount.call_count == 3 + assert patch_mount.call_args_list[0][1]['dvd_device'] == '/dev/sr0' + assert patch_mount.call_args_list[1][1]['dvd_device'] == '/dev/sr1' + assert patch_mount.call_args_list[2][1]['dvd_device'] == '/dev/sr2' + + + def test_scvmm_detection_without_file(self): + # setup + conf.get_dvd_mount_point = Mock(return_value=self.tmp_dir) + conf.get_detect_scvmm_env = Mock(return_value=True) + scvmm_file = os.path.join(self.tmp_dir, scvmm.VMM_CONF_FILE_NAME) + if os.path.exists(scvmm_file): + os.remove(scvmm_file) + + with mock.patch.object(scvmm.ScvmmHandler, 'start_scvmm_agent') as patch_start: + # execute + scvmm.ScvmmHandler().detect_scvmm_env() + # assert + patch_start.assert_not_called() + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/ga/__init__.py b/tests/ga/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/ga/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/distro/test_extension.py b/tests/ga/test_extension.py index d0b631f..71c219c 100644 --- a/tests/distro/test_extension.py +++ b/tests/ga/test_extension.py @@ -14,20 +14,15 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx -from tests.tools import * from tests.protocol.mockwiredata import * -from azurelinuxagent.exception import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.protocol.restapi import get_properties -from azurelinuxagent.protocol.wire import WireProtocol - -@patch("time.sleep") -@patch("azurelinuxagent.protocol.wire.CryptUtil") -@patch("azurelinuxagent.utils.restutil.http_get") +from azurelinuxagent.common.exception import * +from azurelinuxagent.common.protocol import get_protocol_util +from azurelinuxagent.ga.exthandlers import * +from azurelinuxagent.common.protocol.wire import WireProtocol + +@patch("azurelinuxagent.common.protocol.wire.CryptUtil") +@patch("azurelinuxagent.common.utils.restutil.http_get") class TestExtension(AgentTestCase): def _assert_handler_status(self, report_vm_status, expected_status, @@ -42,17 +37,19 @@ class TestExtension(AgentTestCase): handler_status.name) self.assertEquals(version, handler_status.version) self.assertEquals(expected_ext_count, len(handler_status.extensions)) + return def _assert_no_handler_status(self, report_vm_status): self.assertTrue(report_vm_status.called) args, kw = report_vm_status.call_args vm_status = args[0] self.assertEquals(0, len(vm_status.vmAgent.extensionHandlers)) + return + + def _create_mock(self, test_data, mock_http_get, MockCryptUtil): + """Test enable/disable/uninstall of an extension""" + handler = get_exthandlers_handler() - def _create_mock(self, test_data, mock_http_get, MockCryptUtil, _): - """Test enable/disable/unistall of an extension""" - distro = get_distro() - #Mock protocol to return test data mock_http_get.side_effect = test_data.mock_http_get MockCryptUtil.side_effect = test_data.mock_crypt_util @@ -61,104 +58,104 @@ class TestExtension(AgentTestCase): protocol.detect() protocol.report_ext_status = MagicMock() protocol.report_vm_status = MagicMock() - distro.protocol_util.get_protocol = Mock(return_value=protocol) - - return distro, protocol + + handler.protocol_util.get_protocol = Mock(return_value=protocol) + return handler, protocol def test_ext_handler(self, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) #Test enable scenario. - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "success", 0) #Test goal state not changed - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") #Test goal state changed test_data.goal_state = test_data.goal_state.replace("<Incarnation>1<", "<Incarnation>2<") test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"0\"", "seqNo=\"1\"") - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "success", 1) #Test upgrade test_data.goal_state = test_data.goal_state.replace("<Incarnation>2<", "<Incarnation>3<") - test_data.ext_conf = test_data.ext_conf.replace("1.0", "1.1") + test_data.ext_conf = test_data.ext_conf.replace("1.0.0", "1.1.0") test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"1\"", "seqNo=\"2\"") - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1.0") self._assert_ext_status(protocol.report_ext_status, "success", 2) #Test disable test_data.goal_state = test_data.goal_state.replace("<Incarnation>3<", "<Incarnation>4<") test_data.ext_conf = test_data.ext_conf.replace("enabled", "disabled") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "NotReady", - 1, "1.1") + 1, "1.1.0") #Test uninstall test_data.goal_state = test_data.goal_state.replace("<Incarnation>4<", "<Incarnation>5<") test_data.ext_conf = test_data.ext_conf.replace("disabled", "uninstall") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) #Test uninstall again! test_data.goal_state = test_data.goal_state.replace("<Incarnation>5<", "<Incarnation>6<") - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) def test_ext_handler_no_settings(self, *args): test_data = WireProtocolData(DATA_FILE_EXT_NO_SETTINGS) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0.0") def test_ext_handler_no_public_settings(self, *args): test_data = WireProtocolData(DATA_FILE_EXT_NO_PUBLIC) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") def test_ext_handler_no_ext(self, *args): test_data = WireProtocolData(DATA_FILE_NO_EXT) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) #Assert no extension handler status - distro.ext_handlers_handler.run() + exthandlers_handler.run() self._assert_no_handler_status(protocol.report_vm_status) - @patch('azurelinuxagent.distro.default.extension.add_event') + @patch('azurelinuxagent.ga.exthandlers.add_event') def test_ext_handler_download_failure(self, mock_add_event, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) protocol.download_ext_handler_pkg = Mock(side_effect=ProtocolError) - distro.ext_handlers_handler.run() + exthandlers_handler.run() args, kw = mock_add_event.call_args self.assertEquals(False, kw['is_success']) self.assertEquals("OSTCExtensions.ExampleHandlerLinux", kw['name']) self.assertEquals("Download", kw['op']) - @patch('azurelinuxagent.distro.default.extension.fileutil') + @patch('azurelinuxagent.ga.exthandlers.fileutil') def test_ext_handler_io_error(self, mock_fileutil, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) + exthandlers_handler, protocol = self._create_mock(test_data, *args) mock_fileutil.write_file.return_value = IOError("Mock IO Error") - distro.ext_handlers_handler.run() + exthandlers_handler.run() def _assert_ext_status(self, report_ext_status, expected_status, expected_seq_no): @@ -170,21 +167,96 @@ class TestExtension(AgentTestCase): def test_ext_handler_no_reporting_status(self, *args): test_data = WireProtocolData(DATA_FILE) - distro, protocol = self._create_mock(test_data, *args) - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler, protocol = self._create_mock(test_data, *args) + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") #Remove status file and re-run collecting extension status status_file = os.path.join(self.tmp_dir, - "OSTCExtensions.ExampleHandlerLinux-1.0", + "OSTCExtensions.ExampleHandlerLinux-1.0.0", "status", "0.status") self.assertTrue(os.path.isfile(status_file)) os.remove(status_file) - distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + exthandlers_handler.run() + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "error", 0) + def test_ext_handler_version_decide_autoupgrade_internalversion(self, *args): + for internal in [False, True]: + for autoupgrade in [False, True]: + if internal: + config_version = '1.2.0' + decision_version = '1.2.0' + if autoupgrade: + datafile = DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION + else: + datafile = DATA_FILE_EXT_INTERNALVERSION + else: + config_version = '1.0.0' + if autoupgrade: + datafile = DATA_FILE_EXT_AUTOUPGRADE + decision_version = '1.1.0' + else: + datafile = DATA_FILE + decision_version = '1.0.0' + + _, protocol = self._create_mock(WireProtocolData(datafile), *args) + ext_handlers, _ = protocol.get_ext_handlers() + self.assertEqual(1, len(ext_handlers.extHandlers)) + ext_handler = ext_handlers.extHandlers[0] + self.assertEqual('OSTCExtensions.ExampleHandlerLinux', ext_handler.name) + self.assertEqual(config_version, ext_handler.properties.version, "config version.") + ExtHandlerInstance(ext_handler, protocol).decide_version() + self.assertEqual(decision_version, ext_handler.properties.version, "decision version.") + + def test_ext_handler_version_decide_between_minor_versions(self, *args): + """ + Using v2.x~v4.x for unit testing + Available versions via manifest XML (I stands for internal): + 2.0.0, 2.1.0, 2.1.1, 2.2.0, 2.3.0(I), 2.4.0(I), 3.0, 3.1, 4.0.0.0, 4.0.0.1, 4.1.0.0 + See tests/data/wire/manifest.xml for possible versions + """ + + # (installed_version, config_version, exptected_version, autoupgrade_expected_version) + cases = [ + (None, '2.0', '2.0.0', '2.2.0'), + (None, '2.0.0', '2.0.0', '2.2.0'), + ('1.0', '1.0.0', '1.0.0', '1.1.0'), + (None, '2.1.0', '2.1.1', '2.2.0'), + (None, '2.2.0', '2.2.0', '2.2.0'), + (None, '2.3.0', '2.3.0', '2.3.0'), + (None, '2.4.0', '2.4.0', '2.4.0'), + (None, '3.0', '3.0', '3.1'), + (None, '4.0', '4.0.0.1', '4.1.0.0'), + ] + + _, protocol = self._create_mock(WireProtocolData(DATA_FILE), *args) + version_uri = Mock() + version_uri.uri = 'http://some/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml' + + for (installed_version, config_version, expected_version, autoupgrade_expected_version) in cases: + ext_handler = Mock() + ext_handler.properties = Mock() + ext_handler.name = 'OSTCExtensions.ExampleHandlerLinux' + ext_handler.versionUris = [version_uri] + ext_handler.properties.version = config_version + + ext_handler_instance = ExtHandlerInstance(ext_handler, protocol) + ext_handler_instance.get_installed_version = Mock(return_value=installed_version) + + ext_handler_instance.decide_version() + self.assertEqual(expected_version, ext_handler.properties.version) + + ext_handler.properties.version = config_version + ext_handler.properties.upgradePolicy = 'auto' + + ext_handler_instance = ExtHandlerInstance(ext_handler, protocol) + ext_handler_instance.get_installed_version = Mock(return_value=installed_version) + + ext_handler_instance.decide_version() + self.assertEqual(autoupgrade_expected_version, ext_handler.properties.version) + if __name__ == '__main__': unittest.main() diff --git a/tests/distro/test_monitor.py b/tests/ga/test_monitor.py index 1dd7740..838d037 100644 --- a/tests/distro/test_monitor.py +++ b/tests/ga/test_monitor.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.monitor import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.ga.monitor import * class TestMonitor(AgentTestCase): def test_parse_xml_event(self): diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py new file mode 100644 index 0000000..74804fb --- /dev/null +++ b/tests/ga/test_update.py @@ -0,0 +1,1135 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from __future__ import print_function + +import copy +import glob +import json +import os +import platform +import random +import subprocess +import sys +import tempfile +import zipfile + +from tests.protocol.mockwiredata import * +from tests.tools import * + +import azurelinuxagent.common.logger as logger +import azurelinuxagent.common.utils.fileutil as fileutil + +from azurelinuxagent.common.exception import UpdateError +from azurelinuxagent.common.protocol.restapi import * +from azurelinuxagent.common.protocol.wire import * +from azurelinuxagent.common.utils.flexible_version import FlexibleVersion +from azurelinuxagent.common.version import AGENT_NAME, AGENT_VERSION +from azurelinuxagent.ga.update import * + +NO_ERROR = { + "last_failure" : 0.0, + "failure_count" : 0, + "was_fatal" : False +} + +WITH_ERROR = { + "last_failure" : 42.42, + "failure_count" : 2, + "was_fatal" : False +} + +EMPTY_MANIFEST = { + "name": "WALinuxAgent", + "version": 1.0, + "handlerManifest": { + "installCommand": "", + "uninstallCommand": "", + "updateCommand": "", + "enableCommand": "", + "disableCommand": "", + "rebootAfterInstall": False, + "reportHeartbeat": False + } +} + + +def get_agent_pkgs(in_dir=os.path.join(data_dir, "ga")): + path = os.path.join(in_dir, AGENT_PKG_GLOB) + return glob.glob(path) + + +def get_agents(in_dir=os.path.join(data_dir, "ga")): + path = os.path.join(in_dir, AGENT_DIR_GLOB) + return [a for a in glob.glob(path) if os.path.isdir(a)] + + +def get_agent_file_path(): + return get_agent_pkgs()[0] + + +def get_agent_file_name(): + return os.path.basename(get_agent_file_path()) + + +def get_agent_path(): + return fileutil.trim_ext(get_agent_file_path(), "zip") + + +def get_agent_name(): + return os.path.basename(get_agent_path()) + + +def get_agent_version(): + return FlexibleVersion(get_agent_name().split("-")[1]) + + +def faux_logger(): + print("STDOUT message") + print("STDERR message", file=sys.stderr) + return DEFAULT + + +class UpdateTestCase(AgentTestCase): + def setUp(self): + AgentTestCase.setUp(self) + return + + def agent_bin(self, version): + return "bin/{0}-{1}.egg".format(AGENT_NAME, version) + + def agent_count(self): + return len(self.agent_dirs()) + + def agent_dirs(self): + return get_agents(in_dir=self.tmp_dir) + + def agent_dir(self, version): + return os.path.join(self.tmp_dir, "{0}-{1}".format(AGENT_NAME, version)) + + def agent_paths(self): + paths = glob.glob(os.path.join(self.tmp_dir, "*")) + paths.sort() + return paths + + def agent_pkgs(self): + return get_agent_pkgs(in_dir=self.tmp_dir) + + def agent_versions(self): + v = [FlexibleVersion(AGENT_DIR_PATTERN.match(a).group(1)) for a in self.agent_dirs()] + v.sort(reverse=True) + return v + + def get_error_file(self, error_data=NO_ERROR): + fp = tempfile.NamedTemporaryFile(mode="w") + json.dump(error_data if error_data is not None else NO_ERROR, fp) + fp.seek(0) + return fp + + def create_error(self, error_data=NO_ERROR): + with self.get_error_file(error_data) as path: + return GuestAgentError(path.name) + + def copy_agents(self, *agents): + if len(agents) <= 0: + agents = get_agent_pkgs() + for agent in agents: + fileutil.copy_file(agent, to_dir=self.tmp_dir) + return + + def expand_agents(self): + for agent in self.agent_pkgs(): + zipfile.ZipFile(agent).extractall(os.path.join( + self.tmp_dir, + fileutil.trim_ext(agent, "zip"))) + return + + def prepare_agents(self, base_version=AGENT_VERSION, count=5, is_available=True): + base_v = FlexibleVersion(base_version) + + # Ensure the test data is copied over + agent_count = self.agent_count() + if agent_count <= 0: + self.copy_agents(get_agent_pkgs()[0]) + self.expand_agents() + count -= 1 + + # Determine the most recent agent version + versions = self.agent_versions() + src_v = FlexibleVersion(str(versions[0])) + + # If the most recent agent is newer the minimum requested, use the agent version + if base_v < src_v: + base_v = src_v + + # Create agent packages and directories + return self.replicate_agents( + src_v=src_v, + count=count-agent_count, + is_available=is_available) + + def remove_agents(self): + for agent in self.agent_paths(): + try: + if os.path.isfile(agent): + os.remove(agent) + else: + shutil.rmtree(agent) + except: + pass + return + + def replicate_agents( + self, + count=5, + src_v=AGENT_VERSION, + is_available=True, + increment=1): + from_path = self.agent_dir(src_v) + dst_v = FlexibleVersion(str(src_v)) + for i in range(0,count): + dst_v += increment + to_path = self.agent_dir(dst_v) + shutil.copyfile(from_path + ".zip", to_path + ".zip") + shutil.copytree(from_path, to_path) + shutil.move( + os.path.join(to_path, self.agent_bin(src_v)), + os.path.join(to_path, self.agent_bin(dst_v))) + if not is_available: + GuestAgent(to_path).mark_failure(is_fatal=True) + + return dst_v + + +class TestGuestAgentError(UpdateTestCase): + def test_creation(self): + self.assertRaises(TypeError, GuestAgentError) + self.assertRaises(UpdateError, GuestAgentError, None) + + with self.get_error_file(error_data=WITH_ERROR) as path: + err = GuestAgentError(path.name) + self.assertEqual(path.name, err.path) + self.assertNotEqual(None, err) + + self.assertEqual(WITH_ERROR["last_failure"], err.last_failure) + self.assertEqual(WITH_ERROR["failure_count"], err.failure_count) + self.assertEqual(WITH_ERROR["was_fatal"], err.was_fatal) + return + + def test_clear(self): + with self.get_error_file(error_data=WITH_ERROR) as path: + err = GuestAgentError(path.name) + self.assertEqual(path.name, err.path) + self.assertNotEqual(None, err) + + err.clear() + self.assertEqual(NO_ERROR["last_failure"], err.last_failure) + self.assertEqual(NO_ERROR["failure_count"], err.failure_count) + self.assertEqual(NO_ERROR["was_fatal"], err.was_fatal) + return + + def test_load_preserves_error_state(self): + with self.get_error_file(error_data=WITH_ERROR) as path: + err = GuestAgentError(path.name) + self.assertEqual(path.name, err.path) + self.assertNotEqual(None, err) + + with self.get_error_file(error_data=NO_ERROR): + err.load() + self.assertEqual(WITH_ERROR["last_failure"], err.last_failure) + self.assertEqual(WITH_ERROR["failure_count"], err.failure_count) + self.assertEqual(WITH_ERROR["was_fatal"], err.was_fatal) + return + + def test_save(self): + err1 = self.create_error() + err1.mark_failure() + err1.mark_failure(is_fatal=True) + + err2 = self.create_error(err1.to_json()) + self.assertEqual(err1.last_failure, err2.last_failure) + self.assertEqual(err1.failure_count, err2.failure_count) + self.assertEqual(err1.was_fatal, err2.was_fatal) + + def test_mark_failure(self): + err = self.create_error() + self.assertFalse(err.is_blacklisted) + + for i in range(0, MAX_FAILURE): + err.mark_failure() + + # Agent failed >= MAX_FAILURE, it should be blacklisted + self.assertTrue(err.is_blacklisted) + self.assertEqual(MAX_FAILURE, err.failure_count) + + # Clear old failure does not clear recent failure + err.clear_old_failure() + self.assertTrue(err.is_blacklisted) + + # Clear does remove old, outdated failures + err.last_failure -= RETAIN_INTERVAL * 2 + err.clear_old_failure() + self.assertFalse(err.is_blacklisted) + return + + def test_mark_failure_permanent(self): + err = self.create_error() + + self.assertFalse(err.is_blacklisted) + + # Fatal errors immediately blacklist + err.mark_failure(is_fatal=True) + self.assertTrue(err.is_blacklisted) + self.assertTrue(err.failure_count < MAX_FAILURE) + return + + def test_str(self): + err = self.create_error(error_data=NO_ERROR) + s = "Last Failure: {0}, Total Failures: {1}, Fatal: {2}".format( + NO_ERROR["last_failure"], + NO_ERROR["failure_count"], + NO_ERROR["was_fatal"]) + self.assertEqual(s, str(err)) + + err = self.create_error(error_data=WITH_ERROR) + s = "Last Failure: {0}, Total Failures: {1}, Fatal: {2}".format( + WITH_ERROR["last_failure"], + WITH_ERROR["failure_count"], + WITH_ERROR["was_fatal"]) + self.assertEqual(s, str(err)) + return + + +class TestGuestAgent(UpdateTestCase): + def setUp(self): + UpdateTestCase.setUp(self) + self.copy_agents(get_agent_file_path()) + self.agent_path = os.path.join(self.tmp_dir, get_agent_name()) + return + + def tearDown(self): + self.remove_agents() + return + + def test_creation(self): + self.assertRaises(UpdateError, GuestAgent, "A very bad file name") + n = "{0}-a.bad.version".format(AGENT_NAME) + self.assertRaises(UpdateError, GuestAgent, n) + + agent = GuestAgent(path=self.agent_path) + self.assertNotEqual(None, agent) + self.assertEqual(get_agent_name(), agent.name) + self.assertEqual(get_agent_version(), agent.version) + + self.assertEqual(self.agent_path, agent.get_agent_dir()) + + path = os.path.join(self.agent_path, AGENT_MANIFEST_FILE) + self.assertEqual(path, agent.get_agent_manifest_path()) + + self.assertEqual( + os.path.join(self.agent_path, AGENT_ERROR_FILE), + agent.get_agent_error_file()) + + path = ".".join((os.path.join(conf.get_lib_dir(), get_agent_name()), "zip")) + self.assertEqual(path, agent.get_agent_pkg_path()) + + self.assertTrue(agent.is_downloaded) + # Note: Agent will get blacklisted since the package for this test is invalid + self.assertTrue(agent.is_blacklisted) + self.assertFalse(agent.is_available) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_clear_error(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + agent.mark_failure(is_fatal=True) + + self.assertTrue(agent.error.last_failure > 0.0) + self.assertEqual(1, agent.error.failure_count) + self.assertTrue(agent.is_blacklisted) + self.assertEqual(agent.is_blacklisted, agent.error.is_blacklisted) + + agent.clear_error() + self.assertEqual(0.0, agent.error.last_failure) + self.assertEqual(0, agent.error.failure_count) + self.assertFalse(agent.is_blacklisted) + self.assertEqual(agent.is_blacklisted, agent.error.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_is_available(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + + self.assertFalse(agent.is_available) + agent._unpack() + self.assertTrue(agent.is_available) + + agent.mark_failure(is_fatal=True) + self.assertFalse(agent.is_available) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_is_blacklisted(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(agent.is_blacklisted) + + agent._unpack() + self.assertFalse(agent.is_blacklisted) + self.assertEqual(agent.is_blacklisted, agent.error.is_blacklisted) + + agent.mark_failure(is_fatal=True) + self.assertTrue(agent.is_blacklisted) + self.assertEqual(agent.is_blacklisted, agent.error.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_is_downloaded(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(agent.is_downloaded) + agent._unpack() + self.assertTrue(agent.is_downloaded) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_mark_failure(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + agent.mark_failure() + self.assertEqual(1, agent.error.failure_count) + + agent.mark_failure(is_fatal=True) + self.assertEqual(2, agent.error.failure_count) + self.assertTrue(agent.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_unpack(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(os.path.isdir(agent.get_agent_dir())) + agent._unpack() + self.assertTrue(os.path.isdir(agent.get_agent_dir())) + self.assertTrue(os.path.isfile(agent.get_agent_manifest_path())) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_unpack_fail(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(os.path.isdir(agent.get_agent_dir())) + os.remove(agent.get_agent_pkg_path()) + self.assertRaises(UpdateError, agent._unpack) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_load_manifest(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + agent._unpack() + agent._load_manifest() + self.assertEqual(agent.manifest.get_enable_command(), agent.get_agent_cmd()) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_load_manifest_missing(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(os.path.isdir(agent.get_agent_dir())) + agent._unpack() + os.remove(agent.get_agent_manifest_path()) + self.assertRaises(UpdateError, agent._load_manifest) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_load_manifest_is_empty(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(os.path.isdir(agent.get_agent_dir())) + agent._unpack() + self.assertTrue(os.path.isfile(agent.get_agent_manifest_path())) + + with open(agent.get_agent_manifest_path(), "w") as file: + json.dump(EMPTY_MANIFEST, file) + self.assertRaises(UpdateError, agent._load_manifest) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + def test_load_manifest_is_malformed(self, mock_ensure): + agent = GuestAgent(path=self.agent_path) + self.assertFalse(os.path.isdir(agent.get_agent_dir())) + agent._unpack() + self.assertTrue(os.path.isfile(agent.get_agent_manifest_path())) + + with open(agent.get_agent_manifest_path(), "w") as file: + file.write("This is not JSON data") + self.assertRaises(UpdateError, agent._load_manifest) + return + + def test_load_error(self): + agent = GuestAgent(path=self.agent_path) + agent.error = None + + agent._load_error() + self.assertTrue(agent.error is not None) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + @patch("azurelinuxagent.ga.update.restutil.http_get") + def test_download(self, mock_http_get, mock_ensure): + self.remove_agents() + self.assertFalse(os.path.isdir(self.agent_path)) + + agent_pkg = load_bin_data(os.path.join("ga", get_agent_file_name())) + mock_http_get.return_value= ResponseMock(response=agent_pkg) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + agent._download() + + self.assertTrue(os.path.isfile(agent.get_agent_pkg_path())) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") + @patch("azurelinuxagent.ga.update.restutil.http_get") + def test_download_fail(self, mock_http_get, mock_ensure): + self.remove_agents() + self.assertFalse(os.path.isdir(self.agent_path)) + + mock_http_get.return_value= ResponseMock(status=restutil.httpclient.SERVICE_UNAVAILABLE) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertRaises(UpdateError, agent._download) + self.assertFalse(os.path.isfile(agent.get_agent_pkg_path())) + self.assertFalse(agent.is_downloaded) + return + + @patch("azurelinuxagent.ga.update.restutil.http_get") + def test_ensure_downloaded(self, mock_http_get): + self.remove_agents() + self.assertFalse(os.path.isdir(self.agent_path)) + + agent_pkg = load_bin_data(os.path.join("ga", get_agent_file_name())) + mock_http_get.return_value= ResponseMock(response=agent_pkg) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertTrue(os.path.isfile(agent.get_agent_manifest_path())) + self.assertTrue(agent.is_downloaded) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._download", side_effect=UpdateError) + def test_ensure_downloaded_download_fails(self, mock_download): + self.remove_agents() + self.assertFalse(os.path.isdir(self.agent_path)) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertEqual(1, agent.error.failure_count) + self.assertFalse(agent.error.was_fatal) + self.assertFalse(agent.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._download") + @patch("azurelinuxagent.ga.update.GuestAgent._unpack", side_effect=UpdateError) + def test_ensure_downloaded_unpack_fails(self, mock_download, mock_unpack): + self.assertFalse(os.path.isdir(self.agent_path)) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertEqual(1, agent.error.failure_count) + self.assertTrue(agent.error.was_fatal) + self.assertTrue(agent.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._download") + @patch("azurelinuxagent.ga.update.GuestAgent._unpack") + @patch("azurelinuxagent.ga.update.GuestAgent._load_manifest", side_effect=UpdateError) + def test_ensure_downloaded_load_manifest_fails(self, mock_download, mock_unpack, mock_manifest): + self.assertFalse(os.path.isdir(self.agent_path)) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertEqual(1, agent.error.failure_count) + self.assertTrue(agent.error.was_fatal) + self.assertTrue(agent.is_blacklisted) + return + + @patch("azurelinuxagent.ga.update.GuestAgent._download") + @patch("azurelinuxagent.ga.update.GuestAgent._unpack") + @patch("azurelinuxagent.ga.update.GuestAgent._load_manifest") + def test_ensure_download_skips_blacklisted(self, mock_download, mock_unpack, mock_manifest): + agent = GuestAgent(path=self.agent_path) + agent.clear_error() + agent.mark_failure(is_fatal=True) + + pkg = ExtHandlerPackage(version=str(get_agent_version())) + pkg.uris.append(ExtHandlerPackageUri()) + agent = GuestAgent(pkg=pkg) + + self.assertEqual(1, agent.error.failure_count) + self.assertTrue(agent.error.was_fatal) + self.assertTrue(agent.is_blacklisted) + self.assertEqual(0, mock_download.call_count) + self.assertEqual(0, mock_unpack.call_count) + self.assertEqual(0, mock_manifest.call_count) + return + + +class TestUpdate(UpdateTestCase): + def setUp(self): + UpdateTestCase.setUp(self) + self.update_handler = get_update_handler() + return + + def test_creation(self): + self.assertTrue(self.update_handler.running) + + self.assertEqual(None, self.update_handler.last_etag) + self.assertEqual(None, self.update_handler.last_attempt_time) + + self.assertEqual(0, len(self.update_handler.agents)) + + self.assertEqual(None, self.update_handler.child_agent) + self.assertEqual(None, self.update_handler.child_launch_time) + self.assertEqual(0, self.update_handler.child_launch_attempts) + self.assertEqual(None, self.update_handler.child_process) + + self.assertEqual(None, self.update_handler.signal_handler) + return + + def _test_ensure_latest_agent( + self, + base_version=FlexibleVersion(AGENT_VERSION), + protocol=None, + versions=None): + + latest_version = self.prepare_agents() + if versions is None or len(versions) <= 0: + versions = [latest_version] + + etag = self.update_handler.last_etag if self.update_handler.last_etag is not None else 42 + if protocol is None: + protocol = ProtocolMock(etag=etag, versions=versions) + self.update_handler.protocol_util = protocol + conf.get_autoupdate_gafamily = Mock(return_value=protocol.family) + + return self.update_handler._ensure_latest_agent(base_version=base_version) + + def test_ensure_latest_agent_returns_true_on_first_use(self): + self.assertEqual(None, self.update_handler.last_etag) + self.assertTrue(self._test_ensure_latest_agent()) + return + + def test_ensure_latest_agent_includes_old_agents(self): + self.prepare_agents() + + old_count = FlexibleVersion(AGENT_VERSION).version[-1] + old_version = self.agent_versions()[-1] + + self.replicate_agents(src_v=old_version, count=old_count, increment=-1) + all_count = len(self.agent_versions()) + + self.assertTrue(self._test_ensure_latest_agent(versions=self.agent_versions())) + self.assertEqual(all_count, len(self.update_handler.agents)) + return + + def test_ensure_lastest_agent_purges_old_agents(self): + self.prepare_agents() + agent_count = self.agent_count() + self.assertEqual(5, agent_count) + + agent_versions = self.agent_versions()[:3] + self.assertTrue(self._test_ensure_latest_agent(versions=agent_versions)) + self.assertEqual(len(agent_versions), len(self.update_handler.agents)) + self.assertEqual(agent_versions, self.agent_versions()) + return + + def test_ensure_latest_agent_skips_if_too_frequent(self): + conf.get_autoupdate_frequency = Mock(return_value=10000) + self.update_handler.last_attempt_time = time.time() + self.assertFalse(self._test_ensure_latest_agent()) + return + + def test_ensure_latest_agent_skips_when_etag_matches(self): + self.update_handler.last_etag = 42 + self.assertFalse(self._test_ensure_latest_agent()) + return + + def test_ensure_latest_agent_skips_if_when_no_new_versions(self): + self.prepare_agents() + base_version = self.agent_versions()[0] + 1 + self.assertFalse(self._test_ensure_latest_agent(base_version=base_version)) + return + + def test_ensure_latest_agent_skips_when_no_versions(self): + self.assertFalse(self._test_ensure_latest_agent(protocol=ProtocolMock())) + return + + def test_ensure_latest_agent_skips_when_updates_are_disabled(self): + conf.get_autoupdate_enabled = Mock(return_value=False) + self.assertFalse(self._test_ensure_latest_agent()) + return + + def test_ensure_latest_agent_sorts(self): + self.prepare_agents() + self._test_ensure_latest_agent() + + v = FlexibleVersion("100000") + for a in self.update_handler.agents: + self.assertTrue(v > a.version) + v = a.version + return + + def _test_evaluate_agent_health(self, child_agent_index=0): + self.prepare_agents() + + latest_agent = self.update_handler.get_latest_agent() + self.assertTrue(latest_agent.is_available) + self.assertFalse(latest_agent.is_blacklisted) + self.assertTrue(len(self.update_handler.agents) > 1) + + child_agent = self.update_handler.agents[child_agent_index] + self.assertTrue(child_agent.is_available) + self.assertFalse(child_agent.is_blacklisted) + self.update_handler.child_agent = child_agent + + self.update_handler._evaluate_agent_health(latest_agent) + return + + def test_evaluate_agent_health_ignores_installed_agent(self): + self.update_handler._evaluate_agent_health(None) + return + + def test_evaluate_agent_health_raises_exception_for_restarting_agent(self): + self.update_handler.child_launch_time = time.time() - (4 * 60) + self.update_handler.child_launch_attempts = CHILD_LAUNCH_RESTART_MAX - 1 + self.assertRaises(Exception, self._test_evaluate_agent_health) + return + + def test_evaluate_agent_health_will_not_raise_exception_for_long_restarts(self): + self.update_handler.child_launch_time = time.time() - 24 * 60 + self.update_handler.child_launch_attempts = CHILD_LAUNCH_RESTART_MAX + self._test_evaluate_agent_health() + return + + def test_evaluate_agent_health_will_not_raise_exception_too_few_restarts(self): + self.update_handler.child_launch_time = time.time() + self.update_handler.child_launch_attempts = CHILD_LAUNCH_RESTART_MAX - 2 + self._test_evaluate_agent_health() + return + + def test_evaluate_agent_health_resets_with_new_agent(self): + self.update_handler.child_launch_time = time.time() - (4 * 60) + self.update_handler.child_launch_attempts = CHILD_LAUNCH_RESTART_MAX - 1 + self._test_evaluate_agent_health(child_agent_index=1) + self.assertEqual(1, self.update_handler.child_launch_attempts) + return + + def test_filter_blacklisted_agents(self): + self.prepare_agents() + + self.update_handler._set_agents([GuestAgent(path=path) for path in self.agent_dirs()]) + self.assertEqual(len(self.agent_dirs()), len(self.update_handler.agents)) + + kept_agents = self.update_handler.agents[1::2] + blacklisted_agents = self.update_handler.agents[::2] + for agent in blacklisted_agents: + agent.mark_failure(is_fatal=True) + self.update_handler._filter_blacklisted_agents() + self.assertEqual(kept_agents, self.update_handler.agents) + return + + def test_get_latest_agent(self): + latest_version = self.prepare_agents() + + latest_agent = self.update_handler.get_latest_agent() + self.assertEqual(len(get_agents(self.tmp_dir)), len(self.update_handler.agents)) + self.assertEqual(latest_version, latest_agent.version) + return + + def test_get_latest_agent_no_updates(self): + self.assertEqual(None, self.update_handler.get_latest_agent()) + return + + def test_get_latest_agent_skip_updates(self): + conf.get_autoupdate_enabled = Mock(return_value=False) + self.assertEqual(None, self.update_handler.get_latest_agent()) + return + + def test_get_latest_agent_skips_unavailable(self): + self.prepare_agents() + prior_agent = self.update_handler.get_latest_agent() + + latest_version = self.prepare_agents(count=self.agent_count()+1, is_available=False) + latest_path = os.path.join(self.tmp_dir, "{0}-{1}".format(AGENT_NAME, latest_version)) + self.assertFalse(GuestAgent(latest_path).is_available) + + latest_agent = self.update_handler.get_latest_agent() + self.assertTrue(latest_agent.version < latest_version) + self.assertEqual(latest_agent.version, prior_agent.version) + return + + def test_load_agents(self): + self.prepare_agents() + + self.assertTrue(0 <= len(self.update_handler.agents)) + self.update_handler._load_agents() + self.assertEqual(len(get_agents(self.tmp_dir)), len(self.update_handler.agents)) + return + + def test_load_agents_does_not_reload(self): + self.prepare_agents() + + self.update_handler._load_agents() + agents = self.update_handler.agents + + self.update_handler._load_agents() + self.assertEqual(agents, self.update_handler.agents) + return + + def test_load_agents_sorts(self): + self.prepare_agents() + self.update_handler._load_agents() + + v = FlexibleVersion("100000") + for a in self.update_handler.agents: + self.assertTrue(v > a.version) + v = a.version + return + + def test_purge_agents(self): + self.prepare_agents() + self.update_handler._load_agents() + + # Ensure at least three agents initially exist + self.assertTrue(2 < len(self.update_handler.agents)) + + # Purge every other agent + kept_agents = self.update_handler.agents[1::2] + purged_agents = self.update_handler.agents[::2] + + # Reload and assert only the kept agents remain on disk + self.update_handler.agents = kept_agents + self.update_handler._purge_agents() + self.update_handler._load_agents() + self.assertEqual( + [agent.version for agent in kept_agents], + [agent.version for agent in self.update_handler.agents]) + + # Ensure both directories and packages are removed + for agent in purged_agents: + agent_path = os.path.join(self.tmp_dir, "{0}-{1}".format(AGENT_NAME, agent.version)) + self.assertFalse(os.path.exists(agent_path)) + self.assertFalse(os.path.exists(agent_path + ".zip")) + + # Ensure kept agent directories and packages remain + for agent in kept_agents: + agent_path = os.path.join(self.tmp_dir, "{0}-{1}".format(AGENT_NAME, agent.version)) + self.assertTrue(os.path.exists(agent_path)) + self.assertTrue(os.path.exists(agent_path + ".zip")) + return + + def _test_run_latest(self, mock_child=None, mock_time=None): + if mock_child is None: + mock_child = ChildMock() + if mock_time is None: + mock_time = TimeMock() + + with patch('subprocess.Popen', return_value=mock_child) as mock_popen: + with patch('time.time', side_effect=mock_time.time): + with patch('time.sleep', return_value=mock_time.sleep): + self.update_handler.run_latest() + self.assertEqual(1, mock_popen.call_count) + + return mock_popen.call_args + + def test_run_latest(self): + self.prepare_agents() + + agent = self.update_handler.get_latest_agent() + args, kwargs = self._test_run_latest() + cmds = shlex.split(agent.get_agent_cmd()) + if cmds[0].lower() == "python": + cmds[0] = get_python_cmd() + + self.assertEqual(args[0], cmds) + self.assertEqual(True, 'cwd' in kwargs) + self.assertEqual(agent.get_agent_dir(), kwargs['cwd']) + return + + def test_run_latest_polls_and_waits_for_success(self): + mock_child = ChildMock(return_value=None) + mock_time = TimeMock(time_increment=CHILD_HEALTH_INTERVAL/3) + self._test_run_latest(mock_child=mock_child, mock_time=mock_time) + self.assertEqual(2, mock_child.poll.call_count) + self.assertEqual(1, mock_child.wait.call_count) + return + + def test_run_latest_polling_stops_at_success(self): + mock_child = ChildMock(return_value=0) + mock_time = TimeMock(time_increment=CHILD_HEALTH_INTERVAL/3) + self._test_run_latest(mock_child=mock_child, mock_time=mock_time) + self.assertEqual(1, mock_child.poll.call_count) + self.assertEqual(0, mock_child.wait.call_count) + return + + def test_run_latest_polling_stops_at_failure(self): + mock_child = ChildMock(return_value=42) + mock_time = TimeMock() + self._test_run_latest(mock_child=mock_child, mock_time=mock_time) + self.assertEqual(1, mock_child.poll.call_count) + self.assertEqual(0, mock_child.wait.call_count) + self.assertEqual(2, mock_time.time_call_count) + return + + def test_run_latest_defaults_to_current(self): + self.assertEqual(None, self.update_handler.get_latest_agent()) + + args, kwargs = self._test_run_latest() + + self.assertEqual(args[0], [get_python_cmd(), "-u", sys.argv[0], "-run-exthandlers"]) + self.assertEqual(True, 'cwd' in kwargs) + self.assertEqual(os.getcwd(), kwargs['cwd']) + return + + def test_run_latest_forwards_output(self): + try: + tempdir = tempfile.mkdtemp() + stdout_path = os.path.join(tempdir, "stdout") + stderr_path = os.path.join(tempdir, "stderr") + + with open(stdout_path, "w") as stdout: + with open(stderr_path, "w") as stderr: + saved_stdout, sys.stdout = sys.stdout, stdout + saved_stderr, sys.stderr = sys.stderr, stderr + try: + self._test_run_latest(mock_child=ChildMock(side_effect=faux_logger)) + finally: + sys.stdout = saved_stdout + sys.stderr = saved_stderr + + with open(stdout_path, "r") as stdout: + self.assertEqual(1, len(stdout.readlines())) + with open(stderr_path, "r") as stderr: + self.assertEqual(1, len(stderr.readlines())) + finally: + shutil.rmtree(tempdir, True) + return + + def test_run_latest_nonzero_code_marks_failures(self): + # logger.add_logger_appender(logger.AppenderType.STDOUT) + self.prepare_agents() + + latest_agent = self.update_handler.get_latest_agent() + self.assertTrue(latest_agent.is_available) + self.assertEqual(0.0, latest_agent.error.last_failure) + self.assertEqual(0, latest_agent.error.failure_count) + + self._test_run_latest(mock_child=ChildMock(return_value=1)) + + self.assertTrue(latest_agent.is_available) + self.assertNotEqual(0.0, latest_agent.error.last_failure) + self.assertEqual(1, latest_agent.error.failure_count) + return + + def test_run_latest_exception_blacklists(self): + # logger.add_logger_appender(logger.AppenderType.STDOUT) + self.prepare_agents() + + latest_agent = self.update_handler.get_latest_agent() + self.assertTrue(latest_agent.is_available) + self.assertEqual(0.0, latest_agent.error.last_failure) + self.assertEqual(0, latest_agent.error.failure_count) + + self._test_run_latest(mock_child=ChildMock(side_effect=Exception("Force blacklisting"))) + + self.assertFalse(latest_agent.is_available) + self.assertTrue(latest_agent.error.is_blacklisted) + self.assertNotEqual(0.0, latest_agent.error.last_failure) + self.assertEqual(1, latest_agent.error.failure_count) + return + + @patch('signal.signal') + def test_run_latest_captures_signals(self, mock_signal): + self._test_run_latest() + self.assertEqual(1, mock_signal.call_count) + return + + @patch('signal.signal') + def test_run_latest_creates_only_one_signal_handler(self, mock_signal): + self.update_handler.signal_handler = "Not None" + self._test_run_latest() + self.assertEqual(0, mock_signal.call_count) + return + + def _test_run(self, invocations=1, calls=[call.run()], enable_updates=False): + conf.get_autoupdate_enabled = Mock(return_value=enable_updates) + + # Note: + # - Python only allows mutations of objects to which a function has + # a reference. Incrementing an integer directly changes the + # reference. Incrementing an item of a list changes an item to + # which the code has a reference. + # See http://stackoverflow.com/questions/26408941/python-nested-functions-and-variable-scope + iterations = [0] + def iterator(*args, **kwargs): + iterations[0] += 1 + if iterations[0] >= invocations: + self.update_handler.running = False + return + + calls = calls * invocations + + with patch('azurelinuxagent.ga.exthandlers.get_exthandlers_handler') as mock_handler: + with patch('azurelinuxagent.ga.monitor.get_monitor_handler') as mock_monitor: + with patch('azurelinuxagent.ga.env.get_env_handler') as mock_env: + with patch('time.sleep', side_effect=iterator) as mock_sleep: + with patch('sys.exit') as mock_exit: + + self.update_handler.run() + + self.assertEqual(1, mock_handler.call_count) + self.assertEqual(mock_handler.return_value.method_calls, calls) + self.assertEqual(invocations, mock_sleep.call_count) + self.assertEqual(1, mock_monitor.call_count) + self.assertEqual(1, mock_env.call_count) + self.assertEqual(1, mock_exit.call_count) + return + + def test_run(self): + self._test_run() + return + + def test_run_keeps_running(self): + self._test_run(invocations=15) + return + + def test_run_stops_if_update_available(self): + self.update_handler._ensure_latest_agent = Mock(return_value=True) + self._test_run(invocations=0, calls=[], enable_updates=True) + return + + def test_set_agents_sets_agents(self): + self.prepare_agents() + + self.update_handler._set_agents([GuestAgent(path=path) for path in self.agent_dirs()]) + self.assertTrue(len(self.update_handler.agents) > 0) + self.assertEqual(len(self.agent_dirs()), len(self.update_handler.agents)) + return + + def test_set_agents_sorts_agents(self): + self.prepare_agents() + + self.update_handler._set_agents([GuestAgent(path=path) for path in self.agent_dirs()]) + + v = FlexibleVersion("100000") + for a in self.update_handler.agents: + self.assertTrue(v > a.version) + v = a.version + return + + +class ChildMock(Mock): + def __init__(self, return_value=0, side_effect=None): + Mock.__init__(self, return_value=return_value, side_effect=side_effect) + + self.poll = Mock(return_value=return_value, side_effect=side_effect) + self.wait = Mock(return_value=return_value, side_effect=side_effect) + return + + +class ProtocolMock(object): + def __init__(self, family="TestAgent", etag=42, versions=None): + self.family = family + self.etag = etag + self.versions = versions if versions is not None else [] + self.create_manifests() + self.create_packages() + return + + def create_manifests(self): + self.agent_manifests = VMAgentManifestList() + if len(self.versions) <= 0: + return + + if self.family is not None: + manifest = VMAgentManifest(family=self.family) + for i in range(0,10): + manifest_uri = "https://nowhere.msft/agent/{0}".format(i) + manifest.versionsManifestUris.append(VMAgentManifestUri(uri=manifest_uri)) + self.agent_manifests.vmAgentManifests.append(manifest) + return + + def create_packages(self): + self.agent_packages = ExtHandlerPackageList() + if len(self.versions) <= 0: + return + + for version in self.versions: + package = ExtHandlerPackage(str(version)) + for i in range(0,5): + package_uri = "https://nowhere.msft/agent_pkg/{0}".format(i) + package.uris.append(ExtHandlerPackageUri(uri=package_uri)) + self.agent_packages.versions.append(package) + return + + def get_protocol(self): + return self + + def get_vmagent_manifests(self): + return self.agent_manifests, self.etag + + def get_vmagent_pkgs(self, manifest): + return self.agent_packages + + +class ResponseMock(Mock): + def __init__(self, status=restutil.httpclient.OK, response=None): + Mock.__init__(self) + self.status = status + self.response = response + return + + def read(self): + return self.response + + +class TimeMock(Mock): + def __init__(self, time_increment=1): + Mock.__init__(self) + self.next_time = time.time() + self.time_call_count = 0 + self.time_increment = time_increment + + self.sleep = Mock(return_value=0) + return + + def time(self): + self.time_call_count += 1 + current_time = self.next_time + self.next_time += self.time_increment + return current_time + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/pa/__init__.py b/tests/pa/__init__.py new file mode 100644 index 0000000..2ef4c16 --- /dev/null +++ b/tests/pa/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# diff --git a/tests/distro/test_provision.py b/tests/pa/test_provision.py index 60249ce..6508017 100644 --- a/tests/distro/test_provision.py +++ b/tests/pa/test_provision.py @@ -14,33 +14,33 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.distro.default.protocolUtil import * -import azurelinuxagent.utils.fileutil as fileutil +import azurelinuxagent.common.conf as conf +from azurelinuxagent.common.protocol import OVF_FILE_NAME +import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.pa.provision import get_provision_handler class TestProvision(AgentTestCase): - + @distros("redhat") def test_provision(self, distro_name, distro_version, distro_full_name): - distro = get_distro(distro_name, distro_version, distro_full_name) - distro.osutil = MagicMock() - distro.osutil.decode_customdata = Mock(return_value="") - - distro.protocol_util.detect_protocol_by_file = MagicMock() - distro.protocol_util.get_protocol = MagicMock() + provision_handler = get_provision_handler(distro_name, distro_version, + distro_full_name) + mock_osutil = MagicMock() + mock_osutil.decode_customdata = Mock(return_value="") + + provision_handler.osutil = mock_osutil + provision_handler.protocol_util.osutil = mock_osutil + provision_handler.protocol_util.get_protocol_by_file = MagicMock() + provision_handler.protocol_util.get_protocol = MagicMock() + conf.get_dvd_mount_point = Mock(return_value=self.tmp_dir) - ovfenv_file = os.path.join(self.tmp_dir, OVF_FILE_NAME) ovfenv_data = load_data("ovf-env.xml") fileutil.write_file(ovfenv_file, ovfenv_data) - handler = distro.provision_handler - handler.run() + provision_handler.run() if __name__ == '__main__': unittest.main() diff --git a/tests/protocol/__init__.py b/tests/protocol/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/protocol/__init__.py +++ b/tests/protocol/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/protocol/mockmetadata.py b/tests/protocol/mockmetadata.py index 0f7b568..dce3367 100644 --- a/tests/protocol/mockmetadata.py +++ b/tests/protocol/mockmetadata.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.future import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil +from azurelinuxagent.common.future import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil DATA_FILE = { "identity": "metadata/identity.json", diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py index 6ffd19c..c789de5 100644 --- a/tests/protocol/mockwiredata.py +++ b/tests/protocol/mockwiredata.py @@ -14,13 +14,10 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.future import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil +from azurelinuxagent.common.future import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil DATA_FILE = { "version_info": "wire/version_info.xml", @@ -30,6 +27,7 @@ DATA_FILE = { "certs": "wire/certs.xml", "ext_conf": "wire/ext_conf.xml", "manifest": "wire/manifest.xml", + "ga_manifest" : "wire/ga_manifest.xml", "trans_prv": "wire/trans_prv", "trans_cert": "wire/trans_cert", "test_ext": "ext/sample_ext.zip" @@ -44,6 +42,15 @@ DATA_FILE_EXT_NO_SETTINGS["ext_conf"] = "wire/ext_conf_no_settings.xml" DATA_FILE_EXT_NO_PUBLIC = DATA_FILE.copy() DATA_FILE_EXT_NO_PUBLIC["ext_conf"] = "wire/ext_conf_no_public.xml" +DATA_FILE_EXT_AUTOUPGRADE = DATA_FILE.copy() +DATA_FILE_EXT_AUTOUPGRADE["ext_conf"] = "wire/ext_conf_autoupgrade.xml" + +DATA_FILE_EXT_INTERNALVERSION = DATA_FILE.copy() +DATA_FILE_EXT_INTERNALVERSION["ext_conf"] = "wire/ext_conf_internalversion.xml" + +DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION = DATA_FILE.copy() +DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION["ext_conf"] = "wire/ext_conf_autoupgrade_internalversion.xml" + class WireProtocolData(object): def __init__(self, data_files=DATA_FILE): self.version_info = load_data(data_files.get("version_info")) @@ -53,6 +60,7 @@ class WireProtocolData(object): self.certs = load_data(data_files.get("certs")) self.ext_conf = load_data(data_files.get("ext_conf")) self.manifest = load_data(data_files.get("manifest")) + self.ga_manifest = load_data(data_files.get("ga_manifest")) self.trans_prv = load_data(data_files.get("trans_prv")) self.trans_cert = load_data(data_files.get("trans_cert")) self.ext = load_bin_data(data_files.get("test_ext")) @@ -73,6 +81,8 @@ class WireProtocolData(object): content = self.ext_conf elif "manifest.xml" in url: content = self.manifest + elif "manifest_of_ga.xml" in url: + content = self.ga_manifest elif "ExampleHandlerLinux" in url: content = self.ext resp = MagicMock() diff --git a/tests/protocol/test_hostplugin.py b/tests/protocol/test_hostplugin.py new file mode 100644 index 0000000..65c8465 --- /dev/null +++ b/tests/protocol/test_hostplugin.py @@ -0,0 +1,85 @@ +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from tests.tools import * +import unittest +import azurelinuxagent.common.protocol.wire as wire +import azurelinuxagent.common.protocol.restapi as restapi + +wireserver_url = "168.63.129.16" +sas_url = "http://sas_url" +api_versions = '["2015-09-01"]' + + +class TestHostPlugin(AgentTestCase): + def test_fallback(self): + with patch.object(wire.HostPluginProtocol, + "put_vm_status") as patch_put: + with patch.object(wire.StatusBlob, "upload") as patch_upload: + patch_upload.return_value = False + wire_protocol_client = wire.WireProtocol(wireserver_url).client + wire_protocol_client.ext_conf = wire.ExtensionsConfig(None) + wire_protocol_client.ext_conf.status_upload_blob = sas_url + wire_protocol_client.upload_status_blob() + self.assertTrue(patch_put.call_count == 1, + "Fallback was not engaged") + self.assertTrue(patch_put.call_args[0][1] == sas_url) + + def test_no_fallback(self): + with patch.object(wire.HostPluginProtocol, + "put_vm_status") as patch_put: + with patch.object(wire.StatusBlob, "upload") as patch_upload: + patch_upload.return_value = True + wire_protocol_client = wire.WireProtocol(wireserver_url).client + wire_protocol_client.ext_conf = wire.ExtensionsConfig(None) + wire_protocol_client.ext_conf.status_upload_blob = sas_url + wire_protocol_client.upload_status_blob() + self.assertTrue(patch_put.call_count == 0, + "Fallback was engaged") + + def test_init_put(self): + expected_url = "http://168.63.129.16:32526/status" + expected_headers = {'x-ms-version': '2015-09-01'} + expected_content = '{"content": "b2s=", ' \ + '"headers": [{"headerName": "x-ms-version", ' \ + '"headerValue": "2014-02-14"}, ' \ + '{"headerName": "x-ms-blob-type", "headerValue": ' \ + '"BlockBlob"}], ' \ + '"requestUri": "http://sas_url"}' + + host_client = wire.HostPluginProtocol(wireserver_url) + self.assertFalse(host_client.is_initialized) + self.assertTrue(host_client.api_versions is None) + status_blob = wire.StatusBlob(None) + status_blob.vm_status = "ok" + status_blob.type = "BlockBlob" + with patch.object(wire.HostPluginProtocol, + "get_api_versions") as patch_get: + patch_get.return_value = api_versions + with patch.object(restapi.restutil, "http_put") as patch_put: + patch_put.return_value = MagicMock() + host_client.put_vm_status(status_blob, sas_url) + self.assertTrue(host_client.is_initialized) + self.assertFalse(host_client.api_versions is None) + self.assertTrue(patch_put.call_count == 1) + self.assertTrue(patch_put.call_args[0][0] == expected_url) + self.assertTrue(patch_put.call_args[0][1] == expected_content) + self.assertTrue(patch_put.call_args[0][2] == expected_headers) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/protocol/test_metadata.py b/tests/protocol/test_metadata.py index fca1a82..e2ef57a 100644 --- a/tests/protocol/test_metadata.py +++ b/tests/protocol/test_metadata.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * from tests.protocol.mockmetadata import * -from azurelinuxagent.utils.restutil import httpclient -from azurelinuxagent.protocol.metadata import MetadataProtocol +from azurelinuxagent.common.utils.restutil import httpclient +from azurelinuxagent.common.protocol.metadata import MetadataProtocol @patch("time.sleep") -@patch("azurelinuxagent.protocol.metadata.restutil") +@patch("azurelinuxagent.common.protocol.metadata.restutil") class TestWireProtocolGetters(AgentTestCase): def _test_getters(self, test_data, mock_restutil ,_): mock_restutil.http_get.side_effect = test_data.mock_http_get @@ -33,7 +30,7 @@ class TestWireProtocolGetters(AgentTestCase): protocol.detect() protocol.get_vminfo() protocol.get_certs() - ext_handlers, etag= protocol.get_ext_handlers() + ext_handlers, etag = protocol.get_ext_handlers() for ext_handler in ext_handlers.extHandlers: protocol.get_ext_handler_pkgs(ext_handler) diff --git a/tests/distro/test_protocol_util.py b/tests/protocol/test_protocol_util.py index 61339f3..cb9a06f 100644 --- a/tests/distro/test_protocol_util.py +++ b/tests/protocol/test_protocol_util.py @@ -14,72 +14,64 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * -from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.exception import * -from azurelinuxagent.distro.default.protocolUtil import * +from azurelinuxagent.common.exception import * +from azurelinuxagent.common.protocol import get_protocol_util, \ + TAG_FILE_NAME @patch("time.sleep") class TestProtocolUtil(AgentTestCase): - @distros() - @patch("azurelinuxagent.distro.default.protocolUtil.MetadataProtocol") - @patch("azurelinuxagent.distro.default.protocolUtil.WireProtocol") - def test_detect_protocol(self, distro_name, distro_version, distro_full_name, - WireProtocol, MetadataProtocol, _, *distro_args): - + @patch("azurelinuxagent.common.protocol.util.MetadataProtocol") + @patch("azurelinuxagent.common.protocol.util.WireProtocol") + def test_detect_protocol(self, WireProtocol, MetadataProtocol, _): WireProtocol.return_value = MagicMock() MetadataProtocol.return_value = MagicMock() + + protocol_util = get_protocol_util() - distro = get_distro(distro_name, distro_version, distro_full_name) - distro.dhcp_handler = MagicMock() - distro.dhcp_handler.endpoint = "foo.bar" + protocol_util.dhcp_handler = MagicMock() + protocol_util.dhcp_handler.endpoint = "foo.bar" #Test wire protocol is available - protocol = distro.protocol_util.detect_protocol() + protocol = protocol_util.get_protocol() self.assertEquals(WireProtocol.return_value, protocol) #Test wire protocol is not available - distro.protocol_util.protocol = None - WireProtocol.side_effect = ProtocolError() + protocol_util.clear_protocol() + WireProtocol.return_value.detect.side_effect = ProtocolError() - protocol = distro.protocol_util.detect_protocol() + protocol = protocol_util.get_protocol() self.assertEquals(MetadataProtocol.return_value, protocol) #Test no protocol is available - distro.protocol_util.protocol = None - WireProtocol.side_effect = ProtocolError() - MetadataProtocol.side_effect = ProtocolError() - self.assertRaises(ProtocolError, distro.protocol_util.detect_protocol) + protocol_util.clear_protocol() + WireProtocol.return_value.detect.side_effect = ProtocolError() - @distros() - def test_detect_protocol_by_file(self, distro_name, distro_version, - distro_full_name, _): - distro = get_distro(distro_name, distro_version, distro_full_name) - protocol_util = distro.protocol_util + MetadataProtocol.return_value.detect.side_effect = ProtocolError() + self.assertRaises(ProtocolError, protocol_util.get_protocol) + def test_detect_protocol_by_file(self, _): + protocol_util = get_protocol_util() protocol_util._detect_wire_protocol = Mock() protocol_util._detect_metadata_protocol = Mock() tag_file = os.path.join(self.tmp_dir, TAG_FILE_NAME) #Test tag file doesn't exist - protocol_util.detect_protocol_by_file() + protocol_util.get_protocol_by_file() protocol_util._detect_wire_protocol.assert_any_call() protocol_util._detect_metadata_protocol.assert_not_called() #Test tag file exists - protocol_util.protocol = None + protocol_util.clear_protocol() protocol_util._detect_wire_protocol.reset_mock() protocol_util._detect_metadata_protocol.reset_mock() with open(tag_file, "w+") as tag_fd: tag_fd.write("") - protocol_util.detect_protocol_by_file() + protocol_util.get_protocol_by_file() protocol_util._detect_metadata_protocol.assert_any_call() protocol_util._detect_wire_protocol.assert_not_called() diff --git a/tests/protocol/test_restapi.py b/tests/protocol/test_restapi.py index 656ecc6..e4b65c9 100644 --- a/tests/protocol/test_restapi.py +++ b/tests/protocol/test_restapi.py @@ -14,9 +14,6 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid @@ -24,7 +21,7 @@ import unittest import os import shutil import time -from azurelinuxagent.protocol.restapi import * +from azurelinuxagent.common.protocol.restapi import * class SampleDataContract(DataContract): def __init__(self): diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 4c38c13..bd3acaf 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -14,9 +14,6 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * from tests.protocol.mockwiredata import * @@ -24,18 +21,18 @@ import uuid import unittest import os import time -from azurelinuxagent.utils.restutil import httpclient -from azurelinuxagent.utils.cryptutil import CryptUtil -from azurelinuxagent.protocol.restapi import * -from azurelinuxagent.protocol.wire import WireClient, WireProtocol, \ +from azurelinuxagent.common.utils.restutil import httpclient +from azurelinuxagent.common.utils.cryptutil import CryptUtil +from azurelinuxagent.common.protocol.restapi import * +from azurelinuxagent.common.protocol.wire import WireClient, WireProtocol, \ TRANSPORT_PRV_FILE_NAME, \ TRANSPORT_CERT_FILE_NAME data_with_bom = b'\xef\xbb\xbfhehe' @patch("time.sleep") -@patch("azurelinuxagent.protocol.wire.CryptUtil") -@patch("azurelinuxagent.protocol.wire.restutil") +@patch("azurelinuxagent.common.protocol.wire.CryptUtil") +@patch("azurelinuxagent.common.protocol.wire.restutil") class TestWireProtocolGetters(AgentTestCase): def _test_getters(self, test_data, mock_restutil, MockCryptUtil, _): diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 0000000..39a48ab --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,26 @@ +from tests.tools import * +import azurelinuxagent.common.osutil as osutil +import azurelinuxagent.common.dhcp as dhcp +import azurelinuxagent.common.protocol as protocol +import azurelinuxagent.pa.provision as provision +import azurelinuxagent.pa.deprovision as deprovision +import azurelinuxagent.daemon as daemon +import azurelinuxagent.daemon.resourcedisk as resourcedisk +import azurelinuxagent.daemon.scvmm as scvmm +import azurelinuxagent.ga.exthandlers as exthandlers +import azurelinuxagent.ga.monitor as monitor +import azurelinuxagent.ga.update as update + +class TestImportHandler(AgentTestCase): + def test_get_handler(self): + osutil.get_osutil() + protocol.get_protocol_util() + dhcp.get_dhcp_handler() + provision.get_provision_handler() + deprovision.get_deprovision_handler() + daemon.get_daemon_handler() + resourcedisk.get_resourcedisk_handler() + scvmm.get_scvmm_handler() + monitor.get_monitor_handler() + update.get_update_handler() + exthandlers.get_exthandlers_handler() diff --git a/tests/tools.py b/tests/tools.py index 672c60b..8bf23ed 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -14,31 +14,31 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx """ Define util functions for unit test """ -import re +import json import os -import sys -import unittest +import re import shutil -import json +import sys import tempfile +import unittest + from functools import wraps -import azurelinuxagent.conf as conf -import azurelinuxagent.logger as logger -import azurelinuxagent.event as event + +import azurelinuxagent.common.conf as conf +import azurelinuxagent.common.event as event +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.version import PY_VERSION_MAJOR #Import mock module for Python2 and Python3 try: - from unittest.mock import Mock, patch, MagicMock + from unittest.mock import Mock, patch, MagicMock, DEFAULT, call except ImportError: - from mock import Mock, patch, MagicMock + from mock import Mock, patch, MagicMock, DEFAULT, call test_dir = os.path.dirname(os.path.abspath(__file__)) data_dir = os.path.join(test_dir, "data") @@ -56,6 +56,7 @@ class AgentTestCase(unittest.TestCase): def setUp(self): prefix = "{0}_".format(self.__class__.__name__) self.tmp_dir = tempfile.mkdtemp(prefix=prefix) + conf.get_autoupdate_enabled = Mock(return_value=True) conf.get_lib_dir = Mock(return_value=self.tmp_dir) ext_log_dir = os.path.join(self.tmp_dir, "azure") conf.get_ext_log_dir = Mock(return_value=ext_log_dir) @@ -98,6 +99,12 @@ supported_distro = [ ] +def open_patch(): + open_name = '__builtin__.open' + if PY_VERSION_MAJOR == 3: + open_name = 'builtins.open' + return open_name + def distros(distro_name=".*", distro_version=".*", distro_full_name=".*"): """Run test on multiple distros""" def decorator(test_method): diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 9bdb27e..2ef4c16 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -14,6 +14,3 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx diff --git a/tests/utils/test_file_util.py b/tests/utils/test_file_util.py index bf7c638..9a5479e 100644 --- a/tests/utils/test_file_util.py +++ b/tests/utils/test_file_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os import sys -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.fileutil as fileutil +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.fileutil as fileutil class TestFileOperations(AgentTestCase): def test_read_write_file(self): diff --git a/tests/utils/test_flexible_version.py b/tests/utils/test_flexible_version.py new file mode 100644 index 0000000..1162022 --- /dev/null +++ b/tests/utils/test_flexible_version.py @@ -0,0 +1,477 @@ +import random +import re +import unittest + +from azurelinuxagent.common.utils.flexible_version import FlexibleVersion + +class TestFlexibleVersion(unittest.TestCase): + + def setUp(self): + self.v = FlexibleVersion() + + def test_compile_separator(self): + tests = [ + '.', + '', + '-' + ] + for t in tests: + t_escaped = re.escape(t) + t_re = re.compile(t_escaped) + self.assertEqual((t_escaped, t_re), self.v._compile_separator(t)) + self.assertEqual(('', re.compile('')), self.v._compile_separator(None)) + return + + def test_compile_pattern(self): + self.v._compile_pattern() + tests = { + '1': True, + '1.2': True, + '1.2.3': True, + '1.2.3.4': True, + '1.2.3.4.5': True, + + '1alpha': True, + '1.alpha': True, + '1-alpha': True, + '1alpha0': True, + '1.alpha0': True, + '1-alpha0': True, + '1.2alpha': True, + '1.2.alpha': True, + '1.2-alpha': True, + '1.2alpha0': True, + '1.2.alpha0': True, + '1.2-alpha0': True, + + '1beta': True, + '1.beta': True, + '1-beta': True, + '1beta0': True, + '1.beta0': True, + '1-beta0': True, + '1.2beta': True, + '1.2.beta': True, + '1.2-beta': True, + '1.2beta0': True, + '1.2.beta0': True, + '1.2-beta0': True, + + '1rc': True, + '1.rc': True, + '1-rc': True, + '1rc0': True, + '1.rc0': True, + '1-rc0': True, + '1.2rc': True, + '1.2.rc': True, + '1.2-rc': True, + '1.2rc0': True, + '1.2.rc0': True, + '1.2-rc0': True, + + '1.2.3.4alpha5': True, + + ' 1': False, + 'beta': False, + '1delta0': False, + '': False + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + self.v.version_re.match(test) is not None, + "test: {0} expected: {1} ".format(test, expectation)) + return + + def test_compile_pattern_sep(self): + self.v.sep = '-' + self.v._compile_pattern() + tests = { + '1': True, + '1-2': True, + '1-2-3': True, + '1-2-3-4': True, + '1-2-3-4-5': True, + + '1alpha': True, + '1-alpha': True, + '1-alpha': True, + '1alpha0': True, + '1-alpha0': True, + '1-alpha0': True, + '1-2alpha': True, + '1-2.alpha': True, + '1-2-alpha': True, + '1-2alpha0': True, + '1-2.alpha0': True, + '1-2-alpha0': True, + + '1beta': True, + '1-beta': True, + '1-beta': True, + '1beta0': True, + '1-beta0': True, + '1-beta0': True, + '1-2beta': True, + '1-2.beta': True, + '1-2-beta': True, + '1-2beta0': True, + '1-2.beta0': True, + '1-2-beta0': True, + + '1rc': True, + '1-rc': True, + '1-rc': True, + '1rc0': True, + '1-rc0': True, + '1-rc0': True, + '1-2rc': True, + '1-2.rc': True, + '1-2-rc': True, + '1-2rc0': True, + '1-2.rc0': True, + '1-2-rc0': True, + + '1-2-3-4alpha5': True, + + ' 1': False, + 'beta': False, + '1delta0': False, + '': False + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + self.v.version_re.match(test) is not None, + "test: {0} expected: {1} ".format(test, expectation)) + return + + def test_compile_pattern_prerel(self): + self.v.prerel_tags = ('a', 'b', 'c') + self.v._compile_pattern() + tests = { + '1': True, + '1.2': True, + '1.2.3': True, + '1.2.3.4': True, + '1.2.3.4.5': True, + + '1a': True, + '1.a': True, + '1-a': True, + '1a0': True, + '1.a0': True, + '1-a0': True, + '1.2a': True, + '1.2.a': True, + '1.2-a': True, + '1.2a0': True, + '1.2.a0': True, + '1.2-a0': True, + + '1b': True, + '1.b': True, + '1-b': True, + '1b0': True, + '1.b0': True, + '1-b0': True, + '1.2b': True, + '1.2.b': True, + '1.2-b': True, + '1.2b0': True, + '1.2.b0': True, + '1.2-b0': True, + + '1c': True, + '1.c': True, + '1-c': True, + '1c0': True, + '1.c0': True, + '1-c0': True, + '1.2c': True, + '1.2.c': True, + '1.2-c': True, + '1.2c0': True, + '1.2.c0': True, + '1.2-c0': True, + + '1.2.3.4a5': True, + + ' 1': False, + '1.2.3.4alpha5': False, + 'beta': False, + '1delta0': False, + '': False + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + self.v.version_re.match(test) is not None, + "test: {0} expected: {1} ".format(test, expectation)) + return + + def test_ensure_compatible_separators(self): + v1 = FlexibleVersion('1.2.3') + v2 = FlexibleVersion('1-2-3', sep='-') + try: + v1 == v2 + self.assertTrue(False, "Incompatible separators failed to raise an exception") + except ValueError: + pass + except Exception as e: + t = e.__class__.__name__ + self.assertTrue(False, "Incompatible separators raised an unexpected exception: {0}" \ + .format(t)) + return + + def test_ensure_compatible_prerel(self): + v1 = FlexibleVersion('1.2.3', prerel_tags=('alpha', 'beta', 'rc')) + v2 = FlexibleVersion('1.2.3', prerel_tags=('a', 'b', 'c')) + try: + v1 == v2 + self.assertTrue(False, "Incompatible prerel_tags failed to raise an exception") + except ValueError: + pass + except Exception as e: + t = e.__class__.__name__ + self.assertTrue(False, "Incompatible prerel_tags raised an unexpected exception: {0}" \ + .format(t)) + return + + def test_ensure_compatible_prerel_length(self): + v1 = FlexibleVersion('1.2.3', prerel_tags=('a', 'b', 'c')) + v2 = FlexibleVersion('1.2.3', prerel_tags=('a', 'b')) + try: + v1 == v2 + self.assertTrue(False, "Incompatible prerel_tags failed to raise an exception") + except ValueError: + pass + except Exception as e: + t = e.__class__.__name__ + self.assertTrue(False, "Incompatible prerel_tags raised an unexpected exception: {0}" \ + .format(t)) + return + + def test_ensure_compatible_prerel_order(self): + v1 = FlexibleVersion('1.2.3', prerel_tags=('a', 'b')) + v2 = FlexibleVersion('1.2.3', prerel_tags=('b', 'a')) + try: + v1 == v2 + self.assertTrue(False, "Incompatible prerel_tags failed to raise an exception") + except ValueError: + pass + except Exception as e: + t = e.__class__.__name__ + self.assertTrue(False, "Incompatible prerel_tags raised an unexpected exception: {0}" \ + .format(t)) + return + + def test_major(self): + tests = { + '1' : 1, + '1.2' : 1, + '1.2.3' : 1, + '1.2.3.4' : 1 + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + FlexibleVersion(test).major) + return + + def test_minor(self): + tests = { + '1' : 0, + '1.2' : 2, + '1.2.3' : 2, + '1.2.3.4' : 2 + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + FlexibleVersion(test).minor) + return + + def test_patch(self): + tests = { + '1' : 0, + '1.2' : 0, + '1.2.3' : 3, + '1.2.3.4' : 3 + } + for test in iter(tests): + expectation = tests[test] + self.assertEqual( + expectation, + FlexibleVersion(test).patch) + return + + def test_parse(self): + tests = { + "1.2.3.4": ((1, 2, 3, 4), None), + "1.2.3.4alpha5": ((1, 2, 3, 4), ('alpha', 5)), + "1.2.3.4-alpha5": ((1, 2, 3, 4), ('alpha', 5)), + "1.2.3.4.alpha5": ((1, 2, 3, 4), ('alpha', 5)) + } + for test in iter(tests): + expectation = tests[test] + self.v._parse(test) + self.assertEqual(expectation, (self.v.version, self.v.prerelease)) + return + + def test_decrement(self): + src_v = FlexibleVersion('1.0.0.0.10') + dst_v = FlexibleVersion(str(src_v)) + for i in range(1,10): + dst_v -= 1 + self.assertEqual(i, src_v.version[-1] - dst_v.version[-1]) + return + + def test_decrement_disallows_below_zero(self): + try: + FlexibleVersion('1.0') - 1 + self.assertTrue(False, "Decrement failed to raise an exception") + except ArithmeticError: + pass + except Exception as e: + t = e.__class__.__name__ + self.assertTrue(False, "Decrement raised an unexpected exception: {0}".format(t)) + return + + def test_increment(self): + src_v = FlexibleVersion('1.0.0.0.0') + dst_v = FlexibleVersion(str(src_v)) + for i in range(1,10): + dst_v += 1 + self.assertEqual(i, dst_v.version[-1] - src_v.version[-1]) + return + + def test_str(self): + tests = [ + '1', + '1.2', + '1.2.3', + '1.2.3.4', + '1.2.3.4.5', + + '1alpha', + '1.alpha', + '1-alpha', + '1alpha0', + '1.alpha0', + '1-alpha0', + '1.2alpha', + '1.2.alpha', + '1.2-alpha', + '1.2alpha0', + '1.2.alpha0', + '1.2-alpha0', + + '1beta', + '1.beta', + '1-beta', + '1beta0', + '1.beta0', + '1-beta0', + '1.2beta', + '1.2.beta', + '1.2-beta', + '1.2beta0', + '1.2.beta0', + '1.2-beta0', + + '1rc', + '1.rc', + '1-rc', + '1rc0', + '1.rc0', + '1-rc0', + '1.2rc', + '1.2.rc', + '1.2-rc', + '1.2rc0', + '1.2.rc0', + '1.2-rc0', + + '1.2.3.4alpha5', + ] + for test in tests: + self.assertEqual(test, str(FlexibleVersion(test))) + return + + def test_repr(self): + v = FlexibleVersion('1,2,3rc4', ',', ['lol', 'rc']) + expected = "FlexibleVersion ('1,2,3rc4', ',', ('lol', 'rc'))" + self.assertEqual(expected, repr(v)) + + def test_order(self): + test0 = ["1.7.0", "1.7.0rc0", "1.11.0"] + expected0 = ['1.7.0rc0', '1.7.0', '1.11.0'] + self.assertEqual(expected0, list(map(str, sorted([FlexibleVersion(v) for v in test0])))) + + test1 = [ + '2.0.2rc2', + '2.2.0beta3', + '2.0.10', + '2.1.0alpha42', + '2.0.2beta4', + '2.1.1', + '2.0.1', + '2.0.2rc3', + '2.2.0', + '2.0.0', + '3.0.1', + '2.1.0rc1' + ] + expected1 = [ + '2.0.0', + '2.0.1', + '2.0.2beta4', + '2.0.2rc2', + '2.0.2rc3', + '2.0.10', + '2.1.0alpha42', + '2.1.0rc1', + '2.1.1', + '2.2.0beta3', + '2.2.0', + '3.0.1' + ] + self.assertEqual(expected1, list(map(str, sorted([FlexibleVersion(v) for v in test1])))) + + self.assertEqual(FlexibleVersion("1.0.0.0.0.0.0.0"), FlexibleVersion("1")) + + self.assertFalse(FlexibleVersion("1.0") > FlexibleVersion("1.0")) + self.assertFalse(FlexibleVersion("1.0") < FlexibleVersion("1.0")) + + self.assertTrue(FlexibleVersion("1.0") < FlexibleVersion("1.1")) + self.assertTrue(FlexibleVersion("1.9") < FlexibleVersion("1.10")) + self.assertTrue(FlexibleVersion("1.9.9") < FlexibleVersion("1.10.0")) + self.assertTrue(FlexibleVersion("1.0.0.0") < FlexibleVersion("1.2.0.0")) + + self.assertTrue(FlexibleVersion("1.1") > FlexibleVersion("1.0")) + self.assertTrue(FlexibleVersion("1.10") > FlexibleVersion("1.9")) + self.assertTrue(FlexibleVersion("1.10.0") > FlexibleVersion("1.9.9")) + self.assertTrue(FlexibleVersion("1.2.0.0") > FlexibleVersion("1.0.0.0")) + + self.assertTrue(FlexibleVersion("1.0") <= FlexibleVersion("1.1")) + self.assertTrue(FlexibleVersion("1.1") > FlexibleVersion("1.0")) + self.assertTrue(FlexibleVersion("1.1") >= FlexibleVersion("1.0")) + + self.assertTrue(FlexibleVersion("1.0") == FlexibleVersion("1.0")) + self.assertTrue(FlexibleVersion("1.0") >= FlexibleVersion("1.0")) + self.assertTrue(FlexibleVersion("1.0") <= FlexibleVersion("1.0")) + + self.assertFalse(FlexibleVersion("1.0") != FlexibleVersion("1.0")) + self.assertTrue(FlexibleVersion("1.1") != FlexibleVersion("1.0")) + return + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/utils/test_rest_util.py b/tests/utils/test_rest_util.py index bd22c55..874e527 100644 --- a/tests/utils/test_rest_util.py +++ b/tests/utils/test_rest_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import AgentTestCase, patch, Mock, MagicMock import uuid import unittest import os -import azurelinuxagent.utils.restutil as restutil -from azurelinuxagent.future import ustr, httpclient -import azurelinuxagent.logger as logger +import azurelinuxagent.common.utils.restutil as restutil +from azurelinuxagent.common.future import ustr, httpclient +import azurelinuxagent.common.logger as logger class TestHttpOperations(AgentTestCase): @@ -57,8 +54,8 @@ class TestHttpOperations(AgentTestCase): self.assertEquals(rel_uri, "None") - @patch("azurelinuxagent.future.httpclient.HTTPSConnection") - @patch("azurelinuxagent.future.httpclient.HTTPConnection") + @patch("azurelinuxagent.common.future.httpclient.HTTPSConnection") + @patch("azurelinuxagent.common.future.httpclient.HTTPConnection") def test_http_request(self, HTTPConnection, HTTPSConnection): mock_httpconn = MagicMock() mock_httpresp = MagicMock() @@ -98,7 +95,7 @@ class TestHttpOperations(AgentTestCase): self.assertEquals("_(:3| <)_", resp.read()) @patch("time.sleep") - @patch("azurelinuxagent.utils.restutil._http_request") + @patch("azurelinuxagent.common.utils.restutil._http_request") def test_http_request_with_retry(self, _http_request, sleep): mock_httpresp = MagicMock() mock_httpresp.read = Mock(return_value="hehe") diff --git a/tests/utils/test_shell_util.py b/tests/utils/test_shell_util.py index aa89121..57e6c33 100644 --- a/tests/utils/test_shell_util.py +++ b/tests/utils/test_shell_util.py @@ -15,15 +15,12 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os -import azurelinuxagent.utils.shellutil as shellutil +import azurelinuxagent.common.utils.shellutil as shellutil import test class TestrunCmd(AgentTestCase): @@ -38,5 +35,10 @@ class TestrunCmd(AgentTestCase): err = shellutil.run_get_output(u"ls 我") self.assertNotEquals(0, err[0]) + def test_shellquote(self): + self.assertEqual("\'foo\'", shellutil.quote("foo")) + self.assertEqual("\'foo bar\'", shellutil.quote("foo bar")) + self.assertEqual("'foo'\\''bar'", shellutil.quote("foo\'bar")) + if __name__ == '__main__': unittest.main() diff --git a/tests/utils/test_text_util.py b/tests/utils/test_text_util.py index 0e8cc7d..9ac0707 100644 --- a/tests/utils/test_text_util.py +++ b/tests/utils/test_text_util.py @@ -14,17 +14,14 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -# Implements parts of RFC 2131, 1541, 1497 and -# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx -# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx from tests.tools import * import uuid import unittest import os -from azurelinuxagent.future import ustr -import azurelinuxagent.utils.textutil as textutil -from azurelinuxagent.utils.textutil import Version +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.utils.textutil as textutil +from azurelinuxagent.common.utils.textutil import Version class TestTextUtil(AgentTestCase): def test_get_password_hash(self): |