From e6134565917a5a9adcc3727ec72177dcd3af344f Mon Sep 17 00:00:00 2001
From: Chenxiong Qi <cqi@redhat.com>
Date: Oct 16 2017 09:03:09 +0000
Subject: [PATCH 1/2] Tests for update command


Signed-off-by: Chenxiong Qi <cqi@redhat.com>

---

diff --git a/fedpkg/cli.py b/fedpkg/cli.py
index 859dd43..6ffa7ea 100644
--- a/fedpkg/cli.py
+++ b/fedpkg/cli.py
@@ -90,6 +90,18 @@ class fedpkgClient(cliClient):
         return lines[0], "\n".join(log)
 
     def update(self):
+        try:
+            section = '%s.bodhi' % self.name
+            bodhi_config = {
+                'url': self.config.get(section, 'url'),
+                'staging': self.config.getboolean(section, 'staging'),
+                }
+        except (ValueError, NoOptionError, NoSectionError) as e:
+            self.log.error(str(e))
+            raise rpkgError('Could not get bodhi options. It seems configuration is changed. '
+                            'Please try to reinstall %s or consult developers to see what '
+                            'is wrong with it.' % self.name)
+
         template = """\
 [ %(nvr)s ]
 
@@ -130,7 +142,8 @@ suggest_reboot=False
 
         # Extract bug numbers from the latest changelog entry
         self.cmd.clog()
-        clog = file('clog').read()
+        with open('clog', 'r') as f:
+            clog = f.read()
         bugs = re.findall(r'#([0-9]*)', clog)
         if bugs:
             bodhi_args['bugs'] = ','.join(bugs)
@@ -153,9 +166,8 @@ suggest_reboot=False
         orig_hash = orig_hash.hexdigest()
 
         # Write out the template
-        out = file('bodhi.template', 'w')
-        out.write(template.encode('utf-8'))
-        out.close()
+        with open('bodhi.template', 'w') as f:
+            f.write(template.encode('utf-8'))
 
         # Open the template in a text editor
         editor = os.getenv('EDITOR', 'vi')
@@ -166,19 +178,8 @@ suggest_reboot=False
             raise rpkgError('No bodhi update details saved!')
 
         # If the template was changed, submit it to bodhi
-        hash = self.cmd.lookasidecache.hash_file('bodhi.template', 'sha1')
-        if hash != orig_hash:
-            try:
-                section = '%s.bodhi' % self.name
-                bodhi_config = {
-                    'url': self.config.get(section, 'url'),
-                    'staging': self.config.getboolean(section, 'staging'),
-                    }
-            except (ValueError, NoOptionError, NoSectionError) as e:
-                self.log.error(str(e))
-                raise rpkgError('Could not get bodhi options. It seems configuration is changed. '
-                                'Please try to reinstall %s or consult developers to see what '
-                                'is wrong with it.' % self.name)
+        new_hash = self.cmd.lookasidecache.hash_file('bodhi.template', 'sha1')
+        if new_hash != orig_hash:
             try:
                 self.cmd.update(bodhi_config, template='bodhi.template')
             except Exception as e:
diff --git a/test/fedpkg-stage.conf b/test/fedpkg-stage.conf
new file mode 100644
index 0000000..cc3ee04
--- /dev/null
+++ b/test/fedpkg-stage.conf
@@ -0,0 +1,15 @@
+[fedpkg-stage]
+anongiturl = git://pkgs.stg.example.com/%(module)s
+gitbaseurl = ssh://%(user)s@pkgs.stg.example.com/%(module)s
+lookaside_cgi = https://pkgs.stg.example.com/repo/pkgs/upload.cgi
+lookasidehash = sha512
+lookaside = http://pkgs.stg.example.com/repo/pkgs
+branchre = f\d$|f\d\d$|el\d$|olpc\d$|master$
+kojiprofile = koji
+build_client = koji
+distgit_namespaced = True
+kerberos_realms = STG.FEDORAPROJECT.ORG
+
+[fedpkg-stage.bodhi]
+url = https://bodhi.stg.example.com/
+staging = True
\ No newline at end of file
diff --git a/test/fedpkg-test.conf b/test/fedpkg-test.conf
index 091334a..8917e85 100644
--- a/test/fedpkg-test.conf
+++ b/test/fedpkg-test.conf
@@ -12,3 +12,4 @@ kerberos_realms = FEDORAPROJECT.ORG
 
 [fedpkg.bodhi]
 url = https://bodhi.dummy.example.com/
+staging = False
\ No newline at end of file
diff --git a/test/test_cli.py b/test/test_cli.py
new file mode 100644
index 0000000..c015fd1
--- /dev/null
+++ b/test/test_cli.py
@@ -0,0 +1,186 @@
+# fedpkg - a Python library for RPM Packagers
+#
+# Copyright (C) 2017 Red Hat Inc.
+# Author(s): Chenxiong Qi <cqi@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
+# the full text of the license.
+
+import six
+
+from six.moves.configparser import NoOptionError
+from six.moves.configparser import NoSectionError
+
+from pyrpkg.errors import rpkgError
+from utils import CliTestCase
+
+from mock import call, patch, mock_open, PropertyMock
+
+
+class TestUpdate(CliTestCase):
+    """Test update command"""
+
+    def setUp(self):
+        super(TestUpdate, self).setUp()
+
+        self.nvr_patcher = patch('pyrpkg.Commands.nvr',
+                                 new_callable=PropertyMock,
+                                 return_value='fedpkg-1.29-9')
+        self.mock_nvr = self.nvr_patcher.start()
+
+        self.run_command_patcher = patch('pyrpkg.Commands._run_command')
+        self.mock_run_command = self.run_command_patcher.start()
+
+        # Let's always use the bodhi 2 command line to test here
+        self.get_bodhi_version_patcher = patch('fedpkg._get_bodhi_version',
+                                               return_value=[2, 11, 0])
+        self.mock_get_bodhi_version = self.get_bodhi_version_patcher.start()
+
+        # Not write clog actually. Instead, file object will be mocked and
+        # return fake clog content for tests.
+        self.clog_patcher = patch('pyrpkg.Commands.clog')
+        self.clog_patcher.start()
+
+        self.os_environ_patcher = patch.dict('os.environ', {'EDITOR': 'vi'})
+        self.os_environ_patcher.start()
+
+        self.fake_clog = '''Add tests for command update
+New command update - #1000
+Fix tests - #2000
+'''
+
+    def tearDown(self):
+        self.os_environ_patcher.stop()
+        self.clog_patcher.stop()
+        self.get_bodhi_version_patcher.stop()
+        self.run_command_patcher.stop()
+        self.nvr_patcher.stop()
+        super(TestUpdate, self).tearDown()
+
+    def get_cli(self, cli_cmd, name='fedpkg', cfg=None):
+        with patch('sys.argv', new=cli_cmd):
+            return self.new_cli(name=name, cfg=cfg)
+
+    def create_bodhi_update(self, cli):
+        mocked_open = mock_open(read_data=self.fake_clog)
+        with patch('__builtin__.open', mocked_open):
+            with patch('os.unlink') as unlink:
+                cli.update()
+
+                # Ensure these files are removed in the end
+                unlink.assert_has_calls([
+                    call('bodhi.template'),
+                    call('clog')
+                ])
+
+    def test_fail_if_missing_config_options(self):
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+        cli = self.get_cli(cli_cmd)
+
+        with patch.object(cli.config, 'get',
+                          side_effect=NoOptionError('url', 'bodhi')):
+            six.assertRaisesRegex(
+                self, rpkgError, 'Could not get bodhi options.', cli.update)
+
+        with patch.object(cli.config, 'get',
+                          side_effect=NoSectionError('bodhi')):
+            six.assertRaisesRegex(
+                self, rpkgError, 'Could not get bodhi options.', cli.update)
+
+    @patch('os.path.isfile', return_value=False)
+    def test_fail_if_bodhi_template_is_not_a_file(self, isfile):
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+
+        cli = self.get_cli(cli_cmd)
+        six.assertRaisesRegex(
+            self, rpkgError, 'No bodhi update details saved',
+            self.create_bodhi_update, cli)
+
+        self.mock_run_command.assert_called_once_with(
+            ['vi', 'bodhi.template'], shell=True)
+
+    @patch('os.path.isfile', return_value=True)
+    @patch('hashlib.new')
+    def test_dont_update_if_aborted(self, hashlib_new, isfile):
+        hashlib_new.return_value.hexdigest.side_effect = ['ABCDEF', 'ABCDEF']
+
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+
+        cli = self.get_cli(cli_cmd)
+        self.create_bodhi_update(cli)
+
+        self.mock_run_command.assert_called_once_with(
+            ['vi', 'bodhi.template'], shell=True)
+
+    @patch('os.path.isfile', return_value=True)
+    @patch('hashlib.new')
+    @patch('pyrpkg.Commands.user', new_callable=PropertyMock)
+    def test_request_update(self, user, hashlib_new, isfile):
+        user.return_value = 'cqi'
+        hashlib_new.return_value.hexdigest.side_effect = ['origin hash',
+                                                          'different hash']
+
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+
+        cli = self.get_cli(cli_cmd)
+        self.create_bodhi_update(cli)
+
+        self.mock_run_command.assert_has_calls([
+            call(['vi', 'bodhi.template'], shell=True),
+            call(['bodhi', 'updates', 'new', '--file', 'bodhi.template',
+                  '--user', 'cqi', self.mock_nvr.return_value],
+                 shell=True)
+        ])
+
+    @patch('os.path.isfile', return_value=True)
+    @patch('hashlib.new')
+    @patch('fedpkg.Commands.update', side_effect=OSError)
+    def test_handle_any_errors_raised_when_execute_bodhi(
+            self, update, hashlib_new, isfile):
+        hashlib_new.return_value.hexdigest.side_effect = ['origin hash',
+                                                          'different hash']
+
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+
+        cli = self.get_cli(cli_cmd)
+        six.assertRaisesRegex(
+            self, rpkgError, 'Could not generate update request',
+            self.create_bodhi_update, cli)
+
+    @patch('os.path.isfile', return_value=True)
+    @patch('hashlib.new')
+    def test_fail_if_bodhi_version_is_not_supported(self, hashlib_new, isfile):
+        # As of writing this test, only supports version v2 and <v2.
+        self.mock_get_bodhi_version.return_value = [3, 1, 2]
+        hashlib_new.return_value.hexdigest.side_effect = ['origin hash',
+                                                          'different hash']
+
+        cli_cmd = ['fedpkg', '--path', self.cloned_repo_path, 'update']
+
+        cli = self.get_cli(cli_cmd)
+        six.assertRaisesRegex(
+            self, rpkgError, 'This system has bodhi v3, which is unsupported',
+            self.create_bodhi_update, cli)
+
+    @patch('os.path.isfile', return_value=True)
+    @patch('hashlib.new')
+    def test_create_update_in_stage_bodhi(self, hashlib_new, isfile):
+        self.mock_get_bodhi_version.return_value = [2, 8, 1]
+        hashlib_new.return_value.hexdigest.side_effect = ['origin hash',
+                                                          'different hash']
+
+        cli_cmd = ['fedpkg-stage', '--path', self.cloned_repo_path, 'update']
+        cli = self.get_cli(cli_cmd,
+                           name='fedpkg-stage',
+                           cfg='fedpkg-stage.conf')
+        self.create_bodhi_update(cli)
+
+        self.mock_run_command.assert_has_calls([
+            call(['vi', 'bodhi.template'], shell=True),
+            call(['bodhi', 'updates', 'new', '--file', 'bodhi.template',
+                  '--user', 'cqi', '--staging', self.mock_nvr.return_value],
+                 shell=True)
+        ])
diff --git a/test/utils.py b/test/utils.py
index 5cfae0e..510777c 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -15,6 +15,10 @@ import subprocess
 import tempfile
 import unittest
 import shutil
+import logging
+
+import pyrpkg
+import fedpkg.cli
 
 from six.moves import configparser
 from fedpkg import Commands
@@ -216,3 +220,26 @@ rm -rf $$RPM_BUILD_ROOT
 
     def create_branch(self, repo, branch_name):
         repo.git.branch(branch_name)
+
+
+class CliTestCase(CommandTestCase):
+    """Base test case for testing from command line interface"""
+
+    default_config_file = os.path.join(os.path.dirname(__file__),
+                                       'fedpkg-test.conf')
+
+    def new_cli(self, name='fedpkg', cfg=None):
+        config = configparser.SafeConfigParser()
+        if cfg:
+            config_file = os.path.join(os.path.dirname(__file__), cfg)
+        else:
+            config_file = self.default_config_file
+        config.read(config_file)
+
+        client = fedpkg.cli.fedpkgClient(config, name=name)
+        client.setupLogging(pyrpkg.log)
+        pyrpkg.log.setLevel(logging.CRITICAL)
+        client.do_imports(site='fedpkg')
+        client.parse_cmdline()
+
+        return client

From c47a8338efe608ad5f2533fd7b00d94addb9a670 Mon Sep 17 00:00:00 2001
From: Lubomír Sedlář <lsedlar@redhat.com>
Date: Oct 18 2017 12:36:35 +0000
Subject: [PATCH 2/2] Mock user in tests


Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>

---

diff --git a/test/test_cli.py b/test/test_cli.py
index c015fd1..6d2bf3d 100644
--- a/test/test_cli.py
+++ b/test/test_cli.py
@@ -176,6 +176,7 @@ Fix tests - #2000
         cli = self.get_cli(cli_cmd,
                            name='fedpkg-stage',
                            cfg='fedpkg-stage.conf')
+        cli.cmd._user = 'cqi'
         self.create_bodhi_update(cli)
 
         self.mock_run_command.assert_has_calls([

