You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by mc...@apache.org on 2021/04/19 15:55:13 UTC

[cassandra] branch trunk updated (dbedf57 -> 7337fc0)

This is an automated email from the ASF dual-hosted git repository.

mck pushed a change to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git.


    from dbedf57  Merge branch 'cassandra-3.11' into trunk
     new 53b0661  Fix rat checking for files with missing license headers
     new 50a97a0  Merge branch 'cassandra-2.2' into cassandra-3.0
     new 2ec96ae  Merge branch 'cassandra-3.0' into cassandra-3.11
     new 7337fc0  Merge branch 'cassandra-3.11' into trunk

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .build/build-rat.xml                          | 75 +++++++++++++++++++++++++++
 .circleci/config-2_1.yml                      | 18 +++++++
 .circleci/config.yml                          | 18 +++++++
 .circleci/generate.sh                         | 17 ++++++
 .circleci/readme.md                           | 20 +++++++
 .gitignore                                    |  5 ++
 .rat-excludes                                 | 33 ------------
 CONTRIBUTING.md                               | 20 +++++++
 TESTING.md                                    | 20 +++++++
 build-shaded-dtest-jar.sh                     | 17 ++++++
 build.xml                                     | 71 +------------------------
 conf/cassandra.yaml                           |  1 +
 doc/Dockerfile                                |  2 +-
 doc/README.md                                 | 20 +++++++
 doc/SASI.md                                   | 20 +++++++
 doc/cql3/CQL.textile                          | 19 +++++++
 doc/docker-compose.yml                        | 18 +++++++
 doc/make.bat                                  | 18 +++++++
 doc/native_protocol_v3.spec                   | 17 ++++++
 doc/native_protocol_v4.spec                   | 17 ++++++
 doc/native_protocol_v5.spec                   | 17 ++++++
 doc/source/development/index.rst              |  1 +
 doc/source/development/license_compliance.rst | 37 +++++++++++++
 doc/source/tools/stress-example.yaml          | 18 +++++++
 doc/source/tools/stress-lwt-example.yaml      | 18 +++++++
 pylib/cqlshlib/test/test_keyspace_init.cql    | 18 +++++++
 redhat/README.md                              | 20 +++++++
 redhat/cassandra.in.sh                        | 17 ++++++
 redhat/cassandra.spec                         | 18 +++++++
 relocate-dependencies.pom                     | 20 +++++++
 test/data/bloom-filter/ka/foo.cql             | 18 +++++++
 test/resources/blogpost.yaml                  | 18 +++++++
 test/resources/byteman/mutation_limiter.btm   | 20 ++++++-
 test/resources/byteman/stream_failure.btm     | 17 ++++++
 34 files changed, 599 insertions(+), 104 deletions(-)
 create mode 100644 .build/build-rat.xml
 delete mode 100644 .rat-excludes
 create mode 100644 doc/source/development/license_compliance.rst

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org


[cassandra] 01/01: Merge branch 'cassandra-3.11' into trunk

Posted by mc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mck pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 7337fc0ab42a14623c96f258c1dfd19beaab54b6
Merge: dbedf57 2ec96ae
Author: Mick Semb Wever <mc...@apache.org>
AuthorDate: Mon Apr 19 17:38:42 2021 +0200

    Merge branch 'cassandra-3.11' into trunk

 .build/build-rat.xml                          | 75 +++++++++++++++++++++++++++
 .circleci/config-2_1.yml                      | 18 +++++++
 .circleci/config.yml                          | 18 +++++++
 .circleci/generate.sh                         | 17 ++++++
 .circleci/readme.md                           | 20 +++++++
 .gitignore                                    |  5 ++
 .rat-excludes                                 | 33 ------------
 CONTRIBUTING.md                               | 20 +++++++
 TESTING.md                                    | 20 +++++++
 build-shaded-dtest-jar.sh                     | 17 ++++++
 build.xml                                     | 71 +------------------------
 conf/cassandra.yaml                           |  1 +
 doc/Dockerfile                                |  2 +-
 doc/README.md                                 | 20 +++++++
 doc/SASI.md                                   | 20 +++++++
 doc/cql3/CQL.textile                          | 19 +++++++
 doc/docker-compose.yml                        | 18 +++++++
 doc/make.bat                                  | 18 +++++++
 doc/native_protocol_v3.spec                   | 17 ++++++
 doc/native_protocol_v4.spec                   | 17 ++++++
 doc/native_protocol_v5.spec                   | 17 ++++++
 doc/source/development/index.rst              |  1 +
 doc/source/development/license_compliance.rst | 37 +++++++++++++
 doc/source/tools/stress-example.yaml          | 18 +++++++
 doc/source/tools/stress-lwt-example.yaml      | 18 +++++++
 pylib/cqlshlib/test/test_keyspace_init.cql    | 18 +++++++
 redhat/README.md                              | 20 +++++++
 redhat/cassandra.in.sh                        | 17 ++++++
 redhat/cassandra.spec                         | 18 +++++++
 relocate-dependencies.pom                     | 20 +++++++
 test/data/bloom-filter/ka/foo.cql             | 18 +++++++
 test/resources/blogpost.yaml                  | 18 +++++++
 test/resources/byteman/mutation_limiter.btm   | 20 ++++++-
 test/resources/byteman/stream_failure.btm     | 17 ++++++
 34 files changed, 599 insertions(+), 104 deletions(-)

diff --cc .build/build-rat.xml
index 0000000,2194686..363f6ec
mode 000000,100644..100644
--- a/.build/build-rat.xml
+++ b/.build/build-rat.xml
@@@ -1,0 -1,95 +1,75 @@@
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <!--
+ ~ 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
+ ~
+ ~    https://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.
+ -->
+ <project basedir="." name="apache-cassandra--rat-tasks"
 -         xmlns:artifact="antlib:org.apache.maven.artifact.ant"
 -         xmlns:rat="antlib:org.apache.rat.anttasks">
