diff --git a/plugins/executors.py b/plugins/executors.py index ba1c8e8..240f55a 100644 --- a/plugins/executors.py +++ b/plugins/executors.py @@ -34,6 +34,7 @@ def populate_options(self, drove_client: droveclient.DroveClient, subparser: arg sub_parser = commands.add_parser("tasks", help="Show tasks running on this executor") sub_parser.add_argument("executor_id", metavar="executor-id", help="Executor id for which info is to be shown") + sub_parser.add_argument("--app", "-a", help="Show tasks only for the given source app", type=str) sub_parser.add_argument("--sort", "-s", help="Sort output by column", type=int, choices=range(0, 6), default = 1) sub_parser.add_argument("--reverse", "-r", help="Sort in reverse order", action="store_true") sub_parser.set_defaults(func=self.show_tasks) diff --git a/tests/mock_server.py b/tests/mock_server.py index 72a69fd..df48abe 100644 --- a/tests/mock_server.py +++ b/tests/mock_server.py @@ -123,7 +123,20 @@ }, # Running instances (empty by default; populated during test lifecycle) "instances": [], - "tasks": [], + "tasks": [ + { + "instanceId": "TI-mock-task-001", + "sourceAppName": "TEST_APP", + "taskId": "T0012", + "state": "RUNNING", + "resources": [ + {"type": "CPU", "cores": {"0": [0, 1]}}, + {"type": "MEMORY", "memoryInMB": {"0": 256}}, + ], + "created": 1700000020000, + "updated": 1700000020000, + }, + ], "serviceInstances": [], } diff --git a/tests/test_offline_executor.py b/tests/test_offline_executor.py index 9fd9764..2e48cd0 100644 --- a/tests/test_offline_executor.py +++ b/tests/test_offline_executor.py @@ -76,3 +76,37 @@ def test_describe_executor_json(self, offline_executor_id): out = drove_ok("describe", "executor", offline_executor_id, "--json") data = json.loads(out) assert isinstance(data, dict) + + +class TestOfflineExecutorTasks: + """Tests for `drove executor tasks` — verifies the --app filter works. + + The mock executor seed data includes a task with sourceAppName='TEST_APP'. + Before the fix, running `drove executor tasks ` with any tasks present + would crash with ``AttributeError: 'Namespace' object has no attribute 'app'`` + because the ``--app`` argument was missing from the subparser definition. + """ + + def test_executor_tasks_shows_task_data(self, offline_executor_id): + """Tasks output should contain the seeded task information.""" + from conftest import drove_ok + out = drove_ok("executor", "tasks", offline_executor_id) + assert "TEST_APP" in out, ( + f"Expected 'TEST_APP' in tasks output but got:\n{out}" + ) + + def test_executor_tasks_app_filter_shows_match(self, offline_executor_id): + """The --app flag should show tasks matching the given source app.""" + from conftest import drove_ok + out = drove_ok("executor", "tasks", offline_executor_id, "--app", "TEST_APP") + assert "TEST_APP" in out, ( + f"Expected 'TEST_APP' in filtered output but got:\n{out}" + ) + + def test_executor_tasks_app_filter_excludes_nonmatch(self, offline_executor_id): + """The --app flag should exclude tasks from other apps.""" + from conftest import drove_ok + out = drove_ok("executor", "tasks", offline_executor_id, "--app", "NONEXISTENT_APP") + assert "TEST_APP" not in out, ( + f"Expected 'TEST_APP' to be filtered out but got:\n{out}" + )