mansikhara commented on code in PR #238:
URL: 
https://github.com/apache/cassandra-analytics/pull/238#discussion_r4086142246


##########
cassandra-analytics-common/src/test/java/org/apache/cassandra/spark/data/ReplicationFactorTests.java:
##########
@@ -111,4 +118,357 @@ public void testEquality()
         assertThat(replicationFactor1).isEqualTo(replicationFactor2);
         
assertThat(replicationFactor1.hashCode()).isEqualTo(replicationFactor2.hashCode());
     }
+
+    // Transient / witness replicas: the <replicas>/<transient> form, reused 
by witness replicas under
+    // mutation tracking (CEP-45/CEP-46)
+
+    @Test
+    public void testNoTransientReplicasByDefault()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3"));
+        assertThat(replicationFactor.hasTransientReplicas()).isFalse();
+        assertThat(replicationFactor.getTransientOptions()).isEmpty();
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(3);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(0);
+        
assertThat(replicationFactor.getFullReplicas("datacenter1")).isEqualTo(3);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(0);
+    }
+
+    @Test
+    public void testTransientReplicasSingleDatacenter()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThat(replicationFactor.hasTransientReplicas()).isTrue();
+        // total keeps its original meaning: all replicas, witnesses included
+        
assertThat(replicationFactor.getOptions().get("datacenter1")).isEqualTo(Integer.valueOf(3));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(1);
+        
assertThat(replicationFactor.getFullReplicas("datacenter1")).isEqualTo(2);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(1);
+    }
+
+    @Test
+    public void testTransientReplicasMultipleDatacenters()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1",
+        "datacenter2", "3/1"));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(6);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(4);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testMixedTransientAndFullDatacenters()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1",
+        "datacenter2", "3"));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(6);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(5);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(1);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter2")).isEqualTo(0);
+        
assertThat(replicationFactor.getFullReplicas("datacenter2")).isEqualTo(3);
+        // datacenter2 has no transient replicas, so it must be absent rather 
than mapped to zero
+        
assertThat(replicationFactor.getTransientOptions()).containsOnlyKeys("datacenter1");
+    }
+
+    @Test
+    public void testTransientReplicasSimpleStrategy()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "SimpleStrategy",
+        "replication_factor", "3/1"));
+        assertThat(replicationFactor.getReplicationStrategy())
+        .isEqualTo(ReplicationFactor.ReplicationStrategy.SimpleStrategy);
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testTransientReplicasWithWhitespace()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", " 3 / 1 "));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testTransientEqualToTotalIsRejected()
+    {
+        // Cassandra requires at least one full replica, so 3/3 is invalid and 
must not be accepted silently
+        assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/3")))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("datacenter1");
+    }
+
+    @Test
+    public void testMalformedReplicationValuesAreRejected()
+    {
+        for (String malformed : new String[]{"3/", "/1", "3/1/1", "3/x", 
"x/1", "3/-1", ""})
+        {
+            assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+            "class", "NetworkTopologyStrategy",
+            "datacenter1", malformed)))
+            .as("malformed replication value '%s' should be rejected", 
malformed)
+            .isInstanceOf(IllegalArgumentException.class);
+        }
+    }
+
+    @Test
+    public void testGetFullReplicasUnknownDatacenter()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThatThrownBy(() -> replicationFactor.getFullReplicas("nosuchdc"))
+        .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void testTransientOptionsForUnknownDatacenterRejected()
+    {
+        assertThatThrownBy(() -> new ReplicationFactor(
+        ReplicationFactor.ReplicationStrategy.NetworkTopologyStrategy,
+        ImmutableMap.of("datacenter1", 3),
+        ImmutableMap.of("datacenter2", 1)))
+        .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void testEqualityConsidersTransientReplicas()
+    {
+        ReplicationFactor full = new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3"));
+        ReplicationFactor withTransient = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThat(full).isNotEqualTo(withTransient);
+        assertThat(full.hashCode()).isNotEqualTo(withTransient.hashCode());
+    }
+
+    @Test
+    public void testNegativeReplicationFactorIsRejected()
+    {
+        assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "-3")))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("datacenter1");
+    }
+
+    @Test
+    public void testZeroReplicationFactorIsAllowed()
+    {
+        // RF 0 is legitimate for NetworkTopologyStrategy: the keyspace is 
simply not replicated to that datacenter
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3",
+        "datacenter2", "0"));
+        
assertThat(replicationFactor.getOptions().get("datacenter2")).isEqualTo(Integer.valueOf(0));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+    }
+
+    @Test
+    public void testKryoSerializationRoundTripWithTransientReplicas() throws 
Exception

Review Comment:
   Merged, thanks!



##########
cassandra-analytics-common/src/test/java/org/apache/cassandra/spark/data/ReplicationFactorTests.java:
##########
@@ -111,4 +118,357 @@ public void testEquality()
         assertThat(replicationFactor1).isEqualTo(replicationFactor2);
         
assertThat(replicationFactor1.hashCode()).isEqualTo(replicationFactor2.hashCode());
     }
