From 5165fa2acad0b8cddfcaa7e770e697a79454f6c8 Mon Sep 17 00:00:00 2001 From: Digital Studium Date: Mon, 6 May 2024 16:31:10 +0300 Subject: [PATCH] Add more tests --- kls | 16 +++++----- test.py => tests.py | 72 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 21 deletions(-) rename test.py => tests.py (51%) diff --git a/kls b/kls index 124d7d6..aeca621 100755 --- a/kls +++ b/kls @@ -74,11 +74,11 @@ def draw_menu(menu: Menu): draw_row(menu.win, f"/{menu.filter}" if menu.filter else "", curses.LINES - FOOTER_HEIGHT - 2, 2) # draw filter row -def refresh_third_menu(): +def refresh_third_menu(namespace: str, api_resource: str): menu = menus[2] menu.rows = [] - if api_resource() and namespace(): - menu.rows = kubectl(f"-n {namespace()} get {api_resource()} --no-headers --ignore-not-found") + if api_resource and namespace: + menu.rows = kubectl(f"-n {namespace} get {api_resource} --no-headers --ignore-not-found") index_before_update = menu.filtered_rows.index menu.filtered_rows = CircularList([x for x in menu.rows if menu.filter in x]) # update filtered rows menu.filtered_rows.index = index_before_update @@ -87,15 +87,15 @@ def refresh_third_menu(): draw_menu(menu) -def handle_key_bindings(key: str, api_resource: str, resource: str): - if not menus[2].selected_row(): +def handle_key_bindings(key: str, namespace: str, api_resource: str, resource: str): + if not resource: return if key in ("4", "5", "6"): if api_resource not in ["pods", "all"] or (api_resource == "all" and not resource.startswith("pod/")): return curses.def_prog_mode() # save the previous terminal state curses.endwin() # without this, there are problems after exiting vim - command = KEY_BINDINGS[key].format(namespace=namespace(), api_resource=api_resource, resource=resource) + command = KEY_BINDINGS[key].format(namespace=namespace, api_resource=api_resource, resource=resource) if api_resource == "all": command = command.replace(" all", "") subprocess.call(command, shell=True) @@ -189,7 +189,7 @@ def catch_input(menu: Menu): key = SCREEN.getkey() break except curses.error: - refresh_third_menu() + refresh_third_menu(namespace(), api_resource()) time.sleep(0.1) if key in ["\t", "KEY_RIGHT", "KEY_BTAB", "KEY_LEFT"]: handle_horizontal_navigation(key, menu) @@ -198,7 +198,7 @@ def catch_input(menu: Menu): elif key == "KEY_MOUSE": handle_mouse(menu) elif key in KEY_BINDINGS.keys(): - handle_key_bindings(key, api_resource(), resource()) + handle_key_bindings(key, namespace(), api_resource(), resource()) elif key in ["\x1b", "KEY_BACKSPACE", "\x08"] or key.isalpha() or key == "-": # \x1b - escape, \x08 - backspace handle_filter_state(key, menu) diff --git a/test.py b/tests.py similarity index 51% rename from test.py rename to tests.py index bb614f5..093501e 100644 --- a/test.py +++ b/tests.py @@ -6,10 +6,12 @@ os.system("ln -s kls kls.py") import kls +os.unlink('kls.py') + class TestCircularList(unittest.TestCase): def setUp(self): - self.circular_list = kls.CircularList(['a', 'b', 'c']) + self.circular_list = kls.CircularList(['kube-system', 'default', 'kube-public']) def test_forward(self): self.circular_list.shift(1) @@ -19,6 +21,9 @@ class TestCircularList(unittest.TestCase): self.circular_list.shift(-1) self.assertEqual(self.circular_list.index, 2) # Since it's circular, it goes to the end + def tearDown(self): + kls.curses.endwin() + class TestScriptFunctions(unittest.TestCase): @patch('kls.subprocess.check_output') @@ -27,26 +32,30 @@ class TestScriptFunctions(unittest.TestCase): result = kls.kubectl('get pods') self.assertEqual(result, ['pod1', 'pod2', 'pod3']) + def tearDown(self): + kls.curses.endwin() + class TestMenu(unittest.TestCase): def setUp(self): - self.rows = ['a', 'b', 'c'] - self.second_menu = kls.Menu("Test Menu 2", ["option1", "option2", "option3"], 0, 10, 2) - self.third_menu = kls.Menu("Test Menu 3", ["option1", "option2", "option3"], 0, 10, 2) + self.rows = ['kube-system', 'default', 'kube-public'] self.menu = kls.Menu('Test', self.rows, 0, 10, 2) + self.second_menu = kls.Menu("Test Menu 2", ["pods", "services", "secrets"], 0, 10, 2) + self.third_menu = kls.Menu("Test Menu 3", ['pod1', 'pod2', 'pod3'], 0, 10, 2) + kls.menus = [self.menu, self.second_menu, self.third_menu] # Add the menu to the list of menus os.system("ln -s kls kls.py") def test_menu(self): self.assertEqual(self.menu.title, 'Test') self.assertEqual(self.menu.filtered_rows.elements, self.rows) - self.assertEqual(self.menu.visible_rows(), ['a', 'b']) - self.assertEqual(self.menu.selected_row(), 'a') + self.assertEqual(self.menu.visible_rows(), ['kube-system', 'default']) + self.assertEqual(self.menu.selected_row(), 'kube-system') def test_filter_rows_with_filter(self): # Apply a filter and test - self.menu.filter = 'a' + self.menu.filter = 'kube-system' self.menu.filtered_rows = kls.CircularList([x for x in self.menu.rows if self.menu.filter in x]) - self.assertEqual(self.menu.filtered_rows.elements, ['a']) + self.assertEqual(self.menu.filtered_rows.elements, ['kube-system']) def test_filter_rows_with_nonexistent_filter(self): # Apply a filter that matches no rows @@ -56,8 +65,6 @@ class TestMenu(unittest.TestCase): def test_vertical_navigation(self): kls.selected_menu = self.menu - # global menus - kls.menus = [self.menu, self.second_menu, self.third_menu] # Add the menu to the list of menus # Test moving down one row kls.handle_vertical_navigation("KEY_DOWN", self.menu) self.assertEqual(self.menu.visible_row_index, 0) @@ -82,10 +89,49 @@ class TestMenu(unittest.TestCase): kls.handle_vertical_navigation("KEY_END", self.menu) self.assertEqual(self.menu.visible_row_index, -1) + @patch('kls.subprocess.call') + @patch('kls.curses.reset_prog_mode') + @patch('kls.curses.def_prog_mode') + def test_handle_key_bindings(self, mock_def_prog_mode, mock_reset_prog_mode, mock_subprocess_call): + namespace = self.menu.selected_row() + api_resource = self.second_menu.selected_row() + resource = self.third_menu.selected_row() + + key = "1" # Assuming you want to test the case where key is '1' + expected_command = kls.KEY_BINDINGS[key].format(namespace=namespace, api_resource=api_resource, resource=resource) + + kls.handle_key_bindings(key, namespace, api_resource, resource) + + mock_def_prog_mode.assert_called_once() + mock_reset_prog_mode.assert_called_once() + mock_subprocess_call.assert_called_once_with(expected_command, shell=True) + + @patch('kls.curses.def_prog_mode') + def test_handle_key_bindings_empty_resource(self, mock_def_prog_mode): + namespace = self.menu.selected_row() + api_resource = self.second_menu.selected_row() + resource = None + + key = "1" # Assuming you want to test the case where key is '1' + + kls.handle_key_bindings(key, namespace, api_resource, resource) + mock_def_prog_mode.assert_not_called() + + @patch('kls.curses.def_prog_mode') + def test_handle_key_bindings_services(self, mock_def_prog_mode): + namespace = self.menu.selected_row() + api_resource = "services" + resource = self.third_menu.selected_row() + + key = "4" # 4 must not be called for services + + kls.handle_key_bindings(key, namespace, api_resource, resource) + mock_def_prog_mode.assert_not_called() + def tearDown(self): - # Remove the symlink after each test - os.unlink('kls.py') - os.system("reset") + os.unlink('kls.py') # Remove the symlink after each test + kls.curses.endwin() + print('\033[?1003l') # Disable mouse tracking with the XTERM API if __name__ == '__main__':