| # |
| # Copyright (C) 2015 The Android Open Source Project |
| # |
| # 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. |
| # |
| |
| """Unittests for classes in device.py""" |
| |
| |
| import unittest |
| |
| from bsp import device |
| from bsp import operating_system_stub |
| from bsp import package |
| from bsp import package_stub |
| from bsp import status |
| from core import util_stub |
| from test import stubs |
| |
| |
| class DeviceTest(unittest.TestCase): |
| |
| _OS_VERSION = '98.76.54' |
| _OS_PATH = '/path/to/os' |
| |
| def setUp(self): |
| self.dev_json = { |
| 'device_name': 'Test Device 1', |
| 'vendor': 'test_vendor', |
| 'arch': 'test_arch', |
| 'packages': { |
| 'package_1': { |
| 'subpackage_1': 'path/to/link' |
| } |
| } |
| } |
| self.package1 = package_stub.StubPackage( |
| 'package_1', |
| subpackages={'subpackage_1': status.INSTALLED, |
| 'subpackage_2': status.INSTALLED}, |
| licenses=['license1', 'license2']) |
| self.package2 = package_stub.StubPackage( |
| 'package_2', subpackages={'subpackage_2': status.INSTALLED}) |
| self.packages = {'package_1': self.package1, 'package_2': self.package2} |
| |
| self.stub_os = stubs.StubOs() |
| self.stub_open = stubs.StubOpen(self.stub_os) |
| self.stub_hashlib = stubs.StubHashlib() |
| self.stub_tar_package = package_stub.StubTarPackage('tarball_version') |
| self.stub_util = util_stub.StubUtil() |
| |
| device.os = self.stub_os |
| device.open = self.stub_open.open |
| device.hashlib = self.stub_hashlib |
| device.util = self.stub_util |
| device.package = package_stub.StubPackageModule(self.stub_tar_package) |
| |
| self.dev = device.Device( |
| 'test_device', 'Test Device', 'test_vendor', 'test_arch', |
| {self.package1: {'subpackage_1': 'path1', 'subpackage_2': 'path2'}, |
| self.package2: {'subpackage_2': 'path3'}}) |
| self.os_ = operating_system_stub.StubOperatingSystem( |
| root=self._OS_PATH, version=self._OS_VERSION) |
| |
| def test_init(self): |
| # Check all public attributes. |
| self.assertEqual(self.dev.name, 'test_device') |
| self.assertEqual(self.dev.full_name, 'Test Device') |
| self.assertEqual(self.dev.vendor, 'test_vendor') |
| self.assertEqual(self.dev.arch, 'test_arch') |
| self.assertEqual(self.dev.version, '0.0.0') |
| |
| def test_from_dict(self): |
| dev = device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| self.assertIsInstance(dev, device.Device) |
| # pylint: disable=protected-access |
| self.assertTrue(self.package1 in dev._package_map) |
| self.assertEqual(dev._package_map[self.package1]['subpackage_1'], |
| 'path/to/link') |
| self.assertEqual(dev.name, 'a_name') |
| self.assertEqual(dev.full_name, 'Test Device 1') |
| self.assertEqual(dev.vendor, 'test_vendor') |
| self.assertEqual(dev.arch, 'test_arch') |
| self.assertEqual(dev.version, '0.0.0') |
| |
| def test_from_dict_bad_package(self): |
| self.dev_json['packages']['nonexistent'] = {} |
| with self.assertRaisesRegexp(ValueError, |
| 'Package.*nonexistent.*does not exist'): |
| device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| |
| def test_from_dict_bad_subpackage(self): |
| self.dev_json['packages']['package_1']['nonexistent'] = {} |
| with self.assertRaisesRegexp(ValueError, |
| 'Sub.*nonexistent.*does not exist'): |
| device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| |
| def test_from_dict_missing_keys(self): |
| del self.dev_json['arch'] |
| with self.assertRaisesRegexp(KeyError, 'arch'): |
| device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| |
| self.dev_json['arch'] = 'test_arch' |
| del self.dev_json['vendor'] |
| with self.assertRaisesRegexp(KeyError, 'vendor'): |
| device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| |
| self.dev_json['vendor'] = 'test_vendor' |
| del self.dev_json['packages'] |
| with self.assertRaisesRegexp(KeyError, 'packages'): |
| device.Device.from_dict(self.dev_json, 'a_name', self.packages) |
| |
| def test_status_installed(self): |
| self.assertEqual(self.dev.status(self.os_)[0], status.INSTALLED) |
| self.assertEqual(self.dev.status()[0], status.INSTALLED) |
| |
| def test_status_linked(self): |
| self.package1.subpackages['subpackage_1'] = status.LINKED |
| self.assertEqual(self.dev.status(self.os_)[0], status.LINKED) |
| self.assertEqual(self.dev.status()[0], status.INSTALLED) |
| |
| def test_status_unrecognized(self): |
| self.package1.subpackages['subpackage_1'] = status.LINKED |
| self.package1.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| # Also test that this beats out linked. |
| self.assertEqual(self.dev.status(self.os_)[0], |
| status.UNRECOGNIZED) |
| # In certain situations, this could also be missing, but that's more |
| # complex to code into stubs. |
| self.assertEqual(self.dev.status()[0], status.INSTALLED) |
| |
| def test_status_missing(self): |
| self.package1.subpackages['subpackage_1'] = status.LINKED |
| self.package1.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| self.package2.subpackages['subpackage_2'] = status.MISSING |
| # Also test that this beats out linked and unrecognized. |
| self.assertEqual(self.dev.status()[0], status.MISSING) |
| self.assertEqual(self.dev.status(self.os_)[0], status.MISSING) |
| |
| |
| def test_status_not_installed(self): |
| self.package1.subpackages['subpackage_1'] = status.NOT_INSTALLED |
| self.package1.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| self.package2.subpackages['subpackage_2'] = status.MISSING |
| # Also test that this beats out missing and unrecognized |
| # (and transitively linked). |
| self.assertEqual(self.dev.status()[0], status.NOT_INSTALLED) |
| self.assertEqual(self.dev.status(self.os_)[0], |
| status.NOT_INSTALLED) |
| |
| def test_is_available(self): |
| self.assertTrue(self.dev.is_available()) |
| self.package2.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| self.assertTrue(self.dev.is_available()) |
| self.package2.subpackages['subpackage_2'] = status.LINKED |
| self.assertTrue(self.dev.is_available()) |
| self.package2.subpackages['subpackage_2'] = status.MISSING |
| self.assertFalse(self.dev.is_available()) |
| self.package2.subpackages['subpackage_2'] = status.NOT_INSTALLED |
| self.assertFalse(self.dev.is_available()) |
| |
| def test_link(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.should_link['subpackage_1'] = link1 |
| self.package1.should_link['subpackage_2'] = link2 |
| self.package2.should_link['subpackage_2'] = link3 |
| |
| self.dev.link(self.os_) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.LINKED) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.LINKED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_link_fail(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.should_link['subpackage_1'] = link1 |
| # Gonna be problems with package1.subpackage_2 |
| self.package2.should_link['subpackage_2'] = link3 |
| |
| with self.assertRaises(device.PackageLinkError): |
| self.dev.link(self.os_) |
| # Should still link what it can. |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.LINKED) |
| self.assertNotEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.LINKED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_link_not_downloaded(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.should_link['subpackage_1'] = link1 |
| self.package1.should_link['subpackage_2'] = link2 |
| self.package2.should_link['subpackage_2'] = link3 |
| self.package2.downloaded = False |
| |
| with self.assertRaises(device.PackageLinkError): |
| self.dev.link(self.os_) |
| # Should still link what it can. |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.LINKED) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.LINKED) |
| self.assertNotEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_link_overwrite(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.should_link['subpackage_1'] = link1 |
| self.stub_os.path.should_exist = [link2] |
| self.package2.should_link['subpackage_2'] = link3 |
| |
| # Shouldn't raise, but shouldn't link package1.subpackage_2. |
| self.dev.link(self.os_) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.LINKED) |
| self.assertNotEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.LINKED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_unlink(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.subpackages['subpackage_1'] = status.LINKED |
| self.package1.subpackages['subpackage_2'] = status.LINKED |
| self.package2.subpackages['subpackage_2'] = status.LINKED |
| self.package1.should_unlink['subpackage_1'] = link1 |
| self.package1.should_unlink['subpackage_2'] = link2 |
| self.package2.should_unlink['subpackage_2'] = link3 |
| |
| self.dev.unlink(self.os_) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.INSTALLED) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.INSTALLED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.INSTALLED) |
| |
| def test_partial_unlink(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package1.subpackages['subpackage_1'] = status.MISSING |
| self.package1.subpackages['subpackage_2'] = status.INSTALLED |
| self.package2.subpackages['subpackage_2'] = status.LINKED |
| self.package1.should_unlink['subpackage_1'] = link1 |
| self.package1.should_unlink['subpackage_2'] = link2 |
| self.package2.should_unlink['subpackage_2'] = link3 |
| |
| # Should only actually unlink package2.subpackage_2. |
| self.dev.unlink(self.os_) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.MISSING) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.INSTALLED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.INSTALLED) |
| |
| def test_failed_unlink(self): |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| self.package2.subpackages['subpackage_2'] = status.LINKED |
| |
| # Should fail to unlink package2.subpackage_2. |
| with self.assertRaises(device.PackageUnlinkError): |
| self.dev.unlink(self.os_) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.INSTALLED) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.INSTALLED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_unrecognized_paths(self): |
| self.package1.subpackages['subpackage_1'] = status.NOT_INSTALLED |
| self.package1.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| self.package2.subpackages['subpackage_2'] = status.UNRECOGNIZED |
| result = self.dev.unrecognized_paths(self.os_) |
| self.assertIn(self.os_.path('path2'), result) |
| self.assertIn(self.os_.path('path3'), result) |
| self.assertNotIn(self.os_.path('path1'), result) |
| |
| def test_match_tarball(self): |
| matching = package.TarPackage('match', None, |
| self.stub_tar_package.tarball_version, |
| None) |
| non_matching_tar = package_stub.StubPackage( |
| 'non_match', None, '<wrong_version>', None) |
| # While unlikely git and tar hashes would match, it is in theory |
| # possible. Luckily the branch:hash formulation for git versions |
| # should prevent this issue. |
| non_matching_git = package_stub.StubPackage( |
| 'git', None, '<branch>:' + self.stub_tar_package.tarball_version, |
| None) |
| dev = device.Device('name', 'full_name', 'vend', 'arch', { |
| non_matching_tar: {}, matching: {}, non_matching_git: {}}) |
| self.assertEqual(dev.match_tarball('file1'), 'match') |
| |
| def test_non_matching_tarball(self): |
| non_matching_tar = package.TarPackage( |
| 'non_match', None, '<wrong_version>', None) |
| # While unlikely git and tar hashes would match, it is in theory |
| # possible. Luckily the branch:hash formulation for git versions |
| # should prevent this issue. |
| non_matching_git = package.GitPackage( |
| 'git', None, '<branch>:<correct_version>', None) |
| self.stub_open.files = {'file1': stubs.StubFile('file1')} |
| self.stub_os.path.should_exist = ['file1'] |
| self.stub_hashlib.should_return = '<correct_version>' |
| dev = device.Device('name', 'full_name', 'vend', 'arch', |
| {non_matching_tar: {}, non_matching_git: {}}) |
| self.assertEqual(dev.match_tarball('file1'), None) |
| |
| def test_install(self): |
| self.package1.downloaded = False |
| self.package2.downloaded = False |
| self.package1.should_download = True |
| self.package2.should_download = True |
| |
| self.assertFalse(self.dev.is_available()) |
| self.dev.install(auto_accept=True) |
| self.assertTrue(self.dev.is_available()) |
| |
| def test_partial_install_with_link(self): |
| self.package1.downloaded = True |
| self.package2.downloaded = False |
| link1 = self.os_.path('path1') |
| link2 = self.os_.path('path2') |
| link3 = self.os_.path('path3') |
| |
| self.package1.should_link['subpackage_1'] = link1 |
| self.package1.should_link['subpackage_2'] = link2 |
| self.package2.should_link['subpackage_2'] = link3 |
| # Package 1 is already downloaded. But it will still link. |
| self.package1.should_download = False |
| self.package2.should_download = True |
| |
| self.assertFalse(self.dev.is_available()) |
| self.dev.install(auto_accept=True, link_os=self.os_) |
| self.assertTrue(self.dev.is_available()) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_1', link1)[0], status.LINKED) |
| self.assertEqual(self.package1.subpackage_status( |
| 'subpackage_2', link2)[0], status.LINKED) |
| self.assertEqual(self.package2.subpackage_status( |
| 'subpackage_2', link3)[0], status.LINKED) |
| |
| def test_failed_install(self): |
| self.package1.downloaded = False |
| self.package2.downloaded = False |
| self.package1.should_download = True |
| self.package2.should_download = False |
| # Since it will have downloaded successfully, it should be cleaned up. |
| self.package1.should_uninstall = True |
| |
| self.assertFalse(self.dev.is_available()) |
| with self.assertRaises(device.PackageDownloadError): |
| self.dev.install(auto_accept=True) |
| self.assertFalse(self.dev.is_available()) |
| self.assertFalse(self.package1.is_downloaded()) |
| self.assertFalse(self.package2.is_downloaded()) |
| |
| def test_failed_partial_install(self): |
| self.package1.downloaded = True |
| self.package2.downloaded = False |
| self.package1.should_download = False |
| self.package2.should_download = False |
| |
| self.assertFalse(self.dev.is_available()) |
| with self.assertRaises(device.PackageDownloadError): |
| self.dev.install(auto_accept=True) |
| self.assertFalse(self.dev.is_available()) |
| # Package1 was already available; it shouldn't go away just because |
| # Package2 failed. |
| self.assertTrue(self.package1.is_downloaded()) |
| self.assertFalse(self.package2.is_downloaded()) |
| |
| def test_void_install(self): |
| self.package1.downloaded = True |
| self.package2.downloaded = True |
| self.package1.should_download = False |
| self.package2.should_download = False |
| self.package1.licenses = [] |
| |
| self.assertTrue(self.dev.is_available()) |
| self.dev.install(auto_accept=False) |
| self.assertTrue(self.dev.is_available()) |
| self.assertTrue(self.package1.is_downloaded()) |
| self.assertTrue(self.package2.is_downloaded()) |
| |
| def test_install_failed_link(self): |
| self.package1.downloaded = False |
| self.package2.downloaded = False |
| self.package1.should_download = True |
| self.package2.should_download = True |
| |
| self.assertFalse(self.dev.is_available()) |
| with self.assertRaises(device.PackageLinkError): |
| self.dev.install(auto_accept=True, link_os=self.os_) |
| # Should still install, just won't be linked. |
| self.assertTrue(self.dev.is_available()) |
| self.assertNotEqual(self.package1.subpackage_status('subpackage_1')[0], |
| status.LINKED) |
| self.assertNotEqual(self.package1.subpackage_status('subpackage_2')[0], |
| status.LINKED) |
| self.assertNotEqual(self.package2.subpackage_status('subpackage_2')[0], |
| status.LINKED) |
| |
| def test_uninstall(self): |
| self.package1.downloaded = True |
| self.package2.downloaded = True |
| self.package1.should_uninstall = True |
| self.package2.should_uninstall = True |
| self.assertTrue(self.dev.is_available()) |
| self.dev.uninstall() |
| self.assertFalse(self.dev.is_available()) |
| self.assertFalse(self.package1.is_downloaded()) |
| self.assertFalse(self.package2.is_downloaded()) |
| |
| def test_uninstall_unnecessary(self): |
| self.package1.downloaded = False |
| self.package2.downloaded = True |
| # Still ok to try uninstalling package1. |
| self.package1.should_uninstall = True |
| self.package2.should_uninstall = True |
| self.assertFalse(self.dev.is_available()) |
| self.dev.uninstall() |
| self.assertFalse(self.dev.is_available()) |
| self.assertFalse(self.package1.is_downloaded()) |
| self.assertFalse(self.package2.is_downloaded()) |