diff options
Diffstat (limited to 'tests/ga/test_update.py')
-rw-r--r-- | tests/ga/test_update.py | 233 |
1 files changed, 201 insertions, 32 deletions
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() |