# Copyright 2016 Google Inc. All Rights Reserved. # # 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. """Tests for glazier.lib.actions.files.""" from absl.testing import absltest from pyfakefs import fake_filesystem from pyfakefs import fake_filesystem_shutil from glazier.lib import buildinfo from glazier.lib.actions import files import mock class FilesTest(absltest.TestCase): def setUp(self): super(FilesTest, self).setUp() self.filesystem = fake_filesystem.FakeFilesystem() files.open = fake_filesystem.FakeFileOpen(self.filesystem) files.file_util.shutil = fake_filesystem_shutil.FakeShutilModule( self.filesystem) files.WindowsError = Exception # TODO: Split into separate tests. @mock.patch.object(files.execute, 'execute_binary', autospec=True) @mock.patch.object(files.shlex, 'split', autospec=True) @mock.patch.object(files.cache.Cache, 'CacheFromLine', autospec=True) def testExecute(self, cache, split, eb): bi = buildinfo.BuildInfo() cache.side_effect = iter(['cmd.exe /c', 'explorer.exe']) eb.return_value = 0 e = files.Execute([['cmd.exe /c', [0]], ['explorer.exe']], bi) e.Run() self.assertTrue(split.called) # success codes cache.side_effect = None cache.return_value = 'cmd.exe /c script.bat' e = files.Execute([['cmd.exe /c script.bat', [2, 4]]], bi) with self.assertRaises(files.ActionError): e.Run() eb.return_value = 4 e.Run() # reboot codes - no retry e = files.Execute([['cmd.exe /c script.bat', [0], [2, 4]]], bi) with self.assertRaises(files.RestartEvent) as cm: e.Run() exception = cm.exception self.assertEqual(exception.retry_on_restart, False) # reboot codes - retry e = files.Execute([['cmd.exe /c #script.bat', [0], [2, 4], True]], bi) with self.assertRaises(files.RestartEvent) as cm: e.Run() exception = cm.exception self.assertEqual(exception.retry_on_restart, True) cache.assert_called_with(mock.ANY, 'cmd.exe /c #script.bat', bi) # Shell files.Execute([['cmd.exe /c #script.bat', [4], [0], True, True]], bi).Run() eb.assert_called_with(mock.ANY, mock.ANY, [4, 0], shell=True) # KeyboardInterrupt eb.side_effect = KeyboardInterrupt with self.assertRaises(files.ActionError): e.Run() # Execute Error eb.side_effect = files.execute.Error with self.assertRaises(files.ActionError): e.Run() # ValueError split.side_effect = ValueError with self.assertRaises(files.ActionError): e.Run() # Cache error cache.side_effect = files.cache.CacheError with self.assertRaises(files.ActionError): e.Run() # TODO: Paramaterize and add cm for these tests (go/pytotw/011). def testExecuteValidation(self): e = files.Execute([['cmd.exe', [0], [2], False], ['explorer.exe']], None) e.Validate() e = files.Execute([[]], None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute(['explorer.exe'], None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute('explorer.exe', None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute([['cmd.exe', [0]], ['explorer.exe', '0']], None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute([['cmd.exe', [0]], ['explorer.exe', ['0']]], None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute([['cmd.exe', [0], ['2']], ['explorer.exe']], None) self.assertRaises(files.ValidationError, e.Validate) e = files.Execute([['cmd.exe', [0], [2], 'True'], ['explorer.exe']], None) self.assertRaises(files.ValidationError, e.Validate) with self.assertRaises(files.ValidationError): files.Execute([['cmd.exe', [0], [2], False, 'True'], ['explorer.exe']], None).Validate() @mock.patch.object(buildinfo.BuildInfo, 'ReleasePath', autospec=True) @mock.patch.object(files.download.Download, 'DownloadFile', autospec=True) @mock.patch.object(files.download.Download, 'VerifyShaHash', autospec=True) def testGet(self, verify, down_file, r_path): bi = buildinfo.BuildInfo() r_path.return_value = 'https://glazier-server.example.com/' remote = '@glazier/1.0/autobuild.par' local = r'/tmp/autobuild.par' test_sha256 = ( '58157bf41ce54731c0577f801035d47ec20ed16a954f10c29359b8adedcae800') self.filesystem.CreateFile( r'/tmp/autobuild.par.sha256', contents=test_sha256) down_file.return_value = True conf = [[remote, local]] g = files.Get(conf, bi) g.Run() down_file.assert_called_with( mock.ANY, 'https://glazier-server.example.com/bin/glazier/1.0/autobuild.par', local, show_progress=True) # Relative Paths conf = [['autobuild.bat', '/tmp/autobuild.bat']] g = files.Get(conf, bi) g.Run() down_file.assert_called_with( mock.ANY, 'https://glazier-server.example.com/autobuild.bat', '/tmp/autobuild.bat', show_progress=True) down_file.return_value = None # DownloadError err = files.download.DownloadError('Error') down_file.side_effect = err g = files.Get([[remote, local]], bi) self.assertRaises(files.ActionError, g.Run) down_file.side_effect = None # file_util.Error self.filesystem.CreateFile('/directory') g = files.Get([[remote, '/directory/file.txt']], bi) self.assertRaises(files.ActionError, g.Run) # good hash verify.return_value = True g = files.Get([[remote, local, test_sha256]], bi) g.Run() verify.assert_called_with(mock.ANY, local, test_sha256) # bad hash verify.return_value = False g = files.Get([[remote, local, test_sha256]], bi) self.assertRaises(files.ActionError, g.Run) # none hash verify.reset_mock() conf = [[remote, local, '']] g = files.Get(conf, bi) g.Run() self.assertFalse(verify.called) def testGetValidate(self): g = files.Get('String', None) self.assertRaises(files.ValidationError, g.Validate) g = files.Get([[1, 2, 3]], None) self.assertRaises(files.ValidationError, g.Validate) g = files.Get([[1, '/tmp/out/path']], None) self.assertRaises(files.ValidationError, g.Validate) g = files.Get([['/tmp/src.zip', 2]], None) self.assertRaises(files.ValidationError, g.Validate) g = files.Get([['https://glazier/bin/src.zip', '/tmp/out/src.zip']], None) g.Validate() g = files.Get( [['https://glazier/bin/src.zip', '/tmp/out/src.zip', '12345']], None) g.Validate() g = files.Get([['https://glazier/bin/src.zip', '/tmp/out/src.zip', '12345', '67890']], None) self.assertRaises(files.ValidationError, g.Validate) @mock.patch.object(files.file_util, 'CreateDirectories', autospec=True) @mock.patch('glazier.lib.buildinfo.BuildInfo', autospec=True) def testUnzip(self, build_info, create_dir): src = '/tmp/input.zip' dst = '/out/dir/path' # bad args un = files.Unzip([], build_info) self.assertRaises(files.ActionError, un.Run) un = files.Unzip([src], build_info) self.assertRaises(files.ActionError, un.Run) # bad path un = files.Unzip([src, dst], build_info) self.assertRaises(files.ActionError, un.Run) # create error create_dir.side_effect = files.file_util.Error self.assertRaises(files.ActionError, un.Run) # good create_dir.side_effect = None with mock.patch.object(files.zipfile, 'ZipFile', autospec=True) as z: un = files.Unzip([src, dst], build_info) un.Run() z.assert_called_with(src) z.return_value.extractall.assert_called_with(dst) create_dir.assert_called_with(dst) def testUnzipValidate(self): un = files.Unzip('String', None) self.assertRaises(files.ValidationError, un.Validate) un = files.Unzip([1, 2, 3], None) self.assertRaises(files.ValidationError, un.Validate) un = files.Unzip([1, '/tmp/out/path'], None) self.assertRaises(files.ValidationError, un.Validate) un = files.Unzip(['/tmp/src.zip', 2], None) self.assertRaises(files.ValidationError, un.Validate) un = files.Unzip(['/tmp/src.zip', '/tmp/out/path'], None) un.Validate() if __name__ == '__main__': absltest.main()