| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package plugin
- import (
- "bytes"
- "context"
- "io"
- "net"
- "net/rpc"
- "github.com/mitchellh/go-testing-interface"
- hclog "github.com/hashicorp/go-hclog"
- "github.com/hashicorp/go-plugin/internal/plugin"
- "google.golang.org/grpc"
- )
- // TestOptions allows specifying options that can affect the behavior of the
- // test functions
- type TestOptions struct {
- //ServerStdout causes the given value to be used in place of a blank buffer
- //for RPCServer's Stdout
- ServerStdout io.ReadCloser
- //ServerStderr causes the given value to be used in place of a blank buffer
- //for RPCServer's Stderr
- ServerStderr io.ReadCloser
- }
- // The testing file contains test helpers that you can use outside of
- // this package for making it easier to test plugins themselves.
- // TestConn is a helper function for returning a client and server
- // net.Conn connected to each other.
- func TestConn(t testing.T) (net.Conn, net.Conn) {
- // Listen to any local port. This listener will be closed
- // after a single connection is established.
- l, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- // Start a goroutine to accept our client connection
- var serverConn net.Conn
- doneCh := make(chan struct{})
- go func() {
- defer close(doneCh)
- defer l.Close()
- var err error
- serverConn, err = l.Accept()
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- }()
- // Connect to the server
- clientConn, err := net.Dial("tcp", l.Addr().String())
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- // Wait for the server side to acknowledge it has connected
- <-doneCh
- return clientConn, serverConn
- }
- // TestRPCConn returns a rpc client and server connected to each other.
- func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) {
- clientConn, serverConn := TestConn(t)
- server := rpc.NewServer()
- go server.ServeConn(serverConn)
- client := rpc.NewClient(clientConn)
- return client, server
- }
- // TestPluginRPCConn returns a plugin RPC client and server that are connected
- // together and configured.
- func TestPluginRPCConn(t testing.T, ps map[string]Plugin, opts *TestOptions) (*RPCClient, *RPCServer) {
- // Create two net.Conns we can use to shuttle our control connection
- clientConn, serverConn := TestConn(t)
- // Start up the server
- server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)}
- if opts != nil {
- if opts.ServerStdout != nil {
- server.Stdout = opts.ServerStdout
- }
- if opts.ServerStderr != nil {
- server.Stderr = opts.ServerStderr
- }
- }
- go server.ServeConn(serverConn)
- // Connect the client to the server
- client, err := NewRPCClient(clientConn, ps)
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- return client, server
- }
- // TestGRPCConn returns a gRPC client conn and grpc server that are connected
- // together and configured. The register function is used to register services
- // prior to the Serve call. This is used to test gRPC connections.
- func TestGRPCConn(t testing.T, register func(*grpc.Server)) (*grpc.ClientConn, *grpc.Server) {
- // Create a listener
- l, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- server := grpc.NewServer()
- register(server)
- go server.Serve(l)
- // Connect to the server
- conn, err := grpc.Dial(
- l.Addr().String(),
- grpc.WithBlock(),
- grpc.WithInsecure())
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- // Connection successful, close the listener
- l.Close()
- return conn, server
- }
- // TestPluginGRPCConn returns a plugin gRPC client and server that are connected
- // together and configured. This is used to test gRPC connections.
- func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) {
- // Create a listener
- l, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- // Start up the server
- server := &GRPCServer{
- Plugins: ps,
- DoneCh: make(chan struct{}),
- Server: DefaultGRPCServer,
- Stdout: new(bytes.Buffer),
- Stderr: new(bytes.Buffer),
- logger: hclog.Default(),
- }
- if err := server.Init(); err != nil {
- t.Fatalf("err: %s", err)
- }
- go server.Serve(l)
- // Connect to the server
- conn, err := grpc.Dial(
- l.Addr().String(),
- grpc.WithBlock(),
- grpc.WithInsecure())
- if err != nil {
- t.Fatalf("err: %s", err)
- }
- brokerGRPCClient := newGRPCBrokerClient(conn)
- broker := newGRPCBroker(brokerGRPCClient, nil)
- go broker.Run()
- go brokerGRPCClient.StartStream()
- // Create the client
- client := &GRPCClient{
- Conn: conn,
- Plugins: ps,
- broker: broker,
- doneCtx: context.Background(),
- controller: plugin.NewGRPCControllerClient(conn),
- }
- return client, server
- }
|