This is an automated email from the ASF dual-hosted git repository.
dcapwell pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push:
new 9802a70 Add UX tests to intree LHF tooling
9802a70 is described below
commit 9802a70f68cdcd239a9128f90f5d8f9a941168de
Author: Berenguer Blasi <[email protected]>
AuthorDate: Wed Sep 30 12:13:15 2020 -0700
Add UX tests to intree LHF tooling
patch by Berenguer Blasi; reviewed by Brandon Williams, David Capwell for
CASSANDRA-15991
---
.../org/apache/cassandra/tools/SSTableExport.java | 2 -
.../cassandra/tools/SSTableMetadataViewer.java | 1 -
.../cassandra/tools/StandaloneSSTableUtil.java | 4 +-
.../test/FqlReplayDDLExclusionTest.java | 27 +-
test/unit/org/apache/cassandra/cql3/CQLTester.java | 30 +-
.../apache/cassandra/tools/AuditLogViewerTest.java | 93 +++
.../org/apache/cassandra/tools/BulkLoaderTest.java | 120 ++--
.../apache/cassandra/tools/ClearSnapshotTest.java | 41 +-
.../cassandra/tools/CompactionStressTest.java | 47 +-
.../cassandra/tools/GetFullQueryLogTest.java | 36 +-
.../org/apache/cassandra/tools/GetVersionTest.java | 6 +-
.../cassandra/tools/JMXCompatabilityTest.java | 9 +-
.../org/apache/cassandra/tools/JMXToolTest.java | 17 +-
.../apache/cassandra/tools/OfflineToolUtils.java | 9 +-
.../tools/SSTableExpiredBlockersTest.java | 45 +-
.../apache/cassandra/tools/SSTableExportTest.java | 151 ++++-
.../cassandra/tools/SSTableLevelResetterTest.java | 55 +-
.../cassandra/tools/SSTableMetadataViewerTest.java | 139 ++++-
.../cassandra/tools/SSTableOfflineRelevelTest.java | 45 +-
.../tools/SSTableRepairedAtSetterTest.java | 84 ++-
.../cassandra/tools/StandaloneSSTableUtilTest.java | 136 +++-
.../cassandra/tools/StandaloneScrubberTest.java | 152 ++++-
.../cassandra/tools/StandaloneSplitterTest.java | 100 ++-
.../cassandra/tools/StandaloneUpgraderTest.java | 86 ++-
.../cassandra/tools/StandaloneVerifierTest.java | 141 ++++-
.../org/apache/cassandra/tools/ToolRunner.java | 693 ++++++++++++---------
...tVersionTest.java => ToolsEnvsConfigsTest.java} | 30 +-
.../tools/cassandrastress/CassandrastressTest.java | 50 ++
.../{GetVersionTest.java => cqlsh/CqlshTest.java} | 35 +-
29 files changed, 1801 insertions(+), 583 deletions(-)
diff --git a/src/java/org/apache/cassandra/tools/SSTableExport.java
b/src/java/org/apache/cassandra/tools/SSTableExport.java
index 394f4b6..ca01cc3 100644
--- a/src/java/org/apache/cassandra/tools/SSTableExport.java
+++ b/src/java/org/apache/cassandra/tools/SSTableExport.java
@@ -46,8 +46,6 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
-import org.apache.cassandra.io.sstable.metadata.MetadataComponent;
-import org.apache.cassandra.io.sstable.metadata.MetadataType;
import org.apache.cassandra.schema.TableMetadataRef;
import org.apache.cassandra.utils.FBUtilities;
diff --git a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java
b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java
index e99f454..a4da97c 100755
--- a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java
+++ b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java
@@ -73,7 +73,6 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import com.google.common.collect.MinMaxPriorityQueue;
-import org.apache.commons.lang3.time.DurationFormatUtils;
/**
* Shows the contents of sstable metadata
diff --git a/src/java/org/apache/cassandra/tools/StandaloneSSTableUtil.java
b/src/java/org/apache/cassandra/tools/StandaloneSSTableUtil.java
index 9a7847a..cca48fc 100644
--- a/src/java/org/apache/cassandra/tools/StandaloneSSTableUtil.java
+++ b/src/java/org/apache/cassandra/tools/StandaloneSSTableUtil.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.tools;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.schema.Schema;
-import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.Directories;
import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
import org.apache.cassandra.utils.OutputHandler;
@@ -28,7 +27,6 @@ import org.apache.commons.cli.*;
import java.io.File;
import java.io.IOException;
-import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import static org.apache.cassandra.tools.BulkLoader.CmdLineOptions;
@@ -62,7 +60,7 @@ public class StandaloneSSTableUtil
if (options.cleanup)
{
- handler.output("Cleanuping up...");
+ handler.output("Cleaning up...");
LifecycleTransaction.removeUnfinishedLeftovers(metadata);
}
else
diff --git
a/test/distributed/org/apache/cassandra/distributed/test/FqlReplayDDLExclusionTest.java
b/test/distributed/org/apache/cassandra/distributed/test/FqlReplayDDLExclusionTest.java
index 1f53b98..f117c51 100644
---
a/test/distributed/org/apache/cassandra/distributed/test/FqlReplayDDLExclusionTest.java
+++
b/test/distributed/org/apache/cassandra/distributed/test/FqlReplayDDLExclusionTest.java
@@ -27,6 +27,7 @@ import org.apache.cassandra.distributed.Cluster;
import org.apache.cassandra.distributed.api.IInvokableInstance;
import org.apache.cassandra.distributed.api.QueryResults;
import org.apache.cassandra.tools.ToolRunner;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
import static org.apache.cassandra.distributed.api.Feature.GOSSIP;
import static org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL;
@@ -68,14 +69,12 @@ public class FqlReplayDDLExclusionTest extends TestBaseImpl
node.executeInternal("DROP TABLE fql_ks.fql_table;");
- final ToolRunner.Runners runners = new ToolRunner.Runners();
-
// without --replay-ddl-statements, the replay will fail on
insert because underlying table is not there
- final ToolRunner negativeRunner =
runners.invokeClassAsTool("org.apache.cassandra.fqltool.FullQueryLogTool",
-
"replay",
-
"--keyspace", "fql_ks",
-
"--target", "127.0.0.1",
-
"--", temporaryFolder.getRoot().getAbsolutePath());
+ final ToolResult negativeRunner =
ToolRunner.invokeClass("org.apache.cassandra.fqltool.FullQueryLogTool",
+
"replay",
+
"--keyspace", "fql_ks",
+
"--target", "127.0.0.1",
+ "--",
temporaryFolder.getRoot().getAbsolutePath());
assertEquals(0, negativeRunner.getExitCode());
@@ -90,13 +89,13 @@ public class FqlReplayDDLExclusionTest extends TestBaseImpl
}
// here we replay with --replay-ddl-statements so table will
be created and insert will succeed
- final ToolRunner positiveRunner =
runners.invokeClassAsTool("org.apache.cassandra.fqltool.FullQueryLogTool",
-
"replay",
-
"--keyspace", "fql_ks",
-
"--target", "127.0.0.1",
- //
important
-
"--replay-ddl-statements",
-
"--", temporaryFolder.getRoot().getAbsolutePath());
+ final ToolResult positiveRunner =
ToolRunner.invokeClass("org.apache.cassandra.fqltool.FullQueryLogTool",
+
"replay",
+
"--keyspace", "fql_ks",
+
"--target", "127.0.0.1",
+ //
important
+
"--replay-ddl-statements",
+ "--",
temporaryFolder.getRoot().getAbsolutePath());
assertEquals(0, positiveRunner.getExitCode());
diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java
b/test/unit/org/apache/cassandra/cql3/CQLTester.java
index 4392236..3e2f220 100644
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@ -464,7 +464,7 @@ public abstract class CQLTester
}
});
}
-
+
public static List<String> buildNodetoolArgs(List<String> args)
{
List<String> allArgs = new ArrayList<>();
@@ -472,11 +472,35 @@ public abstract class CQLTester
allArgs.add("-p");
allArgs.add(Integer.toString(jmxPort));
allArgs.add("-h");
- allArgs.add(jmxHost);
+ allArgs.add(jmxHost == null ? "127.0.0.1" : jmxHost);
allArgs.addAll(args);
return allArgs;
}
-
+
+ public static List<String> buildCqlshArgs(List<String> args)
+ {
+ List<String> allArgs = new ArrayList<>();
+ allArgs.add("bin/cqlsh");
+ allArgs.add(nativeAddr.getHostAddress());
+ allArgs.add(Integer.toString(nativePort));
+ allArgs.add("-e");
+ allArgs.addAll(args);
+ return allArgs;
+ }
+
+ public static List<String> buildCassandraStressArgs(List<String> args)
+ {
+ List<String> allArgs = new ArrayList<>();
+ allArgs.add("tools/bin/cassandra-stress");
+ allArgs.addAll(args);
+ if (args.indexOf("-port") == -1)
+ {
+ allArgs.add("-port");
+ allArgs.add("native=" + Integer.toString(nativePort));
+ }
+ return allArgs;
+ }
+
// lazy initialization for all tests that require Java Driver
protected static void requireNetwork() throws ConfigurationException
{
diff --git a/test/unit/org/apache/cassandra/tools/AuditLogViewerTest.java
b/test/unit/org/apache/cassandra/tools/AuditLogViewerTest.java
index 649712a..ed23088 100644
--- a/test/unit/org/apache/cassandra/tools/AuditLogViewerTest.java
+++ b/test/unit/org/apache/cassandra/tools/AuditLogViewerTest.java
@@ -22,10 +22,14 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
import org.apache.commons.io.FileUtils;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -38,12 +42,19 @@ import net.openhft.chronicle.queue.ExcerptAppender;
import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.wire.WireOut;
import org.apache.cassandra.audit.BinAuditLogger;
+import org.apache.cassandra.tools.ToolRunner.ObservableTool;
+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.assertThat;
import static org.junit.Assert.assertTrue;
public class AuditLogViewerTest
{
private Path path;
+ private final String toolPath = "tools/bin/auditlogviewer";
@Before
public void setUp() throws IOException
@@ -62,6 +73,88 @@ public class AuditLogViewerTest
}
@Test
+ public void testNoArgs()
+ {
+ ToolResult tool = ToolRunner.invoke(toolPath);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Audit log files directory path is a
required argument."));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invoke(toolPath, "-h");
+ String help = "usage: auditlogviewer <path1> [<path2>...<pathN>]
[options]\n" +
+ "--\n" +
+ "View the audit log contents in human readable
format\n" +
+ "--\n" +
+ "Options are:\n" +
+ " -f,--follow Upon reacahing the end of the
log continue\n" +
+ " indefinitely waiting for more
records\n" +
+ " -h,--help display this help message\n"
+
+ " -i,--ignore Silently ignore unsupported
records\n" +
+ " -r,--roll_cycle <arg> How often to roll the log
file was rolled. May be\n" +
+ " necessary for Chronicle to
correctly parse file names. (MINUTELY, HOURLY,\n" +
+ " DAILY). Default HOURLY.\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testHelpArg()
+ {
+ Arrays.asList("-h", "--help").forEach(arg -> {
+ ToolResult tool = ToolRunner.invoke(toolPath, arg);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+
assertTrue(tool.getCleanedStderr(),tool.getCleanedStderr().isEmpty());
+ tool.assertOnExitCode();
+ });
+ }
+
+ @Test
+ public void testIgnoreArg()
+ {
+ Arrays.asList("-i", "--ignore").forEach(arg -> {
+ ToolResult tool = ToolRunner.invoke(toolPath,
path.toAbsolutePath().toString(), arg);
+ assertTrue(tool.getStdout(), tool.getStdout().isEmpty());
+ // @IgnoreAssert see CASSANDRA-16021
+// assertTrue(tool.getCleanedStderr(),
+// tool.getCleanedStderr().isEmpty() // j8 is fine
+// || tool.getCleanedStderr().startsWith("WARNING:
An illegal reflective access operation has occurred")); //j11 throws an error
+ tool.assertOnExitCode();
+ });
+ }
+
+ @Test
+ public void testFollowNRollArgs()
+ {
+ Lists.cartesianProduct(Arrays.asList("-f", "--follow"),
Arrays.asList("-r", "--roll_cycle")).forEach(arg -> {
+ try (ObservableTool tool = ToolRunner.invokeAsync(toolPath,
+
path.toAbsolutePath().toString(),
+ arg.get(0),
+ arg.get(1),
+ "TEST_SECONDLY");)
+ {
+ // Tool is running in the background 'following' so wait
and then we have to kill it
+ try
+ {
+ Thread.sleep(3000);
+ }
+ catch(InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ assertTrue(tool.getPartialStdout(),
tool.getPartialStdout().isEmpty());
+ // @IgnoreAssert see CASSANDRA-16021
+ // assertTrue(tool.getCleanedStderr(),
+ // tool.getCleanedStderr().isEmpty() // j8 is
fine
+ // ||
tool.getCleanedStderr().startsWith("WARNING: An illegal reflective access
operation has occurred")); //j11 throws an error
+ }
+ });
+ }
+
+ @Test
public void testDisplayRecord()
{
List<String> records = new ArrayList<>();
diff --git a/test/unit/org/apache/cassandra/tools/BulkLoaderTest.java
b/test/unit/org/apache/cassandra/tools/BulkLoaderTest.java
index 354511a..382f352 100644
--- a/test/unit/org/apache/cassandra/tools/BulkLoaderTest.java
+++ b/test/unit/org/apache/cassandra/tools/BulkLoaderTest.java
@@ -23,22 +23,22 @@ import org.junit.runner.RunWith;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
+import org.hamcrest.CoreMatchers;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@RunWith(OrderedJUnit4ClassRunner.class)
public class BulkLoaderTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
public void testBulkLoader_NoArgs() throws Exception
{
- ToolRunner tool =
runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader");
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class);
assertEquals(1, tool.getExitCode());
- assertTrue(!tool.getStderr().isEmpty());
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsString("Missing sstable directory argument"));
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
@@ -51,19 +51,17 @@ public class BulkLoaderTest extends OfflineToolUtils
@Test
public void testBulkLoader_WithArgs() throws Exception
{
- try
- {
- runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader",
"-d", "127.9.9.1", OfflineToolUtils.sstableDirName("legacy_sstables",
"legacy_ma_simple"))
- .waitAndAssertOnCleanExit();
- fail();
- }
- catch (RuntimeException e)
- {
- if (!(e.getCause() instanceof BulkLoadException))
- throw e;
- if (!(e.getCause().getCause() instanceof NoHostAvailableException))
- throw e;
- }
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class,
+ "-d",
+ "127.9.9.1",
+
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
+
+ assertEquals(-1, tool.getExitCode());
+ if (!(tool.getException().getCause() instanceof BulkLoadException))
+ throw tool.getException();
+ if (!(tool.getException().getCause().getCause() instanceof
NoHostAvailableException))
+ throw tool.getException();
+
assertNoUnexpectedThreadsStarted(null, new
String[]{"globalEventExecutor-1-1", "globalEventExecutor-1-2"});
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -75,20 +73,20 @@ public class BulkLoaderTest extends OfflineToolUtils
@Test
public void testBulkLoader_WithArgs1() throws Exception
{
- try
- {
- runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader",
"-d", "127.9.9.1", "--port", "9042",
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"))
- .waitAndAssertOnCleanExit();
- fail();
- }
- catch (RuntimeException e)
- {
- if (!(e.getCause() instanceof BulkLoadException))
- throw e;
- if (!(e.getCause().getCause() instanceof NoHostAvailableException))
- throw e;
- }
- assertNoUnexpectedThreadsStarted(null, new
String[]{"globalEventExecutor-1-1", "globalEventExecutor-1-2"});
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class,
+ "-d",
+ "127.9.9.1",
+ "--port",
+ "9042",
+
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
+
+ assertEquals(-1, tool.getExitCode());
+ if (!(tool.getException().getCause() instanceof BulkLoadException))
+ throw tool.getException();
+ if (!(tool.getException().getCause().getCause() instanceof
NoHostAvailableException))
+ throw tool.getException();
+
+ assertNoUnexpectedThreadsStarted(null, new String[] {
"globalEventExecutor-1-1", "globalEventExecutor-1-2" });
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@@ -99,20 +97,20 @@ public class BulkLoaderTest extends OfflineToolUtils
@Test
public void testBulkLoader_WithArgs2() throws Exception
{
- try
- {
- runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader",
"-d", "127.9.9.1:9042", "--port", "9041",
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"))
- .waitAndAssertOnCleanExit();
- fail();
- }
- catch (RuntimeException e)
- {
- if (!(e.getCause() instanceof BulkLoadException))
- throw e;
- if (!(e.getCause().getCause() instanceof NoHostAvailableException))
- throw e;
- }
- assertNoUnexpectedThreadsStarted(null, new
String[]{"globalEventExecutor-1-1", "globalEventExecutor-1-2"});
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class,
+ "-d",
+ "127.9.9.1:9042",
+ "--port",
+ "9041",
+
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
+
+ assertEquals(-1, tool.getExitCode());
+ if (!(tool.getException().getCause() instanceof BulkLoadException))
+ throw tool.getException();
+ if (!(tool.getException().getCause().getCause() instanceof
NoHostAvailableException))
+ throw tool.getException();
+
+ assertNoUnexpectedThreadsStarted(null, new String[] {
"globalEventExecutor-1-1", "globalEventExecutor-1-2" });
assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
@@ -123,26 +121,24 @@ public class BulkLoaderTest extends OfflineToolUtils
@Test(expected = NoHostAvailableException.class)
public void testBulkLoader_WithArgs3() throws Throwable
{
- try
- {
- runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader",
"-d", "127.9.9.1", "--port", "9041",
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
- }
- catch (RuntimeException e)
- {
- throw e.getCause().getCause();
- }
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class,
+ "-d",
+ "127.9.9.1",
+ "--port",
+ "9041",
+
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
+ assertEquals(-1, tool.getExitCode());
+ throw tool.getException().getCause().getCause();
}
@Test(expected = NoHostAvailableException.class)
public void testBulkLoader_WithArgs4() throws Throwable
{
- try
- {
- runner.invokeClassAsTool("org.apache.cassandra.tools.BulkLoader",
"-d", "127.9.9.1:9041", OfflineToolUtils.sstableDirName("legacy_sstables",
"legacy_ma_simple"));
- }
- catch (RuntimeException e)
- {
- throw e.getCause().getCause();
- }
+ ToolResult tool = ToolRunner.invokeClass(BulkLoader.class,
+ "-d",
+ "127.9.9.1:9041",
+
OfflineToolUtils.sstableDirName("legacy_sstables", "legacy_ma_simple"));
+ assertEquals(-1, tool.getExitCode());
+ throw tool.getException().getCause().getCause();
}
}
diff --git a/test/unit/org/apache/cassandra/tools/ClearSnapshotTest.java
b/test/unit/org/apache/cassandra/tools/ClearSnapshotTest.java
index 7e70467..b631822 100644
--- a/test/unit/org/apache/cassandra/tools/ClearSnapshotTest.java
+++ b/test/unit/org/apache/cassandra/tools/ClearSnapshotTest.java
@@ -29,14 +29,16 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
+import org.hamcrest.CoreMatchers;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class ClearSnapshotTest extends CQLTester
{
private static NodeProbe probe;
- private ToolRunner.Runners runner = new ToolRunner.Runners();
@BeforeClass
public static void setup() throws Exception
@@ -52,33 +54,36 @@ public class ClearSnapshotTest extends CQLTester
}
@Test
- public void testClearSnapshot_NoArgs() throws IOException
+ public void testClearSnapshot_NoArgs()
{
- ToolRunner tool = runner.invokeNodetool("clearsnapshot");
+ ToolResult tool = ToolRunner.invokeNodetool("clearsnapshot");
assertEquals(2, tool.getExitCode());
- assertTrue("Tool stderr: " + tool.getStderr(),
tool.getStderr().contains("Specify snapshot name or --all"));
+ assertTrue("Tool stderr: " + tool.getCleanedStderr(),
tool.getCleanedStderr().contains("Specify snapshot name or --all"));
- runner.invokeNodetool("clearsnapshot",
"--all").waitAndAssertOnCleanExit();
+ tool = ToolRunner.invokeNodetool("clearsnapshot", "--all");
+ tool.assertOnCleanExit();
}
@Test
- public void testClearSnapshot_AllAndName() throws IOException
+ public void testClearSnapshot_AllAndName()
{
- ToolRunner tool = runner.invokeNodetool("clearsnapshot", "-t",
"some-name", "--all");
+ ToolResult tool = ToolRunner.invokeNodetool("clearsnapshot", "-t",
"some-name", "--all");
assertEquals(2, tool.getExitCode());
- assertTrue("Tool stderr: " + tool.getStderr(),
tool.getStderr().contains("Specify only one of snapshot name or --all"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Specify only one of snapshot name or
--all"));
}
@Test
- public void testClearSnapshot_RemoveByName() throws IOException
+ public void testClearSnapshot_RemoveByName()
{
- ToolRunner tool =
runner.invokeNodetool("snapshot","-t","some-name").waitAndAssertOnCleanExit();
+ ToolResult tool =
ToolRunner.invokeNodetool("snapshot","-t","some-name");
+ tool.assertOnCleanExit();
assertTrue(!tool.getStdout().isEmpty());
Map<String, TabularData> snapshots_before = probe.getSnapshotDetails();
Assert.assertTrue(snapshots_before.containsKey("some-name"));
- tool =
runner.invokeNodetool("clearsnapshot","-t","some-name").waitAndAssertOnCleanExit();
+ tool = ToolRunner.invokeNodetool("clearsnapshot","-t","some-name");
+ tool.assertOnCleanExit();
assertTrue(!tool.getStdout().isEmpty());
Map<String, TabularData> snapshots_after = probe.getSnapshotDetails();
@@ -86,17 +91,21 @@ public class ClearSnapshotTest extends CQLTester
}
@Test
- public void testClearSnapshot_RemoveMultiple() throws IOException
+ public void testClearSnapshot_RemoveMultiple()
{
- ToolRunner tool =
runner.invokeNodetool("snapshot","-t","some-name").waitAndAssertOnCleanExit();
- assertTrue(!tool.getStdout().isEmpty());
- tool =
runner.invokeNodetool("snapshot","-t","some-other-name").waitAndAssertOnCleanExit();
+ ToolResult tool =
ToolRunner.invokeNodetool("snapshot","-t","some-name");
+ tool.assertOnCleanExit();
assertTrue(!tool.getStdout().isEmpty());
+
+ tool = ToolRunner.invokeNodetool("snapshot","-t","some-other-name");
+ tool.assertOnCleanExit();
+ assertTrue(!tool.getStdout().isEmpty());
Map<String, TabularData> snapshots_before = probe.getSnapshotDetails();
Assert.assertTrue(snapshots_before.size() == 2);
- tool =
runner.invokeNodetool("clearsnapshot","--all").waitAndAssertOnCleanExit();
+ tool = ToolRunner.invokeNodetool("clearsnapshot","--all");
+ tool.assertOnCleanExit();
assertTrue(!tool.getStdout().isEmpty());
Map<String, TabularData> snapshots_after = probe.getSnapshotDetails();
diff --git a/test/unit/org/apache/cassandra/tools/CompactionStressTest.java
b/test/unit/org/apache/cassandra/tools/CompactionStressTest.java
index 651e24d..09b82fe 100644
--- a/test/unit/org/apache/cassandra/tools/CompactionStressTest.java
+++ b/test/unit/org/apache/cassandra/tools/CompactionStressTest.java
@@ -24,16 +24,16 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
@RunWith(OrderedJUnit4ClassRunner.class)
public class CompactionStressTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
public void testNoArgs()
{
-
runner.invokeClassAsTool("org.apache.cassandra.stress.CompactionStress").waitAndAssertOnCleanExit();
+ ToolResult tool =
ToolRunner.invokeClass("org.apache.cassandra.stress.CompactionStress");
+ tool.assertOnCleanExit();
}
@Test
@@ -43,27 +43,26 @@ public class CompactionStressTest extends OfflineToolUtils
File file = new
File(classLoader.getResource("blogpost.yaml").getFile());
String profileFile = file.getAbsolutePath();
-
runner.invokeClassAsTool("org.apache.cassandra.stress.CompactionStress",
- "write",
- "-d",
- "build/test/cassandra",
- "-g",
- "0",
- "-p",
- profileFile,
- "-t",
- "4")
- .waitAndAssertOnCleanExit();
+ ToolResult tool =
ToolRunner.invokeClass("org.apache.cassandra.stress.CompactionStress",
+ "write",
+ "-d",
+ "build/test/cassandra",
+ "-g",
+ "0",
+ "-p",
+ profileFile,
+ "-t",
+ "4");
+ tool.assertOnCleanExit();
-
runner.invokeClassAsTool("org.apache.cassandra.stress.CompactionStress",
- "compact",
- "-d",
- "build/test/cassandra",
- "-p",
- profileFile,
- "-t",
- "4")
- .waitAndAssertOnCleanExit();
+ tool =
ToolRunner.invokeClass("org.apache.cassandra.stress.CompactionStress",
+ "compact",
+ "-d",
+ "build/test/cassandra",
+ "-p",
+ profileFile,
+ "-t",
+ "4");
+ tool.assertOnCleanExit();
}
-
}
diff --git a/test/unit/org/apache/cassandra/tools/GetFullQueryLogTest.java
b/test/unit/org/apache/cassandra/tools/GetFullQueryLogTest.java
index 82d5482..44007a5 100644
--- a/test/unit/org/apache/cassandra/tools/GetFullQueryLogTest.java
+++ b/test/unit/org/apache/cassandra/tools/GetFullQueryLogTest.java
@@ -29,6 +29,7 @@ import org.junit.rules.TemporaryFolder;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.fql.FullQueryLoggerOptions;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -36,7 +37,6 @@ import static org.junit.Assert.assertTrue;
public class GetFullQueryLogTest extends CQLTester
{
private static NodeProbe probe;
- private ToolRunner.Runners runner = new ToolRunner.Runners();
@ClassRule
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -55,7 +55,7 @@ public class GetFullQueryLogTest extends CQLTester
}
@After
- public void afterTest()
+ public void afterTest() throws InterruptedException
{
disableFullQueryLog();
}
@@ -87,29 +87,39 @@ public class GetFullQueryLogTest extends CQLTester
private String getFullQueryLog()
{
- return
runner.invokeNodetool("getfullquerylog").waitAndAssertOnCleanExit().getStdout();
+ ToolResult tool = ToolRunner.invokeNodetool("getfullquerylog");
+ tool.assertOnCleanExit();
+ return tool.getStdout();
}
private void resetFullQueryLog()
{
- runner.invokeNodetool("resetfullquerylog").waitAndAssertOnCleanExit();
+ ToolRunner.invokeNodetool("resetfullquerylog").assertOnCleanExit();
}
private void disableFullQueryLog()
{
-
runner.invokeNodetool("disablefullquerylog").waitAndAssertOnCleanExit();
+ ToolRunner.invokeNodetool("disablefullquerylog").assertOnCleanExit();
}
private void enableFullQueryLog()
{
- runner.invokeNodetool("enablefullquerylog",
- "--path", temporaryFolder.getRoot().toString(),
- "--blocking", "false",
- "--max-archive-retries", "5",
- "--archive-command", "/path/to/script.sh %path",
- "--max-log-size", "100000",
- "--max-queue-weight", "10000",
- "--roll-cycle",
"DAILY").waitAndAssertOnCleanExit();
+ ToolRunner.invokeNodetool("enablefullquerylog",
+ "--path",
+ temporaryFolder.getRoot().toString(),
+ "--blocking",
+ "false",
+ "--max-archive-retries",
+ "5",
+ "--archive-command",
+ "/path/to/script.sh %path",
+ "--max-log-size",
+ "100000",
+ "--max-queue-weight",
+ "10000",
+ "--roll-cycle",
+ "DAILY")
+ .assertOnCleanExit();
}
private void testChangedOutput(final String getFullQueryLogOutput)
diff --git a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
b/test/unit/org/apache/cassandra/tools/GetVersionTest.java
index c5f5282..1feeb45 100644
--- a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
+++ b/test/unit/org/apache/cassandra/tools/GetVersionTest.java
@@ -22,16 +22,16 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
@RunWith(OrderedJUnit4ClassRunner.class)
public class GetVersionTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
public void testGetVersion()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.GetVersion").waitAndAssertOnCleanExit();
+ ToolResult tool = ToolRunner.invokeClass(GetVersion.class);
+ tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
diff --git a/test/unit/org/apache/cassandra/tools/JMXCompatabilityTest.java
b/test/unit/org/apache/cassandra/tools/JMXCompatabilityTest.java
index 816257e..2494dd2 100644
--- a/test/unit/org/apache/cassandra/tools/JMXCompatabilityTest.java
+++ b/test/unit/org/apache/cassandra/tools/JMXCompatabilityTest.java
@@ -13,11 +13,10 @@ import com.datastax.driver.core.SimpleStatement;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.service.CassandraDaemon;
import org.apache.cassandra.service.GCInspector;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
import org.apache.cassandra.transport.ProtocolVersion;
import org.assertj.core.api.Assertions;
-import static org.apache.cassandra.tools.ToolRunner.Runners.invokeTool;
-
/**
* This class is to monitor the JMX compatability cross different versions,
and relies on a gold set of metrics which
* were generated following the instructions below. These tests only check
for breaking changes, so will ignore any
@@ -66,7 +65,7 @@ public class JMXCompatabilityTest extends CQLTester
executeNet(ProtocolVersion.CURRENT, new SimpleStatement("SELECT * FROM
" + name + " WHERE pk=?", 42));
String script = "tools/bin/jmxtool dump -f yaml --url
service:jmx:rmi:///jndi/rmi://" + jmxHost + ":" + jmxPort + "/jmxrmi > " +
TMP.getRoot().getAbsolutePath() + "/out.yaml";
- invokeTool("bash", "-c",
script).assertOnExitCode().assertCleanStdErr();
+ ToolRunner.invoke("bash", "-c", script).assertOnCleanExit();
CREATED_TABLE = true;
}
@@ -164,8 +163,8 @@ public class JMXCompatabilityTest extends CQLTester
args.add("--exclude-operation");
args.add(a);
});
- ToolRunner result = invokeTool(args);
- result.assertOnExitCode().assertCleanStdErr();
+ ToolResult result = ToolRunner.invoke(args);
+ result.assertOnCleanExit();
Assertions.assertThat(result.getStdout()).isEmpty();
}
}
diff --git a/test/unit/org/apache/cassandra/tools/JMXToolTest.java
b/test/unit/org/apache/cassandra/tools/JMXToolTest.java
index 229354b..4fba8cd 100644
--- a/test/unit/org/apache/cassandra/tools/JMXToolTest.java
+++ b/test/unit/org/apache/cassandra/tools/JMXToolTest.java
@@ -10,6 +10,7 @@ import org.junit.Test;
import org.apache.cassandra.io.util.DataInputBuffer;
import org.apache.cassandra.io.util.DataOutputBuffer;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
import org.apache.cassandra.utils.Generators;
import org.assertj.core.api.Assertions;
import org.quicktheories.core.Gen;
@@ -35,8 +36,8 @@ public class JMXToolTest
@Test
public void cliHelp()
{
- ToolRunner result = jmxtool();
- result.assertCleanStdErr().assertOnExitCode();
+ ToolResult result = jmxtool();
+ result.assertOnCleanExit();
Assertions.assertThat(result.getStdout())
.isEqualTo("usage: jmxtool <command> [<args>]\n" +
@@ -53,8 +54,8 @@ public class JMXToolTest
@Test
public void cliHelpDiff()
{
- ToolRunner result = jmxtool("help", "diff");
- result.assertCleanStdErr().assertOnExitCode();
+ ToolResult result = jmxtool("help", "diff");
+ result.assertOnCleanExit();
Assertions.assertThat(result.getStdout())
.isEqualTo("NAME\n" +
@@ -107,8 +108,8 @@ public class JMXToolTest
@Test
public void cliHelpDump()
{
- ToolRunner result = jmxtool("help", "dump");
- result.assertCleanStdErr().assertOnExitCode();
+ ToolResult result = jmxtool("help", "dump");
+ result.assertOnCleanExit();
Assertions.assertThat(result.getStdout())
.isEqualTo("NAME\n" +
@@ -132,12 +133,12 @@ public class JMXToolTest
"\n");
}
- private static ToolRunner jmxtool(String... args)
+ private static ToolResult jmxtool(String... args)
{
List<String> cmd = new ArrayList<>(1 + args.length);
cmd.add("tools/bin/jmxtool");
cmd.addAll(Arrays.asList(args));
- return ToolRunner.Runners.invokeTool(cmd);
+ return ToolRunner.invoke(cmd);
}
private void serde(JMXTool.Dump.Format serializer, JMXTool.Diff.Format
deserializer)
diff --git a/test/unit/org/apache/cassandra/tools/OfflineToolUtils.java
b/test/unit/org/apache/cassandra/tools/OfflineToolUtils.java
index 9383f7d..ae82fd8 100644
--- a/test/unit/org/apache/cassandra/tools/OfflineToolUtils.java
+++ b/test/unit/org/apache/cassandra/tools/OfflineToolUtils.java
@@ -110,7 +110,7 @@ public abstract class OfflineToolUtils
.filter(threadName ->
optional.stream().anyMatch(pattern -> pattern.matcher(threadName).matches()))
.collect(Collectors.toSet());
- if (!current.isEmpty())
+ if (!remain.isEmpty())
System.err.println("Unexpected thread names: " + remain);
if (!notPresent.isEmpty())
System.err.println("Mandatory thread missing: " + notPresent);
@@ -240,4 +240,11 @@ public abstract class OfflineToolUtils
FileUtils.copyDirectory(new File(srcDir, "legacy_tables"), new
File(dataDir, "legacy_sstables"));
return dataDir;
}
+
+ protected void assertCorrectEnvPostTest()
+ {
+ assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
+ assertSchemaLoaded();
+ assertServerNotLoaded();
+ }
}
diff --git
a/test/unit/org/apache/cassandra/tools/SSTableExpiredBlockersTest.java
b/test/unit/org/apache/cassandra/tools/SSTableExpiredBlockersTest.java
index ad2dc3e..0476453 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableExpiredBlockersTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableExpiredBlockersTest.java
@@ -22,18 +22,24 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableExpiredBlockersTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testSSTableExpiredBlockers_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableExpiredBlockers").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(SSTableExpiredBlockers.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +49,31 @@ public class SSTableExpiredBlockersTest extends
OfflineToolUtils
}
@Test
- public void testSSTableExpiredBlockers_WithArgs()
+ public void testMaybeChangeDocs()
{
- // returns exit code 1, since no sstables are there
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableExpiredBlockers",
"system_schema", "tables").getExitCode());
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(SSTableExpiredBlockers.class);
+ String help = "Usage: sstableexpiredblockers <keyspace> <table>\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgsIgnored()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExpiredBlockers.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No sstables for"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExpiredBlockers.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No sstables for"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
}
}
diff --git a/test/unit/org/apache/cassandra/tools/SSTableExportTest.java
b/test/unit/org/apache/cassandra/tools/SSTableExportTest.java
index 54af60c..15949af 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableExportTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableExportTest.java
@@ -18,22 +18,39 @@
package org.apache.cassandra.tools;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableExportTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
+ private ObjectMapper mapper = new ObjectMapper();
+ private TypeReference<List<Map<String, Object>>> jacksonListOfMapsType =
new TypeReference<List<Map<String, Object>>>() {};
+
@Test
- public void testSSTableExport_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableExport").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("You must supply exactly one sstable"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +60,130 @@ public class SSTableExportTest extends OfflineToolUtils
}
@Test
- public void testSSTableExport_WithArgs() throws Exception
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class);
+ String help = "usage: sstabledump <sstable file path> <options>\n" +
+ " \n" +
+ "Dump contents of given SSTable to standard output in
JSON format.\n" +
+ " -d CQL row per line internal
representation\n" +
+ " -e enumerate partition keys only\n" +
+ " -k <arg> Partition key\n" +
+ " -l Output json lines, by partition\n" +
+ " -t Print raw timestamps instead of iso8601
date strings\n" +
+ " -x <arg> Excluded partition key\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
"--debugwrong", findOneSSTable("legacy_sstables", "legacy_ma_simple"));
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall() throws IOException
+ {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableExport.class,findOneSSTable("legacy_sstables",
"legacy_ma_simple"));
+ List<Map<String, Object>> parsed = mapper.readValue(tool.getStdout(),
jacksonListOfMapsType);
+ assertTrue(tool.getStdout(), parsed.get(0).get("partition") != null);
+ assertTrue(tool.getStdout(), parsed.get(0).get("rows") != null);
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testCQLRowArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-d");
+ assertThat(tool.getStdout(), CoreMatchers.startsWith("[0]"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testPKOnlyArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-e");
+ assertEquals(tool.getStdout(), "[ [ \"0\" ], [ \"1\" ], [ \"2\" ], [
\"3\" ], [ \"4\" ]\n]", tool.getStdout());
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testPKArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-k", "0");
+ List<Map<String, Object>> parsed = mapper.readValue(tool.getStdout(),
jacksonListOfMapsType);
+ assertEquals(tool.getStdout(), 1, parsed.size());
+ assertEquals(tool.getStdout(), "0", ((List) ((Map)
parsed.get(0).get("partition")).get("key")).get(0));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testExcludePKArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-x", "0");
+ List<Map<String, Object>> parsed = mapper.readValue(tool.getStdout(),
jacksonListOfMapsType);
+ assertEquals(tool.getStdout(), 4, parsed.size());
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testTSFormatArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-t");
+ List<Map<String, Object>> parsed = mapper.readValue(tool.getStdout(),
jacksonListOfMapsType);
+ assertEquals(tool.getStdout(),
+ "1445008632854000",
+ ((Map) ((List<Map>)
parsed.get(0).get("rows")).get(0).get("liveness_info")).get("tstamp"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ @Test
+ public void testJSONLineArg() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableExport.class,
findOneSSTable("legacy_sstables", "legacy_ma_simple"), "-l");
+ try
+ {
+ mapper.readValue(tool.getStdout(), jacksonListOfMapsType);
+ fail("Shouldn't be able to deserialize that output, now it's not a
collection anymore.");
+ }
+ catch(MismatchedInputException e)
+ {
+ }
+
+ int parsedCount = 0;
+ for (String jsonLine : tool.getStdout().split("\\R"))
+ {
+ Map line = mapper.readValue(jsonLine, Map.class);
+ assertTrue(jsonLine, line.containsKey("partition"));
+ parsedCount++;
+ }
+
+ assertEquals(tool.getStdout(), 5, parsedCount);
+ assertThat(tool.getStdout(), CoreMatchers.startsWith("{\""));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertPostTestEnv();
+ }
+
+ private void assertPostTestEnv()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableExport",findOneSSTable("legacy_sstables",
"legacy_ma_simple"))
- .waitAndAssertOnCleanExit();
assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaNotLoaded();
assertCLSMNotLoaded();
assertSystemKSNotLoaded();
assertServerNotLoaded();
diff --git a/test/unit/org/apache/cassandra/tools/SSTableLevelResetterTest.java
b/test/unit/org/apache/cassandra/tools/SSTableLevelResetterTest.java
index 947a988..e413b14 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableLevelResetterTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableLevelResetterTest.java
@@ -22,18 +22,23 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableLevelResetterTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testSSTableLevelResetter_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableLevelResetter").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(SSTableLevelResetter.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +48,42 @@ public class SSTableLevelResetterTest extends
OfflineToolUtils
}
@Test
- public void testSSTableLevelResetter_WithArgs()
+ public void testMaybeChangeDocs()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableLevelResetter",
"--really-reset", "system_schema", "tables")
- .waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(SSTableLevelResetter.class,
"-h");
+ String help = "This command should be run with Cassandra stopped,
otherwise you will get very strange behavior\n" +
+ "Verify that Cassandra is not running and then execute
the command like this:\n" +
+ "Usage: sstablelevelreset --really-reset <keyspace>
<table>\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableLevelResetter.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableLevelResetter.class,
"--really-reset", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Found no sstables,"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testMissingSecurityFlagCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableLevelResetter.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
}
}
diff --git
a/test/unit/org/apache/cassandra/tools/SSTableMetadataViewerTest.java
b/test/unit/org/apache/cassandra/tools/SSTableMetadataViewerTest.java
index 9370315..db0c958 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableMetadataViewerTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableMetadataViewerTest.java
@@ -18,22 +18,36 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.tuple.Pair;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableMetadataViewerTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testSSTableOfflineRelevel_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableMetadataViewer").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(SSTableMetadataViewer.class);
+ {
+ assertTrue(tool.getStdout(), tool.getStdout().isEmpty());
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Options:"));
+ assertEquals(1, tool.getExitCode());
+ }
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,9 +57,122 @@ public class SSTableMetadataViewerTest extends
OfflineToolUtils
}
@Test
- public void testSSTableOfflineRelevel_WithArgs()
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(SSTableMetadataViewer.class,
"-h");
+ assertEquals("You must supply at least one sstable\n" +
+ "usage: sstablemetadata <options> <sstable...> [-c] [-g
<arg>] [-s] [-t <arg>] [-u]\n" +
+ "\n" +
+ "Dump information about SSTable[s] for Apache Cassandra
3.x\n" +
+ "Options:\n" +
+ " -c,--colors Use ANSI color
sequences\n" +
+ " -g,--gc_grace_seconds <arg> Time to use when
calculating droppable tombstones\n" +
+ " -s,--scan Full sstable scan for
additional details. Only available in 3.0+ sstables. Defaults: false\n" +
+ " -t,--timestamp_unit <arg> Time unit that cell
timestamps are written with\n" +
+ " -u,--unicode Use unicode to draw
histograms and progress bars\n\n"
+ , tool.getCleanedStderr());
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableMetadataViewer.class,
"--debugwrong", "ks", "tab");
+ assertTrue(tool.getStdout(), tool.getStdout().isEmpty());
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Options:"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableMetadataViewer.class,
"ks", "tab");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No such file"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertGoodEnvPostTest();
+ }
+
+ @Test
+ public void testFlagArgs()
+ {
+ Arrays.asList("-c",
+ "--colors",
+ "-s",
+ "--scan",
+ "-u",
+ "--unicode")
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableMetadataViewer.class, arg, "ks", "tab");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No such file"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg:
[%s]", arg).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertGoodEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testGCArg()
+ {
+ Arrays.asList(Pair.of("-g", ""),
+ Pair.of("-g", "w"),
+ Pair.of("--gc_grace_seconds", ""),
+ Pair.of("--gc_grace_seconds", "w"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableMetadataViewer.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "ks",
+ "tab");
+ assertEquals(-1, tool.getExitCode());
+
Assertions.assertThat(tool.getStderr()).contains(NumberFormatException.class.getSimpleName());
+ });
+
+ Arrays.asList(Pair.of("-g", "5"), Pair.of("--gc_grace_seconds",
"5")).forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableMetadataViewer.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "ks",
+ "tab");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No such file"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertGoodEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testTSUnitArg()
+ {
+ Arrays.asList(Pair.of("-t", ""),
+ Pair.of("-t", "w"),
+ Pair.of("--timestamp_unit", ""),
+ Pair.of("--timestamp_unit", "w"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableMetadataViewer.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "ks",
+ "tab");
+ assertEquals(-1, tool.getExitCode());
+
Assertions.assertThat(tool.getStderr()).contains(IllegalArgumentException.class.getSimpleName());
+ });
+
+ Arrays.asList(Pair.of("-t", "SECONDS"), Pair.of("--timestamp_unit",
"SECONDS")).forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(SSTableMetadataViewer.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "ks",
+ "tab");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No such file"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertGoodEnvPostTest();
+ });
+ }
+
+ private void assertGoodEnvPostTest()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableMetadataViewer",
"ks", "tab").waitAndAssertOnCleanExit();
assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
diff --git
a/test/unit/org/apache/cassandra/tools/SSTableOfflineRelevelTest.java
b/test/unit/org/apache/cassandra/tools/SSTableOfflineRelevelTest.java
index 1d155bc..a49dd49 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableOfflineRelevelTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableOfflineRelevelTest.java
@@ -22,18 +22,23 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableOfflineRelevelTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testSSTableOfflineRelevel_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableOfflineRelevel").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(SSTableOfflineRelevel.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +48,32 @@ public class SSTableOfflineRelevelTest extends
OfflineToolUtils
}
@Test
- public void testSSTableOfflineRelevel_WithArgs()
+ public void testMaybeChangeDocs()
{
- // Note: SSTableOfflineRelevel exits with code 1 if no sstables to
relevel have been found
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableOfflineRelevel",
"system_schema", "tables").getExitCode());
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(SSTableOfflineRelevel.class,
"-h");
+ String help = "This command should be run with Cassandra stopped!\n" +
+ "Usage: sstableofflinerelevel [--dry-run] <keyspace>
<columnfamily>\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableOfflineRelevel.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No sstables to relevel for
system_schema.tables"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testDryrunArg()
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableOfflineRelevel.class,
"--dry-run", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("No sstables to relevel for
system_schema.tables"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
}
}
diff --git
a/test/unit/org/apache/cassandra/tools/SSTableRepairedAtSetterTest.java
b/test/unit/org/apache/cassandra/tools/SSTableRepairedAtSetterTest.java
index 737b0eb..e1f5f95 100644
--- a/test/unit/org/apache/cassandra/tools/SSTableRepairedAtSetterTest.java
+++ b/test/unit/org/apache/cassandra/tools/SSTableRepairedAtSetterTest.java
@@ -18,22 +18,33 @@
package org.apache.cassandra.tools;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+import org.apache.cassandra.io.util.FileUtils;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class SSTableRepairedAtSetterTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testSSTableRepairedAtSetter_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableRepairedAtSetter").getExitCode());
+ ToolResult tool =
ToolRunner.invokeClass(SSTableRepairedAtSetter.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,10 +54,69 @@ public class SSTableRepairedAtSetterTest extends
OfflineToolUtils
}
@Test
- public void testSSTableRepairedAtSetter_WithArgs() throws Exception
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool =
ToolRunner.invokeClass(SSTableRepairedAtSetter.class, "-h");
+ String help = "This command should be run with Cassandra stopped,
otherwise you will get very strange behavior\n" +
+ "Verify that Cassandra is not running and then execute
the command like this:\n" +
+ "Usage: sstablerepairedset --really-set [--is-repaired |
--is-unrepaired] [-f <sstable-list> | <sstables>]\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp() throws IOException
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableRepairedAtSetter.class,
+ "--debugwrong",
+
findOneSSTable("legacy_sstables", "legacy_ma_simple"));
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testIsrepairedArg() throws Exception
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableRepairedAtSetter.class,
+ "--really-set",
+ "--is-repaired",
+
findOneSSTable("legacy_sstables", "legacy_ma_simple"));
+ tool.assertOnCleanExit();
+ assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
+ assertSchemaNotLoaded();
+ assertCLSMNotLoaded();
+ assertSystemKSNotLoaded();
+ assertKeyspaceNotLoaded();
+ assertServerNotLoaded();
+ }
+
+ @Test
+ public void testIsunrepairedArg() throws Exception
+ {
+ ToolResult tool = ToolRunner.invokeClass(SSTableRepairedAtSetter.class,
+ "--really-set",
+ "--is-unrepaired",
+
findOneSSTable("legacy_sstables", "legacy_ma_simple"));
+ tool.assertOnCleanExit();
+ assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
+ assertSchemaNotLoaded();
+ assertCLSMNotLoaded();
+ assertSystemKSNotLoaded();
+ assertKeyspaceNotLoaded();
+ assertServerNotLoaded();
+ }
+
+ @Test
+ public void testFilesArg() throws Exception
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.SSTableRepairedAtSetter",
"--really-set", "--is-repaired", findOneSSTable("legacy_sstables",
"legacy_ma_simple"))
- .waitAndAssertOnCleanExit();
+ File tmpFile = FileUtils.createTempFile("sstablelist.txt", "tmp");
+ tmpFile.deleteOnExit();
+ Files.write(tmpFile.toPath(), findOneSSTable("legacy_sstables",
"legacy_ma_simple").getBytes());
+
+ String file = tmpFile.getAbsolutePath();
+ ToolResult tool =
ToolRunner.invokeClass(SSTableRepairedAtSetter.class, "--really-set",
"--is-repaired", "-f", file);
+ tool.assertOnCleanExit();
assertNoUnexpectedThreadsStarted(null, OPTIONAL_THREADS_WITH_SCHEMA);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
diff --git
a/test/unit/org/apache/cassandra/tools/StandaloneSSTableUtilTest.java
b/test/unit/org/apache/cassandra/tools/StandaloneSSTableUtilTest.java
index 834f537..460fb10 100644
--- a/test/unit/org/apache/cassandra/tools/StandaloneSSTableUtilTest.java
+++ b/test/unit/org/apache/cassandra/tools/StandaloneSSTableUtilTest.java
@@ -18,22 +18,31 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
+import org.apache.commons.lang3.tuple.Pair;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class StandaloneSSTableUtilTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testStandaloneSSTableUtil_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneSSTableUtil").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSSTableUtil.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Missing arguments"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +52,119 @@ public class StandaloneSSTableUtilTest extends
OfflineToolUtils
}
@Test
- public void testStandaloneSSTableUtil_WithArgs()
+ public void testWrongArgFailsAndPrintsHelp()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneSSTableUtil",
"--debug", "-c", "system_schema", "tables")
- .waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSSTableUtil.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSSTableUtil.class,
"-h");
+ String help = "usage: sstableutil [options] <keyspace>
<column_family>\n" +
+ "--\n" +
+ "List sstable files for the provided table.\n" +
+ "--\n" +
+ "Options are:\n" +
+ " -c,--cleanup clean-up any outstanding
transactions\n" +
+ " -d,--debug display stack traces\n" +
+ " -h,--help display this help message\n" +
+ " -o,--oplog include operation logs\n" +
+ " -t,--type <arg> all (list all files, final or
temporary), tmp (list\n" +
+ " temporary files only), final (list
final files only),\n" +
+ " -v,--verbose verbose output\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSSTableUtil.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Listing files..."));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testListFilesArgs()
+ {
+ Arrays.asList("-d", "--debug", "-o", "-oplog", "-v",
"--verbose").forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSSTableUtil.class,
+ arg,
+ "system_schema",
+ "tables");
+ Assertions.assertThat(tool.getStdout()).as("Arg: [%s]",
arg).isEqualTo("Listing files...\n");
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testCleanupArg()
+ {
+ Arrays.asList("-c", "--cleanup").forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSSTableUtil.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Cleaning up..."));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testHelpArg()
+ {
+ Arrays.asList("-h", "--help").forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSSTableUtil.class, arg);
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testTypeArg()
+ {
+ Arrays.asList("-t", "--type").forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSSTableUtil.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat("Arg: [" + arg + "]", tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Missing arguments"));
+ assertEquals("Arg: [" + arg + "]", 1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ });
+
+ //'-t wrong' renders 'all' file types
+ Arrays.asList(Pair.of("-t", "all"),
+ Pair.of("-t", "tmp"),
+ Pair.of("-t", "final"),
+ Pair.of("-t", "wrong"),
+ Pair.of("--type", "all"),
+ Pair.of("--type", "tmp"),
+ Pair.of("--type", "final"),
+ Pair.of("--type", "wrong"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSSTableUtil.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "system_schema",
+ "tables");
+ Assertions.assertThat(tool.getStdout()).as("Arg: [%s]",
arg).isEqualTo("Listing files...\n");
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg:
[%s]", arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
}
}
diff --git a/test/unit/org/apache/cassandra/tools/StandaloneScrubberTest.java
b/test/unit/org/apache/cassandra/tools/StandaloneScrubberTest.java
index a99f657..3593025 100644
--- a/test/unit/org/apache/cassandra/tools/StandaloneScrubberTest.java
+++ b/test/unit/org/apache/cassandra/tools/StandaloneScrubberTest.java
@@ -18,22 +18,32 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
+import org.apache.commons.lang3.tuple.Pair;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
+import static org.junit.Assert.assertTrue;
@RunWith(OrderedJUnit4ClassRunner.class)
public class StandaloneScrubberTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testStandaloneScrubber_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneScrubber").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Missing arguments"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +53,134 @@ public class StandaloneScrubberTest extends
OfflineToolUtils
}
@Test
- public void testStandaloneScrubber_WithArgs()
+ public void testMaybeChangeDocs()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneScrubber",
"--debug", "system_schema", "tables")
- .waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class,
"-h");
+ String help = "usage: sstablescrub [options] <keyspace>
<column_family>\n" +
+ "--\n" +
+ "Scrub the sstable for the provided table.\n" +
+ "--\n" +
+ "Options are:\n" +
+ " --debug display stack
traces\n" +
+ " -e,--header-fix <arg> Option whether and how
to perform a check of the sstable serialization-headers and fix\n" +
+ " known, fixable
issues.\n" +
+ " Possible argument
values:\n" +
+ " - validate-only:
validate the serialization-headers, but do not fix those. Do not continue with
scrub - i.e. only\n" +
+ " validate the header
(dry-run of fix-only).\n" +
+ " - validate: (default)
validate the serialization-headers, but do not fix those and only continue with
scrub if no error\n" +
+ " were detected.\n" +
+ " - fix-only: validate
and fix the serialization-headers, don't continue with scrub.\n" +
+ " - fix: validate and
fix the serialization-headers, do not fix and do not continue with scrub if the
serialization-header\n" +
+ " check encountered
errors.\n" +
+ " - off: don't perform
the serialization-header checks.\n" +
+ " -h,--help display this help
message\n" +
+ " -m,--manifest-check only check and repair
the leveled manifest, without actually scrubbing the sstables\n" +
+ " -n,--no-validate do not validate
columns using column validator\n" +
+ " -r,--reinsert-overflowed-ttl Rewrites rows with
overflowed expiration date affected by CASSANDRA-14092 with the\n" +
+ " maximum supported
expiration date of 2038-01-19T03:14:06+00:00. The rows are rewritten with the
original timestamp\n" +
+ " incremented by one
millisecond to override/supersede any potential tombstone that may have been
generated during\n" +
+ " compaction of the
affected rows.\n" +
+ " -s,--skip-corrupted skip corrupt rows in
counter tables\n" +
+ " -v,--verbose verbose output\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Pre-scrub sstables snapshotted into
snapshot"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testFlagArgs()
+ {
+ Arrays.asList("--debug",
+ "-m",
+ "--manifest-check",
+ "-n",
+ "--no-validate",
+ "-r",
+ "--reinsert-overflowed-ttl",
+ "-s",
+ "--skip-corrupted",
+ "-v",
+ "--verbose")
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneScrubber.class,
+ arg,
+
"system_schema",
+ "tables");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Pre-scrub sstables snapshotted into
snapshot"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg:
[%s]", arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testHelpArg()
+ {
+ Arrays.asList("-h", "--help").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneScrubber.class,
arg);
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testHeaderFixArg()
+ {
+ Arrays.asList(Pair.of("-e", ""),
+ Pair.of("-e", "wrong"),
+ Pair.of("--header-fix", ""),
+ Pair.of("--header-fix", "wrong"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneScrubber.class,
+
arg.getLeft(),
+
arg.getRight(),
+
"system_schema",
+ "tables");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertTrue("Arg: [" + arg + "]\n" + tool.getCleanedStderr(),
tool.getCleanedStderr().contains("Invalid argument value"));
+ assertEquals(1, tool.getExitCode());
+ });
+
+ Arrays.asList(Pair.of("-e", "validate-only"),
+ Pair.of("-e", "validate"),
+ Pair.of("-e", "fix-only"),
+ Pair.of("-e", "fix"),
+ Pair.of("-e", "off"),
+ Pair.of("--header-fix", "validate-only"),
+ Pair.of("--header-fix", "validate"),
+ Pair.of("--header-fix", "fix-only"),
+ Pair.of("--header-fix", "fix"),
+ Pair.of("--header-fix", "off"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneScrubber.class,
+
arg.getLeft(),
+
arg.getRight(),
+
"system_schema",
+ "tables");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Pre-scrub sstables snapshotted into
snapshot"));
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg:
[%s]", arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
}
}
diff --git a/test/unit/org/apache/cassandra/tools/StandaloneSplitterTest.java
b/test/unit/org/apache/cassandra/tools/StandaloneSplitterTest.java
index 753a258..287275b 100644
--- a/test/unit/org/apache/cassandra/tools/StandaloneSplitterTest.java
+++ b/test/unit/org/apache/cassandra/tools/StandaloneSplitterTest.java
@@ -18,19 +18,27 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
+import org.apache.commons.lang3.tuple.Pair;
+
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class StandaloneSplitterTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
+ // Note: StandaloneSplitter modifies sstables
+
@BeforeClass
public static void before()
{
@@ -41,9 +49,12 @@ public class StandaloneSplitterTest extends OfflineToolUtils
}
@Test
- public void testStandaloneSplitter_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneSplitter").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSplitter.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("No sstables to split"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -52,5 +63,84 @@ public class StandaloneSplitterTest extends OfflineToolUtils
assertServerNotLoaded();
}
- // Note: StandaloneSplitter modifies sstables
+ @Test
+ public void testMaybeChangeDocs()
+ {
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSplitter.class,
"-h");
+ String help = "usage: sstablessplit [options] <filename>
[<filename>]*\n" +
+ "--\n" +
+ "Split the provided sstables files in sstables of
maximum provided file\n" +
+ "size (see option --size).\n" +
+ "--\n" +
+ "Options are:\n" +
+ " --debug display stack traces\n" +
+ " -h,--help display this help message\n" +
+ " --no-snapshot don't snapshot the sstables before
splitting\n" +
+ " -s,--size <size> maximum size in MB for the output
sstables (default:\n" +
+ " 50)\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSplitter.class,
"--debugwrong", "mockFile");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testWrongFilename()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSplitter.class,
"mockFile");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Skipping inexisting file mockFile"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("No valid sstables to split"));
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testFlagArgs()
+ {
+ Arrays.asList("--debug", "--no-snapshot").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneSplitter.class,
arg, "mockFile");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Skipping inexisting file mockFile"));
+ assertThat("Arg: [" + arg + "]", tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("No valid sstables to split"));
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testSizeArg()
+ {
+ Arrays.asList(Pair.of("-s", ""), Pair.of("-s", "w"), Pair.of("--size",
""), Pair.of("--size", "w"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSplitter.class,
+ arg.getLeft(),
+ arg.getRight(),
+ "mockFile");
+ assertEquals(-1, tool.getExitCode());
+
Assertions.assertThat(tool.getStderr()).contains(NumberFormatException.class.getSimpleName());
+ });
+
+ Arrays.asList(Pair.of("-s", "0"),
+ Pair.of("-s", "1000"),
+ Pair.of("-s", "-1"),
+ Pair.of("--size", "0"),
+ Pair.of("--size", "1000"),
+ Pair.of("--size", "-1"))
+ .forEach(arg -> {
+ ToolResult tool =
ToolRunner.invokeClass(StandaloneSplitter.class,
+
arg.getLeft(),
+
arg.getRight(),
+ "mockFile");
+ assertThat("Arg: [" + arg + "]", tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("Skipping inexisting file mockFile"));
+ assertThat("Arg: [" + arg + "]", tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("No valid sstables to split"));
+ assertEquals(1, tool.getExitCode());
+ assertCorrectEnvPostTest();
+ });
+ }
}
diff --git a/test/unit/org/apache/cassandra/tools/StandaloneUpgraderTest.java
b/test/unit/org/apache/cassandra/tools/StandaloneUpgraderTest.java
index 1bfbbd2..3a4177b 100644
--- a/test/unit/org/apache/cassandra/tools/StandaloneUpgraderTest.java
+++ b/test/unit/org/apache/cassandra/tools/StandaloneUpgraderTest.java
@@ -18,22 +18,29 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class StandaloneUpgraderTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
@Test
- public void testStandaloneUpgrader_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneUpgrader").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Missing arguments"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +50,71 @@ public class StandaloneUpgraderTest extends OfflineToolUtils
}
@Test
- public void testStandaloneUpgrader_WithArgs()
+ public void testMaybeChangeDocs()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneUpgrader",
"--debug", "system_schema", "tables")
- .waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class,
"-h");
+ String help = "usage: sstableupgrade [options] <keyspace> <cf>
[snapshot]\n" +
+ "--\n" +
+ "Upgrade the sstables in the given cf (or snapshot) to
the current version\n" +
+ "of Cassandra.This operation will rewrite the sstables
in the specified cf\n" +
+ "to match the currently installed version of
Cassandra.\n" +
+ "The snapshot option will only upgrade the specified
snapshot. Upgrading\n" +
+ "snapshots is required before attempting to restore a
snapshot taken in a\n" +
+ "major version older than the major version Cassandra
is currently running.\n" +
+ "This will replace the files in the given snapshot as
well as break any\n" +
+ "hard links to live sstables.\n" +
+ "--\n" +
+ "Options are:\n" +
+ " --debug display stack traces\n" +
+ " -h,--help display this help message\n" +
+ " -k,--keep-source do not delete the source
sstables\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class,
"system_schema", "tables");
+ Assertions.assertThat(tool.getStdout()).isEqualTo("Found 0 sstables
that need upgrading.\n");
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testFlagArgs()
+ {
+ Arrays.asList("--debug", "-k", "--keep-source").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class,
+ arg,
+ "system_schema",
+ "tables");
+ Assertions.assertThat(tool.getStdout()).as("Arg: [%s]",
arg).isEqualTo("Found 0 sstables that need upgrading.\n");
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testHelpArg()
+ {
+ Arrays.asList("-h", "--help").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneUpgrader.class,
arg);
+ Assertions.assertThat(tool.getStdout()).as("Arg: [%s]",
arg).isNotEmpty();
+ Assertions.assertThat(tool.getCleanedStderr()).as("Arg: [%s]",
arg).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
}
}
diff --git a/test/unit/org/apache/cassandra/tools/StandaloneVerifierTest.java
b/test/unit/org/apache/cassandra/tools/StandaloneVerifierTest.java
index e33a154..f736edd 100644
--- a/test/unit/org/apache/cassandra/tools/StandaloneVerifierTest.java
+++ b/test/unit/org/apache/cassandra/tools/StandaloneVerifierTest.java
@@ -18,22 +18,30 @@
package org.apache.cassandra.tools;
+import java.util.Arrays;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.cassandra.OrderedJUnit4ClassRunner;
+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.assertThat;
@RunWith(OrderedJUnit4ClassRunner.class)
public class StandaloneVerifierTest extends OfflineToolUtils
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
+
@Test
- public void testStandaloneVerifier_NoArgs()
+ public void testNoArgsPrintsHelp()
{
- assertEquals(1,
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneVerifier").getExitCode());
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Missing arguments"));
+ assertEquals(1, tool.getExitCode());
assertNoUnexpectedThreadsStarted(null, null);
assertSchemaNotLoaded();
assertCLSMNotLoaded();
@@ -43,12 +51,125 @@ public class StandaloneVerifierTest extends
OfflineToolUtils
}
@Test
- public void testStandaloneVerifier_WithArgs()
+ public void testMaybeChangeDocs()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.StandaloneVerifier",
"--debug", "system_schema", "tables")
- .waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(EXPECTED_THREADS_WITH_SCHEMA,
OPTIONAL_THREADS_WITH_SCHEMA);
- assertSchemaLoaded();
- assertServerNotLoaded();
+ // If you added, modified options or help, please update docs if
necessary
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
"-h");
+ String help = "usage: sstableverify [options] <keyspace>
<column_family>\n" +
+ "--\n" +
+ "Verify the sstable for the provided table.\n" +
+ "--\n" +
+ "Options are:\n" +
+ " -c,--check_version make sure sstables are
the latest version\n" +
+ " --debug display stack traces\n" +
+ " -e,--extended extended verification\n"
+
+ " -h,--help display this help
message\n" +
+ " -q,--quick do a quick check, don't
read all data\n" +
+ " -r,--mutate_repair_status don't mutate repair
status\n" +
+ " -t,--token_range <range> long token range of the
format left,right.\n" +
+ " This may be provided
multiple times to define multiple different ranges\n" +
+ " -v,--verbose verbose output\n";
+ Assertions.assertThat(tool.getStdout()).isEqualTo(help);
+ }
+
+ @Test
+ public void testWrongArgFailsAndPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
"--debugwrong", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("Unrecognized option"));
+ assertEquals(1, tool.getExitCode());
+ }
+
+ @Test
+ public void testDefaultCall()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
"system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("using the following options"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ assertEquals(0,tool.getExitCode());
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testDebugArg()
+ {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
"--debug", "system_schema", "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("debug=true"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ }
+
+ @Test
+ public void testExtendedArg()
+ {
+ Arrays.asList("-e", "--extended").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("extended=true"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testQuickArg()
+ {
+ Arrays.asList("-q", "--quick").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("quick=true"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testRepairStatusArg()
+ {
+ Arrays.asList("-r", "--mutate_repair_status").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("mutateRepairStatus=true"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testHelpArg()
+ {
+ Arrays.asList("-h", "--help").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
arg);
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
+ }
+
+ @Test
+ public void testVerboseArg()
+ {
+ Arrays.asList("-v", "--verbose").forEach(arg -> {
+ ToolResult tool = ToolRunner.invokeClass(StandaloneVerifier.class,
+ arg,
+ "system_schema",
+ "tables");
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("verbose=true"));
+ Assertions.assertThat(tool.getCleanedStderr()).isEmpty();
+ tool.assertOnExitCode();
+ assertCorrectEnvPostTest();
+ });
}
}
diff --git a/test/unit/org/apache/cassandra/tools/ToolRunner.java
b/test/unit/org/apache/cassandra/tools/ToolRunner.java
index 7334347..98fdaed 100644
--- a/test/unit/org/apache/cassandra/tools/ToolRunner.java
+++ b/test/unit/org/apache/cassandra/tools/ToolRunner.java
@@ -18,7 +18,6 @@
package org.apache.cassandra.tools;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -28,13 +27,17 @@ import java.lang.reflect.InvocationTargetException;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
-import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
-import org.apache.commons.io.IOUtils;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,178 +47,11 @@ import
org.apache.cassandra.tools.OfflineToolUtils.SystemExitException;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-public class ToolRunner implements AutoCloseable
+public class ToolRunner
{
protected static final Logger logger =
LoggerFactory.getLogger(ToolRunner.class);
private static final ImmutableList<String> DEFAULT_CLEANERS =
ImmutableList.of("(?im)^picked up.*\\R");
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
- private final List<String> allArgs = new ArrayList<>();
- private Process process;
- @SuppressWarnings("resource")
- private final ByteArrayOutputStream errBuffer = new
ByteArrayOutputStream();
- @SuppressWarnings("resource")
- private final ByteArrayOutputStream outBuffer = new
ByteArrayOutputStream();
- private InputStream stdin;
- private Thread[] ioWatchers;
- private Map<String, String> envs;
- private boolean runOutOfProcess = true;
-
- public ToolRunner(List<String> args)
- {
- this.allArgs.addAll(args);
- }
-
- public ToolRunner(List<String> args, boolean runOutOfProcess)
- {
- this.allArgs.addAll(args);
- this.runOutOfProcess = runOutOfProcess;
- }
-
- public ToolRunner withStdin(InputStream stdin)
- {
- this.stdin = stdin;
- return this;
- }
-
- public ToolRunner withEnvs(Map<String, String> envs)
- {
- Preconditions.checkArgument(runOutOfProcess, "Not supported");
- this.envs = envs;
- return this;
- }
-
- public ToolRunner start()
- {
- if (process != null)
- throw new IllegalStateException("Process already started. Create a
new ToolRunner instance for each invocation.");
-
- logger.debug("Starting {} with args {}", runOutOfProcess ? "process" :
"class" , argsToLogString());
-
- try
- {
- if (runOutOfProcess)
- {
- ProcessBuilder pb = new ProcessBuilder(allArgs);
- if (envs != null)
- pb.environment().putAll(envs);
- process = pb.start();
- }
- else
- {
- PrintStream originalSysOut = System.out;
- PrintStream originalSysErr = System.err;
- InputStream originalSysIn = System.in;
- originalSysOut.flush();
- originalSysErr.flush();
- ByteArrayOutputStream toolOut = new ByteArrayOutputStream();
- ByteArrayOutputStream toolErr = new ByteArrayOutputStream();
-
- System.setIn(stdin == null ? originalSysIn : stdin);
-
- int exit;
- try (PrintStream newOut = new PrintStream(toolOut);
PrintStream newErr = new PrintStream(toolErr))
- {
- System.setOut(newOut);
- System.setErr(newErr);
- String clazz = allArgs.get(0);
- String[] clazzArgs = allArgs.subList(1,
allArgs.size()).toArray(EMPTY_STRING_ARRAY);
- exit = runClassAsTool(clazz, clazzArgs);
- }
-
- final int exitCode = exit;
- System.setOut(originalSysOut);
- System.setErr(originalSysErr);
- System.setIn(originalSysIn);
-
- process = new Process() {
-
- @Override
- public void destroy()
- {
- }
-
- @Override
- public int exitValue()
- {
- return exitCode;
- }
-
- @Override
- public InputStream getErrorStream()
- {
- return new ByteArrayInputStream(toolErr.toByteArray());
- }
-
- @Override
- public InputStream getInputStream()
- {
- return new ByteArrayInputStream(toolOut.toByteArray());
- }
-
- @Override
- public OutputStream getOutputStream()
- {
- if (stdin == null)
- return null;
-
- ByteArrayOutputStream out;
- try
- {
- out = new ByteArrayOutputStream(stdin.available());
- IOUtils.copy(stdin, out);
- }
- catch(IOException e)
- {
- throw new RuntimeException("Failed to get stdin",
e);
- }
- return out;
- }
-
- @Override
- public int waitFor()
- {
- return exitValue();
- }
-
- };
- }
-
- // each stream tends to use a bounded buffer, so need to process
each stream in its own thread else we
- // might block on an idle stream, not consuming the other stream
which is blocked in the other process
- // as nothing is consuming
- int numWatchers = 2;
- // only need a stdin watcher when forking
- boolean includeStdinWatcher = runOutOfProcess && stdin != null;
- if (includeStdinWatcher)
- numWatchers = 3;
- ioWatchers = new Thread[numWatchers];
- ioWatchers[0] = new Thread(new
StreamGobbler<>(process.getErrorStream(), errBuffer));
- ioWatchers[0].setDaemon(true);
- ioWatchers[0].setName("IO Watcher stderr for " + allArgs);
- ioWatchers[0].start();
-
- ioWatchers[1] = new Thread(new
StreamGobbler<>(process.getInputStream(), outBuffer));
- ioWatchers[1].setDaemon(true);
- ioWatchers[1].setName("IO Watcher stdout for " + allArgs);
- ioWatchers[1].start();
-
- if (includeStdinWatcher)
- {
- ioWatchers[2] = new Thread(new StreamGobbler<>(stdin,
process.getOutputStream()));
- ioWatchers[2].setDaemon(true);
- ioWatchers[2].setName("IO Watcher stdin for " + allArgs);
- ioWatchers[2].start();
- }
- }
- catch (IOException e)
- {
- throw new RuntimeException("Failed to start " + allArgs, e);
- }
-
- return this;
- }
public static int runClassAsTool(String clazz, String... args)
{
@@ -273,228 +109,479 @@ public class ToolRunner implements AutoCloseable
}
}
- public boolean isRunning()
+ private static final class StreamGobbler<T extends OutputStream>
implements Runnable
{
- return process != null && process.isAlive();
- }
+ private static final int BUFFER_SIZE = 8_192;
- public int waitFor()
- {
- try
+ private final InputStream input;
+ private final T out;
+
+ private StreamGobbler(InputStream input, T out)
{
- int rc = process.waitFor();
- // must call first in order to make sure the stdin ioWatcher will
exit
- onComplete();
- for (Thread t : ioWatchers)
- t.join();
- return rc;
+ this.input = input;
+ this.out = out;
}
- catch (InterruptedException e)
+
+ public void run()
{
- throw new RuntimeException(e);
+ byte[] buffer = new byte[BUFFER_SIZE];
+ while (true)
+ {
+ try
+ {
+ int read = input.read(buffer);
+ if (read == -1)
+ {
+ return;
+ }
+ out.write(buffer, 0, read);
+ }
+ catch (IOException e)
+ {
+ logger.error("Unexpected IO Error while reading stream",
e);
+ return;
+ }
+ }
}
}
- public ToolRunner waitAndAssertOnExitCode()
- {
- assertExitCode(waitFor());
- return this;
- }
-
- public ToolRunner waitAndAssertOnCleanExit()
+ /**
+ * Invokes Cqlsh. The first arg is the cql to execute
+ */
+ public static ToolResult invokeCqlsh(String... args)
{
- return waitAndAssertOnExitCode().assertCleanStdErr();
+ return invokeCqlsh(Arrays.asList(args));
}
-
+
/**
- * Checks if the stdErr is empty after removing any potential JVM env info
output and other noise
- *
- * Some JVM configs may output env info on stdErr. We need to remove those
to see what was the tool's actual stdErr
- * @return The ToolRunner instance
+ * Invokes Cqlsh. The first arg is the cql to execute
*/
- public ToolRunner assertCleanStdErr()
+ public static ToolResult invokeCqlsh(List<String> args)
{
- assertTrue("Failed because cleaned stdErr wasn't empty: " +
getCleanedStderr(), getCleanedStderr().isEmpty());
- return this;
+ return invoke(CQLTester.buildCqlshArgs(args));
}
- public ToolRunner assertOnExitCode()
+ public static ToolResult invokeCassandraStress(String... args)
{
- assertExitCode(getExitCode());
- return this;
+ return invokeCassandraStress(Arrays.asList(args));
}
- private void assertExitCode(int code)
+ public static ToolResult invokeCassandraStress(List<String> args)
{
- if (code != 0)
- fail(String.format("%s%nexited with code
%d%nstderr:%n%s%nstdout:%n%s",
- argsToLogString(),
- code,
- getStderr(),
- getStdout()));
+ return invoke(CQLTester.buildCassandraStressArgs(args));
}
- public String argsToLogString()
+ public static ToolResult invokeNodetool(String... args)
{
- return allArgs.stream().collect(Collectors.joining(",\n ", "[",
"]"));
+ return invokeNodetool(Arrays.asList(args));
}
- public int getExitCode()
+ public static ToolResult invokeNodetool(List<String> args)
{
- return process.exitValue();
+ return invoke(CQLTester.buildNodetoolArgs(args));
}
- public String getStdout()
+ public static ToolResult invoke(List<String> args)
{
- return outBuffer.toString();
+ return invoke(args.toArray(new String[args.size()]));
}
- public String getStderr()
+ public static ToolResult invoke(String... args)
{
- return errBuffer.toString();
+ try (ObservableTool t = invokeAsync(args))
+ {
+ return t.waitComplete();
+ }
}
- /**
- * Checks if the stdErr is empty after removing any potential JVM env info
output and other noise
- *
- * Some JVM configs may output env info on stdErr. We need to remove those
to see what was the tool's actual stdErr
- *
- * @param regExpCleaners List of regExps to remove from stdErr
- * @return The stdErr with all excludes removed
- */
- public String getCleanedStderr(List<String> regExpCleaners)
+ public static ObservableTool invokeAsync(String... args)
{
- String sanitizedStderr = getStderr();
- for (String regExp: regExpCleaners)
- sanitizedStderr = sanitizedStderr.replaceAll(regExp, "");
- return sanitizedStderr;
+ return invokeAsync(Collections.emptyMap(), null, Arrays.asList(args));
}
- /**
- * Checks if the stdErr is empty after removing any potential JVM env info
output. Uses default list of excludes
- *
- * {@link #getCleanedStderr(List)}
- */
- public String getCleanedStderr()
+ public static ToolResult invoke(Map<String, String> env, InputStream
stdin, List<String> args)
{
- return getCleanedStderr(DEFAULT_CLEANERS);
+ try (ObservableTool t = invokeAsync(env, stdin, args))
+ {
+ return t.waitComplete();
+ }
}
- public void forceKill()
+ public static ObservableTool invokeAsync(Map<String, String> env,
InputStream stdin, List<String> args)
{
+ ProcessBuilder pb = new ProcessBuilder(args);
+ if (env != null && !env.isEmpty())
+ pb.environment().putAll(env);
try
{
- process.exitValue();
- // process no longer alive - just ignore that fact
+ return new ForkedObservableTool(pb.start(), stdin, args);
}
- catch (IllegalThreadStateException e)
+ catch (IOException e)
{
- process.destroyForcibly();
+ return new FailedObservableTool(e, args);
}
}
- @Override
- public void close()
+ public static ToolResult invokeClass(String klass, String... args)
{
- forceKill();
- onComplete();
+ return invokeClass(klass, null, args);
}
- private void onComplete()
+ public static ToolResult invokeClass(Class<?> klass, String... args)
{
- if (stdin != null)
+ return invokeClass(klass.getName(), null, args);
+ }
+
+ public static ToolResult invokeClass(String klass, InputStream stdin,
String... args)
+ {
+ List<String> allArgs = new ArrayList<>();
+ allArgs.add(klass);
+ allArgs.addAll(Arrays.asList(args));
+
+ PrintStream originalSysOut = System.out;
+ PrintStream originalSysErr = System.err;
+ InputStream originalSysIn = System.in;
+ originalSysOut.flush();
+ originalSysErr.flush();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+
+ System.setIn(stdin == null ? originalSysIn : stdin);
+
+ try (PrintStream newOut = new PrintStream(out);
+ PrintStream newErr = new PrintStream(err))
{
- try
- {
- stdin.close();
- }
- catch (IOException e)
- {
- logger.warn("Error closing stdin for {}", allArgs, e);
- }
+ System.setOut(newOut);
+ System.setErr(newErr);
+ int rc = runClassAsTool(klass, args);
+ out.flush();
+ err.flush();
+ return new ToolResult(allArgs, rc, out.toString(), err.toString(),
null);
+ }
+ catch (Exception e)
+ {
+ return new ToolResult(allArgs,
+ -1,
+ out.toString(),
+ err.toString() + "\n" +
Throwables.getStackTraceAsString(e),
+ e);
+ }
+ finally
+ {
+ System.setOut(originalSysOut);
+ System.setErr(originalSysErr);
+ System.setIn(originalSysIn);
}
}
- private static final class StreamGobbler<T extends OutputStream>
implements Runnable
+ public static Builder builder(List<String> args)
{
- private static final int BUFFER_SIZE = 8_192;
+ return new Builder(args);
+ }
- private final InputStream input;
- private final T out;
+ public static final class ToolResult
+ {
+ private final List<String> allArgs;
+ private final int exitCode;
+ private final String stdout;
+ private final String stderr;
+ private final Exception e;
- private StreamGobbler(InputStream input, T out)
+ private ToolResult(List<String> allArgs, int exitCode, String stdout,
String stderr, Exception e)
{
- this.input = input;
- this.out = out;
+ this.allArgs = allArgs;
+ this.exitCode = exitCode;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ this.e = e;
}
- public void run()
+ public int getExitCode()
{
- byte[] buffer = new byte[BUFFER_SIZE];
- while (true)
- {
- try
- {
- int read = input.read(buffer);
- if (read == -1)
- {
- return;
- }
- out.write(buffer, 0, read);
- }
- catch (IOException e)
- {
- logger.error("Unexpected IO Error while reading stream",
e);
- return;
- }
- }
+ return exitCode;
+ }
+
+ public String getStdout()
+ {
+ return stdout;
+ }
+
+ public String getStderr()
+ {
+ return stderr;
+ }
+
+ public Exception getException()
+ {
+ return e;
+ }
+
+ /**
+ * Checks if the stdErr is empty after removing any potential JVM env
info output and other noise
+ *
+ * Some JVM configs may output env info on stdErr. We need to remove
those to see what was the tool's actual
+ * stdErr
+ *
+ * @return The ToolRunner instance
+ */
+ public void assertCleanStdErr()
+ {
+ assertTrue("Failed because cleaned stdErr wasn't empty: " +
getCleanedStderr(),
+ getCleanedStderr().isEmpty());
+ }
+
+ public void assertOnExitCode()
+ {
+ assertExitCode(getExitCode());
+ }
+
+ private void assertExitCode(int code)
+ {
+ if (code != 0)
+ fail(String.format("%s%nexited with code
%d%nstderr:%n%s%nstdout:%n%s",
+ argsToLogString(),
+ code,
+ getStderr(),
+ getStdout()));
}
+
+ public String argsToLogString()
+ {
+ return allArgs.stream().collect(Collectors.joining(",\n ", "[",
"]"));
+ }
+
+ /**
+ * Returns stdErr after removing any potential JVM env info output
through the provided cleaners
+ *
+ * Some JVM configs may output env info on stdErr. We need to remove
those to see what was the tool's actual
+ * stdErr
+ *
+ * @param regExpCleaners
+ * List of regExps to remove from stdErr
+ * @return The stdErr with all excludes removed
+ */
+ public String getCleanedStderr(List<String> regExpCleaners)
+ {
+ String sanitizedStderr = getStderr();
+ for (String regExp : regExpCleaners)
+ sanitizedStderr = sanitizedStderr.replaceAll(regExp, "");
+ return sanitizedStderr;
+ }
+
+ /**
+ * Returns stdErr after removing any potential JVM env info output.
Uses default list of excludes
+ *
+ * {@link #getCleanedStderr(List)}
+ */
+ public String getCleanedStderr()
+ {
+ return getCleanedStderr(DEFAULT_CLEANERS);
+ }
+
+ public void assertOnCleanExit()
+ {
+ assertOnExitCode();
+ assertCleanStdErr();
+ }
+ }
+
+ public interface ObservableTool extends AutoCloseable
+ {
+ String getPartialStdout();
+
+ String getPartialStderr();
+
+ boolean isDone();
+
+ ToolResult waitComplete();
+
+ @Override
+ void close();
}
- public static class Runners
+ private static final class FailedObservableTool implements ObservableTool
{
- public static ToolRunner invokeNodetool(String... args)
+ private final List<String> args;
+ private final IOException error;
+
+ private FailedObservableTool(IOException error, List<String> args)
+ {
+ this.args = args;
+ this.error = error;
+ }
+
+ @Override
+ public String getPartialStdout()
+ {
+ return "";
+ }
+
+ @Override
+ public String getPartialStderr()
{
- return invokeNodetool(Arrays.asList(args));
+ return error.getMessage();
}
- public static ToolRunner invokeNodetool(List<String> args)
+ @Override
+ public boolean isDone()
{
- return invokeTool(buildNodetoolArgs(args), true);
+ return true;
}
- private static List<String> buildNodetoolArgs(List<String> args)
+ @Override
+ public ToolResult waitComplete()
{
- return CQLTester.buildNodetoolArgs(args);
+ return new ToolResult(args, -1, getPartialStdout(),
getPartialStderr(), error);
}
- public static ToolRunner invokeClassAsTool(String... args)
+ @Override
+ public void close()
{
- return invokeClassAsTool(Arrays.asList(args));
+
}
+ }
- public static ToolRunner invokeClassAsTool(List<String> args)
+ private static final class ForkedObservableTool implements ObservableTool
+ {
+ @SuppressWarnings("resource")
+ private final ByteArrayOutputStream err = new ByteArrayOutputStream();
+ @SuppressWarnings("resource")
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ @SuppressWarnings("resource")
+ private final InputStream stdin;
+ private final Process process;
+ private final Thread[] ioWatchers;
+ private final List<String> args;
+
+ private ForkedObservableTool(Process process, InputStream stdin,
List<String> args)
{
- return invokeTool(args, false);
+ this.process = process;
+ this.args = args;
+ this.stdin = stdin;
+
+ // Each stream tends to use a bounded buffer, so need to process
each stream in its own thread else we
+ // might block on an idle stream, not consuming the other stream
which is blocked in the other process
+ // as nothing is consuming
+ int numWatchers = 2;
+ // only need a stdin watcher when forking
+ boolean includeStdinWatcher = stdin != null;
+ if (includeStdinWatcher)
+ numWatchers = 3;
+ ioWatchers = new Thread[numWatchers];
+ ioWatchers[0] = new Thread(new
StreamGobbler<>(process.getErrorStream(), err));
+ ioWatchers[0].setDaemon(true);
+ ioWatchers[0].setName("IO Watcher stderr");
+ ioWatchers[0].start();
+
+ ioWatchers[1] = new Thread(new
StreamGobbler<>(process.getInputStream(), out));
+ ioWatchers[1].setDaemon(true);
+ ioWatchers[1].setName("IO Watcher stdout");
+ ioWatchers[1].start();
+
+ if (includeStdinWatcher)
+ {
+ ioWatchers[2] = new Thread(new StreamGobbler<>(stdin,
process.getOutputStream()));
+ ioWatchers[2].setDaemon(true);
+ ioWatchers[2].setName("IO Watcher stdin");
+ ioWatchers[2].start();
+ }
+ }
+
+ @Override
+ public String getPartialStdout()
+ {
+ return out.toString();
+ }
+
+ @Override
+ public String getPartialStderr()
+ {
+ return err.toString();
}
- public static ToolRunner invokeTool(String... args)
+ @Override
+ public boolean isDone()
{
- return invokeTool(Arrays.asList(args));
+ return !process.isAlive();
}
- public static ToolRunner invokeTool(List<String> args)
+ @Override
+ public ToolResult waitComplete()
{
- return invokeTool(args, true);
+ try
+ {
+ int rc = process.waitFor();
+ onComplete();
+ return new ToolResult(args, rc, out.toString(),
err.toString(), null);
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(e);
+ }
}
- public static ToolRunner invokeTool(List<String> args, boolean
runOutOfProcess)
+ private void onComplete() throws InterruptedException
{
- try (ToolRunner runner = new ToolRunner(args,
runOutOfProcess).start())
+ try
{
- runner.waitFor();
- return runner;
+ if (stdin != null)
+ stdin.close();
}
+ catch (IOException e)
+ {
+ logger.warn("Error closing stdin", e);
+ }
+ for (Thread t : ioWatchers)
+ t.join();
+ }
+
+ @Override
+ public void close()
+ {
+ if (!process.isAlive())
+ return;
+ process.destroyForcibly();
+ }
+ }
+
+ public static final class Builder
+ {
+ private final Map<String, String> env = new HashMap<>();
+ private final List<String> args;
+ private InputStream stdin;
+
+ public Builder(List<String> args)
+ {
+ this.args = Objects.requireNonNull(args);
+ }
+
+ public Builder withEnv(String key, String value)
+ {
+ env.put(key, value);
+ return this;
+ }
+
+ public Builder withEnvs(Map<String, String> map)
+ {
+ env.putAll(map);
+ return this;
+ }
+
+ public Builder withStdin(InputStream input)
+ {
+ this.stdin = input;
+ return this;
+ }
+
+ public ObservableTool invokeAsync()
+ {
+ return ToolRunner.invokeAsync(env, stdin, args);
+ }
+
+ public ToolResult invoke()
+ {
+ return ToolRunner.invoke(env, stdin, args);
}
}
}
diff --git a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
b/test/unit/org/apache/cassandra/tools/ToolsEnvsConfigsTest.java
similarity index 53%
copy from test/unit/org/apache/cassandra/tools/GetVersionTest.java
copy to test/unit/org/apache/cassandra/tools/ToolsEnvsConfigsTest.java
index c5f5282..fd39901 100644
--- a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
+++ b/test/unit/org/apache/cassandra/tools/ToolsEnvsConfigsTest.java
@@ -18,25 +18,27 @@
package org.apache.cassandra.tools;
+import java.util.Collections;
+
+import com.google.common.collect.ImmutableMap;
+
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 static org.junit.Assert.assertTrue;
-@RunWith(OrderedJUnit4ClassRunner.class)
-public class GetVersionTest extends OfflineToolUtils
+public class ToolsEnvsConfigsTest
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
+ //Some JDK can output env info on stdout/err. Check we can clean them
+ @SuppressWarnings("resource")
@Test
- public void testGetVersion()
+ public void testJDKEnvInfoDefaultCleaners()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.GetVersion").waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(null, null);
- assertSchemaNotLoaded();
- assertCLSMNotLoaded();
- assertSystemKSNotLoaded();
- assertKeyspaceNotLoaded();
- assertServerNotLoaded();
+ ToolResult tool = ToolRunner.invoke(ImmutableMap.of("_JAVA_OPTIONS",
"-Djava.net.preferIPv4Stack=true"),
+ null,
+
CQLTester.buildNodetoolArgs(Collections.emptyList()));
+ assertTrue("Cleaned Stderr was not empty: " + tool.getCleanedStderr(),
tool.getCleanedStderr().isEmpty());
}
}
diff --git
a/test/unit/org/apache/cassandra/tools/cassandrastress/CassandrastressTest.java
b/test/unit/org/apache/cassandra/tools/cassandrastress/CassandrastressTest.java
new file mode 100644
index 0000000..8ba091a
--- /dev/null
+++
b/test/unit/org/apache/cassandra/tools/cassandrastress/CassandrastressTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.cassandrastress;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.tools.ToolRunner;
+import org.apache.cassandra.tools.ToolRunner.ToolResult;
+import org.hamcrest.CoreMatchers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class CassandrastressTest extends CQLTester
+{
+ @BeforeClass
+ public static void setUp()
+ {
+ requireNetwork();
+ }
+
+ @Test
+ public void testNoArgsPrintsHelp()
+ {
+ ToolResult tool = ToolRunner.invokeCassandraStress();
+ assertThat(tool.getStdout(),
CoreMatchers.containsStringIgnoringCase("usage:"));
+ assertTrue("Tool stderr: " + tool.getCleanedStderr(),
tool.getCleanedStderr().isEmpty());
+ assertEquals(1, tool.getExitCode());
+ }
+
+}
diff --git a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
b/test/unit/org/apache/cassandra/tools/cqlsh/CqlshTest.java
similarity index 53%
copy from test/unit/org/apache/cassandra/tools/GetVersionTest.java
copy to test/unit/org/apache/cassandra/tools/cqlsh/CqlshTest.java
index c5f5282..4e6dd20 100644
--- a/test/unit/org/apache/cassandra/tools/GetVersionTest.java
+++ b/test/unit/org/apache/cassandra/tools/cqlsh/CqlshTest.java
@@ -16,27 +16,32 @@
* limitations under the License.
*/
-package org.apache.cassandra.tools;
+package org.apache.cassandra.tools.cqlsh;
+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 org.apache.cassandra.tools.ToolRunner.ToolResult;
+import org.hamcrest.CoreMatchers;
-@RunWith(OrderedJUnit4ClassRunner.class)
-public class GetVersionTest extends OfflineToolUtils
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class CqlshTest extends CQLTester
{
- private ToolRunner.Runners runner = new ToolRunner.Runners();
-
+ @BeforeClass
+ public static void setUp()
+ {
+ requireNetwork();
+ }
+
@Test
- public void testGetVersion()
+ public void testKeyspaceRequired()
{
-
runner.invokeClassAsTool("org.apache.cassandra.tools.GetVersion").waitAndAssertOnCleanExit();
- assertNoUnexpectedThreadsStarted(null, null);
- assertSchemaNotLoaded();
- assertCLSMNotLoaded();
- assertSystemKSNotLoaded();
- assertKeyspaceNotLoaded();
- assertServerNotLoaded();
+ ToolResult tool = ToolRunner.invokeCqlsh("SELECT * FROM test");
+ assertThat(tool.getCleanedStderr(),
CoreMatchers.containsStringIgnoringCase("No keyspace has been specified"));
+ assertEquals(2, tool.getExitCode());
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]