788224cfe0
Recently the source-repositories element was updated [0] to set git as a build-only dep. This is fine if you don't request to install git elsewhere as a regular package install [1]. If you mix the two then git gets uninstalled when you expect it to be installed. Address this by checking if a package is already requested to be installed when we find a removal or build-only request. Similarly remove a package from the uninstall list if we ask for it to be installed normally. This means that explicit installs override any cleanup actions. [0] https://review.opendev.org/#/c/745678/1/diskimage_builder/elements/source-repositories/package-installs.yaml [1] https://opendev.org/openstack/project-config/src/branch/master/nodepool/elements/infra-package-needs/package-installs.yaml#L22 Change-Id: Idc1aa86f10cddcd4549066d8ea1d6df6fd906bac
291 lines
9.0 KiB
Python
291 lines
9.0 KiB
Python
# Copyright 2018 Red Hat, Inc.
|
|
#
|
|
# 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.
|
|
import collections
|
|
import functools
|
|
import imp
|
|
import mock
|
|
import os
|
|
|
|
from oslotest import base
|
|
from testtools.matchers import Mismatch
|
|
|
|
installs_squash_src = (os.path.dirname(os.path.realpath(__file__)) +
|
|
'/../bin/package-installs-squash')
|
|
installs_squash = imp.load_source('installs_squash', installs_squash_src)
|
|
|
|
|
|
class IsMatchingInstallList(object):
|
|
|
|
def __init__(self, expected):
|
|
self.expected = expected
|
|
|
|
def match(self, actual):
|
|
for phase, ops in self.expected.items():
|
|
if phase not in actual:
|
|
# missing the phase
|
|
return Mismatch(
|
|
"Phase %d does not exist in %s" % (phase, actual))
|
|
for op, pkgs in ops.items():
|
|
if op not in actual[phase]:
|
|
# missing op (install/uninstall)
|
|
return Mismatch(
|
|
"Operation %s does not exist in %s" % (op, ops))
|
|
# on py2 these can be out of order, we just want a match
|
|
expected_phase_ops = sorted(self.expected[phase][op])
|
|
actual_phase_ops = sorted(actual[phase][op])
|
|
if expected_phase_ops != actual_phase_ops:
|
|
return Mismatch(
|
|
"Operation list %s does not match expected %s" %
|
|
(actual[phase][op], self.expected[phase][op]))
|
|
|
|
|
|
class TestPackageInstall(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(TestPackageInstall, self).setUp()
|
|
self.final_dict = collections.defaultdict(
|
|
functools.partial(collections.defaultdict, list))
|
|
|
|
def test_simple(self):
|
|
'''Test a basic package install'''
|
|
objs = {
|
|
'test_package': ''
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
@mock.patch.object(os, 'environ', dict(ARCH='arm64'))
|
|
def test_arch(self):
|
|
'''Exercise the arch and not-arch flags'''
|
|
objs = {
|
|
'test_package': '',
|
|
'test_arm64_package': {
|
|
'arch': 'arm64'
|
|
},
|
|
'do_not_install': {
|
|
'not-arch': 'arm64'
|
|
}
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element'),
|
|
('test_arm64_package', 'test_element')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
kernel_objs = {
|
|
'linux-image-generic': [
|
|
{
|
|
'not-arch': 'arm64',
|
|
'when': 'DIB_UBUNTU_KERNEL = linux-image-generic',
|
|
},
|
|
{
|
|
'arch': 'arm64',
|
|
'when': (
|
|
'DIB_RELEASE != xenial',
|
|
'DIB_UBUNTU_KERNEL = linux-image-generic',
|
|
)
|
|
},
|
|
],
|
|
'linux-generic-hwe-16.04': {
|
|
'arch': 'arm64',
|
|
'when': (
|
|
'DIB_RELEASE = xenial',
|
|
'DIB_UBUNTU_KERNEL = linux-image-generic',
|
|
)
|
|
},
|
|
}
|
|
|
|
def _test_kernel_objs_match(self, arch, release, expected):
|
|
with mock.patch.object(os, 'environ',
|
|
dict(ARCH=arch,
|
|
DIB_UBUNTU_KERNEL='linux-image-generic',
|
|
DIB_RELEASE=release)):
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, self.kernel_objs, 'test_element')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [(expected, 'test_element')]
|
|
}
|
|
}
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
def test_param_list_x86(self):
|
|
self._test_kernel_objs_match('x86_64', 'focal', 'linux-image-generic')
|
|
|
|
def test_param_list_arm64_xenial(self):
|
|
self._test_kernel_objs_match('arm64', 'xenial',
|
|
'linux-generic-hwe-16.04')
|
|
|
|
def test_param_list_arm64_focal(self):
|
|
self._test_kernel_objs_match('arm64', 'focal', 'linux-image-generic')
|
|
|
|
@mock.patch.object(os, 'environ', dict(DIB_FEATURE='1', **os.environ))
|
|
def test_skip_when(self):
|
|
'''Exercise the when flag'''
|
|
objs = {
|
|
'skipped_package': {
|
|
'when': 'DIB_FEATURE=0'
|
|
},
|
|
'not_skipped_package': {
|
|
'when': 'DIB_FEATURE=1'
|
|
},
|
|
'not_equal_package': {
|
|
'when': 'DIB_FEATURE!=0'
|
|
},
|
|
'not_equal_skipped_package': {
|
|
'when': 'DIB_FEATURE!=1'
|
|
},
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('not_skipped_package', 'test_element'),
|
|
('not_equal_package', 'test_element')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
def test_skip_no_var(self):
|
|
'''Exercise the skip_when missing variable failure case'''
|
|
objs = {
|
|
'package': {
|
|
'when': 'MISSING_VAR=1'
|
|
},
|
|
}
|
|
|
|
self.assertRaises(RuntimeError, installs_squash.collect_data,
|
|
self.final_dict, objs, 'test_element')
|
|
|
|
@mock.patch.object(os, 'environ',
|
|
dict(
|
|
DIB_A_FEATURE='1',
|
|
DIB_B_FEATURE='1',
|
|
DIB_C_FEATURE='1'))
|
|
def test_skip_when_list(self):
|
|
'''Exercise the when flag with lists'''
|
|
objs = {
|
|
'not_skipped_package': {
|
|
'when': [
|
|
'DIB_A_FEATURE=1',
|
|
'DIB_B_FEATURE=1',
|
|
'DIB_C_FEATURE=1'
|
|
]
|
|
},
|
|
'skipped_package': {
|
|
'when': [
|
|
'DIB_A_FEATURE=1',
|
|
'DIB_B_FEATURE=0',
|
|
'DIB_C_FEATURE=1',
|
|
]
|
|
},
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('not_skipped_package', 'test_element')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
def test_install_overrides_uninstall_install_first(self):
|
|
'''Test an install overrides uninstall'''
|
|
objs = {
|
|
'test_package': ''
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element1')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element1')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
objs = {
|
|
'test_package': {'build-only': 'true'}
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element2')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element1'),
|
|
('test_package', 'test_element2')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
def test_install_overrides_uninstall_uninstall_first(self):
|
|
'''Test an install overrides uninstall'''
|
|
objs = {
|
|
'test_package': {'build-only': 'true'}
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element1')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element1')],
|
|
'uninstall': [('test_package', 'test_element1')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|
|
|
|
objs = {
|
|
'test_package': ''
|
|
}
|
|
|
|
result = installs_squash.collect_data(
|
|
self.final_dict, objs, 'test_element2')
|
|
|
|
expected = {
|
|
'install.d': {
|
|
'install': [('test_package', 'test_element1'),
|
|
('test_package', 'test_element2')]
|
|
}
|
|
}
|
|
|
|
self.assertThat(result, IsMatchingInstallList(expected))
|