++     xmlns:rat="antlib:org.apache.rat.anttasks">
+ 
+     <!--
+       License audit tool
+     -->
+ 
+     <condition property="rat.enabled">
+         <available file=".gitignore" />
+     </condition>
+ 
 -    <target name="_rat_init" depends="maven-ant-tasks-init">
 -        <artifact:dependencies pathId="rat.classpath">
 -          <dependency groupId="org.apache.rat" artifactId="apache-rat-tasks" version="0.6" />
 -          <remoteRepository refid="central"/>
 -          <remoteRepository refid="apache"/>
 -        </artifact:dependencies>
++    <target name="_rat_init" depends="resolver-init">
+         <typedef uri="antlib:org.apache.rat.anttasks" classpathref="rat.classpath"/>
+     </target>
+ 
+     <target name="rat-check" depends="_rat_init" if="${rat.enabled}" description="License checks on source" >
+         <rat:report reportFile="${build.dir}/rat.txt">
+             <fileset dir="."
+                      includes="**/*.java,**/*.py,**/*.sh,**/.xml,**/*.spec,**/*.md,**/*.iml,**/*.bat,**/*.btm,**/*.cql,**/*.css,**/*.g,**/*.hmtl,**/*.jflex,**/*.jks,**/*.mod,**/*.name,**/*.pom,**/*.textile,**/*.yml,**/*.yaml"
+                      excludesfile=".gitignore">
+                      <!-- Config files with not much creativity -->
+                      <exclude name="**/metrics-reporter-config-sample.yaml"/>
+                      <exclude name="**/cassandra.yaml"/>
+                      <exclude name="**/cassandra-murmur.yaml"/>
+                      <exclude name="**/cassandra-seeds.yaml"/>
+                      <exclude name="**/test/conf/cassandra.yaml"/>
+                      <exclude name="**/test/conf/cassandra_encryption.yaml"/>
+                      <exclude name="**/test/conf/cdc.yaml"/>
+                      <exclude name="**/test/conf/commitlog_compression_LZ4.yaml"/>
+                      <exclude name="**/test/conf/commitlog_compression_Zstd.yaml"/>
+                      <exclude name="**/test/conf/system_keyspaces_directory.yaml"/>
+                      <exclude name="**/test/conf/unit-test-conf/test-native-port.yaml"/>
+                      <exclude name="**/test/data/jmxdump/cassandra-3.0-jmx.yaml"/>
+                      <exclude name="**/test/data/jmxdump/cassandra-3.11-jmx.yaml"/>
+                      <exclude name="**/test/data/jmxdump/cassandra-4.0-jmx.yaml"/>
+                      <exclude name="**/tools/cqlstress-counter-example.yaml"/>
+                      <exclude name="**/tools/cqlstress-example.yaml"/>
+                      <exclude name="**/tools/cqlstress-insanity-example.yaml"/>
+                      <exclude name="**/tools/cqlstress-lwt-example.yaml"/>
+                      <!-- NOTICE files -->
+                      <exclude NAME="**/NOTICE.md"/>
+                      <!-- LICENSE files -->
+                      <exclude NAME="**/LICENSE.md"/>
+             </fileset>
+         </rat:report>
+         <fail message="Some files have missing or incorrect license information. Check RAT report in ${build.dir}/rat.txt for more details!">
+             <condition>
+                 <and>
+                     <not>
+                         <resourcecontains resource="${build.dir}/rat.txt" substring="0 Unknown Licenses" casesensitive="false" />
+                     </not>
+                 </and>
+             </condition>
+         </fail>
+     </target>
 -
 -    <target name="_write_java_license_headers" depends="_rat_init">
 -      <java classname="org.apache.rat.Report" fork="true"
 -            output="${build.dir}/rat-report.log">
 -        <classpath refid="rat.classpath" />
 -        <arg value="-a" />
 -        <arg value="--force" />
 -        <arg value="interface/thrift" />
 -      </java>
 -    </target>
 -
 -    <target name="write-java-license-headers" unless="without.rat" description="Add missing java license headers">
 -      <antcall target="_write_java_license_headers" />
 -    </target>
+ </project>
diff --cc .gitignore
index 8754b17,4353d4f..cd668ae
--- a/.gitignore
+++ b/.gitignore
@@@ -8,8 -8,7 +8,9 @@@ logs
  data/
  conf/hotspot_compiler
  doc/cql3/CQL.html
+ doc/build/
 +lib/
 +!lib/cassandra-driver-internal-only-*.zip
  
  # C* debs
  build-stamp
@@@ -72,3 -80,7 +73,7 @@@ doc/source/tools/nodetoo
  
  # Python virtual environment
  venv/
+ 
 -# build-scripts will put cassandra-builds and cassandra-dtest into the directory
