NPE on Directory in ShortPaxosSimulationTest

Patch by Alex Petrov, reviewed by Caleb Rackliffe and Marcus Eriksson for CASSANDRA-19794
diff --git a/src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java b/src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java
index 6a90aa1..400553c 100644
--- a/src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java
+++ b/src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java
@@ -106,13 +106,13 @@
                 rf.put(e.getKey(), ReplicationFactor.fullOnly(e.getValue()));
             }
 
-            Directory directory = metadata.directory;
+            Directory tmpDirectory = metadata.directory;
             TokenMap tokenMap = metadata.tokenMap;
             for (NodeId peerId : metadata.directory.peerIds())
             {
                 if (!filter.apply(metadata, peerId))
                 {
-                    directory = directory.without(peerId);
+                    tmpDirectory = tmpDirectory.without(peerId);
                     tokenMap = tokenMap.unassignTokens(peerId);
                 }
             }
@@ -123,7 +123,7 @@
             Token minToken = DatabaseDescriptor.getPartitioner().getMinimumToken();
             EndpointsForRange endpoints = NetworkTopologyStrategy.calculateNaturalReplicas(minToken,
                                                                                            new Range<>(minToken, minToken),
-                                                                                           directory,
+                                                                                           tmpDirectory,
                                                                                            tokenMap,
                                                                                            rf);
 
diff --git a/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java b/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java
index 7daee23..0367640 100644
--- a/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java
+++ b/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java
@@ -215,6 +215,9 @@
 
     public static Diff diff(Set<NodeId> currentCms, Set<NodeId> newCms)
     {
+        assert !currentCms.contains(null) : "Current CMS contains a null value " + currentCms;
+        assert !newCms.contains(null) : "New CMS contains a null value " + newCms;
+
         List<NodeId> additions = new ArrayList<>();
         for (NodeId node : newCms)
         {
diff --git a/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterLeave.java b/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterLeave.java
index 9e77b55..2b2ce15 100644
--- a/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterLeave.java
+++ b/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterLeave.java
@@ -30,9 +30,11 @@
 import org.apache.cassandra.tcm.MultiStepOperation;
 import org.apache.cassandra.tcm.Transformation;
 import org.apache.cassandra.tcm.sequences.LeaveStreams;
+import org.apache.cassandra.tcm.sequences.ReconfigureCMS;
 import org.apache.cassandra.tcm.sequences.UnbootstrapAndLeave;
 import org.apache.cassandra.tcm.transformations.PrepareLeave;
 
+import static org.apache.cassandra.utils.FBUtilities.getBroadcastAddressAndPort;
 import static org.apache.cassandra.utils.LazyToString.lazy;
 
 class OnClusterLeave extends OnClusterChangeTopology
@@ -83,6 +85,9 @@
         {
             super("Prepare Leave", actions, on, () -> {
                 ClusterMetadata metadata = ClusterMetadata.current();
+                ReconfigureCMS.maybeReconfigureCMS(metadata, getBroadcastAddressAndPort());
+
+                metadata = ClusterMetadata.current();
                 ClusterMetadataService.instance().commit(new PrepareLeave(metadata.myNodeId(),
                                                                           false,
                                                                           ClusterMetadataService.instance().placementProvider(),
@@ -114,4 +119,4 @@
             });
         }
     }
-}
+}
\ No newline at end of file
diff --git a/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterReplace.java b/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterReplace.java
index d3f5d86..19204e4 100644
--- a/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterReplace.java
+++ b/test/simulator/main/org/apache/cassandra/simulator/cluster/OnClusterReplace.java
@@ -40,6 +40,7 @@
 import org.apache.cassandra.tcm.Transformation;
 import org.apache.cassandra.tcm.membership.NodeId;
 import org.apache.cassandra.tcm.sequences.BootstrapAndReplace;
+import org.apache.cassandra.tcm.sequences.ReconfigureCMS;
 import org.apache.cassandra.tcm.transformations.PrepareReplace;
 
 import static org.apache.cassandra.simulator.Action.Modifiers.NONE;
@@ -132,7 +133,11 @@
         {
             super("Prepare Replace", actions, joining, () -> {
                 ClusterMetadata metadata = ClusterMetadata.current();
-                ClusterMetadataService.instance().commit(new PrepareReplace(new NodeId(leavingNodeId),
+                NodeId leaving = new NodeId(leavingNodeId);
+                ReconfigureCMS.maybeReconfigureCMS(metadata, metadata.directory.endpoint(leaving));
+
+                metadata = ClusterMetadata.current();
+                ClusterMetadataService.instance().commit(new PrepareReplace(leaving,
                                                                             metadata.myNodeId(),
                                                                             ClusterMetadataService.instance().placementProvider(),
                                                                             true,