diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index c2920bed1..c42adf09e 100644 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -51,6 +51,8 @@ from jenkins import Jenkins JENKINS_URL = 'http://ci.openlp.org/' REPO_REGEX = r'(.*/+)(~.*)' +# Allows us to black list token. So when we change the token, we can display a proper message to the user. +OLD_TOKENS = [] class OpenLPJobs(object): @@ -62,7 +64,6 @@ class OpenLPJobs(object): Branch_Interface = 'Branch-03-Interface-Tests' Branch_Windows = 'Branch-04-Windows_Tests' Branch_PEP = 'Branch-05-Code-Analysis' - PEP_TEST = "sdafajsdklfj lajsldfk jlasdkjf lkajdf lkasjdlfkjalskdjflkajflkadsjkfl jasdlkfj laskdjflka sjdlkfjlaksdjflksajdf" Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP] @@ -82,14 +83,25 @@ class JenkinsTrigger(object): """ Ask our jenkins server to build the "Branch-01-Pull" job. """ - self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name}, token=self.token) + bzr = Popen(('bzr', 'whoami'), stdout=PIPE, stderr=PIPE) + raw_output, error = bzr.communicate() + # We just want the name (not the email). + name = ' '.join(raw_output.decode().split()[:-1]) + cause = 'Build triggered by %s (%s)' % (name, self.repo_name) + self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build( + {'BRANCH_NAME': self.repo_name, 'cause': cause}, token=self.token) def print_output(self): """ Print the status information of the build tirggered. """ - print("Add this to your merge proposal:") - print("--------------------------------") + print('Add this to your merge proposal:') + print('--------------------------------') + bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE) + raw_output, error = bzr.communicate() + revno = raw_output.decode().strip() + print('%s (revision %s)' % (get_repo_name(), revno)) + for job in OpenLPJobs.Jobs: self.__print_build_info(job) @@ -116,10 +128,6 @@ class JenkinsTrigger(object): result_string = build.info['result'] url = build.info['url'] print('[%s] %s' % (result_string, url)) - # On failure open the browser. - #if result_string == "FAILURE": - # url += 'console' - # Popen(('xdg-open', url), stderr=PIPE) def get_repo_name(): @@ -150,41 +158,32 @@ def get_repo_name(): if match: repo_name = 'lp:%s' % match.group(2) break - repo_name = repo_name.strip('/') - - # Did we find the branch name? - if not repo_name: - for line in output_list: - # Check if the branch was pushed. - if 'Shared repository with trees (format: 2a)' in line: - print('Not a branch. cd to a branch.') - return - print('Not a branch. Have you pushed it to launchpad?') - return - return repo_name + return repo_name.strip('/') def main(): usage = 'Usage: python %prog TOKEN [options]' parser = OptionParser(usage=usage) - parser.add_option('-d', '--disable-output', dest='enable_output', action="store_false", default=True, + parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True, help='Disable output.') - parser.add_option('-b', '--open-browser', dest='open_browser', action="store_true", default=False, + parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False, help='Opens the jenkins page in your browser.') - #parser.add_option('-e', '--open-browser-on-error', dest='open_browser_on_error', action="store_true", - # default=False, help='Opens the jenkins page in your browser in case a test fails.') options, args = parser.parse_args(sys.argv) if len(args) == 2: if not get_repo_name(): + print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?') return token = args[-1] + if token in OLD_TOKENS: + print('Your token is not valid anymore. Get the most recent one.') + return jenkins_trigger = JenkinsTrigger(token) try: jenkins_trigger.trigger_build() except HTTPError as e: - print("Wrong token.") + print('Wrong token.') return # Open the browser before printing the output. if options.open_browser: diff --git a/tests/functional/openlp_core_lib/test_image_manager.py b/tests/functional/openlp_core_lib/test_image_manager.py index e9968e1c7..4a73bb40f 100644 --- a/tests/functional/openlp_core_lib/test_image_manager.py +++ b/tests/functional/openlp_core_lib/test_image_manager.py @@ -30,12 +30,16 @@ Package to test the openlp.core.ui package. """ import os +import time +from threading import Lock from unittest import TestCase from PyQt4 import QtGui from openlp.core.common import Registry from openlp.core.lib import ImageManager, ScreenList +from openlp.core.lib.imagemanager import Priority +from tests.functional import patch from tests.helpers.testmixin import TestMixin TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources')) @@ -51,6 +55,8 @@ class TestImageManager(TestCase, TestMixin): self.get_application() ScreenList.create(self.app.desktop()) self.image_manager = ImageManager() + self.lock = Lock() + self.sleep_time = 0.1 def tearDown(self): """ @@ -82,3 +88,85 @@ class TestImageManager(TestCase, TestMixin): with self.assertRaises(KeyError) as context: self.image_manager.get_image(TEST_PATH, 'church1.jpg') self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image') + + + def process_cache_test(self): + """ + Test the process_cache method + """ + with patch('openlp.core.lib.imagemanager.resize_image') as mocked_resize_image, \ + patch('openlp.core.lib.imagemanager.image_to_byte') as mocked_image_to_byte: + # GIVEN: Mocked functions + mocked_resize_image.side_effect = self.mocked_resize_image + mocked_image_to_byte.side_effect = self.mocked_image_to_byte + image1 = 'church.jpg' + image2 = 'church2.jpg' + image3 = 'church3.jpg' + image4 = 'church4.jpg' + + # WHEN: Add the images. Then get the lock (=queue can not be processed). + self.lock.acquire() + self.image_manager.add_image(TEST_PATH, image1, None) + self.image_manager.add_image(TEST_PATH, image2, None) + + # THEN: All images have been added to the queue, and only the first image is not be in the list anymore, but + # is being processed (see mocked methods/functions). + # Note: Priority.Normal means, that the resize_image() was not completed yet (because afterwards the # + # priority is adjusted to Priority.Lowest). + assert self.get_image_priority(image1) == Priority.Normal, "image1's priority should be 'Priority.Normal'" + assert self.get_image_priority(image2) == Priority.Normal, "image2's priority should be 'Priority.Normal'" + + # WHEN: Add more images. + self.image_manager.add_image(TEST_PATH, image3, None) + self.image_manager.add_image(TEST_PATH, image4, None) + # Allow the queue to process. + self.lock.release() + # Request some "data". + image_bytes = self.image_manager.get_image_bytes(TEST_PATH, image4) + image_object = self.image_manager.get_image(TEST_PATH, image3) + # Now the mocked methods/functions do not have to sleep anymore. + self.sleep_time = 0 + # Wait for the queue to finish. + while not self.image_manager._conversion_queue.empty(): + time.sleep(0.1) + # Because empty() is not reliable, wait a litte; just to make sure. + time.sleep(0.1) + # THEN: The images' priority reflect how they were processed. + assert self.image_manager._conversion_queue.qsize() == 0, "The queue should be empty." + assert self.get_image_priority(image1) == Priority.Lowest, \ + "The image should have not been requested (=Lowest)" + assert self.get_image_priority(image2) == Priority.Lowest, \ + "The image should have not been requested (=Lowest)" + assert self.get_image_priority(image3) == Priority.Low, "Only the QImage should have been requested (=Low)." + assert self.get_image_priority(image4) == Priority.Urgent, \ + "The image bytes should have been requested (=Urgent)." + + def get_image_priority(self, image): + """ + This is a help method to get the priority of the given image out of the image_manager's cache. + + NOTE: This requires, that the image has been added to the image manager using the *TEST_PATH*. + + :param image: The name of the image. E. g. ``image1`` + """ + return self.image_manager._cache[(TEST_PATH, image)].priority + + def mocked_resize_image(self, *args): + """ + This is a mocked method, so that we can control the work flow of the image manager. + """ + self.lock.acquire() + self.lock.release() + # The sleep time is adjusted in the test case. + time.sleep(self.sleep_time) + return QtGui.QImage() + + def mocked_image_to_byte(self, *args): + """ + This is a mocked method, so that we can control the work flow of the image manager. + """ + self.lock.acquire() + self.lock.release() + # The sleep time is adjusted in the test case. + time.sleep(self.sleep_time) + return '' \ No newline at end of file diff --git a/tests/resources/church2.jpg b/tests/resources/church2.jpg new file mode 100644 index 000000000..826180870 Binary files /dev/null and b/tests/resources/church2.jpg differ diff --git a/tests/resources/church3.jpg b/tests/resources/church3.jpg new file mode 100644 index 000000000..826180870 Binary files /dev/null and b/tests/resources/church3.jpg differ diff --git a/tests/resources/church4.jpg b/tests/resources/church4.jpg new file mode 100644 index 000000000..826180870 Binary files /dev/null and b/tests/resources/church4.jpg differ