This is an automated email from the ASF dual-hosted git repository. marcuse pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit b0855914ef673b183efec0dd132847ddb9d96f5f Merge: e603418 9e9dffb Author: Marcus Eriksson <[email protected]> AuthorDate: Mon Sep 20 13:38:05 2021 +0200 Merge branch 'cassandra-4.0' into trunk ide/idea/workspace.xml | 1 + .../db/compaction/CompactionAllocationTest.java | 3 - .../apache/cassandra/OrderedJUnit4ClassRunner.java | 55 ----- .../cassandra/audit/AuditLoggerAuthTest.java | 4 +- .../cassandra/config/DatabaseDescriptorTest.java | 3 - .../cql3/validation/operations/AlterNTSTest.java | 103 +++++++++ .../cql3/validation/operations/AlterTest.java | 77 ------- .../cql3/validation/operations/TTLTest.java | 12 +- .../apache/cassandra/db/ColumnFamilyStoreTest.java | 4 +- test/unit/org/apache/cassandra/db/ScrubTest.java | 238 ++++---------------- .../org/apache/cassandra/db/ScrubToolTest.java | 249 +++++++++++++++++++++ test/unit/org/apache/cassandra/db/VerifyTest.java | 6 - .../cassandra/db/compaction/CompactionsTest.java | 4 - .../compaction/LeveledCompactionStrategyTest.java | 3 - .../cassandra/db/compaction/TTLExpiryTest.java | 3 - .../org/apache/cassandra/dht/BootStrapperTest.java | 3 - .../cassandra/diag/DiagnosticEventServiceTest.java | 5 +- .../io/sstable/IndexSummaryManagerTest.java | 6 - .../cassandra/io/sstable/LargePartitionsTest.java | 3 - .../cassandra/locator/TokenMetadataTest.java | 3 - .../apache/cassandra/metrics/BatchMetricsTest.java | 3 - .../cassandra/metrics/BufferPoolMetricsTest.java | 3 - .../apache/cassandra/metrics/CQLMetricsTest.java | 3 - .../apache/cassandra/metrics/CacheMetricsTest.java | 3 - .../apache/cassandra/metrics/TableMetricsTest.java | 5 +- .../schema/MigrationManagerDropKSTest.java | 106 +++++++++ .../cassandra/schema/MigrationManagerTest.java | 53 ----- .../apache/cassandra/service/GCInspectorTest.java | 3 - .../apache/cassandra/service/QueryPagerTest.java | 3 - .../service/StorageServiceServerM3PTest.java | 68 ++++++ .../service/StorageServiceServerTest.java | 25 +-- .../cassandra/streaming/StreamingTransferTest.java | 4 +- .../org/apache/cassandra/tools/BulkLoaderTest.java | 6 +- .../cassandra/tools/CompactionStressTest.java | 3 - .../org/apache/cassandra/tools/GetVersionTest.java | 3 - .../apache/cassandra/tools/OfflineToolUtils.java | 1 + .../tools/SSTableExpiredBlockersTest.java | 3 - .../apache/cassandra/tools/SSTableExportTest.java | 4 - .../cassandra/tools/SSTableLevelResetterTest.java | 3 - .../cassandra/tools/SSTableMetadataViewerTest.java | 3 - .../cassandra/tools/SSTableOfflineRelevelTest.java | 3 - .../tools/SSTableRepairedAtSetterTest.java | 4 - .../cassandra/tools/StandaloneSSTableUtilTest.java | 18 -- .../cassandra/tools/StandaloneScrubberTest.java | 18 -- .../cassandra/tools/StandaloneSplitterTest.java | 18 -- .../tools/StandaloneSplitterWithCQLTesterTest.java | 70 +----- .../tools/StandaloneUpgraderOnSStablesTest.java | 8 +- .../cassandra/tools/StandaloneUpgraderTest.java | 18 -- .../cassandra/tools/StandaloneVerifierTest.java | 19 -- .../cassandra/tools/ToolsSchemaLoadingTest.java | 104 +++++++++ .../tools/nodetool/ClearSnapshotTest.java | 3 - .../cassandra/tools/nodetool/GetAuditLogTest.java | 3 - .../tools/nodetool/GetFullQueryLogTest.java | 3 - .../cassandra/tools/nodetool/GossipInfoTest.java | 3 - .../nodetool/InvalidateCredentialsCacheTest.java | 3 - .../InvalidateJmxPermissionsCacheTest.java | 3 - .../InvalidateNetworkPermissionsCacheTest.java | 3 - .../nodetool/InvalidatePermissionsCacheTest.java | 3 - .../tools/nodetool/InvalidateRolesCacheTest.java | 3 - .../cassandra/tools/nodetool/NetStatsTest.java | 3 - .../apache/cassandra/tools/nodetool/RingTest.java | 3 - .../cassandra/tools/nodetool/StatusTest.java | 3 - .../cassandra/tools/nodetool/TableStatsTest.java | 3 - .../cassandra/tools/nodetool/TpStatsTest.java | 3 - .../cassandra/transport/CQLUserAuditTest.java | 3 - 65 files changed, 693 insertions(+), 722 deletions(-) diff --cc test/memory/org/apache/cassandra/db/compaction/CompactionAllocationTest.java index 8c8b706,4398b3d..976872f --- a/test/memory/org/apache/cassandra/db/compaction/CompactionAllocationTest.java +++ b/test/memory/org/apache/cassandra/db/compaction/CompactionAllocationTest.java @@@ -76,9 -64,7 +74,8 @@@ import org.apache.cassandra.service.Cli import org.apache.cassandra.service.QueryState; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.utils.concurrent.Refs; - @RunWith(OrderedJUnit4ClassRunner.class) public class CompactionAllocationTest { private static final Logger logger = LoggerFactory.getLogger(CompactionAllocationTest.class); diff --cc test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java index 583c1eb,df88374..c22f963 --- a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java +++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java @@@ -30,16 -31,12 +30,15 @@@ import org.junit.Before import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; - import org.junit.runner.RunWith; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; +import org.apache.cassandra.io.util.FileUtils; +import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.service.snapshot.SnapshotManifest; +import org.apache.cassandra.service.snapshot.TableSnapshot; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.google.common.collect.Iterators; diff --cc test/unit/org/apache/cassandra/tools/nodetool/ClearSnapshotTest.java index 07a89d7,975e45b..2bbcf06 --- a/test/unit/org/apache/cassandra/tools/nodetool/ClearSnapshotTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/ClearSnapshotTest.java @@@ -23,18 -23,19 +23,15 @@@ import java.util.Map import javax.management.openmbean.TabularData; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; - import org.junit.runner.RunWith; - import org.apache.cassandra.OrderedJUnit4ClassRunner; import org.apache.cassandra.cql3.CQLTester; -import org.apache.cassandra.tools.ToolRunner.ToolResult; -import org.hamcrest.CoreMatchers; +import org.apache.cassandra.tools.NodeProbe; +import org.apache.cassandra.tools.ToolRunner; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) public class ClearSnapshotTest extends CQLTester { private static NodeProbe probe; diff --cc test/unit/org/apache/cassandra/tools/nodetool/GetAuditLogTest.java index d0eda31,0000000..069710b mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/GetAuditLogTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/GetAuditLogTest.java @@@ -1,155 -1,0 +1,152 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.tools.ToolRunner; + +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class GetAuditLogTest extends CQLTester +{ + @BeforeClass + public static void setup() throws Exception + { + startJMXServer(); + } + + @After + public void afterTest() + { + disableAuditLog(); + } + + @Test + public void getDefaultOutputTest() + { + testDefaultOutput(getAuditLog()); + } + + @Test + public void getSimpleOutputTest() + { + enableAuditLogSimple(); + testChangedOutputSimple(getAuditLog()); + } + + @Test + public void getComplexOutputTest() + { + enableAuditLogComplex(); + testChangedOutputComplex(getAuditLog()); + } + + @Test + public void disablingAuditLogResetsOutputTest() + { + enableAuditLogComplex(); + disableAuditLog(); + testDefaultOutput(getAuditLog()); + } + + private String getAuditLog() + { + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("getauditlog"); + tool.assertOnCleanExit(); + return tool.getStdout(); + } + + private void disableAuditLog() + { + ToolRunner.invokeNodetool("disableauditlog").assertOnCleanExit(); + } + + private void enableAuditLogSimple() + { + ToolRunner.invokeNodetool("enableauditlog").assertOnCleanExit(); + } + + private void enableAuditLogComplex() + { + ToolRunner.invokeNodetool("enableauditlog", + "--included-keyspaces", "ks1,ks2,ks3", + "--excluded-categories", "ddl,dcl").assertOnCleanExit(); + } + + @SuppressWarnings("DynamicRegexReplaceableByCompiledPattern") + private void testChangedOutputSimple(final String getAuditLogOutput) + { + final String output = getAuditLogOutput.replaceAll("( )+", " ").trim(); + assertThat(output).startsWith("enabled true"); + assertThat(output).contains("logger BinAuditLogger"); + assertThat(output).contains("roll_cycle HOURLY"); + assertThat(output).contains("block true"); + assertThat(output).contains("max_log_size 17179869184"); + assertThat(output).contains("max_queue_weight 268435456"); + assertThat(output).contains("max_archive_retries 10"); + assertThat(output).contains("included_keyspaces \n"); + assertThat(output).contains("excluded_keyspaces system,system_schema,system_virtual_schema"); + assertThat(output).contains("included_categories \n"); + assertThat(output).contains("excluded_categories \n"); + assertThat(output).contains("included_users \n"); + assertThat(output).endsWith("excluded_users"); + } + + @SuppressWarnings("DynamicRegexReplaceableByCompiledPattern") + private void testChangedOutputComplex(final String getAuditLogOutput) + { + final String output = getAuditLogOutput.replaceAll("( )+", " ").trim(); + assertThat(output).startsWith("enabled true"); + assertThat(output).contains("logger BinAuditLogger"); + assertThat(output).contains("roll_cycle HOURLY"); + assertThat(output).contains("block true"); + assertThat(output).contains("max_log_size 17179869184"); + assertThat(output).contains("max_queue_weight 268435456"); + assertThat(output).contains("max_archive_retries 10"); + assertThat(output).contains("included_keyspaces ks1,ks2,ks3"); + assertThat(output).contains("excluded_keyspaces system,system_schema,system_virtual_schema"); + assertThat(output).contains("included_categories \n"); + assertThat(output).contains("excluded_categories DDL,DCL"); + assertThat(output).contains("included_users \n"); + assertThat(output).endsWith("excluded_users"); + } + + @SuppressWarnings("DynamicRegexReplaceableByCompiledPattern") + private void testDefaultOutput(final String getAuditLogOutput) + { + final String output = getAuditLogOutput.replaceAll("( )+", " ").trim(); + assertThat(output).startsWith("enabled false"); + assertThat(output).contains("logger BinAuditLogger"); + assertThat(output).contains("roll_cycle HOURLY"); + assertThat(output).contains("block true"); + assertThat(output).contains("max_log_size 17179869184"); + assertThat(output).contains("max_queue_weight 268435456"); + assertThat(output).contains("max_archive_retries 10"); + assertThat(output).contains("included_keyspaces \n"); + assertThat(output).contains("excluded_keyspaces system,system_schema,system_virtual_schema"); + assertThat(output).contains("included_categories \n"); + assertThat(output).contains("excluded_categories \n"); + assertThat(output).contains("included_users \n"); + assertThat(output).endsWith("excluded_users"); + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/GetFullQueryLogTest.java index c4eb70c,44007a5..61d34ec --- a/test/unit/org/apache/cassandra/tools/nodetool/GetFullQueryLogTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/GetFullQueryLogTest.java @@@ -23,18 -26,18 +23,15 @@@ import org.junit.BeforeClass import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.TemporaryFolder; - import org.junit.runner.RunWith; - import org.apache.cassandra.OrderedJUnit4ClassRunner; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.fql.FullQueryLoggerOptions; -import org.apache.cassandra.tools.ToolRunner.ToolResult; +import org.apache.cassandra.tools.ToolRunner; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) public class GetFullQueryLogTest extends CQLTester { - private static NodeProbe probe; - @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); diff --cc test/unit/org/apache/cassandra/tools/nodetool/GossipInfoTest.java index 7a48db8,0000000..35801fd mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/GossipInfoTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/GossipInfoTest.java @@@ -1,124 -1,0 +1,121 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.net.Message; +import org.apache.cassandra.net.MessagingService; +import org.apache.cassandra.net.NoPayload; +import org.apache.cassandra.service.StorageService; +import org.apache.cassandra.tools.ToolRunner; +import org.apache.cassandra.utils.FBUtilities; +import org.assertj.core.api.Assertions; + +import static org.apache.cassandra.net.Verb.ECHO_REQ; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class GossipInfoTest extends CQLTester +{ + private static String token; + + @BeforeClass + public static void setup() throws Exception + { + requireNetwork(); + startJMXServer(); + token = StorageService.instance.getTokens().get(0); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "gossipinfo"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool gossipinfo - Shows the gossip information for the cluster\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)] gossipinfo\n" + + "\n" + + "OPTIONS\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testGossipInfo() + { + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("gossipinfo"); + tool.assertOnCleanExit(); + String stdout = tool.getStdout(); + Assertions.assertThat(stdout).contains("/127.0.0.1"); + Assertions.assertThat(stdout).containsPattern("\\s+generation:[0-9]+"); + Assertions.assertThat(stdout).containsPattern("heartbeat:[0-9]+"); + Assertions.assertThat(stdout).containsPattern("STATUS:[0-9]+:NORMAL," + token); + Assertions.assertThat(stdout).containsPattern("SCHEMA:.+"); + Assertions.assertThat(stdout).containsPattern("DC:[0-9]+:datacenter1"); + Assertions.assertThat(stdout).containsPattern("RACK:[0-9]+:rack1"); + Assertions.assertThat(stdout).containsPattern("RELEASE_VERSION:.+"); + Assertions.assertThat(stdout).containsPattern("RPC_ADDRESS:[0-9]+:127.0.0.1"); + Assertions.assertThat(stdout).containsPattern("NET_VERSION:[0-9]+:.+"); + Assertions.assertThat(stdout).containsPattern("HOST_ID:[0-9]+:.+"); + Assertions.assertThat(stdout).containsPattern("NATIVE_ADDRESS_AND_PORT:[0-9]+:127.0.0.1:[0-9]+"); + Assertions.assertThat(stdout).containsPattern("SSTABLE_VERSIONS:[0-9]+:"); + Assertions.assertThat(stdout).containsPattern("STATUS_WITH_PORT:[0-9]+:NORMAL,.+"); + Assertions.assertThat(stdout).containsPattern("TOKENS:[0-9]+:<hidden>"); + + // Make sure heartbeats are detected + Message<NoPayload> echoMessageOut = Message.out(ECHO_REQ, NoPayload.noPayload); + MessagingService.instance().send(echoMessageOut, FBUtilities.getBroadcastAddressAndPort()); + + String origHeartbeatCount = StringUtils.substringBetween(stdout, "heartbeat:", "\n"); + tool = ToolRunner.invokeNodetool("gossipinfo"); + tool.assertOnCleanExit(); + String newHeartbeatCount = StringUtils.substringBetween(stdout, "heartbeat:", "\n"); + assertThat(Integer.parseInt(origHeartbeatCount)).isLessThanOrEqualTo(Integer.parseInt(newHeartbeatCount)); + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java index 7ed5530,0000000..fbe631b mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java @@@ -1,171 -1,0 +1,168 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + +import com.datastax.driver.core.EndPoint; +import com.datastax.driver.core.PlainTextAuthProvider; - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.auth.AuthTestUtils; +import org.apache.cassandra.auth.AuthenticatedUser; +import org.apache.cassandra.auth.IAuthenticator; +import org.apache.cassandra.auth.PasswordAuthenticator; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.tools.ToolRunner; + +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A; +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B; +import static org.apache.cassandra.auth.AuthTestUtils.getRolesReadCount; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class InvalidateCredentialsCacheTest extends CQLTester +{ + private static IAuthenticator.SaslNegotiator roleANegotiator; + private static IAuthenticator.SaslNegotiator roleBNegotiator; + + @BeforeClass + public static void setup() throws Exception + { + SchemaLoader.prepareServer(); + AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager(); + PasswordAuthenticator authenticator = new AuthTestUtils.LocalPasswordAuthenticator(); + SchemaLoader.setupAuth(roleManager, + authenticator, + new AuthTestUtils.LocalCassandraAuthorizer(), + new AuthTestUtils.LocalCassandraNetworkAuthorizer()); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOprions()); + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOprions()); + + roleANegotiator = authenticator.newSaslNegotiator(null); + roleANegotiator.evaluateResponse(new PlainTextAuthProvider(ROLE_A.getRoleName(), "ignored") + .newAuthenticator((EndPoint) null, null) + .initialResponse()); + roleBNegotiator = authenticator.newSaslNegotiator(null); + roleBNegotiator.evaluateResponse(new PlainTextAuthProvider(ROLE_B.getRoleName(), "ignored") + .newAuthenticator((EndPoint) null, null) + .initialResponse()); + + startJMXServer(); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "invalidatecredentialscache"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool invalidatecredentialscache - Invalidate the credentials cache\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)] invalidatecredentialscache\n" + + " [--] [<role>...]\n" + + "\n" + + "OPTIONS\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + " --\n" + + " This option can be used to separate command-line options from the\n" + + " list of argument, (useful when arguments might be mistaken for\n" + + " command-line options\n" + + "\n" + + " [<role>...]\n" + + " List of roles to invalidate. By default, all roles\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testInvalidateSingleCredential() + { + // cache credential + roleANegotiator.getAuthenticatedUser(); + long originalReadsCount = getRolesReadCount(); + + // enure credential is cached + assertThat(roleANegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_A.getRoleName())); + assertThat(originalReadsCount).isEqualTo(getRolesReadCount()); + + // invalidate credential + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatecredentialscache", ROLE_A.getRoleName()); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure credential is reloaded + assertThat(roleANegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_A.getRoleName())); + assertThat(originalReadsCount).isLessThan(getRolesReadCount()); + } + + @Test + public void testInvalidateAllCredentials() + { + // cache credentials + roleANegotiator.getAuthenticatedUser(); + roleBNegotiator.getAuthenticatedUser(); + long originalReadsCount = getRolesReadCount(); + + // enure credentials are cached + assertThat(roleANegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_A.getRoleName())); + assertThat(roleBNegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_B.getRoleName())); + assertThat(originalReadsCount).isEqualTo(getRolesReadCount()); + + // invalidate both credentials + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatecredentialscache"); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure credential for roleA is reloaded + assertThat(roleANegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_A.getRoleName())); + long readsCountAfterFirstReLoad = getRolesReadCount(); + assertThat(originalReadsCount).isLessThan(readsCountAfterFirstReLoad); + + // ensure credential for roleB is reloaded + assertThat(roleBNegotiator.getAuthenticatedUser()).isEqualTo(new AuthenticatedUser(ROLE_B.getRoleName())); + long readsCountAfterSecondReLoad = getRolesReadCount(); + assertThat(readsCountAfterFirstReLoad).isLessThan(readsCountAfterSecondReLoad); + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java index 81fa2c5,0000000..f412147 mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java @@@ -1,192 -1,0 +1,189 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import java.util.Set; +import javax.security.auth.Subject; + +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.auth.AuthTestUtils; +import org.apache.cassandra.auth.AuthenticatedUser; +import org.apache.cassandra.auth.CassandraPrincipal; +import org.apache.cassandra.auth.JMXResource; +import org.apache.cassandra.auth.Permission; +import org.apache.cassandra.auth.jmx.AuthorizationProxy; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.tools.ToolRunner; + +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A; +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B; +import static org.apache.cassandra.auth.AuthTestUtils.getRolePermissionsReadCount; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class InvalidateJmxPermissionsCacheTest extends CQLTester +{ + private static final AuthorizationProxy authorizationProxy = new NoAuthSetupAuthorizationProxy(); + + @BeforeClass + public static void setup() throws Exception + { + SchemaLoader.prepareServer(); + AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager(); + AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer(); + SchemaLoader.setupAuth(roleManager, + new AuthTestUtils.LocalPasswordAuthenticator(), + authorizer, + new AuthTestUtils.LocalCassandraNetworkAuthorizer()); + + JMXResource rootJmxResource = JMXResource.root(); + Set<Permission> jmxPermissions = rootJmxResource.applicablePermissions(); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOprions()); + authorizer.grant(AuthenticatedUser.SYSTEM_USER, jmxPermissions, rootJmxResource, ROLE_A); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOprions()); + authorizer.grant(AuthenticatedUser.SYSTEM_USER, jmxPermissions, rootJmxResource, ROLE_B); + + startJMXServer(); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "invalidatejmxpermissionscache"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool invalidatejmxpermissionscache - Invalidate the JMX permissions\n" + + " cache\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)] invalidatejmxpermissionscache\n" + + " [--] [<role>...]\n" + + "\n" + + "OPTIONS\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + " --\n" + + " This option can be used to separate command-line options from the\n" + + " list of argument, (useful when arguments might be mistaken for\n" + + " command-line options\n" + + "\n" + + " [<role>...]\n" + + " List of roles to invalidate. By default, all roles\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testInvalidateSingleJMXPermission() + { + Subject userSubject = subject(ROLE_A.getRoleName()); + + // cache role permission + authorizationProxy.authorize(userSubject, "queryNames", null); + long originalReadsCount = getRolePermissionsReadCount(); + + // enure role permission is cached + assertThat(authorizationProxy.authorize(userSubject, "queryNames", null)).isTrue(); + assertThat(originalReadsCount).isEqualTo(getRolePermissionsReadCount()); + + // invalidate role permission + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatejmxpermissionscache", ROLE_A.getRoleName()); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure role permission is reloaded + assertThat(authorizationProxy.authorize(userSubject, "queryNames", null)).isTrue(); + assertThat(originalReadsCount).isLessThan(getRolePermissionsReadCount()); + } + + @Test + public void testInvalidateAllJMXPermissions() + { + Subject roleASubject = subject(ROLE_A.getRoleName()); + Subject roleBSubject = subject(ROLE_B.getRoleName()); + + // cache role permissions + authorizationProxy.authorize(roleASubject, "queryNames", null); + authorizationProxy.authorize(roleBSubject, "queryNames", null); + long originalReadsCount = getRolePermissionsReadCount(); + + // enure role permissions are cached + assertThat(authorizationProxy.authorize(roleASubject, "queryNames", null)).isTrue(); + assertThat(authorizationProxy.authorize(roleBSubject, "queryNames", null)).isTrue(); + assertThat(originalReadsCount).isEqualTo(getRolePermissionsReadCount()); + + // invalidate both role permissions + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatejmxpermissionscache"); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure role permission for roleA is reloaded + assertThat(authorizationProxy.authorize(roleASubject, "queryNames", null)).isTrue(); + long readsCountAfterFirstReLoad = getRolePermissionsReadCount(); + assertThat(originalReadsCount).isLessThan(readsCountAfterFirstReLoad); + + // ensure role permission for roleB is reloaded + assertThat(authorizationProxy.authorize(roleBSubject, "queryNames", null)).isTrue(); + long readsCountAfterSecondReLoad = getRolePermissionsReadCount(); + assertThat(readsCountAfterFirstReLoad).isLessThan(readsCountAfterSecondReLoad); + } + + private static Subject subject(String roleName) + { + Subject subject = new Subject(); + subject.getPrincipals().add(new CassandraPrincipal(roleName)); + return subject; + } + + private static class NoAuthSetupAuthorizationProxy extends AuthorizationProxy + { + public NoAuthSetupAuthorizationProxy() + { + super(); + this.isAuthSetupComplete = () -> true; + } + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java index cef29b3,0000000..8200a80 mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java @@@ -1,160 -1,0 +1,157 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.auth.AuthTestUtils; +import org.apache.cassandra.auth.AuthenticatedUser; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.tools.ToolRunner; + +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A; +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B; +import static org.apache.cassandra.auth.AuthTestUtils.getNetworkPermissionsReadCount; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class InvalidateNetworkPermissionsCacheTest extends CQLTester +{ + @BeforeClass + public static void setup() throws Exception + { + SchemaLoader.prepareServer(); + AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager(); + SchemaLoader.setupAuth(roleManager, + new AuthTestUtils.LocalPasswordAuthenticator(), + new AuthTestUtils.LocalCassandraAuthorizer(), + new AuthTestUtils.LocalCassandraNetworkAuthorizer()); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOprions()); + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOprions()); + + startJMXServer(); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "invalidatenetworkpermissionscache"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool invalidatenetworkpermissionscache - Invalidate the network\n" + + " permissions cache\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)]\n" + + " invalidatenetworkpermissionscache [--] [<role>...]\n" + + "\n" + + "OPTIONS\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + " --\n" + + " This option can be used to separate command-line options from the\n" + + " list of argument, (useful when arguments might be mistaken for\n" + + " command-line options\n" + + "\n" + + " [<role>...]\n" + + " List of roles to invalidate. By default, all roles\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testInvalidateSingleNetworkPermission() + { + AuthenticatedUser role = new AuthenticatedUser(ROLE_A.getRoleName()); + + // cache network permission + role.hasLocalAccess(); + long originalReadsCount = getNetworkPermissionsReadCount(); + + // enure network permission is cached + assertThat(role.hasLocalAccess()).isTrue(); + assertThat(originalReadsCount).isEqualTo(getNetworkPermissionsReadCount()); + + // invalidate network permission + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatenetworkpermissionscache", ROLE_A.getRoleName()); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure network permission is reloaded + assertThat(role.hasLocalAccess()).isTrue(); + assertThat(originalReadsCount).isLessThan(getNetworkPermissionsReadCount()); + } + + @Test + public void testInvalidateAllNetworkPermissions() + { + AuthenticatedUser roleA = new AuthenticatedUser(ROLE_A.getRoleName()); + AuthenticatedUser roleB = new AuthenticatedUser(ROLE_B.getRoleName()); + + // cache network permissions + roleA.hasLocalAccess(); + roleB.hasLocalAccess(); + long originalReadsCount = getNetworkPermissionsReadCount(); + + // enure network permissions are cached + assertThat(roleA.hasLocalAccess()).isTrue(); + assertThat(roleB.hasLocalAccess()).isTrue(); + assertThat(originalReadsCount).isEqualTo(getNetworkPermissionsReadCount()); + + // invalidate both network permissions + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatenetworkpermissionscache"); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure network permission for roleA is reloaded + assertThat(roleA.hasLocalAccess()).isTrue(); + long readsCountAfterFirstReLoad = getNetworkPermissionsReadCount(); + assertThat(originalReadsCount).isLessThan(readsCountAfterFirstReLoad); + + // ensure network permission for roleB is reloaded + assertThat(roleB.hasLocalAccess()).isTrue(); + long readsCountAfterSecondReLoad = getNetworkPermissionsReadCount(); + assertThat(readsCountAfterFirstReLoad).isLessThan(readsCountAfterSecondReLoad); + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java index caaabf2,0000000..4b23a6d mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java @@@ -1,317 -1,0 +1,314 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.auth.AuthTestUtils; +import org.apache.cassandra.auth.AuthenticatedUser; +import org.apache.cassandra.auth.DataResource; +import org.apache.cassandra.auth.FunctionResource; +import org.apache.cassandra.auth.IResource; +import org.apache.cassandra.auth.JMXResource; +import org.apache.cassandra.auth.Permission; +import org.apache.cassandra.auth.RoleResource; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.db.marshal.Int32Type; +import org.apache.cassandra.tools.ToolRunner; + +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A; +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B; +import static org.apache.cassandra.auth.AuthTestUtils.getRolePermissionsReadCount; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class InvalidatePermissionsCacheTest extends CQLTester +{ + @BeforeClass + public static void setup() throws Exception + { + SchemaLoader.prepareServer(); + AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager(); + AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer(); + SchemaLoader.setupAuth(roleManager, + new AuthTestUtils.LocalPasswordAuthenticator(), + authorizer, + new AuthTestUtils.LocalCassandraNetworkAuthorizer()); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOprions()); + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOprions()); + + List<IResource> resources = Arrays.asList( + DataResource.root(), + DataResource.keyspace(KEYSPACE), + DataResource.table(KEYSPACE, "t1"), + RoleResource.root(), + RoleResource.role("role_x"), + FunctionResource.root(), + FunctionResource.keyspace(KEYSPACE), + // Particular function is excluded from here and covered by a separate test because in order to grant + // permissions we need to have a function registered. However, the function cannot be registered via + // CQLTester.createFunction from static contex. That's why we initialize it in a separate test case. + JMXResource.root(), + JMXResource.mbean("org.apache.cassandra.auth:type=*")); + + for (IResource resource : resources) + { + Set<Permission> permissions = resource.applicablePermissions(); + authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_A); + authorizer.grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_B); + } + + startJMXServer(); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "invalidatepermissionscache"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool invalidatepermissionscache - Invalidate the permissions cache\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)] invalidatepermissionscache\n" + + " [--all-functions] [--all-keyspaces] [--all-mbeans] [--all-roles]\n" + + " [--function <function>]\n" + + " [--functions-in-keyspace <functions-in-keyspace>]\n" + + " [--keyspace <keyspace>] [--mbean <mbean>] [--role <role>]\n" + + " [--table <table>] [--] [<user>]\n" + + "\n" + + "OPTIONS\n" + + " --all-functions\n" + + " Invalidate permissions for 'ALL FUNCTIONS'\n" + + "\n" + + " --all-keyspaces\n" + + " Invalidate permissions for 'ALL KEYSPACES'\n" + + "\n" + + " --all-mbeans\n" + + " Invalidate permissions for 'ALL MBEANS'\n" + + "\n" + + " --all-roles\n" + + " Invalidate permissions for 'ALL ROLES'\n" + + "\n" + + " --function <function>\n" + + " Function to invalidate permissions for (you must specify\n" + + " --functions-in-keyspace for using this option; function format:\n" + + " name[arg1^..^agrN], for example: foo[Int32Type^DoubleType])\n" + + "\n" + + " --functions-in-keyspace <functions-in-keyspace>\n" + + " Keyspace to invalidate permissions for\n" + + "\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " --keyspace <keyspace>\n" + + " Keyspace to invalidate permissions for\n" + + "\n" + + " --mbean <mbean>\n" + + " MBean to invalidate permissions for\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " --role <role>\n" + + " Role to invalidate permissions for\n" + + "\n" + + " --table <table>\n" + + " Table to invalidate permissions for (you must specify --keyspace for\n" + + " using this option)\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + " --\n" + + " This option can be used to separate command-line options from the\n" + + " list of argument, (useful when arguments might be mistaken for\n" + + " command-line options\n" + + "\n" + + " [<user>]\n" + + " A specific user for whom permissions need to be invalidated\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testInvalidatePermissionsWithIncorrectParameters() + { + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "--all-keyspaces"); + assertThat(tool.getExitCode()).isEqualTo(1); + assertThat(tool.getStdout()) + .isEqualTo(wrapByDefaultNodetoolMessage("No options allowed without a <user> being specified")); + assertThat(tool.getStderr()).isEmpty(); + + tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--invalid-option"); + assertThat(tool.getExitCode()).isEqualTo(1); + assertThat(tool.getStdout()) + .isEqualTo(wrapByDefaultNodetoolMessage("A single <user> is only supported / you have a typo in the options spelling")); + assertThat(tool.getStderr()).isEmpty(); + + tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--table", "t1"); + assertThat(tool.getExitCode()).isEqualTo(1); + assertThat(tool.getStdout()) + .isEqualTo(wrapByDefaultNodetoolMessage("--table option should be passed along with --keyspace option")); + assertThat(tool.getStderr()).isEmpty(); + + tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--function", "f[Int32Type]"); + assertThat(tool.getExitCode()).isEqualTo(1); + assertThat(tool.getStdout()) + .isEqualTo(wrapByDefaultNodetoolMessage("--function option should be passed along with --functions-in-keyspace option")); + assertThat(tool.getStderr()).isEmpty(); + + tool = ToolRunner.invokeNodetool("invalidatepermissionscache", "user1", "--functions-in-keyspace", + KEYSPACE, "--function", "f[x]"); + assertThat(tool.getExitCode()).isEqualTo(1); + assertThat(tool.getStdout()) + .isEqualTo(wrapByDefaultNodetoolMessage("An error was encountered when looking up function definition; Unable to find abstract-type class 'org.apache.cassandra.db.marshal.x'")); + assertThat(tool.getStderr()).isEmpty(); + } + + @Test + public void testInvalidatePermissionsForEveryResourceExceptFunction() + { + assertInvalidation(DataResource.root(), Collections.singletonList("--all-keyspaces")); + assertInvalidation(DataResource.keyspace(KEYSPACE), Arrays.asList("--keyspace", KEYSPACE)); + assertInvalidation(DataResource.table(KEYSPACE, "t1"), + Arrays.asList("--keyspace", KEYSPACE, "--table", "t1")); + assertInvalidation(RoleResource.root(), Collections.singletonList("--all-roles")); + assertInvalidation(RoleResource.role("role_x"), Arrays.asList("--role", "role_x")); + assertInvalidation(FunctionResource.root(), Collections.singletonList("--all-functions")); + assertInvalidation(FunctionResource.keyspace(KEYSPACE), Arrays.asList("--functions-in-keyspace", KEYSPACE)); + assertInvalidation(JMXResource.root(), Collections.singletonList("--all-mbeans")); + assertInvalidation(JMXResource.mbean("org.apache.cassandra.auth:type=*"), + Arrays.asList("--mbean", "org.apache.cassandra.auth:type=*")); + } + + @Test + public void testInvalidatePermissionsForFunction() throws Throwable + { + String keyspaceAndFunctionName = createFunction(KEYSPACE, "int", + " CREATE FUNCTION %s (val int)" + + " CALLED ON NULL INPUT" + + " RETURNS int" + + " LANGUAGE java" + + " AS 'return val;'"); + String functionName = StringUtils.split(keyspaceAndFunctionName, ".")[1]; + + FunctionResource resource = FunctionResource.function(KEYSPACE, functionName, Collections.singletonList(Int32Type.instance)); + Set<Permission> permissions = resource.applicablePermissions(); + DatabaseDescriptor.getAuthorizer().grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_A); + DatabaseDescriptor.getAuthorizer().grant(AuthenticatedUser.SYSTEM_USER, permissions, resource, ROLE_B); + + assertInvalidation(resource, + Arrays.asList("--functions-in-keyspace", KEYSPACE, "--function", functionName + "[Int32Type]")); + } + + private void assertInvalidation(IResource resource, List<String> options) + { + Set<Permission> dataPermissions = resource.applicablePermissions(); + + AuthenticatedUser role = new AuthenticatedUser(ROLE_A.getRoleName()); + + // cache permission + role.getPermissions(resource); + long originalReadsCount = getRolePermissionsReadCount(); + + // enure permission is cached + assertThat(role.getPermissions(resource)).isEqualTo(dataPermissions); + assertThat(originalReadsCount).isEqualTo(getRolePermissionsReadCount()); + + // invalidate permission + List<String> args = new ArrayList<>(); + args.add("invalidatepermissionscache"); + args.add(ROLE_A.getRoleName()); + args.addAll(options); + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool(args); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure permission is reloaded + assertThat(role.getPermissions(resource)).isEqualTo(dataPermissions); + assertThat(originalReadsCount).isLessThan(getRolePermissionsReadCount()); + } + + @Test + public void testInvalidatePermissionsForAllUsers() + { + DataResource rootDataResource = DataResource.root(); + Set<Permission> dataPermissions = rootDataResource.applicablePermissions(); + + AuthenticatedUser roleA = new AuthenticatedUser(ROLE_A.getRoleName()); + AuthenticatedUser roleB = new AuthenticatedUser(ROLE_B.getRoleName()); + + // cache permissions + roleA.getPermissions(rootDataResource); + roleB.getPermissions(rootDataResource); + long originalReadsCount = getRolePermissionsReadCount(); + + // enure permissions are cached + assertThat(roleA.getPermissions(rootDataResource)).isEqualTo(dataPermissions); + assertThat(roleB.getPermissions(rootDataResource)).isEqualTo(dataPermissions); + assertThat(originalReadsCount).isEqualTo(getRolePermissionsReadCount()); + + // invalidate both permissions + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidatepermissionscache"); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure permission for roleA is reloaded + assertThat(roleA.getPermissions(rootDataResource)).isEqualTo(dataPermissions); + long readsCountAfterFirstReLoad = getRolePermissionsReadCount(); + assertThat(originalReadsCount).isLessThan(readsCountAfterFirstReLoad); + + // ensure permission for roleB is reloaded + assertThat(roleB.getPermissions(rootDataResource)).isEqualTo(dataPermissions); + long readsCountAfterSecondReLoad = getRolePermissionsReadCount(); + assertThat(readsCountAfterFirstReLoad).isLessThan(readsCountAfterSecondReLoad); + } + + private String wrapByDefaultNodetoolMessage(String s) + { + return "nodetool: " + s + "\nSee 'nodetool help' or 'nodetool help <command>'.\n"; + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java index 80596b3,0000000..36eb64e mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java @@@ -1,159 -1,0 +1,156 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.tools.nodetool; + +import org.junit.BeforeClass; +import org.junit.Test; - import org.junit.runner.RunWith; + - import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.auth.AuthTestUtils; +import org.apache.cassandra.auth.AuthenticatedUser; +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.tools.ToolRunner; + +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_A; +import static org.apache.cassandra.auth.AuthTestUtils.ROLE_B; +import static org.apache.cassandra.auth.AuthTestUtils.getRolesReadCount; +import static org.assertj.core.api.Assertions.assertThat; + - @RunWith(OrderedJUnit4ClassRunner.class) +public class InvalidateRolesCacheTest extends CQLTester +{ + @BeforeClass + public static void setup() throws Exception + { + SchemaLoader.prepareServer(); + AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager(); + SchemaLoader.setupAuth(roleManager, + new AuthTestUtils.LocalPasswordAuthenticator(), + new AuthTestUtils.LocalCassandraAuthorizer(), + new AuthTestUtils.LocalCassandraNetworkAuthorizer()); + + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOprions()); + roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOprions()); + + startJMXServer(); + } + + @Test + @SuppressWarnings("SingleCharacterStringConcatenation") + public void testMaybeChangeDocs() + { + // If you added, modified options or help, please update docs if necessary + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "invalidaterolescache"); + tool.assertOnCleanExit(); + + String help = "NAME\n" + + " nodetool invalidaterolescache - Invalidate the roles cache\n" + + "\n" + + "SYNOPSIS\n" + + " nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" + + " [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" + + " [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" + + " [(-u <username> | --username <username>)] invalidaterolescache [--]\n" + + " [<role>...]\n" + + "\n" + + "OPTIONS\n" + + " -h <host>, --host <host>\n" + + " Node hostname or ip address\n" + + "\n" + + " -p <port>, --port <port>\n" + + " Remote jmx agent port number\n" + + "\n" + + " -pp, --print-port\n" + + " Operate in 4.0 mode with hosts disambiguated by port number\n" + + "\n" + + " -pw <password>, --password <password>\n" + + " Remote jmx agent password\n" + + "\n" + + " -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" + + " Path to the JMX password file\n" + + "\n" + + " -u <username>, --username <username>\n" + + " Remote jmx agent username\n" + + "\n" + + " --\n" + + " This option can be used to separate command-line options from the\n" + + " list of argument, (useful when arguments might be mistaken for\n" + + " command-line options\n" + + "\n" + + " [<role>...]\n" + + " List of roles to invalidate. By default, all roles\n" + + "\n" + + "\n"; + assertThat(tool.getStdout()).isEqualTo(help); + } + + @Test + public void testInvalidateSingleRole() + { + AuthenticatedUser role = new AuthenticatedUser(ROLE_A.getRoleName()); + + // cache role + role.canLogin(); + long originalReadsCount = getRolesReadCount(); + + // enure role is cached + assertThat(role.canLogin()).isTrue(); + assertThat(originalReadsCount).isEqualTo(getRolesReadCount()); + + // invalidate role + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidaterolescache", ROLE_A.getRoleName()); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure role is reloaded + assertThat(role.canLogin()).isTrue(); + assertThat(originalReadsCount).isLessThan(getRolesReadCount()); + } + + @Test + public void testInvalidateAllRoles() + { + AuthenticatedUser roleA = new AuthenticatedUser(ROLE_A.getRoleName()); + AuthenticatedUser roleB = new AuthenticatedUser(ROLE_B.getRoleName()); + + // cache roles + roleA.canLogin(); + roleB.canLogin(); + long originalReadsCount = getRolesReadCount(); + + // enure roles are cached + assertThat(roleA.canLogin()).isTrue(); + assertThat(roleB.canLogin()).isTrue(); + assertThat(originalReadsCount).isEqualTo(getRolesReadCount()); + + // invalidate both roles + ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("invalidaterolescache"); + tool.assertOnCleanExit(); + assertThat(tool.getStdout()).isEmpty(); + + // ensure role for roleA is reloaded + assertThat(roleA.canLogin()).isTrue(); + long readsCountAfterFirstReLoad = getRolesReadCount(); + assertThat(originalReadsCount).isLessThan(readsCountAfterFirstReLoad); + + // ensure role for roleB is reloaded + assertThat(roleB.canLogin()).isTrue(); + long readsCountAfterSecondReLoad = getRolesReadCount(); + assertThat(readsCountAfterFirstReLoad).isLessThan(readsCountAfterSecondReLoad); + } +} diff --cc test/unit/org/apache/cassandra/tools/nodetool/NetStatsTest.java index 330a555,bcf8704..f8bd530 --- a/test/unit/org/apache/cassandra/tools/nodetool/NetStatsTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/NetStatsTest.java @@@ -25,11 -25,10 +25,9 @@@ import java.nio.charset.StandardCharset import java.util.Collections; import java.util.List; -import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - import org.junit.runner.RunWith; - import org.apache.cassandra.OrderedJUnit4ClassRunner; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.net.Message; @@@ -39,15 -38,20 +37,14 @@@ import org.apache.cassandra.schema.Tabl import org.apache.cassandra.streaming.SessionInfo; import org.apache.cassandra.streaming.StreamSession.State; import org.apache.cassandra.streaming.StreamSummary; -import org.apache.cassandra.tools.ToolRunner.ToolResult; -import org.apache.cassandra.tools.nodetool.NetStats; +import org.apache.cassandra.tools.ToolRunner; import org.apache.cassandra.utils.FBUtilities; -import org.assertj.core.api.Assertions; -import org.hamcrest.CoreMatchers; import static org.apache.cassandra.net.Verb.ECHO_REQ; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) -public class NodetoolNetStatsTest extends CQLTester +public class NetStatsTest extends CQLTester { - private static NodeProbe probe; - @BeforeClass public static void setup() throws Exception { diff --cc test/unit/org/apache/cassandra/tools/nodetool/RingTest.java index b1a2388,bc83f50..00c8bba --- a/test/unit/org/apache/cassandra/tools/nodetool/RingTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/RingTest.java @@@ -30,10 -28,14 +28,9 @@@ import org.apache.cassandra.locator.Sim import org.apache.cassandra.service.StorageService; import org.apache.cassandra.tools.ToolRunner; import org.apache.cassandra.utils.FBUtilities; -import org.assertj.core.api.Assertions; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.Matchers.matchesPattern; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) public class RingTest extends CQLTester { private static String token; diff --cc test/unit/org/apache/cassandra/tools/nodetool/StatusTest.java index 18b716e,13acb19..9d8496c --- a/test/unit/org/apache/cassandra/tools/nodetool/StatusTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/StatusTest.java @@@ -32,9 -30,10 +30,8 @@@ import org.apache.cassandra.service.Sto import org.apache.cassandra.tools.ToolRunner; import org.apache.cassandra.utils.FBUtilities; -import static org.hamcrest.CoreMatchers.*; -import static org.hamcrest.Matchers.matchesPattern; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) public class StatusTest extends CQLTester { private static final Pattern PATTERN = Pattern.compile("\\R"); diff --cc test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java index ccdb16a,6891cad..1ba30f0 --- a/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/TableStatsTest.java @@@ -25,18 -25,23 +25,15 @@@ import java.util.regex.Matcher import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; - import org.junit.BeforeClass; import org.junit.Test; - import org.junit.runner.RunWith; - import org.apache.cassandra.OrderedJUnit4ClassRunner; import org.apache.cassandra.cql3.CQLTester; -import org.apache.cassandra.service.StorageService; import org.apache.cassandra.tools.ToolRunner; -import org.apache.cassandra.tools.ToolRunner.ToolResult; -import org.assertj.core.api.Assertions; -import org.hamcrest.CoreMatchers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; - @RunWith(OrderedJUnit4ClassRunner.class) -public class NodetoolTableStatsTest extends CQLTester +public class TableStatsTest extends CQLTester { @BeforeClass public static void setup() throws Exception diff --cc test/unit/org/apache/cassandra/tools/nodetool/TpStatsTest.java index edbd6b3,6de2b5b..2b551d3 --- a/test/unit/org/apache/cassandra/tools/nodetool/TpStatsTest.java +++ b/test/unit/org/apache/cassandra/tools/nodetool/TpStatsTest.java @@@ -26,12 -26,12 +26,10 @@@ import java.util.regex.Matcher import java.util.regex.Pattern; import org.apache.commons.lang3.tuple.Pair; - -import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - import org.junit.runner.RunWith; import com.fasterxml.jackson.databind.ObjectMapper; - import org.apache.cassandra.OrderedJUnit4ClassRunner; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.net.Message; import org.apache.cassandra.net.MessagingService; @@@ -42,10 -43,13 +40,9 @@@ import org.yaml.snakeyaml.Yaml import static org.apache.cassandra.net.Verb.ECHO_REQ; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - @RunWith(OrderedJUnit4ClassRunner.class) -public class NodeToolTPStatsTest extends CQLTester +public class TpStatsTest extends CQLTester { - private static NodeProbe probe; @BeforeClass public static void setup() throws Exception --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
