diff options
author | Ćukasz 'sil2100' Zemczak <lukasz.zemczak@ubuntu.com> | 2017-05-18 19:58:02 +0200 |
---|---|---|
committer | usd-importer <ubuntu-server@lists.ubuntu.com> | 2017-05-31 09:53:12 +0000 |
commit | 4fb0b5a09b26135ade285844da5d7dfe582a8d4c (patch) | |
tree | 09b1e5867d6e7501118cdd0af0012b51fc216530 /tests | |
parent | 473ad6fbfe0b9c3b362b530492928303f2b4c7f3 (diff) | |
download | vyos-walinuxagent-4fb0b5a09b26135ade285844da5d7dfe582a8d4c.tar.gz vyos-walinuxagent-4fb0b5a09b26135ade285844da5d7dfe582a8d4c.zip |
Import patches-unapplied version 2.2.12-0ubuntu1 to ubuntu/artful-proposed
Imported using git-ubuntu import.
Changelog parent: 473ad6fbfe0b9c3b362b530492928303f2b4c7f3
New changelog entries:
* New upstream release (LP: #1690854).
- Refreshed debian/patches/disable_import_test.patch.
Diffstat (limited to 'tests')
28 files changed, 1082 insertions, 73 deletions
diff --git a/tests/common/osutil/test_default.py b/tests/common/osutil/test_default.py index 933787b..87acc60 100644 --- a/tests/common/osutil/test_default.py +++ b/tests/common/osutil/test_default.py @@ -18,8 +18,11 @@ import socket import glob import mock + import azurelinuxagent.common.osutil.default as osutil import azurelinuxagent.common.utils.shellutil as shellutil +from azurelinuxagent.common.exception import OSUtilError +from azurelinuxagent.common.future import ustr from azurelinuxagent.common.osutil import get_osutil from azurelinuxagent.common.utils import fileutil from tests.tools import * @@ -40,6 +43,50 @@ class TestOSUtil(AgentTestCase): 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_dvd_device_success(self): + with patch.object(os, 'listdir', return_value=['cpu', 'cdrom0']): + osutil.DefaultOSUtil().get_dvd_device() + + def test_get_dvd_device_failure(self): + with patch.object(os, 'listdir', return_value=['cpu', 'notmatching']): + try: + osutil.DefaultOSUtil().get_dvd_device() + self.fail('OSUtilError was not raised') + except OSUtilError as ose: + self.assertTrue('notmatching' in ustr(ose)) + + @patch('time.sleep') + def test_mount_dvd_success(self, _): + msg = 'message' + with patch.object(osutil.DefaultOSUtil, + 'get_dvd_device', + return_value='/dev/cdrom'): + with patch.object(shellutil, + 'run_get_output', + return_value=(0, msg)) as patch_run: + with patch.object(os, 'makedirs'): + try: + osutil.DefaultOSUtil().mount_dvd() + except OSUtilError: + self.fail("mounting failed") + + @patch('time.sleep') + def test_mount_dvd_failure(self, _): + msg = 'message' + with patch.object(osutil.DefaultOSUtil, + 'get_dvd_device', + return_value='/dev/cdrom'): + with patch.object(shellutil, + 'run_get_output', + return_value=(1, msg)) as patch_run: + with patch.object(os, 'makedirs'): + try: + osutil.DefaultOSUtil().mount_dvd() + self.fail('OSUtilError was not raised') + except OSUtilError as ose: + self.assertTrue(msg in ustr(ose)) + self.assertTrue(patch_run.call_count == 6) + def test_get_first_if(self): ifname, ipaddr = osutil.DefaultOSUtil().get_first_if() self.assertTrue(ifname.startswith('eth')) @@ -315,5 +362,37 @@ Match host 192.168.1.2\n\ conf.get_sshd_conf_file_path(), expected_output) + @patch('os.path.isfile', return_value=True) + @patch('azurelinuxagent.common.utils.fileutil.read_file', + return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502") + def test_get_instance_id_from_file(self, mock_read, mock_isfile): + util = osutil.DefaultOSUtil() + self.assertEqual( + "B9F3C233-9913-9F42-8EB3-BA656DF32502", + util.get_instance_id()) + + @patch('os.path.isfile', return_value=False) + @patch('azurelinuxagent.common.utils.shellutil.run_get_output', + return_value=[0, 'B9F3C233-9913-9F42-8EB3-BA656DF32502']) + def test_get_instance_id_from_dmidecode(self, mock_shell, mock_isfile): + util = osutil.DefaultOSUtil() + self.assertEqual( + "B9F3C233-9913-9F42-8EB3-BA656DF32502", + util.get_instance_id()) + + @patch('os.path.isfile', return_value=False) + @patch('azurelinuxagent.common.utils.shellutil.run_get_output', + return_value=[1, 'Error Value']) + def test_get_instance_id_missing(self, mock_shell, mock_isfile): + util = osutil.DefaultOSUtil() + self.assertEqual("", util.get_instance_id()) + + @patch('os.path.isfile', return_value=False) + @patch('azurelinuxagent.common.utils.shellutil.run_get_output', + return_value=[0, 'Unexpected Value']) + def test_get_instance_id_unexpected(self, mock_shell, mock_isfile): + util = osutil.DefaultOSUtil() + self.assertEqual("", util.get_instance_id()) + if __name__ == '__main__': unittest.main() diff --git a/tests/common/test_conf.py b/tests/common/test_conf.py new file mode 100644 index 0000000..1287b0d --- /dev/null +++ b/tests/common/test_conf.py @@ -0,0 +1,61 @@ +# 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 os.path + +from azurelinuxagent.common.conf import * + +from tests.tools import * + + +class TestConf(AgentTestCase): + def setUp(self): + AgentTestCase.setUp(self) + self.conf = ConfigurationProvider() + load_conf_from_file( + os.path.join(data_dir, "test_waagent.conf"), + self.conf) + + def test_key_value_handling(self): + self.assertEqual("Value1", self.conf.get("FauxKey1", "Bad")) + self.assertEqual("Value2 Value2", self.conf.get("FauxKey2", "Bad")) + + def test_get_ssh_dir(self): + self.assertTrue(get_ssh_dir(self.conf).startswith("/notareal/path")) + + def test_get_sshd_conf_file_path(self): + self.assertTrue(get_sshd_conf_file_path( + self.conf).startswith("/notareal/path")) + + def test_get_ssh_key_glob(self): + self.assertTrue(get_ssh_key_glob( + self.conf).startswith("/notareal/path")) + + def test_get_ssh_key_private_path(self): + self.assertTrue(get_ssh_key_private_path( + self.conf).startswith("/notareal/path")) + + def test_get_ssh_key_public_path(self): + self.assertTrue(get_ssh_key_public_path( + self.conf).startswith("/notareal/path")) + + def test_get_fips_enabled(self): + self.assertTrue(get_fips_enabled(self.conf)) + + def test_get_provision_cloudinit(self): + self.assertTrue(get_provision_cloudinit(self.conf)) diff --git a/tests/daemon/test_daemon.py b/tests/daemon/test_daemon.py index dd31fd7..5694dc9 100644 --- a/tests/daemon/test_daemon.py +++ b/tests/daemon/test_daemon.py @@ -14,7 +14,9 @@ # # Requires Python 2.4+ and Openssl 1.0+ # -from azurelinuxagent.daemon import get_daemon_handler + +from azurelinuxagent.daemon import * +from azurelinuxagent.daemon.main import OPENSSL_FIPS_ENVIRONMENT from tests.tools import * @@ -30,8 +32,9 @@ class MockDaemonCall(object): self.daemon_handler.running = False raise Exception("Mock unhandled exception") -@patch("time.sleep") class TestDaemon(AgentTestCase): + + @patch("time.sleep") def test_daemon_restart(self, mock_sleep): #Mock daemon function daemon_handler = get_daemon_handler() @@ -45,6 +48,7 @@ class TestDaemon(AgentTestCase): mock_sleep.assert_any_call(15) self.assertEquals(2, daemon_handler.daemon.call_count) + @patch("time.sleep") @patch("azurelinuxagent.daemon.main.conf") @patch("azurelinuxagent.daemon.main.sys.exit") def test_check_pid(self, mock_exit, mock_conf, mock_sleep): @@ -58,6 +62,25 @@ class TestDaemon(AgentTestCase): daemon_handler.check_pid() mock_exit.assert_any_call(0) + + @patch("azurelinuxagent.daemon.main.DaemonHandler.check_pid") + @patch("azurelinuxagent.common.conf.get_fips_enabled", return_value=True) + def test_set_openssl_fips(self, mock_conf, mock_daemon): + daemon_handler = get_daemon_handler() + daemon_handler.running = False + with patch.dict("os.environ"): + daemon_handler.run() + self.assertTrue(OPENSSL_FIPS_ENVIRONMENT in os.environ) + self.assertEqual('1', os.environ[OPENSSL_FIPS_ENVIRONMENT]) + + @patch("azurelinuxagent.daemon.main.DaemonHandler.check_pid") + @patch("azurelinuxagent.common.conf.get_fips_enabled", return_value=False) + def test_does_not_set_openssl_fips(self, mock_conf, mock_daemon): + daemon_handler = get_daemon_handler() + daemon_handler.running = False + with patch.dict("os.environ"): + daemon_handler.run() + self.assertFalse(OPENSSL_FIPS_ENVIRONMENT in os.environ) if __name__ == '__main__': unittest.main() diff --git a/tests/data/events/1478123456789000.tld b/tests/data/events/1478123456789000.tld new file mode 100644 index 0000000..a689f4c --- /dev/null +++ b/tests/data/events/1478123456789000.tld @@ -0,0 +1 @@ +{"eventId": 1, "providerId": "69B669B9-4AF8-4C50-BDC4-6006FA76E975", "parameters": [{"name": "Name", "value": "Test Event"}, {"name": "Version", "value": "2.2.0"}, {"name": "IsInternal", "value": false}, {"name": "Operation", "value": "Some Operation"}, {"name": "OperationSuccess", "value": true}, {"name": "Message", "value": ""}, {"name": "Duration", "value": 0}, {"name": "ExtensionType", "value": ""}]}
\ No newline at end of file diff --git a/tests/data/events/1478123456789001.tld b/tests/data/events/1478123456789001.tld new file mode 100644 index 0000000..95460e3 --- /dev/null +++ b/tests/data/events/1478123456789001.tld @@ -0,0 +1 @@ +{"eventId": 1, "providerId": "69B669B9-4AF8-4C50-BDC4-6006FA76E975", "parameters": [{"name": "Name", "value": "Linux Event"}, {"name": "Version", "value": "2.2.0"}, {"name": "IsInternal", "value": false}, {"name": "Operation", "value": "Linux Operation"}, {"name": "OperationSuccess", "value": false}, {"name": "Message", "value": "Linux Message"}, {"name": "Duration", "value": 42}, {"name": "ExtensionType", "value": "Linux Event Type"}]}
\ No newline at end of file diff --git a/tests/data/events/1479766858966718.tld b/tests/data/events/1479766858966718.tld new file mode 100644 index 0000000..cc7ac67 --- /dev/null +++ b/tests/data/events/1479766858966718.tld @@ -0,0 +1 @@ +{"eventId": 1, "providerId": "69B669B9-4AF8-4C50-BDC4-6006FA76E975", "parameters": [{"name": "Name", "value": "WALinuxAgent"}, {"name": "Version", "value": "2.3.0.1"}, {"name": "IsInternal", "value": false}, {"name": "Operation", "value": "Enable"}, {"name": "OperationSuccess", "value": true}, {"name": "Message", "value": "Agent WALinuxAgent-2.3.0.1 launched with command 'python install.py' is successfully running"}, {"name": "Duration", "value": 0}, {"name": "ExtensionType", "value": ""}]}
\ No newline at end of file diff --git a/tests/data/ext/sample_ext.zip b/tests/data/ext/sample_ext-1.2.0.zip Binary files differindex 08cfaf7..08cfaf7 100644 --- a/tests/data/ext/sample_ext.zip +++ b/tests/data/ext/sample_ext-1.2.0.zip diff --git a/tests/data/ext/sample_ext/HandlerManifest.json b/tests/data/ext/sample_ext-1.2.0/HandlerManifest.json index 9890d0c..9890d0c 100644 --- a/tests/data/ext/sample_ext/HandlerManifest.json +++ b/tests/data/ext/sample_ext-1.2.0/HandlerManifest.json diff --git a/tests/data/ext/sample_ext/sample.py b/tests/data/ext/sample_ext-1.2.0/sample.py index 74bd839..74bd839 100755 --- a/tests/data/ext/sample_ext/sample.py +++ b/tests/data/ext/sample_ext-1.2.0/sample.py diff --git a/tests/data/ga/WALinuxAgent-2.2.11.zip b/tests/data/ga/WALinuxAgent-2.2.11.zip Binary files differnew file mode 100644 index 0000000..f018116 --- /dev/null +++ b/tests/data/ga/WALinuxAgent-2.2.11.zip diff --git a/tests/data/ga/WALinuxAgent-2.2.8.zip b/tests/data/ga/WALinuxAgent-2.2.8.zip Binary files differdeleted file mode 100644 index 04c60a8..0000000 --- a/tests/data/ga/WALinuxAgent-2.2.8.zip +++ /dev/null diff --git a/tests/data/ga/supported.json b/tests/data/ga/supported.json new file mode 100644 index 0000000..2ae3753 --- /dev/null +++ b/tests/data/ga/supported.json @@ -0,0 +1,8 @@ +{ + "ubuntu.16.10-x64": { + "versions": [ + "^Ubuntu,16.10,yakkety$" + ], + "slice": 10 + } +} diff --git a/tests/data/metadata/vmagent_manifest1.json b/tests/data/metadata/vmagent_manifest1.json new file mode 100644 index 0000000..544a708 --- /dev/null +++ b/tests/data/metadata/vmagent_manifest1.json @@ -0,0 +1,20 @@ +{ + "versions": [ + { + "version": "2.2.8", + "uris": [ + { + "uri": "https: //notused.com/ga/WALinuxAgent-2.2.8.zip" + } + ] + }, + { + "version": "2.2.9", + "uris": [ + { + "uri": "https: //notused.com/ga/WALinuxAgent-2.2.9.zip" + } + ] + } + ] +}
\ No newline at end of file diff --git a/tests/data/metadata/vmagent_manifest2.json b/tests/data/metadata/vmagent_manifest2.json new file mode 100644 index 0000000..544a708 --- /dev/null +++ b/tests/data/metadata/vmagent_manifest2.json @@ -0,0 +1,20 @@ +{ + "versions": [ + { + "version": "2.2.8", + "uris": [ + { + "uri": "https: //notused.com/ga/WALinuxAgent-2.2.8.zip" + } + ] + }, + { + "version": "2.2.9", + "uris": [ + { + "uri": "https: //notused.com/ga/WALinuxAgent-2.2.9.zip" + } + ] + } + ] +}
\ No newline at end of file diff --git a/tests/data/metadata/vmagent_manifests.json b/tests/data/metadata/vmagent_manifests.json new file mode 100644 index 0000000..2628f89 --- /dev/null +++ b/tests/data/metadata/vmagent_manifests.json @@ -0,0 +1,7 @@ +{ + "versionsManifestUris" : + [ + { "uri" : "https://notused.com/vmagent_manifest1.json" }, + { "uri" : "https://notused.com/vmagent_manifest2.json" } + ] +} diff --git a/tests/data/metadata/vmagent_manifests_invalid1.json b/tests/data/metadata/vmagent_manifests_invalid1.json new file mode 100644 index 0000000..55b08d1 --- /dev/null +++ b/tests/data/metadata/vmagent_manifests_invalid1.json @@ -0,0 +1,10 @@ +{ + "notTheRightKey": [ + { + "uri": "https://notused.com/vmagent_manifest1.json" + }, + { + "uri": "https://notused.com/vmagent_manifest2.json" + } + ] +}
\ No newline at end of file diff --git a/tests/data/metadata/vmagent_manifests_invalid2.json b/tests/data/metadata/vmagent_manifests_invalid2.json new file mode 100644 index 0000000..5df4252 --- /dev/null +++ b/tests/data/metadata/vmagent_manifests_invalid2.json @@ -0,0 +1,10 @@ +{ + "notTheRightKey": [ + { + "foo": "https://notused.com/vmagent_manifest1.json" + }, + { + "bar": "https://notused.com/vmagent_manifest2.json" + } + ] +}
\ No newline at end of file diff --git a/tests/data/test_waagent.conf b/tests/data/test_waagent.conf new file mode 100644 index 0000000..6368c39 --- /dev/null +++ b/tests/data/test_waagent.conf @@ -0,0 +1,111 @@ +# +# Microsoft Azure Linux Agent Configuration +# + +# Key / value handling test entries +=Value0 +FauxKey1= Value1 +FauxKey2=Value2 Value2 + +# Enable instance creation +Provisioning.Enabled=y + +# Rely on cloud-init to provision +Provisioning.UseCloudInit=y + +# Password authentication for root account will be unavailable. +Provisioning.DeleteRootPassword=y + +# Generate fresh host key pair. +Provisioning.RegenerateSshHostKeyPair=y + +# Supported values are "rsa", "dsa" and "ecdsa". +Provisioning.SshHostKeyPairType=rsa + +# Monitor host name changes and publish changes via DHCP requests. +Provisioning.MonitorHostName=y + +# Decode CustomData from Base64. +Provisioning.DecodeCustomData=n + +# Execute CustomData after provisioning. +Provisioning.ExecuteCustomData=n + +# Algorithm used by crypt when generating password hash. +#Provisioning.PasswordCryptId=6 + +# Length of random salt used when generating password hash. +#Provisioning.PasswordCryptSaltLength=10 + +# Allow reset password of sys user +Provisioning.AllowResetSysUser=n + +# Format if unformatted. If 'n', resource disk will not be mounted. +ResourceDisk.Format=y + +# File system on the resource disk +# Typically ext3 or ext4. FreeBSD images should use 'ufs2' here. +ResourceDisk.Filesystem=ext4 + +# Mount point for the resource disk +ResourceDisk.MountPoint=/mnt/resource + +# Create and use swapfile on resource disk. +ResourceDisk.EnableSwap=n + +# Size of the swapfile. +ResourceDisk.SwapSizeMB=0 + +# Comma-seperated list of mount options. See man(8) for valid options. +ResourceDisk.MountOptions=None + +# Enable verbose logging (y|n) +Logs.Verbose=n + +# Is FIPS enabled +OS.EnableFIPS=y + +# Root device timeout in seconds. +OS.RootDeviceScsiTimeout=300 + +# If "None", the system default version is used. +OS.OpensslPath=None + +# Set the path to SSH keys and configuration files +OS.SshDir=/notareal/path + +# If set, agent will use proxy server to access internet +#HttpProxy.Host=None +#HttpProxy.Port=None + +# Detect Scvmm environment, default is n +# DetectScvmmEnv=n + +# +# Lib.Dir=/var/lib/waagent + +# +# DVD.MountPoint=/mnt/cdrom/secure + +# +# Pid.File=/var/run/waagent.pid + +# +# Extension.LogDir=/var/log/azure + +# +# Home.Dir=/home + +# Enable RDMA management and set up, should only be used in HPC images +# OS.EnableRDMA=y + +# Enable or disable goal state processing auto-update, default is enabled +# AutoUpdate.Enabled=y + +# Determine the update family, this should not be changed +# AutoUpdate.GAFamily=Prod + +# Determine if the overprovisioning feature is enabled. If yes, hold extension +# handling until inVMArtifactsProfile.OnHold is false. +# Default is disabled +# EnableOverProvisioning=n diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py index 1df0a04..2a60ea3 100644 --- a/tests/ga/test_extension.py +++ b/tests/ga/test_extension.py @@ -15,6 +15,14 @@ # Requires Python 2.4+ and Openssl 1.0+ # +import glob +import os +import os.path +import shutil +import tempfile +import zipfile + +import azurelinuxagent.common.conf as conf import azurelinuxagent.common.utils.fileutil as fileutil from tests.protocol.mockwiredata import * @@ -30,6 +38,103 @@ from azurelinuxagent.common.protocol.restapi import ExtHandlerStatus, \ from azurelinuxagent.ga.exthandlers import * from azurelinuxagent.common.protocol.wire import WireProtocol +class TestExtensionCleanup(AgentTestCase): + def setUp(self): + AgentTestCase.setUp(self) + self.ext_handlers = ExtHandlersHandler() + self.lib_dir = tempfile.mkdtemp() + + def _install_handlers(self, start=0, count=1, + handler_state=ExtHandlerState.Installed): + src = os.path.join(data_dir, "ext", "sample_ext-1.2.0.zip") + version = FlexibleVersion("1.2.0") + version += start - version.patch + + for i in range(start, start+count): + eh = ExtHandler() + eh.name = "sample_ext" + eh.properties.version = str(version) + handler = ExtHandlerInstance(eh, "unused") + + dst = os.path.join(self.lib_dir, + handler.get_full_name()+HANDLER_PKG_EXT) + shutil.copy(src, dst) + + if not handler_state is None: + zipfile.ZipFile(dst).extractall(handler.get_base_dir()) + handler.set_handler_state(handler_state) + + version += 1 + + def _count_packages(self): + return len(glob.glob(os.path.join(self.lib_dir, "*.zip"))) + + def _count_installed(self): + paths = os.listdir(self.lib_dir) + paths = [os.path.join(self.lib_dir, p) for p in paths] + return len([p for p in paths + if os.path.isdir(p) and self._is_installed(p)]) + + def _count_uninstalled(self): + paths = os.listdir(self.lib_dir) + paths = [os.path.join(self.lib_dir, p) for p in paths] + return len([p for p in paths + if os.path.isdir(p) and not self._is_installed(p)]) + + def _is_installed(self, path): + path = os.path.join(path, 'config', 'HandlerState') + return fileutil.read_file(path) != "NotInstalled" + + @patch("azurelinuxagent.common.conf.get_lib_dir") + def test_cleanup_leaves_installed_extensions(self, mock_conf): + mock_conf.return_value = self.lib_dir + + self._install_handlers(start=0, count=5, handler_state=ExtHandlerState.Installed) + self._install_handlers(start=5, count=5, handler_state=ExtHandlerState.Enabled) + + self.assertEqual(self._count_packages(), 10) + self.assertEqual(self._count_installed(), 10) + + self.ext_handlers.cleanup_outdated_handlers() + + self.assertEqual(self._count_packages(), 10) + self.assertEqual(self._count_installed(), 10) + self.assertEqual(self._count_uninstalled(), 0) + + @patch("azurelinuxagent.common.conf.get_lib_dir") + def test_cleanup_removes_uninstalled_extensions(self, mock_conf): + mock_conf.return_value = self.lib_dir + + self._install_handlers(start=0, count=5, handler_state=ExtHandlerState.Installed) + self._install_handlers(start=5, count=5, handler_state=ExtHandlerState.NotInstalled) + + self.assertEqual(self._count_packages(), 10) + self.assertEqual(self._count_installed(), 5) + self.assertEqual(self._count_uninstalled(), 5) + + self.ext_handlers.cleanup_outdated_handlers() + + self.assertEqual(self._count_packages(), 5) + self.assertEqual(self._count_installed(), 5) + self.assertEqual(self._count_uninstalled(), 0) + + @patch("azurelinuxagent.common.conf.get_lib_dir") + def test_cleanup_removes_orphaned_packages(self, mock_conf): + mock_conf.return_value = self.lib_dir + + self._install_handlers(start=0, count=5, handler_state=ExtHandlerState.Installed) + self._install_handlers(start=5, count=5, handler_state=None) + + self.assertEqual(self._count_packages(), 10) + self.assertEqual(self._count_installed(), 5) + self.assertEqual(self._count_uninstalled(), 0) + + self.ext_handlers.cleanup_outdated_handlers() + + self.assertEqual(self._count_packages(), 5) + self.assertEqual(self._count_installed(), 5) + self.assertEqual(self._count_uninstalled(), 0) + class TestHandlerStateMigration(AgentTestCase): def setUp(self): AgentTestCase.setUp(self) diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py index e7a7af4..a83db95 100644 --- a/tests/ga/test_update.py +++ b/tests/ga/test_update.py @@ -17,9 +17,16 @@ from __future__ import print_function +from datetime import datetime + +import json +import shutil + from azurelinuxagent.common.protocol.hostplugin import * from azurelinuxagent.common.protocol.wire import * +from azurelinuxagent.common.utils.fileutil import * from azurelinuxagent.ga.update import * + from tests.tools import * NO_ERROR = { @@ -28,6 +35,18 @@ NO_ERROR = { "was_fatal" : False } +FATAL_ERROR = { + "last_failure" : 42.42, + "failure_count" : 2, + "was_fatal" : True +} + +SENTINEL_ERROR = { + "last_failure" : 0.0, + "failure_count" : 0, + "was_fatal" : True +} + WITH_ERROR = { "last_failure" : 42.42, "failure_count" : 2, @@ -137,19 +156,25 @@ class UpdateTestCase(AgentTestCase): fileutil.copy_file(agent, to_dir=self.tmp_dir) return - def expand_agents(self): + def expand_agents(self, mark_test=False): for agent in self.agent_pkgs(): - zipfile.ZipFile(agent).extractall(os.path.join( - self.tmp_dir, - fileutil.trim_ext(agent, "zip"))) + path = os.path.join(self.tmp_dir, fileutil.trim_ext(agent, "zip")) + zipfile.ZipFile(agent).extractall(path) + if mark_test: + src = os.path.join(data_dir, 'ga', 'supported.json') + dst = os.path.join(path, 'supported.json') + shutil.copy(src, dst) + + dst = os.path.join(path, 'error.json') + fileutil.write_file(dst, json.dumps(SENTINEL_ERROR)) return - def prepare_agent(self, version): + def prepare_agent(self, version, mark_test=False): """ Create a download for the current agent version, copied from test data """ self.copy_agents(get_agent_pkgs()[0]) - self.expand_agents() + self.expand_agents(mark_test=mark_test) versions = self.agent_versions() src_v = FlexibleVersion(str(versions[0])) @@ -214,6 +239,64 @@ class UpdateTestCase(AgentTestCase): return dst_v +class TestSupportedDistribution(UpdateTestCase): + def setUp(self): + UpdateTestCase.setUp(self) + self.sd = SupportedDistribution({ + 'slice':10, + 'versions': ['^Ubuntu,16.10,yakkety$']}) + + + def test_creation(self): + self.assertRaises(TypeError, SupportedDistribution) + self.assertRaises(UpdateError, SupportedDistribution, None) + + self.assertEqual(self.sd.slice, 10) + self.assertEqual(self.sd.versions, ['^Ubuntu,16.10,yakkety$']) + + @patch('platform.linux_distribution') + def test_is_supported(self, mock_dist): + mock_dist.return_value = ['Ubuntu', '16.10', 'yakkety'] + self.assertTrue(self.sd.is_supported) + + mock_dist.return_value = ['something', 'else', 'entirely'] + self.assertFalse(self.sd.is_supported) + + @patch('azurelinuxagent.ga.update.datetime') + def test_in_slice(self, mock_dt): + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + self.assertTrue(self.sd.in_slice) + + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 42)) + self.assertFalse(self.sd.in_slice) + + +class TestSupported(UpdateTestCase): + def setUp(self): + UpdateTestCase.setUp(self) + self.sp = Supported(os.path.join(data_dir, 'ga', 'supported.json')) + + def test_creation(self): + self.assertRaises(TypeError, Supported) + self.assertRaises(UpdateError, Supported, None) + + @patch('platform.linux_distribution') + def test_is_supported(self, mock_dist): + mock_dist.return_value = ['Ubuntu', '16.10', 'yakkety'] + self.assertTrue(self.sp.is_supported) + + mock_dist.return_value = ['something', 'else', 'entirely'] + self.assertFalse(self.sp.is_supported) + + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + @patch('azurelinuxagent.ga.update.datetime') + def test_in_slice(self, mock_dt, mock_dist): + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + self.assertTrue(self.sp.in_slice) + + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 42)) + self.assertFalse(self.sp.in_slice) + class TestGuestAgentError(UpdateTestCase): def test_creation(self): self.assertRaises(TypeError, GuestAgentError) @@ -241,6 +324,17 @@ class TestGuestAgentError(UpdateTestCase): self.assertEqual(NO_ERROR["was_fatal"], err.was_fatal) return + def test_is_sentinel(self): + with self.get_error_file(error_data=SENTINEL_ERROR) as path: + err = GuestAgentError(path.name) + self.assertTrue(err.is_blacklisted) + self.assertTrue(err.is_sentinel) + + with self.get_error_file(error_data=FATAL_ERROR) as path: + err = GuestAgentError(path.name) + self.assertTrue(err.is_blacklisted) + self.assertFalse(err.is_sentinel) + def test_load_preserves_error_state(self): with self.get_error_file(error_data=WITH_ERROR) as path: err = GuestAgentError(path.name) @@ -274,15 +368,6 @@ class TestGuestAgentError(UpdateTestCase): # 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): @@ -334,6 +419,9 @@ class TestGuestAgent(UpdateTestCase): self.assertEqual(get_agent_name(), agent.name) self.assertEqual(get_agent_version(), agent.version) + self.assertFalse(agent.is_test) + self.assertFalse(agent.in_slice) + self.assertEqual(self.agent_path, agent.get_agent_dir()) path = os.path.join(self.agent_path, AGENT_MANIFEST_FILE) @@ -403,6 +491,48 @@ class TestGuestAgent(UpdateTestCase): self.assertTrue(agent.is_downloaded) return + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + def test_is_test(self, mock_dist): + self.expand_agents(mark_test=True) + agent = GuestAgent(path=self.agent_path) + + self.assertTrue(agent.is_blacklisted) + self.assertTrue(agent.is_test) + + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + @patch('azurelinuxagent.ga.update.datetime') + def test_in_slice(self, mock_dt, mock_dist): + self.expand_agents(mark_test=True) + agent = GuestAgent(path=self.agent_path) + + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + self.assertTrue(agent.in_slice) + + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 42)) + self.assertFalse(agent.in_slice) + + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + @patch('azurelinuxagent.ga.update.datetime') + def test_enable(self, mock_dt, mock_dist): + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + + self.expand_agents(mark_test=True) + agent = GuestAgent(path=self.agent_path) + + self.assertTrue(agent.is_blacklisted) + self.assertTrue(agent.is_test) + self.assertTrue(agent.in_slice) + + agent.enable() + + self.assertFalse(agent.is_blacklisted) + self.assertFalse(agent.is_test) + + # Ensure the new state is preserved to disk + agent = GuestAgent(path=self.agent_path) + self.assertFalse(agent.is_blacklisted) + self.assertFalse(agent.is_test) + @patch("azurelinuxagent.ga.update.GuestAgent._ensure_downloaded") def test_mark_failure(self, mock_ensure): agent = GuestAgent(path=self.agent_path) @@ -933,6 +1063,14 @@ class TestUpdate(UpdateTestCase): self.assertEqual("1250_waagent.pid", os.path.basename(pid_file)) return + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + @patch('azurelinuxagent.ga.update.datetime') + def test_get_test_agent(self, mock_dt, mock_dist): + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + self.prepare_agent(AGENT_VERSION, mark_test=True) + + self.assertNotEqual(None, self.update_handler.get_test_agent()) + def test_is_clean_start_returns_true_when_no_sentinal(self): self.assertFalse(os.path.isfile(self.update_handler._sentinal_file_path())) self.assertTrue(self.update_handler._is_clean_start) @@ -972,27 +1110,27 @@ class TestUpdate(UpdateTestCase): self.assertTrue(self.update_handler._is_orphaned) return - def test_load_agents(self): + def test_find_agents(self): self.prepare_agents() self.assertTrue(0 <= len(self.update_handler.agents)) - self.update_handler._load_agents() + self.update_handler._find_agents() self.assertEqual(len(get_agents(self.tmp_dir)), len(self.update_handler.agents)) return - def test_load_agents_does_reload(self): + def test_find_agents_does_reload(self): self.prepare_agents() - self.update_handler._load_agents() + self.update_handler._find_agents() agents = self.update_handler.agents - self.update_handler._load_agents() + self.update_handler._find_agents() self.assertNotEqual(agents, self.update_handler.agents) return - def test_load_agents_sorts(self): + def test_find_agents_sorts(self): self.prepare_agents() - self.update_handler._load_agents() + self.update_handler._find_agents() v = FlexibleVersion("100000") for a in self.update_handler.agents: @@ -1002,7 +1140,7 @@ class TestUpdate(UpdateTestCase): def test_purge_agents(self): self.prepare_agents() - self.update_handler._load_agents() + self.update_handler._find_agents() # Ensure at least three agents initially exist self.assertTrue(2 < len(self.update_handler.agents)) @@ -1014,7 +1152,7 @@ class TestUpdate(UpdateTestCase): # 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.update_handler._find_agents() self.assertEqual( [agent.version for agent in kept_agents], [agent.version for agent in self.update_handler.agents]) @@ -1032,7 +1170,7 @@ class TestUpdate(UpdateTestCase): self.assertTrue(os.path.exists(agent_path + ".zip")) return - def _test_run_latest(self, mock_child=None, mock_time=None): + def _test_run_latest(self, mock_child=None, mock_time=None, child_args=None): if mock_child is None: mock_child = ChildMock() if mock_time is None: @@ -1041,7 +1179,7 @@ class TestUpdate(UpdateTestCase): with patch('subprocess.Popen', return_value=mock_child) as mock_popen: with patch('time.time', side_effect=mock_time.time): with patch('time.sleep', side_effect=mock_time.sleep): - self.update_handler.run_latest() + self.update_handler.run_latest(child_args=child_args) self.assertEqual(1, mock_popen.call_count) return mock_popen.call_args @@ -1051,16 +1189,32 @@ class TestUpdate(UpdateTestCase): agent = self.update_handler.get_latest_agent() args, kwargs = self._test_run_latest() + args = args[0] cmds = textutil.safe_shlex_split(agent.get_agent_cmd()) if cmds[0].lower() == "python": cmds[0] = get_python_cmd() - self.assertEqual(args[0], cmds) + self.assertEqual(args, cmds) + self.assertTrue(len(args) > 1) + self.assertTrue(args[0].startswith("python")) + self.assertEqual("-run-exthandlers", args[len(args)-1]) self.assertEqual(True, 'cwd' in kwargs) self.assertEqual(agent.get_agent_dir(), kwargs['cwd']) self.assertEqual(False, '\x00' in cmds[0]) return + def test_run_latest_passes_child_args(self): + self.prepare_agents() + + agent = self.update_handler.get_latest_agent() + args, kwargs = self._test_run_latest(child_args="AnArgument") + args = args[0] + + self.assertTrue(len(args) > 1) + self.assertTrue(args[0].startswith("python")) + self.assertEqual("AnArgument", args[len(args)-1]) + 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) @@ -1147,7 +1301,8 @@ class TestUpdate(UpdateTestCase): with patch('azurelinuxagent.ga.update.UpdateHandler.get_latest_agent', return_value=latest_agent): self._test_run_latest(mock_child=ChildMock(return_value=1)) - self.assertTrue(latest_agent.is_available) + self.assertTrue(latest_agent.is_blacklisted) + self.assertFalse(latest_agent.is_available) self.assertNotEqual(0.0, latest_agent.error.last_failure) self.assertEqual(1, latest_agent.error.failure_count) return @@ -1198,8 +1353,6 @@ class TestUpdate(UpdateTestCase): self.update_handler.running = False return - calls = calls * invocations - fileutil.write_file(conf.get_agent_pid_file_path(), ustr(42)) with patch('azurelinuxagent.ga.exthandlers.get_exthandlers_handler') as mock_handler: @@ -1227,13 +1380,30 @@ class TestUpdate(UpdateTestCase): return def test_run_keeps_running(self): - self._test_run(invocations=15) + self._test_run(invocations=15, calls=[call.run()]*15) return def test_run_stops_if_update_available(self): self.update_handler._upgrade_available = Mock(return_value=True) self._test_run(invocations=0, calls=[], enable_updates=True) return + + @patch('platform.linux_distribution', return_value=['Ubuntu', '16.10', 'yakkety']) + @patch('azurelinuxagent.ga.update.datetime') + def test_run_stops_if_test_agent_available(self, mock_dt, mock_dist): + mock_dt.utcnow = Mock(return_value=datetime(2017, 1, 1, 0, 0, 5)) + self.prepare_agent(AGENT_VERSION, mark_test=True) + + agent = GuestAgent(path=self.agent_dir(AGENT_VERSION)) + agent.enable = Mock() + self.assertTrue(agent.is_test) + self.assertTrue(agent.in_slice) + + with patch('azurelinuxagent.ga.update.UpdateHandler.get_test_agent', + return_value=agent) as mock_test: + self._test_run(invocations=0) + self.assertEqual(mock_test.call_count, 1) + self.assertEqual(agent.enable.call_count, 1) def test_run_stops_if_orphaned(self): with patch('os.getppid', return_value=1): @@ -1417,6 +1587,5 @@ class TimeMock(Mock): self.next_time += self.time_increment return current_time - if __name__ == '__main__': unittest.main() diff --git a/tests/pa/test_deprovision.py b/tests/pa/test_deprovision.py index be34915..c4cd9b4 100644 --- a/tests/pa/test_deprovision.py +++ b/tests/pa/test_deprovision.py @@ -15,11 +15,117 @@ # Requires Python 2.4+ and Openssl 1.0+ # -from tests.tools import * +import tempfile + +import azurelinuxagent.common.utils.fileutil as fileutil + from azurelinuxagent.pa.deprovision import get_deprovision_handler +from azurelinuxagent.pa.deprovision.default import DeprovisionHandler +from tests.tools import * class TestDeprovision(AgentTestCase): + @patch("azurelinuxagent.pa.deprovision.default.DeprovisionHandler.cloud_init_dirs") + @patch("azurelinuxagent.pa.deprovision.default.DeprovisionHandler.cloud_init_files") + def test_del_cloud_init_without_once(self, + mock_files, + mock_dirs): + deprovision_handler = get_deprovision_handler("","","") + deprovision_handler.del_cloud_init([], [], include_once=False) + + mock_dirs.assert_called_with(include_once=False) + mock_files.assert_called_with(include_once=False) + + @patch("signal.signal") + @patch("azurelinuxagent.common.protocol.get_protocol_util") + @patch("azurelinuxagent.common.osutil.get_osutil") + @patch("azurelinuxagent.pa.deprovision.default.DeprovisionHandler.cloud_init_dirs") + @patch("azurelinuxagent.pa.deprovision.default.DeprovisionHandler.cloud_init_files") + def test_del_cloud_init(self, + mock_files, + mock_dirs, + mock_osutil, + mock_util, + mock_signal): + try: + with tempfile.NamedTemporaryFile() as f: + warnings = [] + actions = [] + + dirs = [tempfile.mkdtemp()] + mock_dirs.return_value = dirs + + files = [f.name] + mock_files.return_value = files + + deprovision_handler = get_deprovision_handler("","","") + deprovision_handler.del_cloud_init(warnings, actions) + + mock_dirs.assert_called_with(include_once=True) + mock_files.assert_called_with(include_once=True) + + self.assertEqual(len(warnings), 0) + self.assertEqual(len(actions), 2) + for da in actions: + if da.func == fileutil.rm_dirs: + self.assertEqual(da.args, dirs) + elif da.func == fileutil.rm_files: + self.assertEqual(da.args, files) + else: + self.assertTrue(False) + + try: + for da in actions: + da.invoke() + self.assertEqual(len([d for d in dirs if os.path.isdir(d)]), 0) + self.assertEqual(len([f for f in files if os.path.isfile(f)]), 0) + except Exception as e: + self.assertTrue(False, "Exception {0}".format(e)) + except OSError: + # Ignore the error caused by removing the file within the "with" + pass + + @distros("ubuntu") + @patch('azurelinuxagent.common.conf.get_lib_dir') + def test_del_lib_dir_files(self, + distro_name, + distro_version, + distro_full_name, + mock_conf): + files = [ + 'HostingEnvironmentConfig.xml', + 'Incarnation', + 'Protocol', + 'SharedConfig.xml', + 'WireServerEndpoint', + 'Extensions.1.xml', + 'ExtensionsConfig.1.xml', + 'GoalState.1.xml', + 'Extensions.2.xml', + 'ExtensionsConfig.2.xml', + 'GoalState.2.xml' + ] + + tmp = tempfile.mkdtemp() + mock_conf.return_value = tmp + for f in files: + fileutil.write_file(os.path.join(tmp, f), "Value") + + deprovision_handler = get_deprovision_handler(distro_name, + distro_version, + distro_full_name) + warnings = [] + actions = [] + deprovision_handler.del_lib_dir_files(warnings, actions) + + self.assertTrue(len(warnings) == 0) + self.assertTrue(len(actions) == 1) + self.assertEqual(fileutil.rm_files, actions[0].func) + self.assertTrue(len(actions[0].args) > 0) + for f in actions[0].args: + self.assertTrue(os.path.basename(f) in files) + + @distros("redhat") def test_deprovision(self, distro_name, diff --git a/tests/pa/test_provision.py b/tests/pa/test_provision.py index a98eacd..0446442 100644 --- a/tests/pa/test_provision.py +++ b/tests/pa/test_provision.py @@ -16,17 +16,22 @@ # import azurelinuxagent.common.utils.fileutil as fileutil + +from azurelinuxagent.common.exception import ProtocolError from azurelinuxagent.common.osutil.default import DefaultOSUtil from azurelinuxagent.common.protocol import OVF_FILE_NAME from azurelinuxagent.pa.provision import get_provision_handler +from azurelinuxagent.pa.provision.default import ProvisionHandler from tests.tools import * class TestProvision(AgentTestCase): @distros("redhat") - def test_provision(self, distro_name, distro_version, distro_full_name): - provision_handler = get_provision_handler(distro_name, distro_version, + @patch('azurelinuxagent.common.osutil.default.DefaultOSUtil.get_instance_id', + return_value='B9F3C233-9913-9F42-8EB3-BA656DF32502') + def test_provision(self, mock_util, distro_name, distro_version, distro_full_name): + provision_handler = get_provision_handler(distro_name, distro_version, distro_full_name) mock_osutil = MagicMock() mock_osutil.decode_customdata = Mock(return_value="") @@ -48,6 +53,45 @@ class TestProvision(AgentTestCase): data = DefaultOSUtil().decode_customdata(base64data) fileutil.write_file(tempfile.mktemp(), data) + @patch('os.path.isfile', return_value=False) + def test_is_provisioned_not_provisioned(self, mock_isfile): + ph = ProvisionHandler() + self.assertFalse(ph.is_provisioned()) + + @patch('os.path.isfile', return_value=True) + @patch('azurelinuxagent.common.utils.fileutil.read_file', + return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502") + @patch('azurelinuxagent.pa.deprovision.get_deprovision_handler') + def test_is_provisioned_is_provisioned(self, + mock_deprovision, mock_read, mock_isfile): + ph = ProvisionHandler() + ph.osutil = Mock() + ph.osutil.get_instance_id = \ + Mock(return_value="B9F3C233-9913-9F42-8EB3-BA656DF32502") + ph.write_provisioned = Mock() + + deprovision_handler = Mock() + mock_deprovision.return_value = deprovision_handler + + self.assertTrue(ph.is_provisioned()) + deprovision_handler.run_changed_unique_id.assert_not_called() + + @patch('os.path.isfile', return_value=True) + @patch('azurelinuxagent.common.utils.fileutil.read_file', + side_effect=["Value"]) + @patch('azurelinuxagent.pa.deprovision.get_deprovision_handler') + def test_is_provisioned_not_deprovisioned(self, + mock_deprovision, mock_read, mock_isfile): + + ph = ProvisionHandler() + ph.osutil = Mock() + ph.write_provisioned = Mock() + + deprovision_handler = Mock() + mock_deprovision.return_value = deprovision_handler + + self.assertTrue(ph.is_provisioned()) + deprovision_handler.run_changed_unique_id.assert_called_once() if __name__ == '__main__': unittest.main() diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py index c789de5..4e45623 100644 --- a/tests/protocol/mockwiredata.py +++ b/tests/protocol/mockwiredata.py @@ -30,7 +30,7 @@ DATA_FILE = { "ga_manifest" : "wire/ga_manifest.xml", "trans_prv": "wire/trans_prv", "trans_cert": "wire/trans_cert", - "test_ext": "ext/sample_ext.zip" + "test_ext": "ext/sample_ext-1.2.0.zip" } DATA_FILE_NO_EXT = DATA_FILE.copy() diff --git a/tests/protocol/test_hostplugin.py b/tests/protocol/test_hostplugin.py index ef91998..e203615 100644 --- a/tests/protocol/test_hostplugin.py +++ b/tests/protocol/test_hostplugin.py @@ -33,6 +33,7 @@ import azurelinuxagent.common.protocol.wire as wire import azurelinuxagent.common.protocol.hostplugin as hostplugin from azurelinuxagent.common import event +from azurelinuxagent.common.exception import ProtocolError, HttpError from azurelinuxagent.common.protocol.hostplugin import API_VERSION from azurelinuxagent.common.utils import restutil @@ -128,8 +129,10 @@ class TestHostPlugin(AgentTestCase): wire_protocol_client.get_goal_state = Mock(return_value=test_goal_state) wire_protocol_client.ext_conf = wire.ExtensionsConfig(None) wire_protocol_client.ext_conf.status_upload_blob = sas_url + wire_protocol_client.ext_conf.status_upload_blob_type = page_blob_type wire_protocol_client.status_blob.set_vm_status(status) wire_protocol_client.upload_status_blob() + self.assertEqual(patch_upload.call_count, 1) self.assertTrue(patch_put.call_count == 1, "Fallback was not engaged") self.assertTrue(patch_put.call_args[0][0] == sas_url) @@ -156,6 +159,7 @@ class TestHostPlugin(AgentTestCase): client.get_goal_state = Mock(return_value=test_goal_state) client.ext_conf = wire.ExtensionsConfig(None) client.ext_conf.status_upload_blob = sas_url + client.ext_conf.status_upload_blob_type = page_blob_type client.status_blob.set_vm_status(status) client.upload_status_blob() self.assertTrue(patch_put.call_count == 1, diff --git a/tests/protocol/test_metadata.py b/tests/protocol/test_metadata.py index f390f7a..ee4ba3e 100644 --- a/tests/protocol/test_metadata.py +++ b/tests/protocol/test_metadata.py @@ -15,14 +15,23 @@ # Requires Python 2.4+ and Openssl 1.0+ # -from tests.tools import * -from tests.protocol.mockmetadata import * +import json + +from azurelinuxagent.common.future import ustr + from azurelinuxagent.common.utils.restutil import httpclient -from azurelinuxagent.common.protocol.metadata import MetadataProtocol +from azurelinuxagent.common.protocol.metadata import * +from azurelinuxagent.common.protocol.restapi import * + +from tests.protocol.mockmetadata import * +from tests.tools import * -@patch("time.sleep") -@patch("azurelinuxagent.common.protocol.metadata.restutil") class TestMetadataProtocolGetters(AgentTestCase): + def load_json(self, path): + return json.loads(ustr(load_data(path)), encoding="utf-8") + + @patch("time.sleep") + @patch("azurelinuxagent.common.protocol.metadata.restutil") def _test_getters(self, test_data, mock_restutil ,_): mock_restutil.http_get.side_effect = test_data.mock_http_get @@ -43,3 +52,108 @@ class TestMetadataProtocolGetters(AgentTestCase): self._test_getters(test_data, *args) + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol.update_goal_state") + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol._get_data") + def test_get_vmagents_manifests(self, mock_get, mock_update): + data = self.load_json("metadata/vmagent_manifests.json") + mock_get.return_value = data, 42 + + protocol = MetadataProtocol() + manifests, etag = protocol.get_vmagent_manifests() + + self.assertEqual(mock_update.call_count, 1) + self.assertEqual(mock_get.call_count, 1) + + manifests_uri = BASE_URI.format( + METADATA_ENDPOINT, + "vmAgentVersions", + APIVERSION) + self.assertEqual(mock_get.call_args[0][0], manifests_uri) + + self.assertEqual(etag, 42) + self.assertNotEqual(None, manifests) + self.assertEqual(len(manifests.vmAgentManifests), 1) + + manifest = manifests.vmAgentManifests[0] + self.assertEqual(manifest.family, conf.get_autoupdate_gafamily()) + self.assertEqual(len(manifest.versionsManifestUris), 2) + + # Same etag returns the same data + data = self.load_json("metadata/vmagent_manifests_invalid1.json") + mock_get.return_value = data, 42 + next_manifests, etag = protocol.get_vmagent_manifests() + + self.assertEqual(etag, 42) + self.assertEqual(manifests, next_manifests) + + # New etag returns new data + mock_get.return_value = data, 43 + self.assertRaises(ProtocolError, protocol.get_vmagent_manifests) + + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol.update_goal_state") + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol._get_data") + def test_get_vmagents_manifests_raises(self, mock_get, mock_update): + data = self.load_json("metadata/vmagent_manifests_invalid1.json") + mock_get.return_value = data, 42 + + protocol = MetadataProtocol() + self.assertRaises(ProtocolError, protocol.get_vmagent_manifests) + + data = self.load_json("metadata/vmagent_manifests_invalid2.json") + mock_get.return_value = data, 43 + self.assertRaises(ProtocolError, protocol.get_vmagent_manifests) + + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol.update_goal_state") + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol._get_data") + def test_get_vmagent_pkgs(self, mock_get, mock_update): + data = self.load_json("metadata/vmagent_manifests.json") + mock_get.return_value = data, 42 + + protocol = MetadataProtocol() + manifests, etag = protocol.get_vmagent_manifests() + manifest = manifests.vmAgentManifests[0] + + data = self.load_json("metadata/vmagent_manifest1.json") + mock_get.return_value = data, 42 + pkgs = protocol.get_vmagent_pkgs(manifest) + + self.assertNotEqual(None, pkgs) + self.assertEqual(len(pkgs.versions), 2) + + for pkg in pkgs.versions: + self.assertNotEqual(None, pkg.version) + self.assertTrue(len(pkg.uris) > 0) + + for uri in pkg.uris: + self.assertTrue(uri.uri.endswith("zip")) + + @patch("azurelinuxagent.common.protocol.metadata.MetadataProtocol._post_data") + def test_report_event(self, mock_post): + events = TelemetryEventList() + + data = self.load_json("events/1478123456789000.tld") + event = TelemetryEvent() + set_properties("event", event, data) + events.events.append(event) + + data = self.load_json("events/1478123456789001.tld") + event = TelemetryEvent() + set_properties("event", event, data) + events.events.append(event) + + data = self.load_json("events/1479766858966718.tld") + event = TelemetryEvent() + set_properties("event", event, data) + events.events.append(event) + + protocol = MetadataProtocol() + protocol.report_event(events) + + events_uri = BASE_URI.format( + METADATA_ENDPOINT, + "status/telemetry", + APIVERSION) + + self.assertEqual(mock_post.call_count, 1) + self.assertEqual(mock_post.call_args[0][0], events_uri) + self.assertEqual(mock_post.call_args[0][1], get_properties(events)) diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index dda7a2b..ba9fc7d 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -152,11 +152,12 @@ class TestWireProtocolGetters(AgentTestCase): wire_protocol_client = WireProtocol(wireserver_url).client wire_protocol_client.ext_conf = ExtensionsConfig(None) wire_protocol_client.ext_conf.status_upload_blob = testurl + wire_protocol_client.ext_conf.status_upload_blob_type = testtype wire_protocol_client.status_blob.vm_status = vmstatus with patch.object(WireClient, "get_goal_state") as patch_get_goal_state: with patch.object(HostPluginProtocol, "put_vm_status") as patch_host_ga_plugin_upload: - with patch.object(StatusBlob, "upload", return_value=True) as patch_default_upload: + with patch.object(StatusBlob, "upload") as patch_default_upload: HostPluginProtocol.set_default_channel(False) wire_protocol_client.upload_status_blob() @@ -190,7 +191,25 @@ class TestWireProtocolGetters(AgentTestCase): self.assertTrue(HostPluginProtocol.is_default_channel()) HostPluginProtocol.set_default_channel(False) - def test_upload_status_blob_error_reporting(self, *args): + def test_upload_status_blob_unknown_type_assumes_block(self, *args): + vmstatus = VMStatus(message="Ready", status="Ready") + wire_protocol_client = WireProtocol(wireserver_url).client + wire_protocol_client.ext_conf = ExtensionsConfig(None) + wire_protocol_client.ext_conf.status_upload_blob = testurl + wire_protocol_client.ext_conf.status_upload_blob_type = "NotALegalType" + wire_protocol_client.status_blob.vm_status = vmstatus + + with patch.object(WireClient, "get_goal_state") as patch_get_goal_state: + with patch.object(StatusBlob, "prepare") as patch_prepare: + with patch.object(StatusBlob, "upload") as patch_default_upload: + HostPluginProtocol.set_default_channel(False) + wire_protocol_client.upload_status_blob() + + patch_prepare.assert_called_once_with("BlockBlob") + patch_default_upload.assert_called_once_with(testurl) + patch_get_goal_state.assert_not_called() + + def test_upload_status_blob_reports_prepare_error(self, *args): vmstatus = VMStatus(message="Ready", status="Ready") wire_protocol_client = WireProtocol(wireserver_url).client wire_protocol_client.ext_conf = ExtensionsConfig(None) @@ -199,29 +218,13 @@ class TestWireProtocolGetters(AgentTestCase): wire_protocol_client.status_blob.vm_status = vmstatus goal_state = GoalState(WireProtocolData(DATA_FILE).goal_state) - with patch.object(HostPluginProtocol, - "ensure_initialized", - return_value=True): - with patch.object(StatusBlob, - "put_block_blob", - side_effect=HttpError("error")): - with patch.object(StatusBlob, - "get_blob_type", - return_value='BlockBlob'): - with patch.object(HostPluginProtocol, - "put_vm_status"): - with patch.object(WireClient, - "report_blob_type", - side_effect=MagicMock()): - with patch.object(event, - "add_event") as patch_add_event: - HostPluginProtocol.set_default_channel(False) - wire_protocol_client.get_goal_state = Mock(return_value=goal_state) - wire_protocol_client.upload_status_blob() - wire_protocol_client.get_goal_state.assert_called_once() - self.assertTrue(patch_add_event.call_count == 1) - self.assertTrue(patch_add_event.call_args_list[0][1]['op'] == 'ReportStatus') - self.assertFalse(HostPluginProtocol.is_default_channel()) + with patch.object(StatusBlob, "prepare", + side_effect=Exception) as mock_prepare: + with patch.object(WireClient, "report_status_event") as mock_event: + wire_protocol_client.upload_status_blob() + + mock_prepare.assert_called_once() + mock_event.assert_called_once() def test_get_in_vm_artifacts_profile_blob_not_available(self, *args): wire_protocol_client = WireProtocol(wireserver_url).client diff --git a/tests/test_agent.py b/tests/test_agent.py new file mode 100644 index 0000000..1b35933 --- /dev/null +++ b/tests/test_agent.py @@ -0,0 +1,92 @@ +# 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 os.path + +from azurelinuxagent.agent import * +from azurelinuxagent.common.conf import * + +from tests.tools import * + + +class TestAgent(AgentTestCase): + + def test_accepts_configuration_path(self): + conf_path = os.path.join(data_dir, "test_waagent.conf") + c, f, v, cfp = parse_args(["-configuration-path:" + conf_path]) + self.assertEqual(cfp, conf_path) + + @patch("os.path.exists", return_value=True) + def test_checks_configuration_path(self, mock_exists): + conf_path = "/foo/bar-baz/something.conf" + c, f, v, cfp = parse_args(["-configuration-path:"+conf_path]) + self.assertEqual(cfp, conf_path) + self.assertEqual(mock_exists.call_count, 1) + + @patch("sys.stderr") + @patch("os.path.exists", return_value=False) + @patch("sys.exit", side_effect=Exception) + def test_rejects_missing_configuration_path(self, mock_exit, mock_exists, mock_stderr): + try: + c, f, v, cfp = parse_args(["-configuration-path:/foo/bar.conf"]) + self.assertTrue(False) + except Exception: + self.assertEqual(mock_exit.call_count, 1) + + def test_configuration_path_defaults_to_none(self): + c, f, v, cfp = parse_args([]) + self.assertEqual(cfp, None) + + def test_agent_accepts_configuration_path(self): + Agent(False, + conf_file_path=os.path.join(data_dir, "test_waagent.conf")) + self.assertTrue(conf.get_fips_enabled()) + + @patch("azurelinuxagent.common.conf.load_conf_from_file") + def test_agent_uses_default_configuration_path(self, mock_load): + Agent(False) + mock_load.assert_called_once_with("/etc/waagent.conf") + + @patch("azurelinuxagent.daemon.get_daemon_handler") + @patch("azurelinuxagent.common.conf.load_conf_from_file") + def test_agent_does_not_pass_configuration_path(self, + mock_load, mock_handler): + + mock_daemon = Mock() + mock_daemon.run = Mock() + mock_handler.return_value = mock_daemon + + agent = Agent(False) + agent.daemon() + + mock_daemon.run.assert_called_once_with(child_args=None) + mock_load.assert_called_once() + + @patch("azurelinuxagent.daemon.get_daemon_handler") + @patch("azurelinuxagent.common.conf.load_conf_from_file") + def test_agent_passes_configuration_path(self, mock_load, mock_handler): + + mock_daemon = Mock() + mock_daemon.run = Mock() + mock_handler.return_value = mock_daemon + + agent = Agent(False, conf_file_path="/foo/bar.conf") + agent.daemon() + + mock_daemon.run.assert_called_once_with(child_args="-configuration-path:/foo/bar.conf") + mock_load.assert_called_once() diff --git a/tests/utils/test_file_util.py b/tests/utils/test_file_util.py index 76fb15b..0b92513 100644 --- a/tests/utils/test_file_util.py +++ b/tests/utils/test_file_util.py @@ -15,9 +15,14 @@ # Requires Python 2.4+ and Openssl 1.0+ # +import glob +import random +import string +import tempfile import uuid import azurelinuxagent.common.utils.fileutil as fileutil + from azurelinuxagent.common.future import ustr from tests.tools import * @@ -69,9 +74,6 @@ class TestFileOperations(AgentTestCase): self.assertEquals('abc', filename) def test_remove_files(self): - import random - import string - import glob random_word = lambda : ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5)) #Create 10 test files @@ -90,9 +92,27 @@ class TestFileOperations(AgentTestCase): self.assertEqual(0, len(glob.glob(os.path.join(self.tmp_dir, test_file_pattern)))) self.assertEqual(0, len(glob.glob(os.path.join(self.tmp_dir, test_file_pattern2)))) + def test_remove_dirs(self): + dirs = [] + for n in range(0,5): + dirs.append(tempfile.mkdtemp()) + for d in dirs: + for n in range(0, random.choice(range(0,10))): + fileutil.write_file(os.path.join(d, "test"+str(n)), "content") + for n in range(0, random.choice(range(0,10))): + dd = os.path.join(d, "testd"+str(n)) + os.mkdir(dd) + for nn in range(0, random.choice(range(0,10))): + os.symlink(dd, os.path.join(dd, "sym"+str(nn))) + for n in range(0, random.choice(range(0,10))): + os.symlink(d, os.path.join(d, "sym"+str(n))) + + fileutil.rm_dirs(*dirs) + + for d in dirs: + self.assertEqual(len(os.listdir(d)), 0) + def test_get_all_files(self): - import random - import string random_word = lambda: ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5)) # Create 10 test files at the root dir and 10 other in the sub dir |