From f123c72c87fbea19442d83a66ab2befbee689162 Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Mar 17 2019 05:01:52 +0000 Subject: Command check-config supports filtering modules on buildrequires Signed-off-by: Chenxiong Qi --- diff --git a/tests/test_check_config.py b/tests/test_check_config.py new file mode 100644 index 0000000..030731c --- /dev/null +++ b/tests/test_check_config.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 Red Hat, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Written by Chenxiong Qi + +import json +import os +import pytest +import tempfile + +from mock import call, patch, Mock +from tests import TEST_DATA_DIR +from tests import make_mbs_response +from ursa_major.cli import main + + +class TestCheckConfig: + + def setup_method(self): + fd, self.tag_config_file = tempfile.mkstemp() + os.close(fd) + + self.ClientSession_patcher = patch('koji.ClientSession') + self.mock_ClientSession = self.ClientSession_patcher.start() + self.koji_session = self.mock_ClientSession.return_value + + self.get_patcher = patch('requests.get') + self.mock_get = self.get_patcher.start() + + def teardown_method(self): + self.get_patcher.stop() + os.unlink(self.tag_config_file) + + def write_tag_config_file(self, content): + with open(self.tag_config_file, 'w') as f: + json.dump(content, f) + + def check_config(self): + config_file = os.path.join(TEST_DATA_DIR, 'ursa-major-test.conf') + cli_cmd = [ + 'ursa-major', 'check-config', + '--config', config_file, + '--tag-config-file', self.tag_config_file + ] + + with patch('sys.argv', new=cli_cmd): + main() + + @pytest.mark.parametrize('modules,error_log', [ + ([ + [{'name': 'mariadb'}], + 'Missing stream in module config: {}'.format({u'name': u'mariadb'}) + ]), + ([ + [{'stream': '10.4', 'priority': 10}], + 'Missing name in module config: {}'.format( + {u'stream': u'10.4', u'priority': 10}) + ]), + ([ + [{'name': 'mariadb', 'stream': '10.4'}], + 'Missing priority in module config: {}'.format( + {u'name': u'mariadb', u'stream': u'10.4'}) + ]), + ]) + def test_missing_mandatory_fields(self, modules, error_log): + self.write_tag_config_file({ + 'f30-build': { + 'modules': modules, + 'owners': ['owner@example.com'] + } + }) + + self.koji_session.getInheritanceData.return_value = [ + { + 'parent': 10, + 'name': 'module-ant-1.10-20181122140939-819b5873', + 'priority': 10 + } + ] + + with patch('ursa_major.handlers.check_config.log') as log: + # This is only for making the program terminate and raise SystemExit + log.error.counter = 3 + + with pytest.raises(SystemExit): + self.check_config() + + log.error.assert_has_calls([call(error_log)]) + + def test_show_error_if_cannot_get_tag_inheritance_data(self): + self.write_tag_config_file({ + 'f30-build': { + 'modules': [], + 'owners': ['owner@example.com'] + } + }) + + # This test requires an error raised from Koji API getInheritanceData + # So, just raise any error + self.koji_session.getInheritanceData.side_effect = ValueError + + with patch('ursa_major.handlers.check_config.log') as log: + # This is only for making the program terminate and raise SystemExit + log.error.counter = 3 + + with pytest.raises(SystemExit): + self.check_config() + + log.error.assert_has_calls([ + call('Unable to get inheritance data of tag %s: %s', u'f30-build', '') + ], any_order=True) + + def test_verify_valid_module_config(self): + self.write_tag_config_file({ + 'f30-build': { + 'modules': [ + { + 'name': 'mariadb', 'stream': '10.4', 'priority': 30, + 'requires': {'platform': 'f30'}, + 'buildrequires': {'platform': 'f30'} + }, + {'name': 'ffsend', 'stream': 'latest', 'priority': 40}, + ], + 'owners': ['owner@example.com'] + } + }) + + self.mock_get.return_value = Mock(status_code=200) + self.mock_get.return_value.json.return_value = make_mbs_response([ + { + 'id': 3617, + 'name': 'mariadb', + 'koji_tag': 'module-mariadb-10.4-3020190313091759-a5b0195c', + 'modulemd': "---\ndocument: modulemd\nversion: 2\ndata:\n name: mariadb\n stream: 10.4\n version: 3020190313091759\n context: a5b0195c\n summary: 'MariaDB: a very fast and robust SQL database server'\n description: >-\n MariaDB is a community developed branch of MySQL. MariaDB is a multi-user, multi-threaded\n SQL database server. It is a client/server implementation consisting of a server\n daemon (mysqld) and many different client programs and libraries. The base package\n contains the standard MariaDB/MySQL client programs and generic MySQL files.\n license:\n module:\n - MIT\n xmd:\n mbs:\n mse: TRUE\n scmurl: https://src.fedoraproject.org/modules/mariadb.git?#253aec1ecde2bcdb308cf796098f0255c13c46d8\n commit: 253aec1ecde2bcdb308cf796098f0255c13c46d8\n buildrequires:\n platform:\n stream_collision_modules: \n stream: f30\n ref: f30\n filtered_rpms: []\n ursine_rpms: \n koji_tag: module-f30-build\n version: 6\n context: 00000000\n rpms:\n galera:\n ref: d3badbee4bef85128e4d8849f2a9fb433ac4d9a5\n mariadb:\n ref: ff6cb12c8c560d09cf69b02b89008d3de3a39edf\n dependencies:\n - buildrequires:\n platform: [f30]\n requires:\n platform: [f30]\n...\n", # noqa + }, + { + 'id': 3640, + 'name': 'ffsend', + 'koji_tag': 'module-ffsend-latest-3020190316024948-a5b0195c', + 'modulemd': '---\ndocument: modulemd\nversion: 2\ndata:\n name: ffsend\n stream: latest\n version: 3020190316024948\n context: a5b0195c\n summary: Easily and securely share files from the command line\n description: >-\n Easily and securely share files from the command line.\n\n A fully featured Firefox Send client.\n license:\n module:\n - MIT\n dependencies:\n - buildrequires:\n platform: [f30]\n requires:\n platform: [f30]\n references:\n community: https://github.com/timvisee/ffsend\n documentation: https://github.com/timvisee/ffsend/blob/master/LICENSE\n tracker: https://github.com/timvisee/ffsend/issues\n profiles:\n default:\n rpms:\n - ffsend\n api:\n rpms:\n - ffsend\n...\n', # noqa + } + ]) + + self.koji_session.getInheritanceData.return_value = [ + { + 'parent': 10, + 'name': 'module-ant-1.10-20181122140939-819b5873', + 'priority': 10 + } + ] + + with patch('ursa_major.handlers.check_config.log') as log: + # This is only for making the program terminate normally + log.error.counter = 0 + + self.check_config() + log.error.assert_not_called() diff --git a/ursa_major/handlers/check_config.py b/ursa_major/handlers/check_config.py index 5b0a3f0..5fe75e6 100644 --- a/ursa_major/handlers/check_config.py +++ b/ursa_major/handlers/check_config.py @@ -112,6 +112,7 @@ class CheckConfigHandler(BaseHandler): modules_of_config = self.mbs.get_modules_with_requires( requires=module_config.get('requires', {}), + buildrequires=module_config.get('buildrequires'), name=module_config['name'], stream=module_config['stream'], state=5, # state_name = ready