testing.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package plugin
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "net"
  7. "net/rpc"
  8. "github.com/mitchellh/go-testing-interface"
  9. "google.golang.org/grpc"
  10. )
  11. // TestOptions allows specifying options that can affect the behavior of the
  12. // test functions
  13. type TestOptions struct {
  14. //ServerStdout causes the given value to be used in place of a blank buffer
  15. //for RPCServer's Stdout
  16. ServerStdout io.ReadCloser
  17. //ServerStderr causes the given value to be used in place of a blank buffer
  18. //for RPCServer's Stderr
  19. ServerStderr io.ReadCloser
  20. }
  21. // The testing file contains test helpers that you can use outside of
  22. // this package for making it easier to test plugins themselves.
  23. // TestConn is a helper function for returning a client and server
  24. // net.Conn connected to each other.
  25. func TestConn(t testing.T) (net.Conn, net.Conn) {
  26. // Listen to any local port. This listener will be closed
  27. // after a single connection is established.
  28. l, err := net.Listen("tcp", "127.0.0.1:0")
  29. if err != nil {
  30. t.Fatalf("err: %s", err)
  31. }
  32. // Start a goroutine to accept our client connection
  33. var serverConn net.Conn
  34. doneCh := make(chan struct{})
  35. go func() {
  36. defer close(doneCh)
  37. defer l.Close()
  38. var err error
  39. serverConn, err = l.Accept()
  40. if err != nil {
  41. t.Fatalf("err: %s", err)
  42. }
  43. }()
  44. // Connect to the server
  45. clientConn, err := net.Dial("tcp", l.Addr().String())
  46. if err != nil {
  47. t.Fatalf("err: %s", err)
  48. }
  49. // Wait for the server side to acknowledge it has connected
  50. <-doneCh
  51. return clientConn, serverConn
  52. }
  53. // TestRPCConn returns a rpc client and server connected to each other.
  54. func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) {
  55. clientConn, serverConn := TestConn(t)
  56. server := rpc.NewServer()
  57. go server.ServeConn(serverConn)
  58. client := rpc.NewClient(clientConn)
  59. return client, server
  60. }
  61. // TestPluginRPCConn returns a plugin RPC client and server that are connected
  62. // together and configured.
  63. func TestPluginRPCConn(t testing.T, ps map[string]Plugin, opts *TestOptions) (*RPCClient, *RPCServer) {
  64. // Create two net.Conns we can use to shuttle our control connection
  65. clientConn, serverConn := TestConn(t)
  66. // Start up the server
  67. server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)}
  68. if opts != nil {
  69. if opts.ServerStdout != nil {
  70. server.Stdout = opts.ServerStdout
  71. }
  72. if opts.ServerStderr != nil {
  73. server.Stderr = opts.ServerStderr
  74. }
  75. }
  76. go server.ServeConn(serverConn)
  77. // Connect the client to the server
  78. client, err := NewRPCClient(clientConn, ps)
  79. if err != nil {
  80. t.Fatalf("err: %s", err)
  81. }
  82. return client, server
  83. }
  84. // TestGRPCConn returns a gRPC client conn and grpc server that are connected
  85. // together and configured. The register function is used to register services
  86. // prior to the Serve call. This is used to test gRPC connections.
  87. func TestGRPCConn(t testing.T, register func(*grpc.Server)) (*grpc.ClientConn, *grpc.Server) {
  88. // Create a listener
  89. l, err := net.Listen("tcp", "127.0.0.1:0")
  90. if err != nil {
  91. t.Fatalf("err: %s", err)
  92. }
  93. server := grpc.NewServer()
  94. register(server)
  95. go server.Serve(l)
  96. // Connect to the server
  97. conn, err := grpc.Dial(
  98. l.Addr().String(),
  99. grpc.WithBlock(),
  100. grpc.WithInsecure())
  101. if err != nil {
  102. t.Fatalf("err: %s", err)
  103. }
  104. // Connection successful, close the listener
  105. l.Close()
  106. return conn, server
  107. }
  108. // TestPluginGRPCConn returns a plugin gRPC client and server that are connected
  109. // together and configured. This is used to test gRPC connections.
  110. func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) {
  111. // Create a listener
  112. l, err := net.Listen("tcp", "127.0.0.1:0")
  113. if err != nil {
  114. t.Fatalf("err: %s", err)
  115. }
  116. // Start up the server
  117. server := &GRPCServer{
  118. Plugins: ps,
  119. Server: DefaultGRPCServer,
  120. Stdout: new(bytes.Buffer),
  121. Stderr: new(bytes.Buffer),
  122. }
  123. if err := server.Init(); err != nil {
  124. t.Fatalf("err: %s", err)
  125. }
  126. go server.Serve(l)
  127. // Connect to the server
  128. conn, err := grpc.Dial(
  129. l.Addr().String(),
  130. grpc.WithBlock(),
  131. grpc.WithInsecure())
  132. if err != nil {
  133. t.Fatalf("err: %s", err)
  134. }
  135. brokerGRPCClient := newGRPCBrokerClient(conn)
  136. broker := newGRPCBroker(brokerGRPCClient, nil)
  137. go broker.Run()
  138. go brokerGRPCClient.StartStream()
  139. // Create the client
  140. client := &GRPCClient{
  141. Conn: conn,
  142. Plugins: ps,
  143. broker: broker,
  144. doneCtx: context.Background(),
  145. }
  146. return client, server
  147. }