aboutsummaryrefslogtreecommitdiffstats
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/config_test.go18
-rw-r--r--node/node.go23
-rw-r--r--node/node_example_test.go2
-rw-r--r--node/node_test.go24
-rw-r--r--node/service_test.go1
5 files changed, 65 insertions, 3 deletions
diff --git a/node/config_test.go b/node/config_test.go
index b81d3d612..00c24a239 100644
--- a/node/config_test.go
+++ b/node/config_test.go
@@ -38,14 +38,22 @@ func TestDatadirCreation(t *testing.T) {
}
defer os.RemoveAll(dir)
- if _, err := New(&Config{DataDir: dir}); err != nil {
+ node, err := New(&Config{DataDir: dir})
+ if err != nil {
t.Fatalf("failed to create stack with existing datadir: %v", err)
}
+ if err := node.Close(); err != nil {
+ t.Fatalf("failed to close node: %v", err)
+ }
// Generate a long non-existing datadir path and check that it gets created by a node
dir = filepath.Join(dir, "a", "b", "c", "d", "e", "f")
- if _, err := New(&Config{DataDir: dir}); err != nil {
+ node, err = New(&Config{DataDir: dir})
+ if err != nil {
t.Fatalf("failed to create stack with creatable datadir: %v", err)
}
+ if err := node.Close(); err != nil {
+ t.Fatalf("failed to close node: %v", err)
+ }
if _, err := os.Stat(dir); err != nil {
t.Fatalf("freshly created datadir not accessible: %v", err)
}
@@ -57,8 +65,12 @@ func TestDatadirCreation(t *testing.T) {
defer os.Remove(file.Name())
dir = filepath.Join(file.Name(), "invalid/path")
- if _, err := New(&Config{DataDir: dir}); err == nil {
+ node, err = New(&Config{DataDir: dir})
+ if err == nil {
t.Fatalf("protocol stack created with an invalid datadir")
+ if err := node.Close(); err != nil {
+ t.Fatalf("failed to close node: %v", err)
+ }
}
}
diff --git a/node/node.go b/node/node.go
index c35a50972..f267cdc46 100644
--- a/node/node.go
+++ b/node/node.go
@@ -121,6 +121,29 @@ func New(conf *Config) (*Node, error) {
}, nil
}
+// Close stops the Node and releases resources acquired in
+// Node constructor New.
+func (n *Node) Close() error {
+ var errs []error
+
+ // Terminate all subsystems and collect any errors
+ if err := n.Stop(); err != nil && err != ErrNodeStopped {
+ errs = append(errs, err)
+ }
+ if err := n.accman.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ // Report any errors that might have occurred
+ switch len(errs) {
+ case 0:
+ return nil
+ case 1:
+ return errs[0]
+ default:
+ return fmt.Errorf("%v", errs)
+ }
+}
+
// Register injects a new service into the node's stack. The service created by
// the passed constructor must be unique in its type with regard to sibling ones.
func (n *Node) Register(constructor ServiceConstructor) error {
diff --git a/node/node_example_test.go b/node/node_example_test.go
index ee06f4065..57b18855f 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -46,6 +46,8 @@ func ExampleService() {
if err != nil {
log.Fatalf("Failed to create network node: %v", err)
}
+ defer stack.Close()
+
// Create and register a simple network service. This is done through the definition
// of a node.ServiceConstructor that will instantiate a node.Service. The reason for
// the factory method approach is to support service restarts without relying on the
diff --git a/node/node_test.go b/node/node_test.go
index f833cd688..c464771cd 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -46,6 +46,8 @@ func TestNodeLifeCycle(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Ensure that a stopped node can be stopped again
for i := 0; i < 3; i++ {
if err := stack.Stop(); err != ErrNodeStopped {
@@ -88,6 +90,8 @@ func TestNodeUsedDataDir(t *testing.T) {
if err != nil {
t.Fatalf("failed to create original protocol stack: %v", err)
}
+ defer original.Close()
+
if err := original.Start(); err != nil {
t.Fatalf("failed to start original protocol stack: %v", err)
}
@@ -98,6 +102,8 @@ func TestNodeUsedDataDir(t *testing.T) {
if err != nil {
t.Fatalf("failed to create duplicate protocol stack: %v", err)
}
+ defer duplicate.Close()
+
if err := duplicate.Start(); err != ErrDatadirUsed {
t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed)
}
@@ -109,6 +115,8 @@ func TestServiceRegistry(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of unique services and ensure they start successfully
services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC}
for i, constructor := range services {
@@ -141,6 +149,8 @@ func TestServiceLifeCycle(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of life-cycle instrumented services
services := map[string]InstrumentingWrapper{
"A": InstrumentedServiceMakerA,
@@ -191,6 +201,8 @@ func TestServiceRestarts(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Define a service that does not support restarts
var (
running bool
@@ -239,6 +251,8 @@ func TestServiceConstructionAbortion(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Define a batch of good services
services := map[string]InstrumentingWrapper{
"A": InstrumentedServiceMakerA,
@@ -286,6 +300,8 @@ func TestServiceStartupAbortion(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of good services
services := map[string]InstrumentingWrapper{
"A": InstrumentedServiceMakerA,
@@ -339,6 +355,8 @@ func TestServiceTerminationGuarantee(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of good services
services := map[string]InstrumentingWrapper{
"A": InstrumentedServiceMakerA,
@@ -414,6 +432,8 @@ func TestServiceRetrieval(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
if err := stack.Register(NewNoopService); err != nil {
t.Fatalf("noop service registration failed: %v", err)
}
@@ -449,6 +469,8 @@ func TestProtocolGather(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of services with some configured number of protocols
services := map[string]struct {
Count int
@@ -505,6 +527,8 @@ func TestAPIGather(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
+
// Register a batch of services with some configured APIs
calls := make(chan string, 1)
makeAPI := func(result string) *OneMethodAPI {
diff --git a/node/service_test.go b/node/service_test.go
index a7ae439e0..73c51eccb 100644
--- a/node/service_test.go
+++ b/node/service_test.go
@@ -67,6 +67,7 @@ func TestContextServices(t *testing.T) {
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
+ defer stack.Close()
// Define a verifier that ensures a NoopA is before it and NoopB after
verifier := func(ctx *ServiceContext) (Service, error) {
var objA *NoopServiceA