GOSSIP-85 Factor out PassiveGossipThread
This commit is contained in:
238
gossip-itest/src/test/java/org/apache/gossip/DataTest.java
Normal file
238
gossip-itest/src/test/java/org/apache/gossip/DataTest.java
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.gossip.crdt.GrowOnlyCounter;
|
||||
import org.apache.gossip.crdt.GrowOnlySet;
|
||||
import org.apache.gossip.crdt.OrSet;
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.apache.gossip.model.PerNodeDataMessage;
|
||||
import org.apache.gossip.model.SharedDataMessage;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.teknek.tunit.TUnit;
|
||||
|
||||
public class DataTest extends AbstractIntegrationBase {
|
||||
|
||||
private String orSetKey = "cror";
|
||||
private String gCounterKey = "crdtgc";
|
||||
|
||||
@Test
|
||||
public void dataTest() throws InterruptedException, UnknownHostException, URISyntaxException{
|
||||
GossipSettings settings = new GossipSettings();
|
||||
settings.setPersistRingState(false);
|
||||
settings.setPersistDataState(false);
|
||||
String cluster = UUID.randomUUID().toString();
|
||||
int seedNodes = 1;
|
||||
List<Member> startupMembers = new ArrayList<>();
|
||||
for (int i = 1; i < seedNodes+1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
|
||||
startupMembers.add(new RemoteMember(cluster, uri, i + ""));
|
||||
}
|
||||
final List<GossipManager> clients = new ArrayList<>();
|
||||
final int clusterMembers = 2;
|
||||
for (int i = 1; i < clusterMembers + 1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
|
||||
GossipManager gossipService = GossipManagerBuilder.newBuilder().cluster(cluster).uri(uri)
|
||||
.id(i + "").gossipMembers(startupMembers).gossipSettings(settings).build();
|
||||
clients.add(gossipService);
|
||||
gossipService.init();
|
||||
register(gossipService);
|
||||
}
|
||||
TUnit.assertThat(() -> {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(2);
|
||||
clients.get(0).gossipPerNodeData(msg());
|
||||
clients.get(0).gossipSharedData(sharedMsg());
|
||||
|
||||
TUnit.assertThat(()-> {
|
||||
PerNodeDataMessage x = clients.get(1).findPerNodeGossipData(1 + "", "a");
|
||||
if (x == null)
|
||||
return "";
|
||||
else
|
||||
return x.getPayload();
|
||||
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo("b");
|
||||
|
||||
TUnit.assertThat(() -> {
|
||||
SharedDataMessage x = clients.get(1).findSharedGossipData("a");
|
||||
if (x == null)
|
||||
return "";
|
||||
else
|
||||
return x.getPayload();
|
||||
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo("c");
|
||||
|
||||
|
||||
givenDifferentDatumsInSet(clients);
|
||||
assertThatListIsMerged(clients);
|
||||
|
||||
givenOrs(clients);
|
||||
assertThatOrSetIsMerged(clients);
|
||||
dropIt(clients);
|
||||
assertThatOrSetDelIsMerged(clients);
|
||||
|
||||
|
||||
// test g counter
|
||||
givenDifferentIncrement(clients);
|
||||
assertThatCountIsUpdated(clients, 3);
|
||||
givenIncreaseOther(clients);
|
||||
assertThatCountIsUpdated(clients, 7);
|
||||
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
clients.get(i).shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void givenDifferentIncrement(final List<GossipManager> clients) {
|
||||
{
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(gCounterKey);
|
||||
d.setPayload(new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L)));
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(0).merge(d);
|
||||
}
|
||||
{
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(gCounterKey);
|
||||
d.setPayload(new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(1)).increment(2L)));
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(1).merge(d);
|
||||
}
|
||||
}
|
||||
|
||||
private void givenIncreaseOther(final List<GossipManager> clients) {
|
||||
GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(1).findCrdt(gCounterKey);
|
||||
GrowOnlyCounter gc2 = new GrowOnlyCounter(gc,
|
||||
new GrowOnlyCounter.Builder(clients.get(1)).increment(4L));
|
||||
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(gCounterKey);
|
||||
d.setPayload(gc2);
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(1).merge(d);
|
||||
}
|
||||
|
||||
private void givenOrs(List<GossipManager> clients) {
|
||||
{
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(orSetKey);
|
||||
d.setPayload(new OrSet<String>("1", "2"));
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(0).merge(d);
|
||||
}
|
||||
{
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(orSetKey);
|
||||
d.setPayload(new OrSet<String>("3", "4"));
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(1).merge(d);
|
||||
}
|
||||
}
|
||||
|
||||
private void dropIt(List<GossipManager> clients) {
|
||||
@SuppressWarnings("unchecked")
|
||||
OrSet<String> o = (OrSet<String>) clients.get(0).findCrdt(orSetKey);
|
||||
OrSet<String> o2 = new OrSet<String>(o, new OrSet.Builder<String>().remove("3"));
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey(orSetKey);
|
||||
d.setPayload(o2);
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
clients.get(0).merge(d);
|
||||
}
|
||||
|
||||
private void assertThatOrSetIsMerged(final List<GossipManager> clients){
|
||||
TUnit.assertThat(() -> {
|
||||
return clients.get(0).findCrdt(orSetKey).value();
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new OrSet<String>("1", "2", "3", "4").value());
|
||||
TUnit.assertThat(() -> {
|
||||
return clients.get(1).findCrdt(orSetKey).value();
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new OrSet<String>("1", "2", "3", "4").value());
|
||||
}
|
||||
|
||||
private void assertThatOrSetDelIsMerged(final List<GossipManager> clients){
|
||||
TUnit.assertThat(() -> {
|
||||
return clients.get(0).findCrdt(orSetKey);
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).equals(new OrSet<String>("1", "2", "4"));
|
||||
}
|
||||
|
||||
private void givenDifferentDatumsInSet(final List<GossipManager> clients){
|
||||
clients.get(0).merge(CrdtMessage("1"));
|
||||
clients.get(1).merge(CrdtMessage("2"));
|
||||
}
|
||||
|
||||
|
||||
private void assertThatCountIsUpdated(final List<GossipManager> clients, long finalCount) {
|
||||
TUnit.assertThat(() -> {
|
||||
return clients.get(0).findCrdt(gCounterKey);
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new GrowOnlyCounter(
|
||||
new GrowOnlyCounter.Builder(clients.get(0)).increment(finalCount)));
|
||||
}
|
||||
|
||||
private void assertThatListIsMerged(final List<GossipManager> clients){
|
||||
TUnit.assertThat(() -> {
|
||||
return clients.get(0).findCrdt("cr");
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new GrowOnlySet<String>(Arrays.asList("1","2")));
|
||||
}
|
||||
|
||||
private SharedDataMessage CrdtMessage(String item){
|
||||
SharedDataMessage d = new SharedDataMessage();
|
||||
d.setKey("cr");
|
||||
d.setPayload(new GrowOnlySet<String>( Arrays.asList(item)));
|
||||
d.setExpireAt(Long.MAX_VALUE);
|
||||
d.setTimestamp(System.currentTimeMillis());
|
||||
return d;
|
||||
}
|
||||
|
||||
private PerNodeDataMessage msg(){
|
||||
PerNodeDataMessage g = new PerNodeDataMessage();
|
||||
g.setExpireAt(Long.MAX_VALUE);
|
||||
g.setKey("a");
|
||||
g.setPayload("b");
|
||||
g.setTimestamp(System.currentTimeMillis());
|
||||
return g;
|
||||
}
|
||||
|
||||
private SharedDataMessage sharedMsg(){
|
||||
SharedDataMessage g = new SharedDataMessage();
|
||||
g.setExpireAt(Long.MAX_VALUE);
|
||||
g.setKey("a");
|
||||
g.setPayload("c");
|
||||
g.setTimestamp(System.currentTimeMillis());
|
||||
return g;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.gossip.manager.DatacenterRackAwareActiveGossiper;
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import io.teknek.tunit.TUnit;
|
||||
|
||||
@RunWith(JUnitPlatform.class)
|
||||
public class IdAndPropertyTest extends AbstractIntegrationBase {
|
||||
|
||||
@Test
|
||||
public void testDatacenterRackGossiper() throws URISyntaxException, UnknownHostException, InterruptedException {
|
||||
GossipSettings settings = new GossipSettings();
|
||||
settings.setActiveGossipClass(DatacenterRackAwareActiveGossiper.class.getName());
|
||||
List<Member> startupMembers = new ArrayList<>();
|
||||
Map<String, String> x = new HashMap<>();
|
||||
x.put("a", "b");
|
||||
x.put("datacenter", "dc1");
|
||||
x.put("rack", "rack1");
|
||||
GossipManager gossipService1 = GossipManagerBuilder.newBuilder()
|
||||
.cluster("a")
|
||||
.uri(new URI("udp://" + "127.0.0.1" + ":" + (29000 + 0)))
|
||||
.id("0")
|
||||
.properties(x)
|
||||
.gossipMembers(startupMembers)
|
||||
.gossipSettings(settings).build();
|
||||
gossipService1.init();
|
||||
register(gossipService1);
|
||||
|
||||
Map<String, String> y = new HashMap<>();
|
||||
y.put("a", "c");
|
||||
y.put("datacenter", "dc2");
|
||||
y.put("rack", "rack2");
|
||||
GossipManager gossipService2 = GossipManagerBuilder.newBuilder().cluster("a")
|
||||
.uri( new URI("udp://" + "127.0.0.1" + ":" + (29000 + 10)))
|
||||
.id("1")
|
||||
.properties(y)
|
||||
.gossipMembers(Arrays.asList(new RemoteMember("a",
|
||||
new URI("udp://" + "127.0.0.1" + ":" + (29000 + 0)), "0")))
|
||||
.gossipSettings(settings).build();
|
||||
gossipService2.init();
|
||||
register(gossipService2);
|
||||
|
||||
TUnit.assertThat(() -> {
|
||||
String value = "";
|
||||
try {
|
||||
value = gossipService1.getLiveMembers().get(0).getProperties().get("a");
|
||||
} catch (RuntimeException e){ }
|
||||
return value;
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo("c");
|
||||
|
||||
TUnit.assertThat(() -> {
|
||||
String value = "";
|
||||
try {
|
||||
value = gossipService2.getLiveMembers().get(0).getProperties().get("a");
|
||||
} catch (RuntimeException e){ }
|
||||
return value;
|
||||
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo("b");
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import io.teknek.tunit.TUnit;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(JUnitPlatform.class)
|
||||
public class ShutdownDeadtimeTest {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ShutdownDeadtimeTest.class);
|
||||
|
||||
// Note: this test is floppy depending on the values in GossipSettings (smaller values seem to do harm), and the
|
||||
// sleep that happens after startup.
|
||||
@Test
|
||||
public void DeadNodesDoNotComeAliveAgain()
|
||||
throws InterruptedException, UnknownHostException, URISyntaxException {
|
||||
GossipSettings settings = new GossipSettings(100, 10000, 1000, 1, 10.0, "normal");
|
||||
settings.setPersistRingState(false);
|
||||
settings.setPersistDataState(false);
|
||||
String cluster = UUID.randomUUID().toString();
|
||||
int seedNodes = 3;
|
||||
List<Member> startupMembers = new ArrayList<>();
|
||||
for (int i = 1; i < seedNodes + 1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30300 + i));
|
||||
startupMembers.add(new RemoteMember(cluster, uri, i + ""));
|
||||
}
|
||||
final List<GossipManager> clients = Collections.synchronizedList(new ArrayList<GossipManager>());
|
||||
final int clusterMembers = 5;
|
||||
for (int i = 1; i < clusterMembers + 1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30300 + i));
|
||||
GossipManager gossipService = GossipManagerBuilder.newBuilder()
|
||||
.cluster(cluster)
|
||||
.uri(uri)
|
||||
.id(i + "")
|
||||
.gossipMembers(startupMembers)
|
||||
.gossipSettings(settings)
|
||||
.build();
|
||||
clients.add(gossipService);
|
||||
gossipService.init();
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
TUnit.assertThat(new Callable<Integer>() {
|
||||
public Integer call() throws Exception {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}).afterWaitingAtMost(40, TimeUnit.SECONDS).isEqualTo(20);
|
||||
|
||||
// shutdown one client and verify that one client is lost.
|
||||
Random r = new Random();
|
||||
int randomClientId = r.nextInt(clusterMembers);
|
||||
log.info("shutting down " + randomClientId);
|
||||
final int shutdownPort = clients.get(randomClientId).getMyself().getUri()
|
||||
.getPort();
|
||||
final String shutdownId = clients.get(randomClientId).getMyself().getId();
|
||||
clients.get(randomClientId).shutdown();
|
||||
TUnit.assertThat(new Callable<Integer>() {
|
||||
public Integer call() throws Exception {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}).afterWaitingAtMost(40, TimeUnit.SECONDS).isEqualTo(16);
|
||||
clients.remove(randomClientId);
|
||||
|
||||
TUnit.assertThat(new Callable<Integer>() {
|
||||
public Integer call() throws Exception {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers - 1; ++i) {
|
||||
total += clients.get(i).getDeadMembers().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}).afterWaitingAtMost(50, TimeUnit.SECONDS).isEqualTo(4);
|
||||
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + shutdownPort);
|
||||
// start client again
|
||||
GossipManager gossipService = GossipManagerBuilder.newBuilder()
|
||||
.gossipSettings(settings)
|
||||
.cluster(cluster)
|
||||
.uri(uri)
|
||||
.id(shutdownId+"")
|
||||
.gossipMembers(startupMembers)
|
||||
.build();
|
||||
clients.add(gossipService);
|
||||
gossipService.init();
|
||||
|
||||
// verify that the client is alive again for every node
|
||||
TUnit.assertThat(new Callable<Integer>() {
|
||||
public Integer call() throws Exception {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}).afterWaitingAtMost(60, TimeUnit.SECONDS).isEqualTo(20);
|
||||
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
final int j = i;
|
||||
new Thread() {
|
||||
public void run(){
|
||||
clients.get(j).shutdown();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.apache.gossip.manager.PassiveGossipConstants;
|
||||
import org.apache.gossip.secure.KeyTool;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.teknek.tunit.TUnit;
|
||||
|
||||
public class SignedMessageTest extends AbstractIntegrationBase {
|
||||
|
||||
private GossipSettings gossiperThatSigns(){
|
||||
GossipSettings settings = new GossipSettings();
|
||||
settings.setPersistRingState(false);
|
||||
settings.setPersistDataState(false);
|
||||
settings.setSignMessages(true);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private GossipSettings gossiperThatSigns(String keysDir){
|
||||
GossipSettings settings = gossiperThatSigns();
|
||||
settings.setPathToKeyStore(Objects.requireNonNull(keysDir));
|
||||
return settings;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dataTest() throws InterruptedException, URISyntaxException, NoSuchAlgorithmException, NoSuchProviderException, IOException {
|
||||
final String keys = System.getProperty("java.io.tmpdir") + "/keys";
|
||||
GossipSettings settings = gossiperThatSigns(keys);
|
||||
setup(keys);
|
||||
String cluster = UUID.randomUUID().toString();
|
||||
List<Member> startupMembers = new ArrayList<>();
|
||||
for (int i = 1; i < 2; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30000 + i));
|
||||
startupMembers.add(new RemoteMember(cluster, uri, i + ""));
|
||||
}
|
||||
final List<GossipManager> clients = new ArrayList<>();
|
||||
for (int i = 1; i < 3; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30000 + i));
|
||||
GossipManager gossipService = GossipManagerBuilder.newBuilder()
|
||||
.cluster(cluster)
|
||||
.uri(uri)
|
||||
.id(i + "")
|
||||
.gossipMembers(startupMembers)
|
||||
.gossipSettings(settings)
|
||||
.build();
|
||||
gossipService.init();
|
||||
clients.add(gossipService);
|
||||
}
|
||||
assertTwoAlive(clients);
|
||||
assertOnlySignedMessages(clients);
|
||||
cleanup(keys, clients);
|
||||
}
|
||||
|
||||
private void assertTwoAlive(List<GossipManager> clients){
|
||||
TUnit.assertThat(() -> {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clients.size(); ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(2);
|
||||
}
|
||||
|
||||
private void assertOnlySignedMessages(List<GossipManager> clients){
|
||||
Assert.assertEquals(0, clients.get(0).getRegistry()
|
||||
.meter(PassiveGossipConstants.UNSIGNED_MESSAGE).getCount());
|
||||
Assert.assertTrue(clients.get(0).getRegistry()
|
||||
.meter(PassiveGossipConstants.SIGNED_MESSAGE).getCount() > 0);
|
||||
}
|
||||
|
||||
private void cleanup(String keys, List<GossipManager> clients){
|
||||
new File(keys, "1").delete();
|
||||
new File(keys, "2").delete();
|
||||
new File(keys).delete();
|
||||
for (int i = 0; i < clients.size(); ++i) {
|
||||
clients.get(i).shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void setup(String keys) throws NoSuchAlgorithmException, NoSuchProviderException, IOException {
|
||||
new File(keys).mkdir();
|
||||
KeyTool.generatePubandPrivateKeyFiles(keys, "1");
|
||||
KeyTool.generatePubandPrivateKeyFiles(keys, "2");
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.UUID;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Tests support of using {@code StartupSettings} and thereby reading
|
||||
* setup config from file.
|
||||
*/
|
||||
@RunWith(JUnitPlatform.class)
|
||||
public class StartupSettingsTest {
|
||||
private static final Logger log = Logger.getLogger(StartupSettingsTest.class);
|
||||
private static final String CLUSTER = UUID.randomUUID().toString();
|
||||
|
||||
@Test
|
||||
public void testUsingSettingsFile() throws IOException, InterruptedException, URISyntaxException {
|
||||
File settingsFile = File.createTempFile("gossipTest",".json");
|
||||
settingsFile.deleteOnExit();
|
||||
writeSettingsFile(settingsFile);
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + 50000);
|
||||
GossipSettings firstGossipSettings = new GossipSettings();
|
||||
firstGossipSettings.setTransportManagerClass("org.apache.gossip.transport.UnitTestTransportManager");
|
||||
firstGossipSettings.setProtocolManagerClass("org.apache.gossip.protocol.UnitTestProtocolManager");
|
||||
GossipManager firstService = GossipManagerBuilder.newBuilder()
|
||||
.cluster(CLUSTER)
|
||||
.uri(uri)
|
||||
.id("1")
|
||||
.gossipSettings(firstGossipSettings).build();
|
||||
firstService.init();
|
||||
GossipManager manager = GossipManagerBuilder.newBuilder()
|
||||
.startupSettings(StartupSettings.fromJSONFile(settingsFile)).build();
|
||||
manager.init();
|
||||
firstService.shutdown();
|
||||
manager.shutdown();
|
||||
}
|
||||
|
||||
private void writeSettingsFile( File target ) throws IOException {
|
||||
String settings =
|
||||
"[{\n" + // It is odd that this is meant to be in an array, but oh well.
|
||||
" \"cluster\":\"" + CLUSTER + "\",\n" +
|
||||
" \"id\":\"" + "2" + "\",\n" +
|
||||
" \"uri\":\"udp://127.0.0.1:50001\",\n" +
|
||||
" \"gossip_interval\":1000,\n" +
|
||||
" \"window_size\":1000,\n" +
|
||||
" \"minimum_samples\":5,\n" +
|
||||
" \"cleanup_interval\":10000,\n" +
|
||||
" \"convict_threshold\":2.6,\n" +
|
||||
" \"distribution\":\"exponential\",\n" +
|
||||
" \"transport_manager_class\":\"org.apache.gossip.transport.UnitTestTransportManager\",\n" +
|
||||
" \"protocol_manager_class\":\"org.apache.gossip.protocol.UnitTestProtocolManager\",\n" +
|
||||
" \"properties\":{},\n" +
|
||||
" \"members\":[\n" +
|
||||
" {\"cluster\": \"" + CLUSTER + "\",\"uri\":\"udp://127.0.0.1:5000\"}\n" +
|
||||
" ]\n" +
|
||||
"}]";
|
||||
|
||||
log.info( "Using settings file with contents of:\n---\n" + settings + "\n---" );
|
||||
FileOutputStream output = new FileOutputStream(target);
|
||||
output.write(settings.getBytes());
|
||||
output.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.gossip;
|
||||
|
||||
import io.teknek.tunit.TUnit;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.apache.gossip.manager.GossipManager;
|
||||
import org.apache.gossip.manager.GossipManagerBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@RunWith(JUnitPlatform.class)
|
||||
public class TenNodeThreeSeedTest {
|
||||
|
||||
@Test
|
||||
public void test() throws UnknownHostException, InterruptedException, URISyntaxException {
|
||||
abc(30150);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAgain() throws UnknownHostException, InterruptedException, URISyntaxException {
|
||||
abc(30100);
|
||||
}
|
||||
|
||||
public void abc(int base) throws InterruptedException, UnknownHostException, URISyntaxException {
|
||||
GossipSettings settings = new GossipSettings(1000, 10000, 1000, 1, 1.6, "exponential");
|
||||
settings.setPersistRingState(false);
|
||||
settings.setPersistDataState(false);
|
||||
String cluster = UUID.randomUUID().toString();
|
||||
int seedNodes = 3;
|
||||
List<Member> startupMembers = new ArrayList<>();
|
||||
for (int i = 1; i < seedNodes+1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
|
||||
startupMembers.add(new RemoteMember(cluster, uri, i + ""));
|
||||
}
|
||||
final List<GossipManager> clients = new ArrayList<>();
|
||||
final int clusterMembers = 5;
|
||||
for (int i = 1; i < clusterMembers+1; ++i) {
|
||||
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
|
||||
GossipManager gossipService = GossipManagerBuilder.newBuilder()
|
||||
.cluster(cluster)
|
||||
.uri(uri)
|
||||
.id(i + "")
|
||||
.gossipSettings(settings)
|
||||
.gossipMembers(startupMembers)
|
||||
.build();
|
||||
gossipService.init();
|
||||
clients.add(gossipService);
|
||||
}
|
||||
TUnit.assertThat(new Callable<Integer> (){
|
||||
public Integer call() throws Exception {
|
||||
int total = 0;
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
total += clients.get(i).getLiveMembers().size();
|
||||
}
|
||||
return total;
|
||||
}}).afterWaitingAtMost(40, TimeUnit.SECONDS).isEqualTo(20);
|
||||
|
||||
for (int i = 0; i < clusterMembers; ++i) {
|
||||
int j = i;
|
||||
new Thread(){
|
||||
public void run(){
|
||||
clients.get(j).shutdown();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user