+
+    // Transient / witness replicas: the <replicas>/<transient> form, reused 
by witness replicas under
+    // mutation tracking (CEP-45/CEP-46)
+
+    @Test
+    public void testNoTransientReplicasByDefault()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3"));
+        assertThat(replicationFactor.hasTransientReplicas()).isFalse();
+        assertThat(replicationFactor.getTransientOptions()).isEmpty();
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(3);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(0);
+        
assertThat(replicationFactor.getFullReplicas("datacenter1")).isEqualTo(3);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(0);
+    }
+
+    @Test
+    public void testTransientReplicasSingleDatacenter()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThat(replicationFactor.hasTransientReplicas()).isTrue();
+        // total keeps its original meaning: all replicas, witnesses included
+        
assertThat(replicationFactor.getOptions().get("datacenter1")).isEqualTo(Integer.valueOf(3));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(1);
+        
assertThat(replicationFactor.getFullReplicas("datacenter1")).isEqualTo(2);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(1);
+    }
+
+    @Test
+    public void testTransientReplicasMultipleDatacenters()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1",
+        "datacenter2", "3/1"));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(6);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(4);
+        
assertThat(replicationFactor.getTransientReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testMixedTransientAndFullDatacenters()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1",
+        "datacenter2", "3"));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(6);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(5);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter1")).isEqualTo(1);
+        
assertThat(replicationFactor.getTransientReplicas("datacenter2")).isEqualTo(0);
+        
assertThat(replicationFactor.getFullReplicas("datacenter2")).isEqualTo(3);
+        // datacenter2 has no transient replicas, so it must be absent rather 
than mapped to zero
+        
assertThat(replicationFactor.getTransientOptions()).containsOnlyKeys("datacenter1");
+    }
+
+    @Test
+    public void testTransientReplicasSimpleStrategy()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "SimpleStrategy",
+        "replication_factor", "3/1"));
+        assertThat(replicationFactor.getReplicationStrategy())
+        .isEqualTo(ReplicationFactor.ReplicationStrategy.SimpleStrategy);
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testTransientReplicasWithWhitespace()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", " 3 / 1 "));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+        assertThat(replicationFactor.getFullReplicationFactor()).isEqualTo(2);
+    }
+
+    @Test
+    public void testTransientEqualToTotalIsRejected()
+    {
+        // Cassandra requires at least one full replica, so 3/3 is invalid and 
must not be accepted silently
+        assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/3")))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("datacenter1");
+    }
+
+    @Test
+    public void testMalformedReplicationValuesAreRejected()
+    {
+        for (String malformed : new String[]{"3/", "/1", "3/1/1", "3/x", 
"x/1", "3/-1", ""})
+        {
+            assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+            "class", "NetworkTopologyStrategy",
+            "datacenter1", malformed)))
+            .as("malformed replication value '%s' should be rejected", 
malformed)
+            .isInstanceOf(IllegalArgumentException.class);
+        }
+    }
+
+    @Test
+    public void testGetFullReplicasUnknownDatacenter()
+    {
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThatThrownBy(() -> replicationFactor.getFullReplicas("nosuchdc"))
+        .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void testTransientOptionsForUnknownDatacenterRejected()
+    {
+        assertThatThrownBy(() -> new ReplicationFactor(
+        ReplicationFactor.ReplicationStrategy.NetworkTopologyStrategy,
+        ImmutableMap.of("datacenter1", 3),
+        ImmutableMap.of("datacenter2", 1)))
+        .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    public void testEqualityConsidersTransientReplicas()
+    {
+        ReplicationFactor full = new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3"));
+        ReplicationFactor withTransient = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1"));
+        assertThat(full).isNotEqualTo(withTransient);
+        assertThat(full.hashCode()).isNotEqualTo(withTransient.hashCode());
+    }
+
+    @Test
+    public void testNegativeReplicationFactorIsRejected()
+    {
+        assertThatThrownBy(() -> new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "-3")))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("datacenter1");
+    }
+
+    @Test
+    public void testZeroReplicationFactorIsAllowed()
+    {
+        // RF 0 is legitimate for NetworkTopologyStrategy: the keyspace is 
simply not replicated to that datacenter
+        ReplicationFactor replicationFactor = new 
ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3",
+        "datacenter2", "0"));
+        
assertThat(replicationFactor.getOptions().get("datacenter2")).isEqualTo(Integer.valueOf(0));
+        assertThat(replicationFactor.getTotalReplicationFactor()).isEqualTo(3);
+    }
+
+    @Test
+    public void testKryoSerializationRoundTripWithTransientReplicas() throws 
Exception
+    {
+        ReplicationFactor original = new ReplicationFactor(ImmutableMap.of(
+        "class", "NetworkTopologyStrategy",
+        "datacenter1", "3/1",
+        "datacenter2", "3"));
+
+        Kryo kryo = new Kryo();
+        kryo.register(ReplicationFactor.class, new 
ReplicationFactor.Serializer());
+
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        try (Output out = new Output(bytes))
+        {
+            kryo.writeObject(out, original);
+        }
+        ReplicationFactor deserialized;
+        try (Input in = new Input(new 
ByteArrayInputStream(bytes.toByteArray())))
+        {
+            deserialized = kryo.readObject(in, ReplicationFactor.class);
+        }
+
+        assertThat(deserialized).isEqualTo(original);
+        assertThat(deserialized.getTotalReplicationFactor()).isEqualTo(6);
+        assertThat(deserialized.getFullReplicationFactor()).isEqualTo(5);
+        
assertThat(deserialized.getTransientReplicas("datacenter1")).isEqualTo(1);
+        
assertThat(deserialized.getTransientReplicas("datacenter2")).isEqualTo(0);
+    }
+
+    @Test
+    public void testJdkSerializationRoundTripWithTransientReplicas() throws 
Exception

Review Comment:
   Merged, thanks!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to