This patches introduces the test_scrub_drop_unfixable_sstables_option testcase, which verifies that correct request is generated when the --drop-unfixable-sstables flag is used. It also validates that an error is thrown if the drop-unfixable-sstables flag is enabled and mode is not set to SEGREGATE. This patch introduces test_scrub_drop_unfixable_sstables_option, which test
207 lines
10 KiB
Python
207 lines
10 KiB
Python
#
|
|
# Copyright 2023-present ScyllaDB
|
|
#
|
|
# SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
|
|
#
|
|
|
|
import enum
|
|
import pytest
|
|
|
|
from test.nodetool.utils import check_nodetool_fails_with
|
|
from test.nodetool.rest_api_mock import expected_request
|
|
|
|
|
|
class scrub_status(enum.Enum):
|
|
successful = 0
|
|
aborted = 1
|
|
unable_to_cancel = 2 # not used by ScyllaDB
|
|
validation_errors = 3
|
|
|
|
|
|
def test_scrub(nodetool):
|
|
nodetool("scrub", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks1", "ks2"],
|
|
multiple=expected_request.MULTIPLE),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks1", response=scrub_status.successful.value),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks2", response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_keyspace(nodetool):
|
|
nodetool("scrub", "ks", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_one_table(nodetool):
|
|
nodetool("scrub", "ks", "tbl1", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"cf": "tbl1"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_two_tables(nodetool):
|
|
nodetool("scrub", "ks", "tbl1", "tbl2", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"cf": "tbl1,tbl2"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_non_existent_keyspace(nodetool):
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "non_existent_ks"),
|
|
{"expected_requests": [expected_request("GET", "/storage_service/keyspaces", response=["ks"])]},
|
|
["nodetool: Keyspace [non_existent_ks] does not exist.",
|
|
"error processing arguments: keyspace non_existent_ks does not exist"])
|
|
|
|
|
|
# We don't test all values for --mode and --qurantine-mode, they are passed as-is
|
|
# to the REST API, so their value make no difference when testing nodetool itself.
|
|
@pytest.mark.parametrize("table", [[], ["tbl1"], ["tbl1", "tbl2"]])
|
|
@pytest.mark.parametrize("mode", [None, ("-m", "ABORT"), ("--mode", "ABORT"), "ABORT"])
|
|
@pytest.mark.parametrize("quarantine_mode", [None, ("--quarantine-mode", "INCLUDE"), ("-q", "ONLY")])
|
|
@pytest.mark.parametrize("disable_snapshot", [None, "--no-snapshot", "-ns"])
|
|
def test_scrub_options(request, nodetool, table, mode, quarantine_mode, disable_snapshot):
|
|
args = ["scrub", "ks"] + table
|
|
expected_params = {}
|
|
|
|
if table:
|
|
expected_params["cf"] = ",".join(table)
|
|
|
|
if mode is not None:
|
|
if type(mode) is tuple:
|
|
args += list(mode)
|
|
expected_params["scrub_mode"] = mode[1]
|
|
else:
|
|
args += ["--mode", mode]
|
|
expected_params["scrub_mode"] = mode
|
|
|
|
if quarantine_mode is not None:
|
|
if request.config.getoption("nodetool") == "scylla":
|
|
args += list(quarantine_mode)
|
|
expected_params["quarantine_mode"] = quarantine_mode[1]
|
|
else:
|
|
pytest.skip("--quarantine-mode only supported by scylla-nodetool")
|
|
|
|
if disable_snapshot:
|
|
args.append(disable_snapshot)
|
|
expected_params["disable_snapshot"] = "true"
|
|
|
|
nodetool(*args, expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params=expected_params,
|
|
response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_skip_corrupted(nodetool):
|
|
nodetool("scrub", "ks", "tbl1", "tbl2", "--skip-corrupted", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"cf": "tbl1,tbl2", "scrub_mode": "SKIP"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
nodetool("scrub", "ks", "tbl1", "tbl2", "-s", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"cf": "tbl1,tbl2", "scrub_mode": "SKIP"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
|
|
def test_scrub_skip_corrupted_with_mode(nodetool):
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "ks", "--skip-corrupted", "--mode", "ABORT"),
|
|
{"expected_requests": [expected_request("GET", "/storage_service/keyspaces", response=["ks"])]},
|
|
["nodetool: skipCorrupted and scrubMode must not be specified together",
|
|
"error processing arguments: cannot use --skip-corrupted when --mode is used"])
|
|
|
|
|
|
@pytest.mark.parametrize("ignored_opt", ["--reinsert-overflowed-ttl", "-r", ("--jobs", "2"), "-j2", "--no-validate",
|
|
"-n"])
|
|
def test_scrub_ignored_options(nodetool, ignored_opt):
|
|
args = ["scrub", "ks"]
|
|
if type(ignored_opt) is tuple:
|
|
args += list(ignored_opt)
|
|
else:
|
|
args.append(ignored_opt)
|
|
|
|
nodetool(*args, expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", response=scrub_status.successful.value)])
|
|
|
|
|
|
# Cassandra nodetool ignores the returned status
|
|
@pytest.mark.parametrize("status", [scrub_status.successful, scrub_status.aborted, scrub_status.validation_errors])
|
|
def test_scrub_return_status(nodetool, status, cassandra_only):
|
|
nodetool("scrub", "ks", "--mode=VALIDATE", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"scrub_mode": "VALIDATE"},
|
|
response=status.value)])
|
|
|
|
|
|
def test_scrub_validation_errors_exit_code(nodetool, scylla_only):
|
|
nodetool("scrub", "ks", "--mode=VALIDATE", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"scrub_mode": "VALIDATE"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "ks", "--mode=VALIDATE"),
|
|
{"expected_requests": [
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"scrub_mode": "VALIDATE"},
|
|
response=scrub_status.validation_errors.value)]},
|
|
["scrub failed: there are invalid sstables"])
|
|
|
|
# Check that when the first scrub fails, nodetool goes on to scrub the remainder
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "--mode=VALIDATE"),
|
|
{"expected_requests": [
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks1", "ks2"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks1", params={"scrub_mode": "VALIDATE"},
|
|
response=scrub_status.validation_errors.value),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks2", params={"scrub_mode": "VALIDATE"},
|
|
response=scrub_status.successful.value)]},
|
|
["scrub failed: there are invalid sstables"])
|
|
|
|
|
|
def test_scrub_abort_exit_code(nodetool, scylla_only):
|
|
nodetool("scrub", "ks", "--mode=ABORT", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"scrub_mode": "ABORT"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "ks", "--mode=ABORT"),
|
|
{"expected_requests": [
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"scrub_mode": "ABORT"},
|
|
response=scrub_status.aborted.value)]},
|
|
["scrub failed: aborted"])
|
|
|
|
# Check that when the first scrub fails, nodetool goes on to scrub the remainder
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "--mode=ABORT"),
|
|
{"expected_requests": [
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks1", "ks2"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks1", params={"scrub_mode": "ABORT"},
|
|
response=scrub_status.aborted.value),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks2", params={"scrub_mode": "ABORT"},
|
|
response=scrub_status.successful.value)]},
|
|
["scrub failed: aborted"])
|
|
|
|
def test_scrub_drop_unfixable_sstables_option(nodetool):
|
|
nodetool("scrub", "ks", "tbl1", "--mode=SEGREGATE", "--drop-unfixable-sstables", expected_requests=[
|
|
expected_request("GET", "/storage_service/keyspaces", response=["ks"]),
|
|
expected_request("GET", "/storage_service/keyspace_scrub/ks", params={"cf": "tbl1", "scrub_mode": "SEGREGATE",
|
|
"drop_unfixable_sstables": "true"},
|
|
response=scrub_status.successful.value)])
|
|
|
|
check_nodetool_fails_with(
|
|
nodetool,
|
|
("scrub", "ks", "tbl1", "--mode=ABORT", "--drop-unfixable-sstables"),
|
|
{"expected_requests": [expected_request("GET", "/storage_service/keyspaces", response=["ks"])]},
|
|
["error processing arguments: --drop-unfixable-sstables is only valid with --mode=SEGREGATE"])
|