Merge pull request #1165 from lyuxuan/service_config_pr

Expand service config support
diff --git a/Documentation/gomock-example.md b/Documentation/gomock-example.md
index fa634a7..54743e8 100644
--- a/Documentation/gomock-example.md
+++ b/Documentation/gomock-example.md
@@ -1,6 +1,8 @@
 # Mocking Service for gRPC
 
-[Example code](https://github.com/grpc/grpc-go/tree/master/examples/helloworld/mock_helloworld)
+[Example code unary RPC](https://github.com/grpc/grpc-go/tree/master/examples/helloworld/mock_helloworld)
+
+[Example code streaming RPC](https://github.com/grpc/grpc-go/tree/master/examples/route_guide/mock_routeguide)
 
 ## Why?
 
@@ -117,5 +119,64 @@
 ).Return(&helloworld.HelloReply{Message: "Mocked Interface"}, nil)
 ```
 
+## Mock streaming RPCs:
 
+For our example we consider the case of bi-directional streaming RPCs. Concretely, we'll write a test for RouteChat function from the route guide example to demonstrate how to write mocks for streams.
 
+RouteChat is a bi-directional streaming RPC, which means calling RouteChat returns a stream that can __Send__ and __Recv__ messages to  and from the server, respectively. We'll start by creating a mock of this stream interface returned by RouteChat and then we'll mock the client interface and set expectation on the method RouteChat to return our mocked stream.
+
+### Generating mocking code:
+Like before we'll use [mockgen](https://github.com/golang/mock#running-mockgen). From the `examples/route_guide` directory run:  `mockgen google.golang.org/grpc/examples/route_guide/routeguide RouteGuideClient,RouteGuide_RouteChatClient > mock_route_guide/rg_mock.go`
+
+Notice that we are mocking both client(`RouteGuideClient`) and stream(`RouteGuide_RouteChatClient`) interfaces here.
+
+This will create a file `rg_mock.go` under directory `mock_route_guide`. This file contins all the mocking code we need to write our test.
+
+In our test code, like before, we import the this mocking code along with the generated code
+
+```go
+import (
+    rgmock "google.golang.org/grpc/examples/route_guide/mock_routeguide"
+    rgpb "google.golang.org/grpc/examples/route_guide/routeguide"
+)
+```
+
+Now conside a test that takes the RouteGuide client object as a parameter, makes a RouteChat rpc call and sends a message on the resulting stream. Furthermore, this test expects to see the same message to be received on the stream. 
+
+```go
+var msg = ...
+
+// Creates a RouteChat call and sends msg on it.
+// Checks if the received message was equal to msg.
+func testRouteChat(client rgb.RouteChatClient) error{
+    ...
+}
+```
+
+We can inject our mock in here by simply passing it as an argument to the method.
+
+Creating mock for stream interface:
+
+```go
+    stream := rgmock.NewMockRouteGuide_RouteChatClient(ctrl)
+}
+```
+
+Setting Expectations:
+
+```go
+    stream.EXPECT().Send(gomock.Any()).Return(nil)
+    stream.EXPECT().Recv().Return(msg, nil)
+```
+
+Creating mock for client interface:
+
+```go
+    rgclient := rgmock.NewMockRouteGuideClient(ctrl)
+```
+
+Setting Expectations:
+
+```go
+    rgclient.EXPECT().RouteChat(gomock.Any()).Return(stream, nil)
+```
diff --git a/clientconn.go b/clientconn.go
index 9dca29c..04c1652 100644
--- a/clientconn.go
+++ b/clientconn.go
@@ -898,11 +898,14 @@
 			}
 			ac.mu.Unlock()
 			closeTransport = false
+			timer := time.NewTimer(sleepTime - time.Since(connectTime))
 			select {
-			case <-time.After(sleepTime - time.Since(connectTime)):
+			case <-timer.C:
 			case <-ac.ctx.Done():
+				timer.Stop()
 				return ac.ctx.Err()
 			}
+			timer.Stop()
 			continue
 		}
 		ac.mu.Lock()
diff --git a/examples/route_guide/mock_routeguide/rg_mock.go b/examples/route_guide/mock_routeguide/rg_mock.go
new file mode 100644
index 0000000..328c929
--- /dev/null
+++ b/examples/route_guide/mock_routeguide/rg_mock.go
@@ -0,0 +1,200 @@
+// Automatically generated by MockGen. DO NOT EDIT!
+// Source: google.golang.org/grpc/examples/route_guide/routeguide (interfaces: RouteGuideClient,RouteGuide_RouteChatClient)
+
+package mock_routeguide
+
+import (
+	gomock "github.com/golang/mock/gomock"
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+	routeguide "google.golang.org/grpc/examples/route_guide/routeguide"
+	metadata "google.golang.org/grpc/metadata"
+)
+
+// Mock of RouteGuideClient interface
+type MockRouteGuideClient struct {
+	ctrl     *gomock.Controller
+	recorder *_MockRouteGuideClientRecorder
+}
+
+// Recorder for MockRouteGuideClient (not exported)
+type _MockRouteGuideClientRecorder struct {
+	mock *MockRouteGuideClient
+}
+
+func NewMockRouteGuideClient(ctrl *gomock.Controller) *MockRouteGuideClient {
+	mock := &MockRouteGuideClient{ctrl: ctrl}
+	mock.recorder = &_MockRouteGuideClientRecorder{mock}
+	return mock
+}
+
+func (_m *MockRouteGuideClient) EXPECT() *_MockRouteGuideClientRecorder {
+	return _m.recorder
+}
+
+func (_m *MockRouteGuideClient) GetFeature(_param0 context.Context, _param1 *routeguide.Point, _param2 ...grpc.CallOption) (*routeguide.Feature, error) {
+	_s := []interface{}{_param0, _param1}
+	for _, _x := range _param2 {
+		_s = append(_s, _x)
+	}
+	ret := _m.ctrl.Call(_m, "GetFeature", _s...)
+	ret0, _ := ret[0].(*routeguide.Feature)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuideClientRecorder) GetFeature(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	_s := append([]interface{}{arg0, arg1}, arg2...)
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "GetFeature", _s...)
+}
+
+func (_m *MockRouteGuideClient) ListFeatures(_param0 context.Context, _param1 *routeguide.Rectangle, _param2 ...grpc.CallOption) (routeguide.RouteGuide_ListFeaturesClient, error) {
+	_s := []interface{}{_param0, _param1}
+	for _, _x := range _param2 {
+		_s = append(_s, _x)
+	}
+	ret := _m.ctrl.Call(_m, "ListFeatures", _s...)
+	ret0, _ := ret[0].(routeguide.RouteGuide_ListFeaturesClient)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuideClientRecorder) ListFeatures(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	_s := append([]interface{}{arg0, arg1}, arg2...)
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ListFeatures", _s...)
+}
+
+func (_m *MockRouteGuideClient) RecordRoute(_param0 context.Context, _param1 ...grpc.CallOption) (routeguide.RouteGuide_RecordRouteClient, error) {
+	_s := []interface{}{_param0}
+	for _, _x := range _param1 {
+		_s = append(_s, _x)
+	}
+	ret := _m.ctrl.Call(_m, "RecordRoute", _s...)
+	ret0, _ := ret[0].(routeguide.RouteGuide_RecordRouteClient)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuideClientRecorder) RecordRoute(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+	_s := append([]interface{}{arg0}, arg1...)
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "RecordRoute", _s...)
+}
+
+func (_m *MockRouteGuideClient) RouteChat(_param0 context.Context, _param1 ...grpc.CallOption) (routeguide.RouteGuide_RouteChatClient, error) {
+	_s := []interface{}{_param0}
+	for _, _x := range _param1 {
+		_s = append(_s, _x)
+	}
+	ret := _m.ctrl.Call(_m, "RouteChat", _s...)
+	ret0, _ := ret[0].(routeguide.RouteGuide_RouteChatClient)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuideClientRecorder) RouteChat(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+	_s := append([]interface{}{arg0}, arg1...)
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "RouteChat", _s...)
+}
+
+// Mock of RouteGuide_RouteChatClient interface
+type MockRouteGuide_RouteChatClient struct {
+	ctrl     *gomock.Controller
+	recorder *_MockRouteGuide_RouteChatClientRecorder
+}
+
+// Recorder for MockRouteGuide_RouteChatClient (not exported)
+type _MockRouteGuide_RouteChatClientRecorder struct {
+	mock *MockRouteGuide_RouteChatClient
+}
+
+func NewMockRouteGuide_RouteChatClient(ctrl *gomock.Controller) *MockRouteGuide_RouteChatClient {
+	mock := &MockRouteGuide_RouteChatClient{ctrl: ctrl}
+	mock.recorder = &_MockRouteGuide_RouteChatClientRecorder{mock}
+	return mock
+}
+
+func (_m *MockRouteGuide_RouteChatClient) EXPECT() *_MockRouteGuide_RouteChatClientRecorder {
+	return _m.recorder
+}
+
+func (_m *MockRouteGuide_RouteChatClient) CloseSend() error {
+	ret := _m.ctrl.Call(_m, "CloseSend")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) CloseSend() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "CloseSend")
+}
+
+func (_m *MockRouteGuide_RouteChatClient) Context() context.Context {
+	ret := _m.ctrl.Call(_m, "Context")
+	ret0, _ := ret[0].(context.Context)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) Context() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Context")
+}
+
+func (_m *MockRouteGuide_RouteChatClient) Header() (metadata.MD, error) {
+	ret := _m.ctrl.Call(_m, "Header")
+	ret0, _ := ret[0].(metadata.MD)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) Header() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Header")
+}
+
+func (_m *MockRouteGuide_RouteChatClient) Recv() (*routeguide.RouteNote, error) {
+	ret := _m.ctrl.Call(_m, "Recv")
+	ret0, _ := ret[0].(*routeguide.RouteNote)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) Recv() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Recv")
+}
+
+func (_m *MockRouteGuide_RouteChatClient) RecvMsg(_param0 interface{}) error {
+	ret := _m.ctrl.Call(_m, "RecvMsg", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) RecvMsg(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "RecvMsg", arg0)
+}
+
+func (_m *MockRouteGuide_RouteChatClient) Send(_param0 *routeguide.RouteNote) error {
+	ret := _m.ctrl.Call(_m, "Send", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) Send(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Send", arg0)
+}
+
+func (_m *MockRouteGuide_RouteChatClient) SendMsg(_param0 interface{}) error {
+	ret := _m.ctrl.Call(_m, "SendMsg", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) SendMsg(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "SendMsg", arg0)
+}
+
+func (_m *MockRouteGuide_RouteChatClient) Trailer() metadata.MD {
+	ret := _m.ctrl.Call(_m, "Trailer")
+	ret0, _ := ret[0].(metadata.MD)
+	return ret0
+}
+
+func (_mr *_MockRouteGuide_RouteChatClientRecorder) Trailer() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Trailer")
+}
diff --git a/examples/route_guide/mock_routeguide/rg_mock_test.go b/examples/route_guide/mock_routeguide/rg_mock_test.go
new file mode 100644
index 0000000..247399b
--- /dev/null
+++ b/examples/route_guide/mock_routeguide/rg_mock_test.go
@@ -0,0 +1,64 @@
+package mock_routeguide_test
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	"github.com/golang/protobuf/proto"
+	"golang.org/x/net/context"
+	rgmock "google.golang.org/grpc/examples/route_guide/mock_routeguide"
+	rgpb "google.golang.org/grpc/examples/route_guide/routeguide"
+)
+
+var (
+	msg = &rgpb.RouteNote{
+		Location: &rgpb.Point{Latitude: 17, Longitude: 29},
+		Message:  "Taxi-cab",
+	}
+)
+
+func TestRouteChat(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	// Create mock for the stream returned by RouteChat
+	stream := rgmock.NewMockRouteGuide_RouteChatClient(ctrl)
+	// set expectation on sending.
+	stream.EXPECT().Send(
+		gomock.Any(),
+	).Return(nil)
+	// Set expectation on receiving.
+	stream.EXPECT().Recv().Return(msg, nil)
+	stream.EXPECT().CloseSend().Return(nil)
+	// Create mock for the client interface.
+	rgclient := rgmock.NewMockRouteGuideClient(ctrl)
+	// Set expectation on RouteChat
+	rgclient.EXPECT().RouteChat(
+		gomock.Any(),
+	).Return(stream, nil)
+	if err := testRouteChat(rgclient); err != nil {
+		t.Fatalf("Test failed: %v", err)
+	}
+}
+
+func testRouteChat(client rgpb.RouteGuideClient) error {
+	stream, err := client.RouteChat(context.Background())
+	if err != nil {
+		return err
+	}
+	if err := stream.Send(msg); err != nil {
+		return err
+	}
+	if err := stream.CloseSend(); err != nil {
+		return err
+	}
+	got, err := stream.Recv()
+	if err != nil {
+		return err
+	}
+	if !proto.Equal(got, msg) {
+		return fmt.Errorf("stream.Recv() = %v, want %v", got, msg)
+	}
+	return nil
+}
diff --git a/grpclb.go b/grpclb.go
index 0e4d269..8638fc9 100644
--- a/grpclb.go
+++ b/grpclb.go
@@ -745,6 +745,9 @@
 func (b *balancer) Close() error {
 	b.mu.Lock()
 	defer b.mu.Unlock()
+	if b.done {
+		return errBalancerClosed
+	}
 	b.done = true
 	if b.expTimer != nil {
 		b.expTimer.Stop()
diff --git a/server.go b/server.go
index 62f4149..c2b523c 100644
--- a/server.go
+++ b/server.go
@@ -467,10 +467,12 @@
 				s.mu.Lock()
 				s.printf("Accept error: %v; retrying in %v", err, tempDelay)
 				s.mu.Unlock()
+				timer := time.NewTimer(tempDelay)
 				select {
-				case <-time.After(tempDelay):
+				case <-timer.C:
 				case <-s.ctx.Done():
 				}
+				timer.Stop()
 				continue
 			}
 			s.mu.Lock()