# # Copyright 2024-present ScyllaDB # # SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 # import pytest from subprocess import CalledProcessError from test.nodetool.rest_api_mock import expected_request def get_keyspace_view_from_args(args): keyspace = None view = None if len(args) == 1: keyspace_view = args[0].replace('/', '.', 1) try: keyspace, view = keyspace_view.split('.', 1) except ValueError: pass elif len(args) == 2: keyspace, view = args return keyspace, view def format_status(host, info): return f"{host:<9} {info:<7}\n" def format_output(keyspace, view, view_status): table = format_status("Host", "Info") succeed = True for host, status in view_status.items(): if status != 'SUCCESS': succeed = False table += format_status(host, status) output = '' if succeed: output += f"{keyspace}.{view} has finished building\n" else: output += f"{keyspace}.{view} has not finished building; node status is below.\n" output += "\n" output += table return output def id_from_param(param): args, statuses, _ = param if args: args_fmt = ','.join(args) else: args_fmt = '' if statuses: statuses_fmt = ','.join(statuses) else: statuses_fmt = '' return f"args({args_fmt})-statuses({statuses_fmt})" def format_invalid_argument_error(is_scylla): stdout = '' stderr = '' message = 'viewbuildstatus requires keyspace and view name arguments' if is_scylla: stderr += f'error processing arguments: {message}\n' else: progname = "nodetool" stdout += f"{progname}: {message}\n" stdout += f"See '{progname} help' or '{progname} help '.\n" return stdout, stderr test_params = [ ([], [], 1), (["ks"], [], 1), (["ks.view"], ['UNKNOWN'], 1), (["ks.view"], ['SUCCESS'], 0), (["ks.view"], ['STARTED', 'UNKNOWN', 'SUCCESS'], 1), (["ks.view"], ['STARTED', 'STARTED', 'STARTED'], 1), (["ks.view"], ['SUCCESS', 'SUCCESS', 'SUCCESS'], 0), (["ks/view"], ['SUCCESS'], 0), (["ks", "view"], ['SUCCESS'], 0), (["ks", "view", "something-more"], [], 1), ] @pytest.mark.parametrize("args,statuses,returncode", [pytest.param(*param, id=id_from_param(param)) for param in test_params]) def test_viewbuildstatus(request, nodetool, args, statuses, returncode): keyspace, view = get_keyspace_view_from_args(args) if keyspace is None: expected_requests = [] else: view_status = {f"127.0.0.{i}": status for i, status in enumerate(statuses)} expected_requests = [ expected_request("GET", f"/storage_service/view_build_statuses/{keyspace}/{view}", response=[{"key": host, "value": status} for host, status in view_status.items()]) ] expected_output = format_output(keyspace, view, view_status) if returncode != 0: is_scylla = request.config.getoption("nodetool") == "scylla" if all(status == 'SUCCESS' for status in statuses): # invalid argument with pytest.raises(CalledProcessError) as exc_info: res = nodetool("viewbuildstatus", *args, expected_requests=expected_requests) actual_output = res.stdout assert exc_info.type is CalledProcessError assert exc_info.value.returncode == 1 expected_stdout, expected_stderr = format_invalid_argument_error(is_scylla) assert exc_info.value.stdout == expected_stdout assert expected_stderr in exc_info.value.stderr else: with pytest.raises(CalledProcessError) as exc_info: res = nodetool("viewbuildstatus", *args, expected_requests=expected_requests) actual_output = res.stdout assert exc_info.type is CalledProcessError assert exc_info.value.returncode == 1 assert exc_info.value.output == expected_output else: res = nodetool("viewbuildstatus", *args, expected_requests=expected_requests) actual_output = res.stdout assert actual_output == expected_output