From 349908a11d7173af53dd8ad7653b5e3b30bcef8e Mon Sep 17 00:00:00 2001 From: Leela Prasad <47483946+leelaprasadv@users.noreply.github.com> Date: Sun, 19 Nov 2023 03:29:29 +0530 Subject: [PATCH 1/4] Feature: Recent Test Plans Menu --- .gitignore | 2 +- hamster/__main__.py | 7 +++--- hamster/menu.py | 56 +++++++++++++++++++++++++++++++++------------ hamster/utils.py | 19 ++++----------- 4 files changed, 51 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index cdef503..50b9c44 100644 --- a/.gitignore +++ b/.gitignore @@ -159,4 +159,4 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +.idea/ \ No newline at end of file diff --git a/hamster/__main__.py b/hamster/__main__.py index b330219..147d1ce 100644 --- a/hamster/__main__.py +++ b/hamster/__main__.py @@ -1,12 +1,13 @@ import config, menu, utils + def main(): """ Entry point of the Hamster - menu bar application. """ - utils.prechecks(config.jmeter_plist, config.jmeter_home, config.jmeter_path) - menu_items = utils.get_recent_jmeter_test_plans() - menu.DynamicMenuApp("JMeter", menu_items).run() + menu_builder = menu.DynamicMenuApp("JMeter") + menu_builder.run() + if __name__ == "__main__": main() diff --git a/hamster/menu.py b/hamster/menu.py index 0cfe834..1ba13eb 100644 --- a/hamster/menu.py +++ b/hamster/menu.py @@ -1,7 +1,7 @@ import rumps import subprocess -from utils import restart, update_properties, show_splash_screen -from config import jmeter_path, icon_path, properties_file_path, config_parser +from utils import update_properties, show_splash_screen, prechecks, get_recent_jmeter_test_plans, sleep +from config import jmeter_path, icon_path, properties_file_path, config_parser, jmeter_plist, jmeter_home class DynamicMenuApp(rumps.App): @@ -10,7 +10,6 @@ class DynamicMenuApp(rumps.App): Attributes: title (str): The title of the application. - menu_items (list): A list of menu items. Methods: __init__(self, title, menu_items): Initializes the DynamicMenuApp object. @@ -22,17 +21,41 @@ class DynamicMenuApp(rumps.App): just_jmeter(self, _): Launches JMeter without any test plan. about(self, _): Displays information about the application. """ - def __init__(self, title, menu_items): + def __init__(self, title): super(DynamicMenuApp, self).__init__(title, icon=icon_path, quit_button='Quit') - self.menu = ['Just JMeter', None] + [rumps.MenuItem(item, callback=self.menu_callback) for item in menu_items] \ - + [None, 'View Config', 'Edit JMETER_HOME'] + [None, 'Restart', None, 'Help', 'About'] - - @rumps.clicked("Restart") - def restart(self, _): + self.menu = ['Launch JMeter', 'Recent Test Plans', None, 'View Config', 'Edit JMETER_HOME', None, + 'Refresh', 'Help', 'About'] + prechecks(jmeter_plist, jmeter_home, jmeter_path) + self.refresh_test_plans(delay=1) + + def refresh_test_plans(self, delay=5): """ - Restarts the application. + Refreshes Recent Test Plans Menu Items + Args: + delay: in seconds, defaults to 5 + + Returns: None + """ - restart(1) + sleep(delay) + recent_test_plans_menu = self.menu["Recent Test Plans"] + if recent_test_plans_menu: + recent_test_plans_menu.clear() + + recent_test_plans = get_recent_jmeter_test_plans() + if not len(recent_test_plans) > 0: + recent_test_plans_menu.add(rumps.MenuItem("No recent JMeter test plans files found.")) + return + + for test_plan in recent_test_plans: + recent_test_plans_menu.add(rumps.MenuItem(test_plan, callback=self.menu_callback)) + + @rumps.clicked("Refresh") + def refresh(self, _): + """ + Refreshes Test Plans + """ + self.refresh_test_plans(1) @rumps.clicked("Help") def help(self, _): @@ -58,15 +81,17 @@ def edit_home_path(self, _): Allows the user to edit the JMETER_HOME path. """ try: - window_builder = rumps.Window(message='Enter absolute JMETER_HOME path', cancel="Cancel", dimensions=(300, 100)) + window_builder = rumps.Window(message='Enter absolute JMETER_HOME path', cancel="Cancel", + dimensions=(300, 100)) window_builder.default_text = config_parser.get('JMETER', 'HOME') window_builder.icon = icon_path window_builder.title = "Configure JMETER_HOME" - response = window_builder.run() + if response.clicked: - update_properties({'HOME': str(response.text)}) + update_properties({'HOME': str(response.text.strip())}) config_parser.read(properties_file_path) + self.refresh_test_plans() except Exception as e: rumps.alert("Error", e) @@ -76,10 +101,11 @@ def menu_callback(self, sender): """ try: subprocess.Popen([jmeter_path, '-t', sender.title], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + self.refresh_test_plans() except Exception as e: rumps.alert("Error", e) - @rumps.clicked("Just JMeter") + @rumps.clicked("Launch JMeter") def just_jmeter(self, _): """ Launches JMeter without any test plan. diff --git a/hamster/utils.py b/hamster/utils.py index c7404e6..d3fe907 100644 --- a/hamster/utils.py +++ b/hamster/utils.py @@ -1,22 +1,13 @@ -import os import plistlib -import psutil import time -import sys import rumps from pathlib import Path from config import properties_file_path, config_parser, jmeter_plist, pattern, icon_path -def restart(delay): - if delay: - time.sleep(delay) - else: - time.sleep(1) - python = sys.executable - psutil.Popen([python] + sys.argv) - psutil.Process(os.getpid()).terminate() +def sleep(delay=1): + time.sleep(delay) def refresh_plist(plist_path): @@ -49,13 +40,13 @@ def get_recent_jmeter_test_plans(): recent_files = {k: v for k, v in pl['/org/apache/jmeter/']["gui/"]["action/"].items() if pattern.match(k)} # escape file names with spaces - recent_files = {k: v.replace(' ', '\\ ') for k, v in recent_files.items()} + recent_files = {k: v for k, v in recent_files.items()} recent_files = dict(sorted(recent_files.items())) recent_files = list(recent_files.values()) # check if recent_files is empty - if not recent_files: - recent_files.append("No recent JMeter test plans files found.") + # if not recent_files: + # recent_files.append("No recent JMeter test plans files found.") except Exception as e: rumps.alert("Error", e) From 8b9a38577b4b1fecb2600f82e78cedf4ca1d0ec6 Mon Sep 17 00:00:00 2001 From: Leela Prasad <47483946+leelaprasadv@users.noreply.github.com> Date: Sun, 19 Nov 2023 03:34:57 +0530 Subject: [PATCH 2/4] Removed commented code --- hamster/utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/hamster/utils.py b/hamster/utils.py index d3fe907..e3b3394 100644 --- a/hamster/utils.py +++ b/hamster/utils.py @@ -44,9 +44,6 @@ def get_recent_jmeter_test_plans(): recent_files = dict(sorted(recent_files.items())) recent_files = list(recent_files.values()) - # check if recent_files is empty - # if not recent_files: - # recent_files.append("No recent JMeter test plans files found.") except Exception as e: rumps.alert("Error", e) From e129ee2fb6a467361644dbbf0673b1869dbb43b7 Mon Sep 17 00:00:00 2001 From: Leela Prasad <47483946+leelaprasadv@users.noreply.github.com> Date: Sun, 19 Nov 2023 03:45:36 +0530 Subject: [PATCH 3/4] Fix jmeter path issue --- hamster/config.py | 5 ++++- hamster/menu.py | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hamster/config.py b/hamster/config.py index 06f55de..b7888f1 100644 --- a/hamster/config.py +++ b/hamster/config.py @@ -14,4 +14,7 @@ jmeter_plist = f"/Users/{username}/Library/Preferences/org.apache.jmeter.plist" jmeter_home = config_parser.get('JMETER', 'HOME') -jmeter_path = jmeter_home + '/bin/jmeter' \ No newline at end of file + + +def jmeter_path(): + return jmeter_home + '/bin/jmeter' diff --git a/hamster/menu.py b/hamster/menu.py index 1ba13eb..02df9b3 100644 --- a/hamster/menu.py +++ b/hamster/menu.py @@ -25,7 +25,8 @@ def __init__(self, title): super(DynamicMenuApp, self).__init__(title, icon=icon_path, quit_button='Quit') self.menu = ['Launch JMeter', 'Recent Test Plans', None, 'View Config', 'Edit JMETER_HOME', None, 'Refresh', 'Help', 'About'] - prechecks(jmeter_plist, jmeter_home, jmeter_path) + self.jmeter_path = jmeter_path() + prechecks(jmeter_plist, jmeter_home, self.jmeter_path) self.refresh_test_plans(delay=1) def refresh_test_plans(self, delay=5): @@ -100,7 +101,7 @@ def menu_callback(self, sender): Callback function for menu items. """ try: - subprocess.Popen([jmeter_path, '-t', sender.title], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.Popen([self.jmeter_path, '-t', sender.title], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.refresh_test_plans() except Exception as e: rumps.alert("Error", e) @@ -111,7 +112,7 @@ def just_jmeter(self, _): Launches JMeter without any test plan. """ try: - subprocess.Popen([jmeter_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.Popen([self.jmeter_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except Exception as e: rumps.alert("Error", e) From bb2c9797e8e4dcc32f839de60472986574cbca49 Mon Sep 17 00:00:00 2001 From: Leela Prasad <47483946+leelaprasadv@users.noreply.github.com> Date: Sun, 19 Nov 2023 04:08:43 +0530 Subject: [PATCH 4/4] Fix jmeter launch and home path update issues --- hamster/config.py | 5 +++-- hamster/menu.py | 16 +++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hamster/config.py b/hamster/config.py index b7888f1..917dbff 100644 --- a/hamster/config.py +++ b/hamster/config.py @@ -13,8 +13,9 @@ pattern = re.compile("recent_file_.*") jmeter_plist = f"/Users/{username}/Library/Preferences/org.apache.jmeter.plist" -jmeter_home = config_parser.get('JMETER', 'HOME') def jmeter_path(): - return jmeter_home + '/bin/jmeter' + jmeter_home = config_parser.get('JMETER', 'HOME') + jmeter_bin = jmeter_home + '/bin/jmeter' + return jmeter_home, jmeter_bin diff --git a/hamster/menu.py b/hamster/menu.py index 02df9b3..68829ef 100644 --- a/hamster/menu.py +++ b/hamster/menu.py @@ -1,7 +1,7 @@ import rumps import subprocess from utils import update_properties, show_splash_screen, prechecks, get_recent_jmeter_test_plans, sleep -from config import jmeter_path, icon_path, properties_file_path, config_parser, jmeter_plist, jmeter_home +from config import jmeter_path, icon_path, properties_file_path, config_parser, jmeter_plist class DynamicMenuApp(rumps.App): @@ -25,8 +25,8 @@ def __init__(self, title): super(DynamicMenuApp, self).__init__(title, icon=icon_path, quit_button='Quit') self.menu = ['Launch JMeter', 'Recent Test Plans', None, 'View Config', 'Edit JMETER_HOME', None, 'Refresh', 'Help', 'About'] - self.jmeter_path = jmeter_path() - prechecks(jmeter_plist, jmeter_home, self.jmeter_path) + self.jmeter_home, self.jmeter_bin = jmeter_path() + prechecks(jmeter_plist, self.jmeter_home, self.jmeter_bin) self.refresh_test_plans(delay=1) def refresh_test_plans(self, delay=5): @@ -90,9 +90,11 @@ def edit_home_path(self, _): response = window_builder.run() if response.clicked: - update_properties({'HOME': str(response.text.strip())}) + updated_jmeter_home = response.text.strip() + update_properties({'HOME': str(updated_jmeter_home)}) config_parser.read(properties_file_path) - self.refresh_test_plans() + self.jmeter_home, self.jmeter_bin = jmeter_path() + self.refresh_test_plans(1) except Exception as e: rumps.alert("Error", e) @@ -101,7 +103,7 @@ def menu_callback(self, sender): Callback function for menu items. """ try: - subprocess.Popen([self.jmeter_path, '-t', sender.title], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.Popen([self.jmeter_bin, '-t', sender.title], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.refresh_test_plans() except Exception as e: rumps.alert("Error", e) @@ -112,7 +114,7 @@ def just_jmeter(self, _): Launches JMeter without any test plan. """ try: - subprocess.Popen([self.jmeter_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.Popen([self.jmeter_bin], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except Exception as e: rumps.alert("Error", e)