diff --git a/.gitignore b/.gitignore
index 51321392fb..ed7f15ce3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ last_test_dir
upgrade
html/
doxygen/doxypy-0.4.2/
+.pytest_cache/
+.vscode/
diff --git a/auth_test.py b/auth_test.py
index df57fb0120..a961465aaf 100644
--- a/auth_test.py
+++ b/auth_test.py
@@ -541,10 +541,16 @@ def test_materialized_views_auth(self):
* Create a new user, 'cathy', with no permissions
* Create a ks, table
* Connect as cathy
+ *
* Try CREATE MV without ALTER permission on base table, assert throws Unauthorized
* Grant cathy ALTER permissions, then CREATE MV successfully
+ *
+ * Try to MODIFY base without WRITE permission on base, assert throws Unauthorized
+ * Grant cathy WRITE permissions on base, and modify base successfully
+ *
* Try to SELECT from the mv, assert throws Unauthorized
- * Grant cathy SELECT permissions, and read from the MV successfully
+ * Grant cathy SELECT permissions on base, and read from the MV successfully
+ *
* Revoke cathy's ALTER permissions, assert DROP MV throws Unauthorized
* Restore cathy's ALTER permissions, DROP MV successfully
"""
@@ -565,12 +571,36 @@ def test_materialized_views_auth(self):
cassandra.execute("GRANT ALTER ON ks.cf TO cathy")
cathy.execute(create_mv)
- # TRY SELECT MV without SELECT permission on base table
- assert_unauthorized(cathy, "SELECT * FROM ks.mv1", "User cathy has no SELECT permission on
or any of its parents")
+ # Try MODIFY base without WRITE permission on base
+ assert_unauthorized(cathy, "INSERT INTO ks.cf(id, value) VALUES(1, '1')", "User cathy has no MODIFY permission on or any of its parents")
- # Grant SELECT permission and CREATE MV
- cassandra.execute("GRANT SELECT ON ks.cf TO cathy")
- cathy.execute("SELECT * FROM ks.mv1")
+ if self.cluster.version() >= LooseVersion('4.0'):
+ # From 4.0 onward, only base MODIFY permission is required to update base with MV
+ # Grant WRITE permission on Base
+ cassandra.execute("GRANT MODIFY ON ks.cf TO cathy")
+ cathy.execute("INSERT INTO ks.cf(id, value) VALUES(1, '1')")
+
+ # TRY SELECT MV without SELECT permission on base table
+ assert_unauthorized(cathy, "SELECT * FROM ks.cf", "User cathy has no SELECT permission on or any of its parents")
+ assert_unauthorized(cathy, "SELECT * FROM ks.mv1", "User cathy has no SELECT permission on or any of its parents")
+
+ # Grant SELECT permission
+ cassandra.execute("GRANT SELECT ON ks.cf TO cathy")
+ assert_one(cathy, "SELECT * FROM ks.cf", [1, '1'])
+ assert_one(cathy, "SELECT * FROM ks.mv1", ['1', 1])
+ else:
+ # Before 4.0, MODIFY on MV is required to insert to base
+ # Grant WRITE permission on Base
+ cassandra.execute("GRANT MODIFY ON ks.cf TO cathy")
+ assert_unauthorized(cathy, "INSERT INTO ks.cf(id, value) VALUES(1, '1')", "User cathy has no SELECT permission on or any of its parents")
+ cassandra.execute("GRANT SELECT ON ks.cf TO cathy")
+ assert_unauthorized(cathy, "INSERT INTO ks.cf(id, value) VALUES(1, '1')", "User cathy has no MODIFY permission on or any of its parents")
+
+ # Grant WRITE permission on MV
+ cassandra.execute("GRANT MODIFY ON ks.mv1 TO cathy")
+ cathy.execute("INSERT INTO ks.cf(id, value) VALUES(1, '1')")
+ assert_one(cathy, "SELECT * FROM ks.cf", [1, '1'])
+ assert_one(cathy, "SELECT * FROM ks.mv1", ['1', 1])
# Revoke ALTER permission and try DROP MV
cassandra.execute("REVOKE ALTER ON ks.cf FROM cathy")
diff --git a/repair_tests/repair_test.py b/repair_tests/repair_test.py
index ddae777343..4ff6d024ea 100644
--- a/repair_tests/repair_test.py
+++ b/repair_tests/repair_test.py
@@ -1195,6 +1195,40 @@ def run_repair():
else:
node1.nodetool('repair keyspace1 standard1 -inc -par')
+ @since('3.0')
+ def test_repair_one_node_cluster(self):
+ options = []
+ fix_STAR582 = self.cluster.version() >= "4.0"
+ if not fix_STAR582:
+ options = ['--ignore-unreplicated-keyspaces'] + options
+ self._repair_abort_test(options=options, nodes=1, rf=2)
+
+ @since('3.0')
+ def test_repair_one_node_in_local_dc(self):
+ self._repair_abort_test(options=['--ignore-unreplicated-keyspaces', '--in-local-dc'], nodes=[1, 1], rf={'dc1': 1, 'dc2': 1}, no_common_range=True)
+
+ def _repair_abort_test(self, options=[], nodes=1, rf=1, no_common_range=False):
+ cluster = self.cluster
+ logger.debug("Starting cluster..")
+ cluster.populate(nodes).start(wait_for_binary_proto=True)
+
+ node1 = self.cluster.nodelist()[0]
+ session = self.patient_cql_connection(node1)
+ create_ks(session, 'ks', rf=rf)
+
+ support_preview = self.cluster.version() >= "4.0"
+ if support_preview:
+ logger.debug("Preview repair")
+ out = node1.repair(["--preview"] + options)
+ if no_common_range:
+ assert "Nothing to repair for " in str(out), "Expect 'Nothing to repair for '"
+
+ logger.debug("Full repair")
+ node1.repair(["--full"] + options)
+
+ logger.debug("Incremental repair")
+ node1.repair(options)
+
@since('2.2')
def test_dead_sync_initiator(self):
"""