mockserver.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2018 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package mockserver
  15. import (
  16. "context"
  17. "fmt"
  18. "io/ioutil"
  19. "net"
  20. "os"
  21. "sync"
  22. pb "go.etcd.io/etcd/etcdserver/etcdserverpb"
  23. "google.golang.org/grpc"
  24. "google.golang.org/grpc/resolver"
  25. )
  26. // MockServer provides a mocked out grpc server of the etcdserver interface.
  27. type MockServer struct {
  28. ln net.Listener
  29. Network string
  30. Address string
  31. GrpcServer *grpc.Server
  32. }
  33. func (ms *MockServer) ResolverAddress() resolver.Address {
  34. switch ms.Network {
  35. case "unix":
  36. return resolver.Address{Addr: fmt.Sprintf("unix://%s", ms.Address)}
  37. case "tcp":
  38. return resolver.Address{Addr: ms.Address}
  39. default:
  40. panic("illegal network type: " + ms.Network)
  41. }
  42. }
  43. // MockServers provides a cluster of mocket out gprc servers of the etcdserver interface.
  44. type MockServers struct {
  45. mu sync.RWMutex
  46. Servers []*MockServer
  47. wg sync.WaitGroup
  48. }
  49. // StartMockServers creates the desired count of mock servers
  50. // and starts them.
  51. func StartMockServers(count int) (ms *MockServers, err error) {
  52. return StartMockServersOnNetwork(count, "tcp")
  53. }
  54. // StartMockServersOnNetwork creates mock servers on either 'tcp' or 'unix' sockets.
  55. func StartMockServersOnNetwork(count int, network string) (ms *MockServers, err error) {
  56. switch network {
  57. case "tcp":
  58. return startMockServersTcp(count)
  59. case "unix":
  60. return startMockServersUnix(count)
  61. default:
  62. return nil, fmt.Errorf("unsupported network type: %s", network)
  63. }
  64. }
  65. func startMockServersTcp(count int) (ms *MockServers, err error) {
  66. addrs := make([]string, 0, count)
  67. for i := 0; i < count; i++ {
  68. addrs = append(addrs, "localhost:0")
  69. }
  70. return startMockServers("tcp", addrs)
  71. }
  72. func startMockServersUnix(count int) (ms *MockServers, err error) {
  73. dir := os.TempDir()
  74. addrs := make([]string, 0, count)
  75. for i := 0; i < count; i++ {
  76. f, err := ioutil.TempFile(dir, "etcd-unix-so-")
  77. if err != nil {
  78. return nil, fmt.Errorf("failed to allocate temp file for unix socket: %v", err)
  79. }
  80. fn := f.Name()
  81. err = os.Remove(fn)
  82. if err != nil {
  83. return nil, fmt.Errorf("failed to remove temp file before creating unix socket: %v", err)
  84. }
  85. addrs = append(addrs, fn)
  86. }
  87. return startMockServers("unix", addrs)
  88. }
  89. func startMockServers(network string, addrs []string) (ms *MockServers, err error) {
  90. ms = &MockServers{
  91. Servers: make([]*MockServer, len(addrs)),
  92. wg: sync.WaitGroup{},
  93. }
  94. defer func() {
  95. if err != nil {
  96. ms.Stop()
  97. }
  98. }()
  99. for idx, addr := range addrs {
  100. ln, err := net.Listen(network, addr)
  101. if err != nil {
  102. return nil, fmt.Errorf("failed to listen %v", err)
  103. }
  104. ms.Servers[idx] = &MockServer{ln: ln, Network: network, Address: ln.Addr().String()}
  105. ms.StartAt(idx)
  106. }
  107. return ms, nil
  108. }
  109. // StartAt restarts mock server at given index.
  110. func (ms *MockServers) StartAt(idx int) (err error) {
  111. ms.mu.Lock()
  112. defer ms.mu.Unlock()
  113. if ms.Servers[idx].ln == nil {
  114. ms.Servers[idx].ln, err = net.Listen(ms.Servers[idx].Network, ms.Servers[idx].Address)
  115. if err != nil {
  116. return fmt.Errorf("failed to listen %v", err)
  117. }
  118. }
  119. svr := grpc.NewServer()
  120. pb.RegisterKVServer(svr, &mockKVServer{})
  121. ms.Servers[idx].GrpcServer = svr
  122. ms.wg.Add(1)
  123. go func(svr *grpc.Server, l net.Listener) {
  124. svr.Serve(l)
  125. }(ms.Servers[idx].GrpcServer, ms.Servers[idx].ln)
  126. return nil
  127. }
  128. // StopAt stops mock server at given index.
  129. func (ms *MockServers) StopAt(idx int) {
  130. ms.mu.Lock()
  131. defer ms.mu.Unlock()
  132. if ms.Servers[idx].ln == nil {
  133. return
  134. }
  135. ms.Servers[idx].GrpcServer.Stop()
  136. ms.Servers[idx].GrpcServer = nil
  137. ms.Servers[idx].ln = nil
  138. ms.wg.Done()
  139. }
  140. // Stop stops the mock server, immediately closing all open connections and listeners.
  141. func (ms *MockServers) Stop() {
  142. for idx := range ms.Servers {
  143. ms.StopAt(idx)
  144. }
  145. ms.wg.Wait()
  146. }
  147. type mockKVServer struct{}
  148. func (m *mockKVServer) Range(context.Context, *pb.RangeRequest) (*pb.RangeResponse, error) {
  149. return &pb.RangeResponse{}, nil
  150. }
  151. func (m *mockKVServer) Put(context.Context, *pb.PutRequest) (*pb.PutResponse, error) {
  152. return &pb.PutResponse{}, nil
  153. }
  154. func (m *mockKVServer) DeleteRange(context.Context, *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
  155. return &pb.DeleteRangeResponse{}, nil
  156. }
  157. func (m *mockKVServer) Txn(context.Context, *pb.TxnRequest) (*pb.TxnResponse, error) {
  158. return &pb.TxnResponse{}, nil
  159. }
  160. func (m *mockKVServer) Compact(context.Context, *pb.CompactionRequest) (*pb.CompactionResponse, error) {
  161. return &pb.CompactionResponse{}, nil
  162. }