Added test for StartupSettings
and documentation of use - in README.md
.
* Also tweaked the `StartupSettings` so that it now reads in an `id` for the node, rather than just resulting in a blank `id`; * Moved some logging from stdout to log4j * Full `maven test` passing Arguably this would result in a version change, as the settings file format has changed and now requires an id field. However we could make it optional, but it seems odd to have nodes with no ids.
This commit is contained in:
43
README.md
43
README.md
@ -40,6 +40,46 @@ Later we can check that the nodes discover each other
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Usage with Settings File
|
||||||
|
-----
|
||||||
|
|
||||||
|
For a very simple client setup with a settings file you first need a JSON file such as:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{
|
||||||
|
"id":"419af818-0114-4c7b-8fdb-952915335ce4",
|
||||||
|
"port":50001,
|
||||||
|
"gossip_interval":1000,
|
||||||
|
"cleanup_interval":10000,
|
||||||
|
"members":[
|
||||||
|
{"host":"127.0.0.1", "port":50000}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
where:
|
||||||
|
|
||||||
|
* `id` - is a unique id for this node (you can use any string, but above we use a UUID)
|
||||||
|
* `port` - the port to use on the default adapter on the node's machine
|
||||||
|
* `gossip_interval` - how often (in milliseconds) to gossip list of members to other node(s)
|
||||||
|
* `cleanup_interval` - when to remove 'dead' nodes (in milliseconds)
|
||||||
|
* `members` - initial seed nodes
|
||||||
|
|
||||||
|
Then starting a local node is as simple as:
|
||||||
|
|
||||||
|
```java
|
||||||
|
GossipService gossipService = new GossipService(
|
||||||
|
StartupSettings.fromJSONFile( "node_settings.json" )
|
||||||
|
);
|
||||||
|
gossipService.start();
|
||||||
|
```
|
||||||
|
|
||||||
|
And then when all is done, shutdown with:
|
||||||
|
|
||||||
|
```java
|
||||||
|
gossipService.shutdown();
|
||||||
|
```
|
||||||
|
|
||||||
Event Listener
|
Event Listener
|
||||||
------
|
------
|
||||||
|
|
||||||
@ -50,6 +90,9 @@ The status can be polled using the getters that return immutable lists.
|
|||||||
public List<LocalGossipMember> getDeadList()
|
public List<LocalGossipMember> getDeadList()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
These can be accessed from the `GossipManager` on your `GossipService`, e.g:
|
||||||
|
`gossipService.get_gossipManager().getMemberList();`
|
||||||
|
|
||||||
Users can also attach an event listener:
|
Users can also attach an event listener:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
@ -29,7 +29,7 @@ public class GossipService {
|
|||||||
*/
|
*/
|
||||||
public GossipService(StartupSettings startupSettings) throws InterruptedException,
|
public GossipService(StartupSettings startupSettings) throws InterruptedException,
|
||||||
UnknownHostException {
|
UnknownHostException {
|
||||||
this(InetAddress.getLocalHost().getHostAddress(), startupSettings.getPort(), "",
|
this(InetAddress.getLocalHost().getHostAddress(), startupSettings.getPort(), startupSettings.getId(),
|
||||||
startupSettings.getGossipMembers(), startupSettings
|
startupSettings.getGossipMembers(), startupSettings
|
||||||
.getGossipSettings(), null);
|
.getGossipSettings(), null);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -18,6 +19,10 @@ import org.json.JSONObject;
|
|||||||
* @author harmenw
|
* @author harmenw
|
||||||
*/
|
*/
|
||||||
public class StartupSettings {
|
public class StartupSettings {
|
||||||
|
private static final Logger log = Logger.getLogger(StartupSettings.class);
|
||||||
|
|
||||||
|
/** The id to use fo the service */
|
||||||
|
private String _id;
|
||||||
|
|
||||||
/** The port to start the gossip service on. */
|
/** The port to start the gossip service on. */
|
||||||
private int _port;
|
private int _port;
|
||||||
@ -31,25 +36,51 @@ public class StartupSettings {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
* @param id
|
||||||
|
* The id to be used for this service
|
||||||
* @param port
|
* @param port
|
||||||
* The port to start the service on.
|
* The port to start the service on.
|
||||||
|
* @param logLevel
|
||||||
|
* unused
|
||||||
*/
|
*/
|
||||||
public StartupSettings(int port, int logLevel) {
|
public StartupSettings(String id, int port, int logLevel) {
|
||||||
this(port, new GossipSettings());
|
this(id, port, new GossipSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
* @param id
|
||||||
|
* The id to be used for this service
|
||||||
* @param port
|
* @param port
|
||||||
* The port to start the service on.
|
* The port to start the service on.
|
||||||
*/
|
*/
|
||||||
public StartupSettings(int port, GossipSettings gossipSettings) {
|
public StartupSettings(String id, int port, GossipSettings gossipSettings) {
|
||||||
|
_id = id;
|
||||||
_port = port;
|
_port = port;
|
||||||
_gossipSettings = gossipSettings;
|
_gossipSettings = gossipSettings;
|
||||||
_gossipMembers = new ArrayList<>();
|
_gossipMembers = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the id to be used for this service.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* The id for this service.
|
||||||
|
*/
|
||||||
|
public void setId( String id ) {
|
||||||
|
_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the id for this service.
|
||||||
|
*
|
||||||
|
* @return the service's id.
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the port of the gossip service.
|
* Set the port of the gossip service.
|
||||||
*
|
*
|
||||||
@ -126,6 +157,9 @@ public class StartupSettings {
|
|||||||
// Now get the port number.
|
// Now get the port number.
|
||||||
int port = jsonObject.getInt("port");
|
int port = jsonObject.getInt("port");
|
||||||
|
|
||||||
|
// Get the id to be used
|
||||||
|
String id = jsonObject.getString("id");
|
||||||
|
|
||||||
// Get the gossip_interval from the config file.
|
// Get the gossip_interval from the config file.
|
||||||
int gossipInterval = jsonObject.getInt("gossip_interval");
|
int gossipInterval = jsonObject.getInt("gossip_interval");
|
||||||
|
|
||||||
@ -133,22 +167,22 @@ public class StartupSettings {
|
|||||||
int cleanupInterval = jsonObject.getInt("cleanup_interval");
|
int cleanupInterval = jsonObject.getInt("cleanup_interval");
|
||||||
|
|
||||||
// Initiate the settings with the port number.
|
// Initiate the settings with the port number.
|
||||||
StartupSettings settings = new StartupSettings(port, new GossipSettings(
|
StartupSettings settings = new StartupSettings(id, port, new GossipSettings(
|
||||||
gossipInterval, cleanupInterval));
|
gossipInterval, cleanupInterval));
|
||||||
|
|
||||||
// Now iterate over the members from the config file and add them to the settings.
|
// Now iterate over the members from the config file and add them to the settings.
|
||||||
System.out.print("Config-members [");
|
String configMembersDetails = "Config-members [";
|
||||||
JSONArray membersJSON = jsonObject.getJSONArray("members");
|
JSONArray membersJSON = jsonObject.getJSONArray("members");
|
||||||
for (int i = 0; i < membersJSON.length(); i++) {
|
for (int i = 0; i < membersJSON.length(); i++) {
|
||||||
JSONObject memberJSON = membersJSON.getJSONObject(i);
|
JSONObject memberJSON = membersJSON.getJSONObject(i);
|
||||||
RemoteGossipMember member = new RemoteGossipMember(memberJSON.getString("host"),
|
RemoteGossipMember member = new RemoteGossipMember(memberJSON.getString("host"),
|
||||||
memberJSON.getInt("port"), "");
|
memberJSON.getInt("port"), "");
|
||||||
settings.addGossipMember(member);
|
settings.addGossipMember(member);
|
||||||
System.out.print(member.getAddress());
|
configMembersDetails += member.getAddress();
|
||||||
if (i < (membersJSON.length() - 1))
|
if (i < (membersJSON.length() - 1))
|
||||||
System.out.print(", ");
|
configMembersDetails += ", ";
|
||||||
}
|
}
|
||||||
System.out.println("]");
|
log.info( configMembersDetails + "]" );
|
||||||
|
|
||||||
// Return the created settings object.
|
// Return the created settings object.
|
||||||
return settings;
|
return settings;
|
||||||
|
79
src/test/java/io/teknek/gossip/StartupSettingsTest.java
Normal file
79
src/test/java/io/teknek/gossip/StartupSettingsTest.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package io.teknek.gossip;
|
||||||
|
|
||||||
|
import com.google.code.gossip.GossipMember;
|
||||||
|
import com.google.code.gossip.GossipService;
|
||||||
|
import com.google.code.gossip.GossipSettings;
|
||||||
|
import com.google.code.gossip.StartupSettings;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests support of using {@code StartupSettings} and thereby reading
|
||||||
|
* setup config from file.
|
||||||
|
*/
|
||||||
|
public class StartupSettingsTest {
|
||||||
|
private static final Logger log = Logger.getLogger( StartupSettingsTest.class );
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUsingSettingsFile() throws IOException, InterruptedException, JSONException {
|
||||||
|
File settingsFile = File.createTempFile("gossipTest",".json");
|
||||||
|
log.debug( "Using settings file: " + settingsFile.getAbsolutePath() );
|
||||||
|
settingsFile.deleteOnExit();
|
||||||
|
writeSettingsFile(settingsFile);
|
||||||
|
|
||||||
|
// Start the other simple node that the settings file points to
|
||||||
|
GossipService firstService = new GossipService(
|
||||||
|
"127.0.0.1", 50000, UUID.randomUUID().toString(),
|
||||||
|
new ArrayList<GossipMember>(), new GossipSettings(), null
|
||||||
|
);
|
||||||
|
firstService.start();
|
||||||
|
|
||||||
|
// Start a node with the settings file
|
||||||
|
GossipService serviceUnderTest = new GossipService(
|
||||||
|
StartupSettings.fromJSONFile( settingsFile )
|
||||||
|
);
|
||||||
|
serviceUnderTest.start();
|
||||||
|
|
||||||
|
// Let the sync up
|
||||||
|
TimeUnit.SECONDS.sleep(2);
|
||||||
|
|
||||||
|
// Check the results
|
||||||
|
assertEquals(1, firstService.get_gossipManager().getMemberList().size() );
|
||||||
|
assertEquals(1, serviceUnderTest.get_gossipManager().getMemberList().size() );
|
||||||
|
assertTrue(
|
||||||
|
firstService.get_gossipManager().getMemberList().size() ==
|
||||||
|
serviceUnderTest.get_gossipManager().getMemberList().size() );
|
||||||
|
|
||||||
|
firstService.shutdown();
|
||||||
|
serviceUnderTest.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.
|
||||||
|
" \"id\":\"" + UUID.randomUUID() + "\",\n" +
|
||||||
|
" \"port\":50001,\n" +
|
||||||
|
" \"gossip_interval\":1000,\n" +
|
||||||
|
" \"cleanup_interval\":10000,\n" +
|
||||||
|
" \"members\":[\n" +
|
||||||
|
" {\"host\":\"127.0.0.1\", \"port\":50000}\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();
|
||||||
|
}
|
||||||
|
}
|
@ -52,11 +52,12 @@ public class TenNodeThreeSeedTest {
|
|||||||
new GossipListener(){
|
new GossipListener(){
|
||||||
@Override
|
@Override
|
||||||
public void gossipEvent(GossipMember member, GossipState state) {
|
public void gossipEvent(GossipMember member, GossipState state) {
|
||||||
System.out.println(member+" "+ state);
|
log.info(member+" "+ state);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
clients.add(gossipService);
|
clients.add(gossipService);
|
||||||
gossipService.start();
|
gossipService.start();
|
||||||
|
gossipService.get_gossipManager().getMemberList();
|
||||||
}
|
}
|
||||||
TUnit.assertThat(new Callable<Integer> (){
|
TUnit.assertThat(new Callable<Integer> (){
|
||||||
public Integer call() throws Exception {
|
public Integer call() throws Exception {
|
||||||
|
Reference in New Issue
Block a user