++# build-scripts will put cassandra-builds into the directory
+ cassandra-builds/
+ cassandra-dtest/
diff --cc TESTING.md
index b6e27aa,0000000..0f25743
mode 100644,000000..100644
--- a/TESTING.md
+++ b/TESTING.md
@@@ -1,448 -1,0 +1,468 @@@
++<!--
++#
++# 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.
++#
++-->
++
 +The goal of this document is to establish guidelines on writing tests that drive incremental improvement of the test coverage and testability of 
 +Cassandra, without overly burdening day to day work. While not every point here will be immediately practical to implement or relevant for every 
 +contribution, it errs on the side of not making rules out of potential exceptions. It provides guidelines on test scope, style, and goals, as
 +well as guidelines for dealing with global state and refactoring untested code.
 +
 +## What to Test
 +
 +There are 3 main types of tests in Cassandra, unit tests, integration tests, and dtests. Below, each type of test is described, and a high level description of 
 +what should and shouldn't be tested in each is given.
 +
 +### Unit Tests
 +JUnit tests of smaller components that are fairly narrow in scope (ie: data structures, verb handlers, helper classes)
 +
 +#### What should be tested
 + * All state transitions should be tested
 + * Illegal state transitions should be tested (that they throw exceptions)
 + * all conditional branches should be tested. 
 + * Code that deals with ranges of values should have tests around expected ranges, unexpected ranges, different functional ranges and their boundaries.
 + * Exception handling should be tested.
 +
 +#### What shouldn't be tested
 +* implementation details (test that the system under test works a certain way, not that it's implemented a certain way)
 +
 +### Integration Tests
 +JUnit tests of larger components with a lot of moving parts, usually involved in some internode communication (ie: Gossip, MessagingService).
 +The smaller components that make up the system under test in an integration test should be individually unit tested.
 +
 +#### What should be tested
 +* messages are sent when expected
 +* received messages have the intended side effects
 +* internal interfaces work as expected
 +* external interfaces are interacted with as expected
 +* multiple instances of components interact as expected (with a mocked messaging service, and other dependencies, where appropriate)
 +* dry start - test that a system starts up properly the first time a node start
 +* restart - test that a system starts up properly on node restart (from both clean and unclean shutdown)
 +* shutdown - test that a system can shutdown properly
 +* upgrade - test that a system is able to restart with data from a previous version
 +
 +#### What shouldn't be tested
 +* The rest of the application. It should be possible to test large systems without starting the entire database through the use of mocks.
 +
 +**Note:** it's generally not a good idea to mock out the storage layer if the component under test needs to interact with it. If you're testing
 +how multiple instances interact with each other, AND they need to use the storage layer, parameterizing the keyspace/table they store data is
 +the way to do it.
 +
 +### dtests
 +python/ccm tests that start local clusters and interact with them via the python client.
 +
 +dtests are effectively black box tests, and should be used for checking that clusters and client side interfaces work as expected. They are not 
 +a replacement for proper functional java tests. They take much longer to run, and are much less flexible in what they can test.
 +
 +Systems under test in dtest should have more granular integration tests as well.
 +
 +#### What should be tested
 +* end to end cluster functionality
 +* client contracts
 +* trivial (to create) failure cases
 +
 +#### What shouldn't be tested
 +* internal implementation details
 +
 +## Expanded Guidelines
 +
 +This section has more in depth descriptions and reasoning about some of the points raised in the previous section.
 +
 +### Test structure
 +
 +Tests cases should have a clear progression of setup, precondition check, performing some action under test, then a postcondition check.
 +
 +**Example**
 +
 +```java
 +@Test
 +public void increment() throws Exception
 +{
 +	// setup code
 +	int x = 1;
 +
 +	// check preconditions
 +	assertEquals(1, x);
 +
 +	// perform the state changing action under test
 +	x++;
 +
 +	// check post conditions
 +	assertEquals(2, x);
 +}
 +```
 +
 +#### Reason
 +
 +Test cases should be optimized for readability
 +
 +#### Exceptions
 +
 +Cases where simple cases can be tested in one line. Such as validation logic checks:
 +property-based state testing (ie: ScalaCheck/QuickCheck)
 +
 +*Example:*
 +```java
 +@Test
 +public void validation()
 +{
 +	assertValidationFailure(b -> b.withState(null));
 +	assertValidationFailure(b -> b.withSessionID(null));
 +	assertValidationFailure(b -> b.withCoordinator(null));
 +	assertValidationFailure(b -> b.withTableIds(null));
 +	assertValidationFailure(b -> b.withTableIds(new HashSet<>()));
 +	assertValidationFailure(b -> b.withRepairedAt(0));
 +	assertValidationFailure(b -> b.withRepairedAt(-1));
 +	assertValidationFailure(b -> b.withRanges(null));
 +	assertValidationFailure(b -> b.withRanges(new HashSet<>()));
 +	assertValidationFailure(b -> b.withParticipants(null));
 +	assertValidationFailure(b -> b.withParticipants(new HashSet<>()));
 +	assertValidationFailure(b -> b.withStartedAt(0));
 +	assertValidationFailure(b -> b.withLastUpdate(0));
 +}
 +```
 +
 +### Test distributed components in junit
 +
 +Components that rely on nodes communicating with each other should be testable in java. 
 +
 +#### Reason
 +
 +One of the more difficult aspects of distributed systems is ensuring that they continue to behave correctly during various failure modes.  This includes weird 
 +edge cases involving specific ordering of events between nodes that rarely occur in the wild. Testing these sorts of scenarios is much easier in junit because 
 +mock 'clusters' can be placed in specific states, and deterministically stepped through a sequence of events, ensuring that they behave as expected, and are in 
 +the expected state after each step.
 +
 +#### Exceptions
 +
 +This rule mainly applies to new or significantly overhauled systems. Older systems *should* be refactored to be thoroughly tested, but it's not necessarily a 
 +prerequisite for working on them.
 +
 +### Test all branches and inputs.
 +
 +All branches and inputs of a method should be exercised. For branches that require multiple criteria to be met, (ie `x > 10 && y < 100`), there
 +should be tests demonstrating that the branch is taken when all critera are met (ie `x=11,y=99`), and that it is not taken when only one is met 
 +(ie: `x=11, y=200 or x=5,y=99`). If a method deals with ranges of values, (ie `x >= 10`), the boundaries of the ranges should be tested (ie: `x=9, x=10`)
 +
 +In the following example
 +
 +**Example**
 +```java
 +class SomeClass
 +{
 +	public static int someFunction(bool aFlag, int aValue)
 +	{
 +		if (aFlag && aValue > 10)
 +		{
 +			return 20;
 +		}
 +		else if (aValue > 5)
 +		{
 +			return 10;
 +		else
 +		{
 +			return 0;
 +		}
 +	}
 +}
 +
 +class SomeTest
 +{
 +	public void someFunction() throws Exception
 +	{
 +		assertEquals(10, somefunction(true, 11));
 +		assertEquals(5, somefunction(false, 11));
 +		assertEquals(5, somefunction(true, 8));
 +		assertEquals(5, somefunction(false, 8));
 +		assertEquals(0, somefunction(false, 4));
 +	}
 +}
 +```
 +
 +### Test any state transitions
 +
 +As an extension of testing all branches and inputs. For stateful systems, there should be tests demonstrating that states change under the intended 
 +circumstances, and that state changes have the intended side effects.
 + 
 +### Test unsupported arguments and states throw exceptions
 +
 +If a system is not intended to perform an action in a given state (ie: a node performing reads during bootstrap), or a method is not intended
 +to encounter some type of argument (ie: a method that is only designed to work with numeric values > 0), then there should be tests demonstrating
 +that an appropriate exception is raised (IllegalStateException or IllegalArgumentException, respectively) in that case.
 +
 +The guava preconditions module makes this straightforward.
 +
 +#### Reason
 +
 +Inadvertent misuse of methods and systems cause bugs that are often silent and subtle. Raising exceptions on unintended usage helps
 +protect against future bugs and reduces developer surprise.
 +
 +## Dealing with global state
 +
 +Unfortunately, the project has extensive amounts of global state which makes actually writing robust tests difficult, but not impossible.
 +
 +Having dependencies on global state is not an excuse to not test something, or to throw a dtest or assertion at it and call it a day.
 +
 +Structuring code in a way that interacts with global state that can still be deterministically tested just takes a few tweaks
 +
 +**Example, bad**
 +```java
 +class SomeVerbHandler implements IVerbHandler<SomeMessage>
 +{
 +	public void doVerb(MessageIn<SomeMessage> msg)
 +	{
 +		if (FailureDetector.instance.isAlive(msg.payload.otherNode))
 +		{
 +			new StreamPlan(msg.payload.otherNode).requestRanges(someRanges).execute();
 +		}
 +		else
 +		{
 +			CompactionManager.instance.submitBackground(msg.payload.cfs);
 +		}
 +	}
 +}
 +```
 +
 +In this made up example, we're checking global state, and then taking some action against other global state. None of the global state
 +we're working with is easy to manipulate for tests, so comprehensive tests for this aren't very likely to be written. Even worse, whether
 +the FailureDetector, streaming, or compaction work properly are out of scope for our purposes. We're concerned with whether SomeVerbHandler
 +works as expected.
 +
 +Ideally though, classes won't have dependencies on global state at all, and have everything they need to work passed in as constructor arguments.
 +This also enables comprehensive testing, and stops the spread of global state. 
 +
 +This prevents the spread of global state, and also begins to identify and define the internal interfaces that will replace global state.
 +
 +**Example, better**
 +```java
 +class SomeVerbHandler implements IVerbHandler<SomeMessage>
 +{
 +	private final IFailureDetector failureDetector;
 +	private final ICompactionManager compactionManager;
 +	private final IStreamManager streamManager;
 +
 +	public SomeVerbHandler(IFailureDetector failureDetector, ICompactionManager compactionManager, IStreamManager streamManager)
 +	{
 +		this.failureDetector = failureDetector;
 +		this.compactionManager = compactionManager;
 +		this.streamManager = streamManager;
 +	}
 +
 +	public void doVerb(MessageIn<SomeMessage> msg)
 +	{
 +		if (failureDetector.isAlive(msg.payload.otherNode))
 +		{
 +			streamExecutor.submitPlan(new StreamPlan(msg.payload.otherNode).requestRanges(someRanges));
 +		}
 +		else
 +		{
 +			compactionManager.submitBackground(msg.payload.cfs);
 +		}
 +	}
 +}
 +```
 +
 +**Example test**
 +```java
 +class SomeVerbTest
 +{
 +	class InstrumentedFailureDetector implements IFailureDetector
 +	{
 +		boolean alive = false;
 +		@Override
 +		public boolean isAlive(InetAddress address)
 +		{
 +			return alive;
 +		}
 +	}
 +
 +	class InstrumentedCompactionManager implements ICompactionManager
 +	{
 +		boolean submitted = false;
 +		@Override
 +		public void submitBackground(ColumnFamilyStore cfs)
 +		{
 +			submitted = true;
 +		}
 +	}
 +
 +	class InstrumentedStreamManager implements IStreamManager
 +	{
 +		boolean submitted = false;
 +		@Override
 +		public void submitPlan(StreamPlan plan)
 +		{
 +			submitted = true;
 +		}
 +	}
 +
 +	@Test
 +	public void liveNode() throws Exception
 +	{
 +		InstrumentedFailureDetector failureDetector = new InstrumentedFailureDetector();
 +		failureDetector.alive = true;
 +		InstrumentedCompactionManager compactionManager = new InstrumentedCompactionManager();
 +		InstrumentedStreamManager streamManager = new InstrumentedStreamManager();
 +		SomeVerbHandler handler = new SomeVerbHandler(failureDetector, compactionManager, streamManager);
 +
 +		MessageIn<SomeMessage> msg = new MessageIn<>(...);
 +
 +		assertFalse(streamManager.submitted);
 +		assertFalse(compactionManager.submitted);
 +
 +		handler.doVerb(msg);
 +
 +		assertTrue(streamManager.submitted);
 +		assertFalse(compactionManager.submitted);
 +	}
 +
 +	@Test
 +	public void deadNode() throws Exception
 +	{
 +		InstrumentedFailureDetector failureDetector = new InstrumentedFailureDetector();
 +		failureDetector.alive = false;
 +		InstrumentedCompactionManager compactionManager = new InstrumentedCompactionManager();
 +		InstrumentedStreamManager streamManager = new InstrumentedStreamManager();
 +		SomeVerbHandler handler = new SomeVerbHandler(failureDetector, compactionManager, streamManager);
 +
 +		MessageIn<SomeMessage> msg = new MessageIn<>(...);
 +
 +		assertFalse(streamManager.submitted);
 +		assertFalse(compactionManager.submitted);
 +
 +		handler.doVerb(msg);
 +
 +		assertFalse(streamManager.submitted);
 +		assertTrue(compactionManager.submitted);
 +	}
 +}
 +```
 +
 +By abstracting away accesses to global state we can exhaustively test the paths this verb handler can take, and directly confirm that it's taking the correct 
 +actions. Obviously, this is a simple example, but for classes or functions with more complex logic, this makes comprehensive testing much easier.
 +
 +Note that the interfaces used here probably shouldn't be the same ones we use for MBeans.
 +
 +However, in some cases, passing interfaces into the constructor may not be practical. Classes that are instantiated on startup need to be handled with care, since accessing
 +a singleton may change the initialization order of the database. It may also be a larger change than is warranted for something like a bug fix. In any case, if passing
 +dependencies into the constructor is not practical, wrapping accesses to global state in protected methods that are overridden for tests will achieve the same thing.
 +
 +
 +**Example, alternative**
 +```javayy
 +class SomeVerbHandler implements IVerbHandler<SomeMessage>
 +{ 
 +	@VisibleForTesting
 +	protected boolean isAlive(InetAddress addr) { return FailureDetector.instance.isAlive(msg.payload.otherNode); }
 +
 +	@VisibleForTesting
 +	protected void streamSomethind(InetAddress to) { new StreamPlan(to).requestRanges(someRanges).execute(); }
 +
 +	@VisibleForTesting
 +	protected void compactSomething(ColumnFamilyStore cfs ) { CompactionManager.instance.submitBackground(); }
 +
 +	public void doVerb(MessageIn<SomeMessage> msg)
 +	{
 +		if (isAlive(msg.payload.otherNode))
 +		{
 +			streamSomething(msg.payload.otherNode);
 +		}
 +		else
 +		{
 +			compactSomething();
 +		}
 +	}
 +}
 +```
 +
 +**Example test**
 +```java
 +class SomeVerbTest
 +{
 +	static class InstrumentedSomeVerbHandler extends SomeVerbHandler
 +	{
 +		public boolean alive = false;
 +		public boolean streamCalled = false;
 +		public boolean compactCalled = false;
 +
 +		@Override
 +		protected boolean isAlive(InetAddress addr) { return alive; }
 +		
 +		@Override
 +		protected void streamSomethind(InetAddress to) { streamCalled = true; }
 +
 +		@Override
 +		protected void compactSomething(ColumnFamilyStore cfs ) { compactCalled = true; }
 +	}
 +
 +	@Test
 +	public void liveNode() throws Exception
 +	{
 +		InstrumentedSomeVerbHandler handler = new InstrumentedSomeVerbHandler();
 +		handler.alive = true;
 +		MessageIn<SomeMessage> msg = new MessageIn<>(...);
 +
 +		assertFalse(handler.streamCalled);
 +		assertFalse(handler.compactCalled);
 +
 +		handler.doVerb(msg);
 +
 +		assertTrue(handler.streamCalled);
 +		assertFalse(handler.compactCalled);
 +	}
 +
 +	@Test
 +	public void deadNode() throws Exception
 +	{
 +		InstrumentedSomeVerbHandler handler = new InstrumentedSomeVerbHandler();
 +		handler.alive = false;
 +		MessageIn<SomeMessage> msg = new MessageIn<>(...);
 +
 +		assertFalse(handler.streamCalled);
 +		assertFalse(handler.compactCalled);
 +
 +		handler.doVerb(msg);
 +
 +		assertFalse(handler.streamCalled);
 +		assertTrue(handler.compactCalled);
 +	}
 +}
 +```
 +
 +## Refactoring Existing Code
 +
 +If you're working on a section of the project that historically hasn't been well tested, it will likely be more difficult for you to write tests around
 +whatever you're doing, since the code may not have been written with testing in mind. You do need to add tests around the subject of you're 
 +jira, and this will probably involve some refactoring, but you're also not expected to completely refactor a huge class to submit a bugfix. 
 +
 +Basically, you need to be able to verify the behavior you intend to modify before and after your patch. The amount of testing debt you pay back should be 
 +roughly proportional to the scope of your change. If you're doing a small bugfix, you can get away with refactoring just enough to make the subject of your 
 +fix testable, even if you start to get into 'testing implementation details' territory'. The goal is incremental improvement, not making things perfect on 
 +the first iteration. If you're doing something more ambitious though, you may have to do some extra work to sufficiently test your changes.
 +
 +## Refactoring Untested Code
 +
 +There are several components that have very little, if any, direct test coverage. We really should try to improve the test coverage of these components.
 +For people interested in getting involved with the project, adding tests for these is a great way to get familiar with the codebase.
 +
 +First, get feedback on the subject and scope of your proposed refactor, especially larger ones. The smaller and more narrowly focused your proposed 
 +refactor is, the easier it will be for you to get it reviewed and committed.
 +
 +Start with smaller pieces, refactor and test them, and work outwards, iteratively. Preferably in several jiras. Ideally, each patch should add some value
 +to the project on it's own in terms of test coverage. Patches that are heavy on refactoring, and light on tests are not likely to get committed. People come and go
 +from projects, and having a many small improvements is better for the project than several unfinished or ongoing refactors that don't add much test coverage.
diff --cc build-shaded-dtest-jar.sh
index b35ec47,0000000..72f0d68
mode 100755,000000..100755
--- a/build-shaded-dtest-jar.sh
+++ b/build-shaded-dtest-jar.sh
@@@ -1,40 -1,0 +1,57 @@@
 +#!/bin/bash
++#
++# 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.
++#
 +
 +set -xe
 +
 +ARTIFACT_NAME=cassandra-dtest
 +REPO_DIR=~/.m2/repository
 +CASSANDRA_VERSION=$(cat build.xml | grep 'property name="base.version"' | awk -F "\"" '{print $4}')
 +DTEST_VERSION=$(cat relocate-dependencies.pom | grep "dtest-local.version>" | awk -F "\>|\<" '{print $3}')
 +SHADED_DTEST_VERSION=$(cat relocate-dependencies.pom | grep -m 1 "<version>" | awk -F "\>|\<" '{print $3}')
 +
 +echo $CASSANDRA_VERSION
 +echo $DTEST_VERSION
 +
 +ant clean
 +ant dtest-jar
 +
 +# Install the version that will be shaded
 +mvn install:install-file               \
 +   -Dfile=./build/dtest-${CASSANDRA_VERSION}.jar \
 +   -DgroupId=org.apache.cassandra      \
 +   -DartifactId=${ARTIFACT_NAME}-local \
 +   -Dversion=${DTEST_VERSION}          \
 +   -Dpackaging=jar                     \
 +   -DgeneratePom=true                  \
 +   -DlocalRepositoryPath=${REPO_DIR}
 +
 +# Create shaded artifact
 +mvn -f relocate-dependencies.pom package -DskipTests -nsu
 +
 +# Deploy shaded artifact
 +mvn install:install-file                 \
 +   -Dfile=./target/${ARTIFACT_NAME}-shaded-${SHADED_DTEST_VERSION}.jar \
 +   -DgroupId=org.apache.cassandra        \
 +   -DartifactId=${ARTIFACT_NAME}-shaded  \
 +   -Dversion=${DTEST_VERSION}            \
 +   -Dpackaging=jar                       \
 +   -DgeneratePom=true                    \
 +   -DlocalRepositoryPath=${REPO_DIR}
 +
 +set +xe
diff --cc build.xml
index 2fddbb0,0f2f425..2b0a345
--- a/build.xml
+++ b/build.xml
@@@ -880,18 -857,9 +880,18 @@@
              <src path="${build.src.java}"/>
              <src path="${build.src.gen-java}"/>
              <compilerarg value="-XDignore.symbol.file"/>
 -            <compilerarg value="-Xbootclasspath/p:${build.src.jdkoverride}"/>
 -            <classpath refid="cassandra.classpath"/>
 +            <compilerarg line="${jdk11-javac-exports}"/>
 +            <classpath>
 +                <path refid="cassandra.classpath"/>
 +            </classpath>
          </javac>
 +    </target>
 +
-     <target depends="init,gen-cql3-grammar,generate-cql-html,generate-jflex-java,rat-report"
++    <target depends="init,gen-cql3-grammar,generate-cql-html,generate-jflex-java,rat-check"
 +            name="build-project">
 +        <echo message="${ant.project.name}: ${ant.file}"/>
 +        <!-- Order matters! -->
 +        <antcall target="_build_java"/>
          <antcall target="createVersionPropFile"/>
          <copy todir="${build.classes.main}">
              <fileset dir="${build.src.resources}" />
@@@ -1216,44 -1182,7 +1216,7 @@@
        </checksum>
      </target>
  
-     <target name="rat" depends="rat-init" description="License checks on artifacts">
-       <rat:report xmlns:rat="antlib:org.apache.rat.anttasks"
-                   reportFile="${build.dir}/${final.name}-bin.rat.txt">
-         <tarfileset>
-           <gzipresource>
-             <file file="${build.dir}/${final.name}-bin.tar.gz" />
-           </gzipresource>
-         </tarfileset>
-       </rat:report>
-       <rat:report xmlns:rat="antlib:org.apache.rat.anttasks"
-                   reportFile="${build.dir}/${final.name}-src.rat.txt">
-         <tarfileset>
-           <gzipresource>
-             <file file="${build.dir}/${final.name}-src.tar.gz" />
-           </gzipresource>
-         </tarfileset>
-       </rat:report>
-     </target>
- 
-     <target name="rat-report" depends="rat-init" description="License checks on source" >
-       <rat:report xmlns:rat="antlib:org.apache.rat.anttasks"
-                   reportFile="${build.dir}/src.rat.txt">
-         <fileset dir="src/java"/>
-         <fileset dir="test/unit"/>
-         <fileset dir="test/distributed"/>
-       </rat:report>
-       <fail message="Some files have missing or incorrect license information. Check RAT report in ${build.dir}/src.rat.txt for more details!">
-         <condition>
-           <and>
-             <not>
-               <resourcecontains resource="${build.dir}/src.rat.txt" substring="0 Unknown Licenses" casesensitive="false" />
-             </not>
-           </and>
-         </condition>
-       </fail>
-     </target>
- 
 -  <target name="build-jmh" depends="build-test" description="Create JMH uber jar">
 +  <target name="build-jmh" depends="build-test, jar" description="Create JMH uber jar">
        <jar jarfile="${build.test.dir}/deps.jar">
            <zipgroupfileset dir="${build.dir.lib}/jars">
                <include name="*jmh*.jar"/>
@@@ -1758,43 -1623,15 +1721,12 @@@
      <delete dir="${jacoco.export.dir}"/>
    </target>
  
-   <!--
-     License audit tool
-   -->
-   <target name="rat-init" depends="resolver-init">
-     <typedef uri="antlib:org.apache.rat.anttasks" classpathref="rat.classpath"/>
-   </target>
- 
-   <target name="rat-check" depends="rat-init">
-     <rat:report xmlns:rat="antlib:org.apache.rat.anttasks"
-                 reportFile="${build.dir}/rat-report.log">
-       <fileset dir="."  excludesfile=".rat-excludes" />
-     </rat:report>
-     <condition property="rat.passed">
-       <isfileselected file="${build.dir}/rat-report.log">
-         <containsregexp expression="^0 Unknown Licenses"/>
-       </isfileselected>
-     </condition>
-     <fail unless="rat.passed">Unknown licenses: See build/rat-report.log.</fail>
-   </target>
- 
-   <target name="rat-write" depends="rat-init">
-     <echo>RAT: invoking addLicense to write missing headers</echo>
-     <java classname="org.apache.rat.Report" fork="true"
-           output="${build.dir}/rat-report.log">
-       <classpath refid="rat.classpath" />
-       <arg value="-a" />
-       <arg value="--force" />
-       <arg value="." />
-     </java>
-   </target>
- 
 -  <target name="javadoc" depends="init" description="Create javadoc" unless="no-javadoc">
 +  <target name="javadoc" depends="build" description="Create javadoc" unless="no-javadoc">
      <create-javadoc destdir="${javadoc.dir}">
        <filesets>
 -      <fileset dir="${build.src.java}" defaultexcludes="yes">
 -        <include name="org/apache/**/*.java"/>
 -      </fileset>
 -      <fileset dir="${interface.thrift.gen-java}" defaultexcludes="yes">
 -        <include name="org/apache/**/*.java"/>
 -      </fileset>
 +        <fileset dir="${build.src.java}" defaultexcludes="yes">
 +          <include name="org/apache/**/*.java"/>
 +        </fileset>
        </filesets>
      </create-javadoc>
     </target>
@@@ -2207,5 -2018,5 +2139,6 @@@
  
    </target>
  
 +  <import file="${basedir}/.build/build-resolver.xml"/>
+   <import file="${basedir}/.build/build-rat.xml"/>
  </project>
diff --cc doc/Dockerfile
index fcb4c41,0000000..ed60904
mode 100644,000000..100644
--- a/doc/Dockerfile
+++ b/doc/Dockerfile
@@@ -1,22 -1,0 +1,22 @@@
 +# Dockerfile for building the Cassandra documentation.
 +# If wanting to regenerate the documentation from scratch,
 +# run `ant realclean` from the root directory of this project.
 +
 +FROM python:2.7
 +
 +WORKDIR /usr/src/code
 +
 +RUN pip install --no-cache-dir sphinx sphinx_rtd_theme
 +
 +RUN apt-get update && apt-get install -y software-properties-common
 +
 +RUN wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add - \
 +    && add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/ \
 +    && apt-get update \
 +    && apt-get install -y adoptopenjdk-11-hotspot ant
 +
 +
 +RUN apt-get clean
 +
- CMD CASSANDRA_USE_JDK11=true ant gen-doc \
++CMD CASSANDRA_USE_JDK11=true ant realclean gen-doc \
 +    && echo "The locally built documentation can be found here:\n\n    build/html/index.html\n\n"
diff --cc doc/docker-compose.yml
index 392f8d8,0000000..b1477b6
mode 100644,000000..100644
--- a/doc/docker-compose.yml
+++ b/doc/docker-compose.yml
@@@ -1,11 -1,0 +1,29 @@@
++#
++# 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.
++#
++
 +# docker-compose.yml for building the Cassandra documentation.
 +
 +version: '2.0'
 +
 +services:
 +  build-docs:
 +    build: .
 +    volumes:
 +      - ..:/usr/src/code
 +    environment:
 +      - SKIP_NODETOOL # set this to skip nodetool build, saves a lot of time when debugging html
diff --cc doc/source/development/index.rst
index ffa7134,be3d254..e4f4402
--- a/doc/source/development/index.rst
+++ b/doc/source/development/index.rst
@@@ -25,9 -24,6 +25,10 @@@ Contributing to Cassandr
     testing
     patches
     code_style
+    license_compliance
     how_to_review
     how_to_commit
 +   documentation
 +   ci
 +   dependencies
 +   release_process
diff --cc doc/source/tools/stress-example.yaml
index 17161af,0000000..4a67102
mode 100644,000000..100644
--- a/doc/source/tools/stress-example.yaml
+++ b/doc/source/tools/stress-example.yaml
@@@ -1,44 -1,0 +1,62 @@@
++#
++# 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.
++#
++
 +spacenam: example # idenitifier for this spec if running with multiple yaml files
 +keyspace: example
 +
 +# Would almost always be network topology unless running something locally
 +keyspace_definition: |
 +  CREATE KEYSPACE example WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
 +
 +table: staff_activities
 +
 +# The table under test. Start with a partition per staff member
 +# Is this a good idea?
 +table_definition: |
 +  CREATE TABLE staff_activities (
 +        name text,
 +        when timeuuid,
 +        what text,
 +        PRIMARY KEY(name, when)
 +  ) 
 +
 +columnspec:
 +  - name: name
 +    size: uniform(5..10) # The names of the staff members are between 5-10 characters
 +    population: uniform(1..10) # 10 possible staff members to pick from 
 +  - name: when
 +    cluster: uniform(20..500) # Staff members do between 20 and 500 events
 +  - name: what
 +    size: normal(10..100,50)
 +
 +insert:
 +  # we only update a single partition in any given insert 
 +  partitions: fixed(1) 
 +  # we want to insert a single row per partition and we have between 20 and 500
 +  # rows per partition
 +  select: fixed(1)/500 
 +  batchtype: UNLOGGED             # Single partition unlogged batches are essentially noops
 +
 +queries:
 +   events:
 +      cql: select *  from staff_activities where name = ?
 +      fields: samerow
 +   latest_event:
 +      cql: select * from staff_activities where name = ?  LIMIT 1
 +      fields: samerow
 +
diff --cc doc/source/tools/stress-lwt-example.yaml
index fc5db08,0000000..1f12c24
mode 100644,000000..100644
--- a/doc/source/tools/stress-lwt-example.yaml
+++ b/doc/source/tools/stress-lwt-example.yaml
@@@ -1,70 -1,0 +1,88 @@@
++#
++# 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.
++#
++
 +# Keyspace Name
 +keyspace: stresscql
 +
 +# The CQL for creating a keyspace (optional if it already exists)
 +# Would almost always be network topology unless running something locall
 +keyspace_definition: |
 +  CREATE KEYSPACE stresscql WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
 +
 +# Table name
 +table: blogposts
 +
 +# The CQL for creating a table you wish to stress (optional if it already exists)
 +table_definition: |
 +  CREATE TABLE blogposts (
 +        domain text,
 +        published_date timeuuid,
 +        url text,
 +        author text,
 +        title text,
 +        body text,
 +        PRIMARY KEY(domain, published_date)
 +  ) WITH CLUSTERING ORDER BY (published_date DESC) 
 +    AND compaction = { 'class':'LeveledCompactionStrategy' } 
 +    AND comment='A table to hold blog posts'
 +
 +### Column Distribution Specifications ###
 + 
 +columnspec:
 +  - name: domain
 +    size: gaussian(5..100)       #domain names are relatively short
 +    population: uniform(1..10M)  #10M possible domains to pick from
 +
 +  - name: published_date
 +    cluster: fixed(1000)         #under each domain we will have max 1000 posts
 +
 +  - name: url
 +    size: uniform(30..300)       
 +
 +  - name: title                  #titles shouldn't go beyond 200 chars
 +    size: gaussian(10..200)
 +
 +  - name: author
 +    size: uniform(5..20)         #author names should be short
 +
 +  - name: body
 +    size: gaussian(100..5000)    #the body of the blog post can be long
 +   
 +### Batch Ratio Distribution Specifications ###
 +
 +insert:
 +  partitions: fixed(1)            # Our partition key is the domain so only insert one per batch
 +
 +  select:    fixed(1)/1000        # We have 1000 posts per domain so 1/1000 will allow 1 post per batch
 +
 +  batchtype: UNLOGGED             # Unlogged batches
 +
 +
 +#
 +# A list of queries you wish to run against the schema
 +#
 +queries:
 +   singlepost:
 +      cql: select * from blogposts where domain = ? LIMIT 1
 +      fields: samerow
 +   regularupdate:
 +      cql: update blogposts set author = ? where domain = ? and published_date = ?
 +      fields: samerow
 +   updatewithlwt:
 +      cql: update blogposts set author = ? where domain = ? and published_date = ? IF body = ? AND url = ?
 +      fields: samerow
diff --cc relocate-dependencies.pom
index d6b4265,0000000..07728dd
mode 100644,000000..100644
--- a/relocate-dependencies.pom
+++ b/relocate-dependencies.pom
@@@ -1,133 -1,0 +1,153 @@@
++<!--
++#
++# 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.
++#
++-->
++
 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 +         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 +    <modelVersion>4.0.0</modelVersion>
 +
 +    <groupId>org.apache.cassandra</groupId>
 +    <artifactId>cassandra-dtest-shaded</artifactId>
 +    <version>4.0.1-SNAPSHOT</version>
 +    <packaging>jar</packaging>
 +
 +    <name>Cassandra in-jvm dtests shaded jar</name>
 +
 +    <properties>
 +        <project.type>library</project.type>
 +        <java.version>1.8</java.version>
 +        <test.source.directory>src/test/unit/java</test.source.directory>
 +        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 +        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 +
 +        <junit.version>4.12</junit.version>
 +        <maven.compiler.source>${java.version}</maven.compiler.source>
 +        <maven.compiler.target>${java.version}</maven.compiler.target>
 +        <dtest-local.version>4.0.0-SNAPSHOT</dtest-local.version>
 +    </properties>
 +
 +    <dependencies>
 +
 +        <dependency>
 +            <groupId>org.apache.cassandra</groupId>
 +            <artifactId>cassandra-dtest-local</artifactId>
 +            <version>${dtest-local.version}</version>
 +        </dependency>
 +
 +        <dependency>
 +            <groupId>junit</groupId>
 +            <artifactId>junit</artifactId>
 +            <version>${junit.version}</version>
 +            <scope>test</scope>
 +        </dependency>
 +
 +    </dependencies>
 +
 +    <build>
 +        <testSourceDirectory>${test.source.directory}</testSourceDirectory>
 +
 +        <plugins>
 +            <!-- generate a shaded JAR -->
 +            <plugin>
 +                <groupId>org.apache.maven.plugins</groupId>
 +                <artifactId>maven-shade-plugin</artifactId>
 +                <version>3.2.1</version>
 +
 +                <configuration>
 +                    <createSourcesJar>false</createSourcesJar>
 +
 +                    <artifactSet>
 +                        <includes>
 +                            <include>org.apache.cassandra:cassandra-dtest-local</include>
 +                        </includes>
 +                    </artifactSet>
 +
 +                    <relocations>
 +                        <relocation>
 +                            <pattern>io.netty</pattern>
 +                            <shadedPattern>relocated.shaded.io.netty</shadedPattern>
 +                        </relocation>
 +
 +                        <relocation>
 +                            <pattern>com.google</pattern>
 +                            <shadedPattern>relocated.shaded.com.google</shadedPattern>
 +                        </relocation>
 +
 +                        <relocation>
 +                            <pattern>com.datastax</pattern>
 +                            <shadedPattern>relocated.shaded.com.datastax</shadedPattern>
 +                        </relocation>
 +                    </relocations>
 +
 +                    <filters>
 +                        <filter>
 +                            <artifact>*:*</artifact>
 +                            <excludes>
 +                                <exclude>**/Log4j2Plugins.dat</exclude>
 +                            </excludes>
 +                        </filter>
 +
 +                        <filter>
 +                            <artifact>io.netty:netty-*</artifact>
 +                            <excludes>
 +                                <exclude>META-INF/maven/</exclude>
 +                                <exclude>META-INF/io.netty.versions.properties</exclude>
 +                            </excludes>
 +                        </filter>
 +
 +                        <filter>
 +                            <artifact>com.google.guava:guava</artifact>
 +                            <excludes>
 +                                <exclude>META-INF/maven/</exclude>
 +                            </excludes>
 +                        </filter>
 +
 +                        <filter>
 +                            <artifact>com.google.guava:failureaccess</artifact>
 +                            <excludes>
 +                                <exclude>META-INF/maven/</exclude>
 +                            </excludes>
 +                        </filter>
 +
 +                        <filter>
 +                            <artifact>com.datastax.cassandra:cassandra-driver-core</artifact>
 +                            <excludes>
 +                                <exclude>META-INF/maven/</exclude>
 +                            </excludes>
 +                        </filter>
 +
 +                    </filters>
 +                </configuration>
 +
 +                <executions>
 +                    <execution>
 +                        <phase>package</phase>
 +                        <goals>
 +                            <goal>shade</goal>
 +                        </goals>
 +                        <configuration>
 +
 +                        </configuration>
 +                    </execution>
 +                </executions>
 +
 +            </plugin>
 +        </plugins>
 +    </build>
 +</project>

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org