| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	testNodeKey, _ = crypto.GenerateKey() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | func testNodeConfig() *Config { | 
					
						
							|  |  |  | 	return &Config{ | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 		Name: "test node", | 
					
						
							|  |  |  | 		P2P:  p2p.Config{PrivateKey: testNodeKey}, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that an empty protocol stack can be started, restarted and stopped. | 
					
						
							|  |  |  | func TestNodeLifeCycle(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that a stopped node can be stopped again | 
					
						
							|  |  |  | 	for i := 0; i < 3; i++ { | 
					
						
							|  |  |  | 		if err := stack.Stop(); err != ErrNodeStopped { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that a node can be successfully started, but only once | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := stack.Start(); err != ErrNodeRunning { | 
					
						
							|  |  |  | 		t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that a node can be restarted arbitrarily many times | 
					
						
							|  |  |  | 	for i := 0; i < 3; i++ { | 
					
						
							|  |  |  | 		if err := stack.Restart(); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: failed to restart node: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that a node can be stopped, but only once | 
					
						
							|  |  |  | 	if err := stack.Stop(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to stop node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := stack.Stop(); err != ErrNodeStopped { | 
					
						
							|  |  |  | 		t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that if the data dir is already in use, an appropriate error is returned. | 
					
						
							|  |  |  | func TestNodeUsedDataDir(t *testing.T) { | 
					
						
							|  |  |  | 	// Create a temporary folder to use as the data directory | 
					
						
							|  |  |  | 	dir, err := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create temporary data directory: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a new node based on the data directory | 
					
						
							|  |  |  | 	original, err := New(&Config{DataDir: dir}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create original protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := original.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start original protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer original.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a second node based on the same data directory and ensure failure | 
					
						
							|  |  |  | 	duplicate, err := New(&Config{DataDir: dir}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create duplicate protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := duplicate.Start(); err != ErrDatadirUsed { | 
					
						
							|  |  |  | 		t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | // Tests whether services can be registered and duplicates caught. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | func TestServiceRegistry(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	// Register a batch of unique services and ensure they start successfully | 
					
						
							|  |  |  | 	services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC} | 
					
						
							|  |  |  | 	for i, constructor := range services { | 
					
						
							|  |  |  | 		if err := stack.Register(constructor); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("service #%d: registration failed: %v", i, err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start original service stack: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Stop(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to stop original service stack: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	// Duplicate one of the services and retry starting the node | 
					
						
							|  |  |  | 	if err := stack.Register(NewNoopServiceB); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("duplicate registration failed: %v", err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Start(); err == nil { | 
					
						
							|  |  |  | 		t.Fatalf("duplicate service started") | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if _, ok := err.(*DuplicateServiceError); !ok { | 
					
						
							|  |  |  | 			t.Fatalf("duplicate error mismatch: have %v, want %v", err, DuplicateServiceError{}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that registered services get started and stopped correctly. | 
					
						
							|  |  |  | func TestServiceLifeCycle(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a batch of life-cycle instrumented services | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := map[string]InstrumentingWrapper{ | 
					
						
							|  |  |  | 		"A": InstrumentedServiceMakerA, | 
					
						
							|  |  |  | 		"B": InstrumentedServiceMakerB, | 
					
						
							|  |  |  | 		"C": InstrumentedServiceMakerC, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							|  |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for id, maker := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		id := id // Closure for the constructor | 
					
						
							|  |  |  | 		constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 			return &InstrumentedService{ | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 				startHook: func(*p2p.Server) { started[id] = true }, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 				stopHook:  func() { stopped[id] = true }, | 
					
						
							|  |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		if err := stack.Register(maker(constructor)); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: registration failed: %v", id, err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the node and check that all services are running | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 	for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		if !started[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			t.Fatalf("service %s: freshly started service not running", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if stopped[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			t.Fatalf("service %s: freshly started service already stopped", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Stop the node and check that all services have been stopped | 
					
						
							|  |  |  | 	if err := stack.Stop(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to stop protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 	for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		if !stopped[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			t.Fatalf("service %s: freshly terminated service still running", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that services are restarted cleanly as new instances. | 
					
						
							|  |  |  | func TestServiceRestarts(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Define a service that does not support restarts | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		running bool | 
					
						
							|  |  |  | 		started int | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 		running = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return &InstrumentedService{ | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 			startHook: func(*p2p.Server) { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 				if running { | 
					
						
							|  |  |  | 					panic("already running") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				running = true | 
					
						
							|  |  |  | 				started++ | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register the service and start the protocol stack | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(constructor); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("failed to register the service: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer stack.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 16:55:03 +01:00
										 |  |  | 	if !running || started != 1 { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Restart the stack a few times and check successful service restarts | 
					
						
							|  |  |  | 	for i := 0; i < 3; i++ { | 
					
						
							|  |  |  | 		if err := stack.Restart(); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: failed to restart stack: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-06 16:44:20 +01:00
										 |  |  | 	if !running || started != 4 { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Define a batch of good services | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := map[string]InstrumentingWrapper{ | 
					
						
							|  |  |  | 		"A": InstrumentedServiceMakerA, | 
					
						
							|  |  |  | 		"B": InstrumentedServiceMakerB, | 
					
						
							|  |  |  | 		"C": InstrumentedServiceMakerC, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for id, maker := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		id := id // Closure for the constructor | 
					
						
							|  |  |  | 		constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 			return &InstrumentedService{ | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 				startHook: func(*p2p.Server) { started[id] = true }, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		if err := stack.Register(maker(constructor)); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: registration failed: %v", id, err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a service that fails to construct itself | 
					
						
							|  |  |  | 	failure := errors.New("fail") | 
					
						
							|  |  |  | 	failer := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 		return nil, failure | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(failer); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("failer registration failed: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the protocol stack and ensure none of the services get started | 
					
						
							|  |  |  | 	for i := 0; i < 100; i++ { | 
					
						
							|  |  |  | 		if err := stack.Start(); err != failure { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			if started[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 				t.Fatalf("service %s: started should not have", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			delete(started, id) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that if a service fails to start, all others started before it will be | 
					
						
							|  |  |  | // shut down. | 
					
						
							|  |  |  | func TestServiceStartupAbortion(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a batch of good services | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := map[string]InstrumentingWrapper{ | 
					
						
							|  |  |  | 		"A": InstrumentedServiceMakerA, | 
					
						
							|  |  |  | 		"B": InstrumentedServiceMakerB, | 
					
						
							|  |  |  | 		"C": InstrumentedServiceMakerC, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							|  |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for id, maker := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		id := id // Closure for the constructor | 
					
						
							|  |  |  | 		constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 			return &InstrumentedService{ | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 				startHook: func(*p2p.Server) { started[id] = true }, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 				stopHook:  func() { stopped[id] = true }, | 
					
						
							|  |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		if err := stack.Register(maker(constructor)); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: registration failed: %v", id, err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a service that fails to start | 
					
						
							|  |  |  | 	failure := errors.New("fail") | 
					
						
							|  |  |  | 	failer := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 		return &InstrumentedService{ | 
					
						
							|  |  |  | 			start: failure, | 
					
						
							|  |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(failer); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("failer registration failed: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the protocol stack and ensure all started services stop | 
					
						
							|  |  |  | 	for i := 0; i < 100; i++ { | 
					
						
							|  |  |  | 		if err := stack.Start(); err != failure { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			if started[id] && !stopped[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 				t.Fatalf("service %s: started but not stopped", id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			delete(started, id) | 
					
						
							|  |  |  | 			delete(stopped, id) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a batch of good services | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := map[string]InstrumentingWrapper{ | 
					
						
							|  |  |  | 		"A": InstrumentedServiceMakerA, | 
					
						
							|  |  |  | 		"B": InstrumentedServiceMakerB, | 
					
						
							|  |  |  | 		"C": InstrumentedServiceMakerC, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	started := make(map[string]bool) | 
					
						
							|  |  |  | 	stopped := make(map[string]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for id, maker := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		id := id // Closure for the constructor | 
					
						
							|  |  |  | 		constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 			return &InstrumentedService{ | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 				startHook: func(*p2p.Server) { started[id] = true }, | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 				stopHook:  func() { stopped[id] = true }, | 
					
						
							|  |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		if err := stack.Register(maker(constructor)); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("service %s: registration failed: %v", id, err) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a service that fails to shot down cleanly | 
					
						
							|  |  |  | 	failure := errors.New("fail") | 
					
						
							|  |  |  | 	failer := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 		return &InstrumentedService{ | 
					
						
							|  |  |  | 			stop: failure, | 
					
						
							|  |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(failer); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		t.Fatalf("failer registration failed: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the protocol stack, and ensure that a failing shut down terminates all | 
					
						
							|  |  |  | 	for i := 0; i < 100; i++ { | 
					
						
							|  |  |  | 		// Start the stack and make sure all is online | 
					
						
							|  |  |  | 		if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: failed to start protocol stack: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			if !started[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 				t.Fatalf("iter %d, service %s: service not running", i, id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if stopped[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 				t.Fatalf("iter %d, service %s: service already stopped", i, id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Stop the stack, verify failure and check all terminations | 
					
						
							|  |  |  | 		err := stack.Stop() | 
					
						
							|  |  |  | 		if err, ok := err.(*StopError); !ok { | 
					
						
							|  |  |  | 			t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			failer := reflect.TypeOf(&InstrumentedService{}) | 
					
						
							|  |  |  | 			if err.Services[failer] != failure { | 
					
						
							|  |  |  | 				t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if len(err.Services) != 1 { | 
					
						
							|  |  |  | 				t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for id := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			if !stopped[id] { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 				t.Fatalf("iter %d, service %s: service not terminated", i, id) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			delete(started, id) | 
					
						
							|  |  |  | 			delete(stopped, id) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | // TestServiceRetrieval tests that individual services can be retrieved. | 
					
						
							|  |  |  | func TestServiceRetrieval(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	// Create a simple stack and register two service types | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(NewNoopService); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		t.Fatalf("noop service registration failed: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Register(NewInstrumentedService); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		t.Fatalf("instrumented service registration failed: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Make sure none of the services can be retrieved until started | 
					
						
							|  |  |  | 	var noopServ *NoopService | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Service(&noopServ); err != ErrNodeStopped { | 
					
						
							|  |  |  | 		t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	var instServ *InstrumentedService | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Service(&instServ); err != ErrNodeStopped { | 
					
						
							|  |  |  | 		t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Start the stack and ensure everything is retrievable now | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer stack.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Service(&noopServ); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	if err := stack.Service(&instServ); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil) | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Tests that all protocols defined by individual services get launched. | 
					
						
							|  |  |  | func TestProtocolGather(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	stack, err := New(testNodeConfig()) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to create protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register a batch of services with some configured number of protocols | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := map[string]struct { | 
					
						
							|  |  |  | 		Count int | 
					
						
							|  |  |  | 		Maker InstrumentingWrapper | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"Zero Protocols":  {0, InstrumentedServiceMakerA}, | 
					
						
							|  |  |  | 		"Single Protocol": {1, InstrumentedServiceMakerB}, | 
					
						
							|  |  |  | 		"Many Protocols":  {25, InstrumentedServiceMakerC}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for id, config := range services { | 
					
						
							|  |  |  | 		protocols := make([]p2p.Protocol, config.Count) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		for i := 0; i < len(protocols); i++ { | 
					
						
							|  |  |  | 			protocols[i].Name = id | 
					
						
							|  |  |  | 			protocols[i].Version = uint(i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		constructor := func(*ServiceContext) (Service, error) { | 
					
						
							|  |  |  | 			return &InstrumentedService{ | 
					
						
							|  |  |  | 				protocols: protocols, | 
					
						
							|  |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		if err := stack.Register(config.Maker(constructor)); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			t.Fatalf("service %s: registration failed: %v", id, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the services and ensure all protocols start successfully | 
					
						
							|  |  |  | 	if err := stack.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("failed to start protocol stack: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer stack.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	protocols := stack.Server().Protocols | 
					
						
							|  |  |  | 	if len(protocols) != 26 { | 
					
						
							|  |  |  | 		t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for id, config := range services { | 
					
						
							|  |  |  | 		for ver := 0; ver < config.Count; ver++ { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			launched := false | 
					
						
							|  |  |  | 			for i := 0; i < len(protocols); i++ { | 
					
						
							|  |  |  | 				if protocols[i].Name == id && protocols[i].Version == uint(ver) { | 
					
						
							|  |  |  | 					launched = true | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !launched { | 
					
						
							|  |  |  | 				t.Errorf("configured protocol not launched: %s v%d", id, ver) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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) | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | 	makeAPI := func(result string) *OneMethodApi { | 
					
						
							|  |  |  | 		return &OneMethodApi{fun: func() { calls <- result }} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	services := map[string]struct { | 
					
						
							|  |  |  | 		APIs  []rpc.API | 
					
						
							|  |  |  | 		Maker InstrumentingWrapper | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | 		"Zero APIs": { | 
					
						
							|  |  |  | 			[]rpc.API{}, InstrumentedServiceMakerA}, | 
					
						
							|  |  |  | 		"Single API": { | 
					
						
							|  |  |  | 			[]rpc.API{ | 
					
						
							|  |  |  | 				{Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true}, | 
					
						
							|  |  |  | 			}, InstrumentedServiceMakerB}, | 
					
						
							|  |  |  | 		"Many APIs": { | 
					
						
							|  |  |  | 			[]rpc.API{ | 
					
						
							|  |  |  | 				{Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true}, | 
					
						
							|  |  |  | 				{Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true}, | 
					
						
							|  |  |  | 				{Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true}, | 
					
						
							|  |  |  | 			}, InstrumentedServiceMakerC}, | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 	client, err := stack.Attach() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 		t.Fatalf("failed to connect to the inproc API server: %v", err) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 	defer client.Close() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | 		if err := client.Call(nil, test.Method); err != nil { | 
					
						
							|  |  |  | 			t.Errorf("test %d: API request failed: %v", i, err) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |