cmd, common, node, rpc: move IPC into the node itself

This commit is contained in:
Péter Szilágyi
2016-02-02 19:06:43 +02:00
parent 3274db19c7
commit 188ab928c3
14 changed files with 292 additions and 156 deletions

View File

@ -18,27 +18,34 @@ package node
import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"os"
"reflect"
"testing"
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
)
var (
testNodeKey, _ = crypto.GenerateKey()
)
testNodeConfig = &Config{
func testNodeConfig() *Config {
return &Config{
IpcPath: fmt.Sprintf("test-%d.ipc", rand.Int63()),
PrivateKey: testNodeKey,
Name: "test node",
}
)
}
// Tests that an empty protocol stack can be started, restarted and stopped.
func TestNodeLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -101,7 +108,7 @@ func TestNodeUsedDataDir(t *testing.T) {
// Tests whether services can be registered and duplicates caught.
func TestServiceRegistry(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -133,7 +140,7 @@ func TestServiceRegistry(t *testing.T) {
// Tests that registered services get started and stopped correctly.
func TestServiceLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -183,7 +190,7 @@ func TestServiceLifeCycle(t *testing.T) {
// Tests that services are restarted cleanly as new instances.
func TestServiceRestarts(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -231,7 +238,7 @@ func TestServiceRestarts(t *testing.T) {
// Tests that if a service fails to initialize itself, none of the other services
// will be allowed to even start.
func TestServiceConstructionAbortion(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -278,7 +285,7 @@ func TestServiceConstructionAbortion(t *testing.T) {
// Tests that if a service fails to start, all others started before it will be
// shut down.
func TestServiceStartupAbortion(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -331,7 +338,7 @@ func TestServiceStartupAbortion(t *testing.T) {
// Tests that even if a registered service fails to shut down cleanly, it does
// not influece the rest of the shutdown invocations.
func TestServiceTerminationGuarantee(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -406,7 +413,7 @@ func TestServiceTerminationGuarantee(t *testing.T) {
// TestServiceRetrieval tests that individual services can be retrieved.
func TestServiceRetrieval(t *testing.T) {
// Create a simple stack and register two service types
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -441,7 +448,7 @@ func TestServiceRetrieval(t *testing.T) {
// Tests that all protocols defined by individual services get launched.
func TestProtocolGather(t *testing.T) {
stack, err := New(testNodeConfig)
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
@ -494,3 +501,75 @@ func TestProtocolGather(t *testing.T) {
}
}
}
// Tests that all APIs defined by individual services get exposed.
func TestAPIGather(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
// Register a batch of services with some configured APIs
calls := make(chan string, 1)
services := map[string]struct {
APIs []rpc.API
Maker InstrumentingWrapper
}{
"Zero APIs": {[]rpc.API{}, InstrumentedServiceMakerA},
"Single API": {[]rpc.API{
{"single", "1", &OneMethodApi{fun: func() { calls <- "single.v1" }}, true},
}, InstrumentedServiceMakerB},
"Many APIs": {[]rpc.API{
{"multi", "1", &OneMethodApi{fun: func() { calls <- "multi.v1" }}, true},
{"multi.v2", "2", &OneMethodApi{fun: func() { calls <- "multi.v2" }}, true},
{"multi.v2.nested", "2", &OneMethodApi{fun: func() { calls <- "multi.v2.nested" }}, true},
}, InstrumentedServiceMakerC},
}
for id, config := range services {
config := config
constructor := func(*ServiceContext) (Service, error) {
return &InstrumentedService{apis: config.APIs}, nil
}
if err := stack.Register(config.Maker(constructor)); err != nil {
t.Fatalf("service %s: registration failed: %v", id, err)
}
}
// Start the services and ensure all API start successfully
if err := stack.Start(); err != nil {
t.Fatalf("failed to start protocol stack: %v", err)
}
defer stack.Stop()
// Connect to the RPC server and verify the various registered endpoints
ipcClient, err := rpc.NewIPCClient(stack.IpcEndpoint())
if err != nil {
t.Fatalf("failed to connect to the IPC API server: %v", err)
}
tests := []struct {
Method string
Result string
}{
{"single_theOneMethod", "single.v1"},
{"multi_theOneMethod", "multi.v1"},
{"multi.v2_theOneMethod", "multi.v2"},
{"multi.v2.nested_theOneMethod", "multi.v2.nested"},
}
for i, test := range tests {
if err := ipcClient.Send(rpc.JSONRequest{Id: new(int64), Version: "2.0", Method: test.Method}); err != nil {
t.Fatalf("test %d: failed to send API request: %v", i, err)
}
reply := new(rpc.JSONSuccessResponse)
if err := ipcClient.Recv(reply); err != nil {
t.Fatalf("test %d: failed to read API reply: %v", i, err)
}
select {
case result := <-calls:
if result != test.Result {
t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result)
}
case <-time.After(time.Second):
t.Fatalf("test %d: rpc execution timeout", i)
}
}
}