1#!/usr/bin/python 2# Copyright 2016 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16"""Unittest for script_executor.py module.""" 17 18import stat 19 20from google_compute_engine.metadata_scripts import script_executor 21from google_compute_engine.test_compat import mock 22from google_compute_engine.test_compat import unittest 23 24 25class ScriptExecutorTest(unittest.TestCase): 26 27 def setUp(self): 28 self.script_type = 'test' 29 self.metadata_script = '/tmp/script' 30 self.mock_logger = mock.Mock() 31 self.executor = script_executor.ScriptExecutor( 32 self.mock_logger, self.script_type) 33 34 @mock.patch('google_compute_engine.metadata_scripts.script_executor.os') 35 def testMakeExecutable(self, mock_os): 36 st_mode = 1 37 chmod_mode = st_mode + stat.S_IEXEC 38 mock_os_stat = mock.Mock() 39 mock_os_stat.st_mode = st_mode 40 mock_os.stat.return_value = mock_os_stat 41 self.executor._MakeExecutable(self.metadata_script) 42 mock_os.chmod.assert_called_once_with(self.metadata_script, chmod_mode) 43 44 @mock.patch('google_compute_engine.metadata_scripts.script_executor.subprocess') 45 def testRunScript(self, mock_subprocess): 46 mock_readline = mock.Mock() 47 mock_readline.side_effect = [bytes(b'a\n'), bytes(b'b\n'), bytes(b'')] 48 mock_stdout = mock.Mock() 49 mock_stdout.readline = mock_readline 50 mock_process = mock.Mock() 51 mock_process.poll.return_value = 0 52 mock_process.stdout = mock_stdout 53 mock_process.returncode = 1 54 mock_subprocess.Popen.return_value = mock_process 55 metadata_key = '%s-script' % self.script_type 56 57 self.executor._RunScript(metadata_key, self.metadata_script) 58 expected_calls = [ 59 mock.call('%s: %s', metadata_key, 'a'), 60 mock.call('%s: %s', metadata_key, 'b'), 61 mock.call('%s: Return code %s.', metadata_key, 1), 62 ] 63 self.assertEqual(self.mock_logger.info.mock_calls, expected_calls) 64 mock_subprocess.Popen.assert_called_once_with( 65 self.metadata_script, shell=True, executable='/bin/bash', 66 stderr=mock_subprocess.STDOUT, stdout=mock_subprocess.PIPE) 67 mock_process.poll.assert_called_once_with() 68 69 def testRunScripts(self): 70 self.executor._MakeExecutable = mock.Mock() 71 self.executor._RunScript = mock.Mock() 72 mocks = mock.Mock() 73 mocks.attach_mock(self.executor._MakeExecutable, 'make_executable') 74 mocks.attach_mock(self.executor._RunScript, 'run_script') 75 mocks.attach_mock(self.mock_logger, 'logger') 76 script_dict = { 77 '%s-script' % self.script_type: 'a', 78 '%s-script-key' % self.script_type: 'b', 79 '%s-script-url' % self.script_type: 'c', 80 } 81 82 self.executor.RunScripts(script_dict) 83 expected_calls = [ 84 mock.call.make_executable('c'), 85 mock.call.run_script('%s-script-url' % self.script_type, 'c'), 86 mock.call.make_executable('a'), 87 mock.call.run_script('%s-script' % self.script_type, 'a'), 88 ] 89 self.assertEqual(mocks.mock_calls, expected_calls) 90 91 def testRunScriptsEmpty(self): 92 self.executor._MakeExecutable = mock.Mock() 93 self.executor._RunScript = mock.Mock() 94 mocks = mock.Mock() 95 mocks.attach_mock(self.executor._MakeExecutable, 'make_executable') 96 mocks.attach_mock(self.executor._RunScript, 'run_script') 97 mocks.attach_mock(self.mock_logger, 'logger') 98 script_dict = { 99 '%s-invalid' % self.script_type: 'script', 100 } 101 102 self.executor.RunScripts(script_dict) 103 expected_calls = [ 104 mock.call.logger.info(mock.ANY, self.script_type), 105 ] 106 self.assertEqual(mocks.mock_calls, expected_calls) 107 108 109if __name__ == '__main__': 110 unittest.main() 111