github.com/hashicorp/go-plugin@v1.6.0/plugin_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package plugin
     5  
     6  import (
     7  	"context"
     8  	"crypto/tls"
     9  	"crypto/x509"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"log"
    15  	"net/rpc"
    16  	"os"
    17  	"os/exec"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/golang/protobuf/ptypes/empty"
    22  	"github.com/hashicorp/go-hclog"
    23  	grpctest "github.com/hashicorp/go-plugin/test/grpc"
    24  	"google.golang.org/grpc"
    25  )
    26  
    27  // Test that NetRPCUnsupportedPlugin implements the correct interfaces.
    28  var _ Plugin = new(NetRPCUnsupportedPlugin)
    29  
    30  var testHandshake = HandshakeConfig{
    31  	ProtocolVersion:  1,
    32  	MagicCookieKey:   "TEST_MAGIC_COOKIE",
    33  	MagicCookieValue: "test",
    34  }
    35  
    36  var testVersionedHandshake = HandshakeConfig{
    37  	MagicCookieKey:   "TEST_MAGIC_COOKIE",
    38  	MagicCookieValue: "test",
    39  }
    40  
    41  // testInterface is the test interface we use for plugins.
    42  type testInterface interface {
    43  	Double(int) int
    44  	PrintKV(string, interface{})
    45  	Bidirectional() error
    46  	PrintStdio(stdout, stderr []byte)
    47  }
    48  
    49  // testStreamer is used to test the grpc streaming interface
    50  type testStreamer interface {
    51  	Stream(int32, int32) ([]int32, error)
    52  }
    53  
    54  // testInterfacePlugin implements the Plugin interface
    55  var _ Plugin = (*testInterfacePlugin)(nil)
    56  
    57  // testInterfacePlugin is the implementation of Plugin to create
    58  // RPC client/server implementations for testInterface.
    59  type testInterfacePlugin struct {
    60  	Impl testInterface
    61  }
    62  
    63  func (p *testInterfacePlugin) Server(b *MuxBroker) (interface{}, error) {
    64  	return &testInterfaceServer{Impl: p.impl()}, nil
    65  }
    66  
    67  func (p *testInterfacePlugin) Client(b *MuxBroker, c *rpc.Client) (interface{}, error) {
    68  	return &testInterfaceClient{Client: c}, nil
    69  }
    70  
    71  func (p *testInterfacePlugin) impl() testInterface {
    72  	if p.Impl != nil {
    73  		return p.Impl
    74  	}
    75  
    76  	return &testInterfaceImpl{
    77  		logger: hclog.New(&hclog.LoggerOptions{
    78  			Level:      hclog.Trace,
    79  			Output:     os.Stderr,
    80  			JSONFormat: true,
    81  		}),
    82  	}
    83  }
    84  
    85  // testGRPCInterfacePlugin implements both Plugin and GRPCPlugin interfaces
    86  var _ Plugin = (*testGRPCInterfacePlugin)(nil)
    87  var _ GRPCPlugin = (*testGRPCInterfacePlugin)(nil)
    88  
    89  // testGRPCInterfacePlugin is a test implementation of the GRPCPlugin interface
    90  type testGRPCInterfacePlugin struct {
    91  	Impl testInterface
    92  }
    93  
    94  func (p *testGRPCInterfacePlugin) Server(b *MuxBroker) (interface{}, error) {
    95  	return &testInterfaceServer{Impl: p.impl()}, nil
    96  }
    97  
    98  func (p *testGRPCInterfacePlugin) Client(b *MuxBroker, c *rpc.Client) (interface{}, error) {
    99  	return &testInterfaceClient{Client: c}, nil
   100  }
   101  
   102  func (p *testGRPCInterfacePlugin) GRPCServer(b *GRPCBroker, s *grpc.Server) error {
   103  	grpctest.RegisterTestServer(s, &testGRPCServer{broker: b, Impl: p.impl()})
   104  	return nil
   105  }
   106  
   107  func (p *testGRPCInterfacePlugin) GRPCClient(doneCtx context.Context, b *GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
   108  	return &testGRPCClient{broker: b, Client: grpctest.NewTestClient(c)}, nil
   109  }
   110  
   111  func (p *testGRPCInterfacePlugin) impl() testInterface {
   112  	if p.Impl != nil {
   113  		return p.Impl
   114  	}
   115  
   116  	return &testInterfaceImpl{
   117  		logger: hclog.New(&hclog.LoggerOptions{
   118  			Level:      hclog.Trace,
   119  			Output:     os.Stderr,
   120  			JSONFormat: true,
   121  		}),
   122  	}
   123  }
   124  
   125  // testInterfaceImpl implements testInterface concretely
   126  var _ testInterface = (*testInterfaceImpl)(nil)
   127  
   128  type testInterfaceImpl struct {
   129  	logger hclog.Logger
   130  }
   131  
   132  func (i *testInterfaceImpl) Double(v int) int { return v * 2 }
   133  
   134  func (i *testInterfaceImpl) PrintKV(key string, value interface{}) {
   135  	i.logger.Info("PrintKV called", key, value)
   136  }
   137  
   138  func (i *testInterfaceImpl) Bidirectional() error {
   139  	return nil
   140  }
   141  
   142  func (i *testInterfaceImpl) PrintStdio(stdout, stderr []byte) {
   143  	if len(stdout) > 0 {
   144  		fmt.Fprint(os.Stdout, string(stdout))
   145  		os.Stdout.Sync()
   146  	}
   147  
   148  	if len(stderr) > 0 {
   149  		fmt.Fprint(os.Stderr, string(stderr))
   150  		os.Stderr.Sync()
   151  	}
   152  }
   153  
   154  // testInterfaceClient implements testInterface to communicate over RPC
   155  type testInterfaceClient struct {
   156  	Client *rpc.Client
   157  }
   158  
   159  func (impl *testInterfaceClient) Double(v int) int {
   160  	var resp int
   161  	err := impl.Client.Call("Plugin.Double", v, &resp)
   162  	if err != nil {
   163  		panic(err)
   164  	}
   165  
   166  	return resp
   167  }
   168  
   169  func (impl *testInterfaceClient) PrintKV(key string, value interface{}) {
   170  	err := impl.Client.Call("Plugin.PrintKV", map[string]interface{}{
   171  		"key":   key,
   172  		"value": value,
   173  	}, &struct{}{})
   174  	if err != nil {
   175  		panic(err)
   176  	}
   177  }
   178  
   179  func (impl *testInterfaceClient) Bidirectional() error {
   180  	return nil
   181  }
   182  
   183  func (impl *testInterfaceClient) PrintStdio(stdout, stderr []byte) {
   184  	// We don't implement this because we test stream syncing another
   185  	// way (see rpc_client_test.go). We probably should test this way
   186  	// but very few people use the net/rpc protocol nowadays so we didn'
   187  	// put in the effort.
   188  	return
   189  }
   190  
   191  // testInterfaceServer is the RPC server for testInterfaceClient
   192  type testInterfaceServer struct {
   193  	Broker *MuxBroker
   194  	Impl   testInterface
   195  }
   196  
   197  func (s *testInterfaceServer) Double(arg int, resp *int) error {
   198  	*resp = s.Impl.Double(arg)
   199  	return nil
   200  }
   201  
   202  func (s *testInterfaceServer) PrintKV(args map[string]interface{}, _ *struct{}) error {
   203  	s.Impl.PrintKV(args["key"].(string), args["value"])
   204  	return nil
   205  }
   206  
   207  // testPluginMap can be used for tests as a plugin map
   208  var testPluginMap = map[string]Plugin{
   209  	"test": new(testInterfacePlugin),
   210  }
   211  
   212  // testGRPCPluginMap can be used for tests as that need a GRPC plugin
   213  var testGRPCPluginMap = map[string]Plugin{
   214  	"test": new(testGRPCInterfacePlugin),
   215  }
   216  
   217  // testGRPCServer is the implementation of our GRPC service.
   218  type testGRPCServer struct {
   219  	Impl   testInterface
   220  	broker *GRPCBroker
   221  }
   222  
   223  func (s *testGRPCServer) Double(
   224  	ctx context.Context,
   225  	req *grpctest.TestRequest) (*grpctest.TestResponse, error) {
   226  	return &grpctest.TestResponse{
   227  		Output: int32(s.Impl.Double(int(req.Input))),
   228  	}, nil
   229  }
   230  
   231  func (s *testGRPCServer) PrintKV(
   232  	ctx context.Context,
   233  	req *grpctest.PrintKVRequest) (*grpctest.PrintKVResponse, error) {
   234  	var v interface{}
   235  	switch rv := req.Value.(type) {
   236  	case *grpctest.PrintKVRequest_ValueString:
   237  		v = rv.ValueString
   238  
   239  	case *grpctest.PrintKVRequest_ValueInt:
   240  		v = rv.ValueInt
   241  
   242  	default:
   243  		panic(fmt.Sprintf("unknown value: %#v", req.Value))
   244  	}
   245  
   246  	s.Impl.PrintKV(req.Key, v)
   247  	return &grpctest.PrintKVResponse{}, nil
   248  }
   249  
   250  func (s *testGRPCServer) Bidirectional(ctx context.Context, req *grpctest.BidirectionalRequest) (*grpctest.BidirectionalResponse, error) {
   251  	conn, err := s.broker.Dial(req.Id)
   252  	if err != nil {
   253  		return nil, fmt.Errorf("server dial error: %w", err)
   254  	}
   255  
   256  	pingPongClient := grpctest.NewPingPongClient(conn)
   257  	resp, err := pingPongClient.Ping(ctx, &grpctest.PingRequest{})
   258  	if err != nil {
   259  		return nil, fmt.Errorf("server Ping() error: %w", err)
   260  	}
   261  	if resp.Msg != "pong" {
   262  		return nil, errors.New("server Bad PingPong")
   263  	}
   264  
   265  	nextID := s.broker.NextId()
   266  	go s.broker.AcceptAndServe(nextID, func(opts []grpc.ServerOption) *grpc.Server {
   267  		s := grpc.NewServer(opts...)
   268  		grpctest.RegisterPingPongServer(s, &pingPongServer{})
   269  		return s
   270  	})
   271  
   272  	return &grpctest.BidirectionalResponse{
   273  		Id: nextID,
   274  	}, nil
   275  }
   276  
   277  func (s *testGRPCServer) PrintStdio(
   278  	ctx context.Context,
   279  	req *grpctest.PrintStdioRequest,
   280  ) (*empty.Empty, error) {
   281  	s.Impl.PrintStdio(req.Stdout, req.Stderr)
   282  	return &empty.Empty{}, nil
   283  }
   284  
   285  type pingPongServer struct{}
   286  
   287  func (p *pingPongServer) Ping(ctx context.Context, req *grpctest.PingRequest) (*grpctest.PongResponse, error) {
   288  	return &grpctest.PongResponse{
   289  		Msg: "pong",
   290  	}, nil
   291  }
   292  
   293  func (s testGRPCServer) Stream(stream grpctest.Test_StreamServer) error {
   294  	for {
   295  		req, err := stream.Recv()
   296  		if err != nil {
   297  			if err != io.EOF {
   298  				return err
   299  			}
   300  			return nil
   301  		}
   302  
   303  		if err := stream.Send(&grpctest.TestResponse{Output: req.Input}); err != nil {
   304  			return err
   305  		}
   306  	}
   307  
   308  	return nil
   309  }
   310  
   311  // testGRPCClient is an implementation of TestInterface that communicates
   312  // over gRPC.
   313  type testGRPCClient struct {
   314  	Client grpctest.TestClient
   315  	broker *GRPCBroker
   316  }
   317  
   318  func (c *testGRPCClient) Double(v int) int {
   319  	resp, err := c.Client.Double(context.Background(), &grpctest.TestRequest{
   320  		Input: int32(v),
   321  	})
   322  	if err != nil {
   323  		panic(err)
   324  	}
   325  
   326  	return int(resp.Output)
   327  }
   328  
   329  func (c *testGRPCClient) PrintKV(key string, value interface{}) {
   330  	req := &grpctest.PrintKVRequest{Key: key}
   331  	switch v := value.(type) {
   332  	case string:
   333  		req.Value = &grpctest.PrintKVRequest_ValueString{
   334  			ValueString: v,
   335  		}
   336  
   337  	case int:
   338  		req.Value = &grpctest.PrintKVRequest_ValueInt{
   339  			ValueInt: int32(v),
   340  		}
   341  
   342  	default:
   343  		panic(fmt.Sprintf("unknown type: %T", value))
   344  	}
   345  
   346  	_, err := c.Client.PrintKV(context.Background(), req)
   347  	if err != nil {
   348  		panic(err)
   349  	}
   350  }
   351  
   352  func (c *testGRPCClient) Bidirectional() error {
   353  	nextID := c.broker.NextId()
   354  	go c.broker.AcceptAndServe(nextID, func(opts []grpc.ServerOption) *grpc.Server {
   355  		s := grpc.NewServer(opts...)
   356  		grpctest.RegisterPingPongServer(s, &pingPongServer{})
   357  		return s
   358  	})
   359  
   360  	resp, err := c.Client.Bidirectional(context.Background(), &grpctest.BidirectionalRequest{
   361  		Id: nextID,
   362  	})
   363  	if err != nil {
   364  		return fmt.Errorf("client Bidirectional() error: %w", err)
   365  	}
   366  
   367  	conn, err := c.broker.Dial(resp.Id)
   368  	if err != nil {
   369  		return fmt.Errorf("client dial error: %w", err)
   370  	}
   371  
   372  	pingPongClient := grpctest.NewPingPongClient(conn)
   373  	pResp, err := pingPongClient.Ping(context.Background(), &grpctest.PingRequest{})
   374  	if err != nil {
   375  		return fmt.Errorf("client Ping() error: %w", err)
   376  	}
   377  	if pResp.Msg != "pong" {
   378  		return errors.New("client Bad PingPong")
   379  	}
   380  	return nil
   381  }
   382  
   383  // Stream sends a series of requests from [start, stop) using a bidirectional
   384  // streaming service, and returns the streamed responses.
   385  func (impl *testGRPCClient) Stream(start, stop int32) ([]int32, error) {
   386  	if stop <= start {
   387  		return nil, fmt.Errorf("invalid range [%d, %d)", start, stop)
   388  	}
   389  	streamClient, err := impl.Client.Stream(context.Background())
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  
   394  	var resp []int32
   395  	for i := start; i < stop; i++ {
   396  		if err := streamClient.Send(&grpctest.TestRequest{Input: i}); err != nil {
   397  			return resp, err
   398  		}
   399  
   400  		out, err := streamClient.Recv()
   401  		if err != nil {
   402  			return resp, err
   403  		}
   404  
   405  		resp = append(resp, out.Output)
   406  	}
   407  
   408  	streamClient.CloseSend()
   409  
   410  	return resp, nil
   411  }
   412  
   413  func (c *testGRPCClient) PrintStdio(stdout, stderr []byte) {
   414  	_, err := c.Client.PrintStdio(context.Background(), &grpctest.PrintStdioRequest{
   415  		Stdout: stdout,
   416  		Stderr: stderr,
   417  	})
   418  	if err != nil {
   419  		panic(err)
   420  	}
   421  }
   422  
   423  func helperProcess(s ...string) *exec.Cmd {
   424  	cs := []string{"-test.run=TestHelperProcess", "--"}
   425  	cs = append(cs, s...)
   426  	env := []string{
   427  		"GO_WANT_HELPER_PROCESS=1",
   428  	}
   429  
   430  	cmd := exec.Command(os.Args[0], cs...)
   431  	cmd.Env = append(env, os.Environ()...)
   432  	return cmd
   433  }
   434  
   435  // This is not a real test. This is just a helper process kicked off by
   436  // tests.
   437  func TestHelperProcess(*testing.T) {
   438  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   439  		return
   440  	}
   441  
   442  	defer os.Exit(0)
   443  
   444  	args := os.Args
   445  	for len(args) > 0 {
   446  		if args[0] == "--" {
   447  			args = args[1:]
   448  			break
   449  		}
   450  
   451  		args = args[1:]
   452  	}
   453  
   454  	if len(args) == 0 {
   455  		fmt.Fprintf(os.Stderr, "No command\n")
   456  		os.Exit(2)
   457  	}
   458  
   459  	// override testPluginMap with one that uses
   460  	// hclog logger on its implementation
   461  	pluginLogger := hclog.New(&hclog.LoggerOptions{
   462  		Level:      hclog.Trace,
   463  		Output:     os.Stderr,
   464  		JSONFormat: true,
   465  	})
   466  
   467  	testPlugin := &testInterfaceImpl{
   468  		logger: pluginLogger,
   469  	}
   470  
   471  	testPluginMap := map[string]Plugin{
   472  		"test": &testInterfacePlugin{Impl: testPlugin},
   473  	}
   474  
   475  	testGRPCPluginMap := map[string]Plugin{
   476  		"test": &testGRPCInterfacePlugin{Impl: testPlugin},
   477  	}
   478  
   479  	cmd, args := args[0], args[1:]
   480  	switch cmd {
   481  	case "bad-version":
   482  		// If we have an arg, we write there on start
   483  		if len(args) > 0 {
   484  			path := args[0]
   485  			err := ioutil.WriteFile(path, []byte("foo"), 0644)
   486  			if err != nil {
   487  				panic(err)
   488  			}
   489  		}
   490  
   491  		fmt.Printf("%d|%d1|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   492  		<-make(chan int)
   493  	case "invalid-rpc-address":
   494  		fmt.Println("lolinvalid")
   495  	case "mock":
   496  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   497  		<-make(chan int)
   498  	case "start-timeout":
   499  		time.Sleep(1 * time.Minute)
   500  		os.Exit(1)
   501  	case "stderr":
   502  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   503  		os.Stderr.WriteString("HELLO\n")
   504  		os.Stderr.WriteString("WORLD\n")
   505  	case "stderr-json":
   506  		// write values that might be JSON, but aren't KVs
   507  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   508  		os.Stderr.WriteString("[\"HELLO\"]\n")
   509  		os.Stderr.WriteString("12345\n")
   510  		os.Stderr.WriteString("{\"a\":1}\n")
   511  	case "level-warn-text":
   512  		// write values that might be JSON, but aren't KVs
   513  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   514  		os.Stderr.WriteString("[WARN] test line 98765\n")
   515  	case "stdin":
   516  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   517  		data := make([]byte, 5)
   518  		if _, err := os.Stdin.Read(data); err != nil {
   519  			log.Printf("stdin read error: %s", err)
   520  			os.Exit(100)
   521  		}
   522  
   523  		if string(data) == "hello" {
   524  			os.Exit(0)
   525  		}
   526  
   527  		os.Exit(1)
   528  	case "cleanup":
   529  		// Create a defer to write the file. This tests that we get cleaned
   530  		// up properly versus just calling os.Exit
   531  		path := args[0]
   532  		defer func() {
   533  			err := ioutil.WriteFile(path, []byte("foo"), 0644)
   534  			if err != nil {
   535  				panic(err)
   536  			}
   537  		}()
   538  
   539  		Serve(&ServeConfig{
   540  			HandshakeConfig: testHandshake,
   541  			Plugins:         testPluginMap,
   542  		})
   543  
   544  		// Exit
   545  		return
   546  	case "test-grpc":
   547  		Serve(&ServeConfig{
   548  			HandshakeConfig: testHandshake,
   549  			Plugins:         testGRPCPluginMap,
   550  			GRPCServer:      DefaultGRPCServer,
   551  		})
   552  
   553  		// Shouldn't reach here but make sure we exit anyways
   554  		os.Exit(0)
   555  	case "test-grpc-tls":
   556  		// Serve!
   557  		Serve(&ServeConfig{
   558  			HandshakeConfig: testHandshake,
   559  			Plugins:         testGRPCPluginMap,
   560  			GRPCServer:      DefaultGRPCServer,
   561  			TLSProvider:     helperTLSProvider,
   562  		})
   563  
   564  		// Shouldn't reach here but make sure we exit anyways
   565  		os.Exit(0)
   566  	case "test-interface":
   567  		Serve(&ServeConfig{
   568  			HandshakeConfig: testHandshake,
   569  			Plugins:         testPluginMap,
   570  		})
   571  
   572  		// Shouldn't reach here but make sure we exit anyways
   573  		os.Exit(0)
   574  	case "test-interface-logger-netrpc":
   575  		Serve(&ServeConfig{
   576  			HandshakeConfig: testHandshake,
   577  			Plugins:         testPluginMap,
   578  		})
   579  		// Shouldn't reach here but make sure we exit anyways
   580  		os.Exit(0)
   581  	case "test-interface-logger-grpc":
   582  		Serve(&ServeConfig{
   583  			HandshakeConfig: testHandshake,
   584  			Plugins:         testPluginMap,
   585  			GRPCServer:      DefaultGRPCServer,
   586  		})
   587  		// Shouldn't reach here but make sure we exit anyways
   588  		os.Exit(0)
   589  	case "test-interface-daemon":
   590  		// Serve!
   591  		Serve(&ServeConfig{
   592  			HandshakeConfig: testHandshake,
   593  			Plugins:         testPluginMap,
   594  		})
   595  
   596  		// Shouldn't reach here but make sure we exit anyways
   597  		os.Exit(0)
   598  	case "test-interface-tls":
   599  		// Serve!
   600  		Serve(&ServeConfig{
   601  			HandshakeConfig: testHandshake,
   602  			Plugins:         testPluginMap,
   603  			TLSProvider:     helperTLSProvider,
   604  		})
   605  
   606  		// Shouldn't reach here but make sure we exit anyways
   607  		os.Exit(0)
   608  
   609  	case "test-interface-mtls":
   610  		// Serve!
   611  		Serve(&ServeConfig{
   612  			HandshakeConfig: testVersionedHandshake,
   613  			Plugins:         testPluginMap,
   614  		})
   615  
   616  		// Shouldn't reach here but make sure we exit anyways
   617  		os.Exit(0)
   618  
   619  	case "test-versioned-plugins":
   620  		// Serve!
   621  		Serve(&ServeConfig{
   622  			HandshakeConfig: testVersionedHandshake,
   623  			VersionedPlugins: map[int]PluginSet{
   624  				2: testGRPCPluginMap,
   625  			},
   626  			GRPCServer:  DefaultGRPCServer,
   627  			TLSProvider: helperTLSProvider,
   628  		})
   629  
   630  		// Shouldn't reach here but make sure we exit anyways
   631  		os.Exit(0)
   632  	case "test-proto-upgraded-plugin":
   633  		// Serve 2 plugins over different protocols
   634  		Serve(&ServeConfig{
   635  			HandshakeConfig: testVersionedHandshake,
   636  			VersionedPlugins: map[int]PluginSet{
   637  				1: PluginSet{
   638  					"old": &testInterfacePlugin{Impl: testPlugin},
   639  				},
   640  				2: testGRPCPluginMap,
   641  			},
   642  			GRPCServer:  DefaultGRPCServer,
   643  			TLSProvider: helperTLSProvider,
   644  		})
   645  
   646  		// Shouldn't reach here but make sure we exit anyways
   647  		os.Exit(0)
   648  	case "test-proto-upgraded-client":
   649  		// Serve 2 plugins over different protocols
   650  		Serve(&ServeConfig{
   651  			HandshakeConfig: HandshakeConfig{
   652  				ProtocolVersion:  2,
   653  				MagicCookieKey:   "TEST_MAGIC_COOKIE",
   654  				MagicCookieValue: "test",
   655  			},
   656  			Plugins:     testGRPCPluginMap,
   657  			GRPCServer:  DefaultGRPCServer,
   658  			TLSProvider: helperTLSProvider,
   659  		})
   660  
   661  		// Shouldn't reach here but make sure we exit anyways
   662  		os.Exit(0)
   663  	case "test-mtls":
   664  		// Serve 2 plugins over different protocols
   665  		Serve(&ServeConfig{
   666  			HandshakeConfig: HandshakeConfig{
   667  				ProtocolVersion:  2,
   668  				MagicCookieKey:   "TEST_MAGIC_COOKIE",
   669  				MagicCookieValue: "test",
   670  			},
   671  			Plugins:    testGRPCPluginMap,
   672  			GRPCServer: DefaultGRPCServer,
   673  		})
   674  
   675  		// Shouldn't reach here but make sure we exit anyways
   676  		os.Exit(0)
   677  	case "test-skip-host-env-true":
   678  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   679  		if os.Getenv("PLUGIN_TEST_SKIP_HOST_ENV") == "" {
   680  			os.Exit(0)
   681  		}
   682  
   683  		os.Exit(1)
   684  	case "test-skip-host-env-false":
   685  		fmt.Printf("%d|%d|tcp|:1234\n", CoreProtocolVersion, testHandshake.ProtocolVersion)
   686  		if os.Getenv("PLUGIN_TEST_SKIP_HOST_ENV") != "" {
   687  			os.Exit(0)
   688  		}
   689  
   690  		os.Exit(1)
   691  	case "mux-grpc-with-old-plugin":
   692  		// gRPC broker multiplexing requested, but plugin has no awareness of the
   693  		// feature, so just prints 6 segments in the protocol negotiation line.
   694  		// Client should fail with a helpful error.
   695  		if os.Getenv(envMultiplexGRPC) == "" {
   696  			fmt.Println("failed precondition for mux test")
   697  			os.Exit(1)
   698  		}
   699  		fmt.Printf("%d|%d|tcp|:1234|%s|\n", CoreProtocolVersion, testHandshake.ProtocolVersion, ProtocolGRPC)
   700  		<-make(chan int)
   701  	case "mux-grpc-with-unsupported-plugin":
   702  		// gRPC broker multiplexing requested, but plugin explicitly does not
   703  		// support it. Client should fail with a helpful error.
   704  		if os.Getenv(envMultiplexGRPC) == "" {
   705  			fmt.Println("failed precondition for mux test")
   706  			os.Exit(1)
   707  		}
   708  		fmt.Printf("%d|%d|tcp|:1234|%s||false\n", CoreProtocolVersion, testHandshake.ProtocolVersion, ProtocolGRPC)
   709  		<-make(chan int)
   710  	default:
   711  		fmt.Fprintf(os.Stderr, "Unknown command: %q\n", cmd)
   712  		os.Exit(2)
   713  	}
   714  }
   715  
   716  func helperTLSProvider() (*tls.Config, error) {
   717  	serverCert, err := tls.X509KeyPair([]byte(TestClusterServerCert), []byte(TestClusterServerKey))
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  
   722  	rootCAs := x509.NewCertPool()
   723  	rootCAs.AppendCertsFromPEM([]byte(TestClusterCACert))
   724  	tlsConfig := &tls.Config{
   725  		Certificates: []tls.Certificate{serverCert},
   726  		RootCAs:      rootCAs,
   727  		ClientCAs:    rootCAs,
   728  		ClientAuth:   tls.VerifyClientCertIfGiven,
   729  		ServerName:   "127.0.0.1",
   730  	}
   731  	tlsConfig.BuildNameToCertificate()
   732  
   733  	return tlsConfig, nil
   734  }
   735  
   736  const (
   737  	TestClusterCACert = `-----BEGIN CERTIFICATE-----
   738  MIIDPjCCAiagAwIBAgIUfIKsF2VPT7sdFcKOHJH2Ii6K4MwwDQYJKoZIhvcNAQEL
   739  BQAwFjEUMBIGA1UEAxMLbXl2YXVsdC5jb20wIBcNMTYwNTAyMTYwNTQyWhgPMjA2
   740  NjA0MjAxNjA2MTJaMBYxFDASBgNVBAMTC215dmF1bHQuY29tMIIBIjANBgkqhkiG
   741  9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuOimEXawD2qBoLCFP3Skq5zi1XzzcMAJlfdS
   742  xz9hfymuJb+cN8rB91HOdU9wQCwVKnkUtGWxUnMp0tT0uAZj5NzhNfyinf0JGAbP
   743  67HDzVZhGBHlHTjPX0638yaiUx90cTnucX0N20SgCYct29dMSgcPl+W78D3Jw3xE
   744  JsHQPYS9ASe2eONxG09F/qNw7w/RO5/6WYoV2EmdarMMxq52pPe2chtNMQdSyOUb
   745  cCcIZyk4QVFZ1ZLl6jTnUPb+JoCx1uMxXvMek4NF/5IL0Wr9dw2gKXKVKoHDr6SY
   746  WrCONRw61A5Zwx1V+kn73YX3USRlkufQv/ih6/xThYDAXDC9cwIDAQABo4GBMH8w
   747  DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOuKvPiU
   748  G06iHkRXAOeMiUdBfHFyMB8GA1UdIwQYMBaAFOuKvPiUG06iHkRXAOeMiUdBfHFy
   749  MBwGA1UdEQQVMBOCC215dmF1bHQuY29thwR/AAABMA0GCSqGSIb3DQEBCwUAA4IB
   750  AQBcN/UdAMzc7UjRdnIpZvO+5keBGhL/vjltnGM1dMWYHa60Y5oh7UIXF+P1RdNW
   751  n7g80lOyvkSR15/r1rDkqOK8/4oruXU31EcwGhDOC4hU6yMUy4ltV/nBoodHBXNh
   752  MfKiXeOstH1vdI6G0P6W93Bcww6RyV1KH6sT2dbETCw+iq2VN9CrruGIWzd67UT/
   753  spe/kYttr3UYVV3O9kqgffVVgVXg/JoRZ3J7Hy2UEXfh9UtWNanDlRuXaZgE9s/d
   754  CpA30CHpNXvKeyNeW2ktv+2nAbSpvNW+e6MecBCTBIoDSkgU8ShbrzmDKVwNN66Q
   755  5gn6KxUPBKHEtNzs5DgGM7nq
   756  -----END CERTIFICATE-----`
   757  
   758  	TestClusterServerCert = `-----BEGIN CERTIFICATE-----
   759  MIIDtzCCAp+gAwIBAgIUBLqh6ctGWVDUxFhxJX7m6S/bnrcwDQYJKoZIhvcNAQEL
   760  BQAwFjEUMBIGA1UEAxMLbXl2YXVsdC5jb20wIBcNMTYwNTAyMTYwOTI2WhgPMjA2
   761  NjA0MjAxNTA5NTZaMBsxGTAXBgNVBAMTEGNlcnQubXl2YXVsdC5jb20wggEiMA0G
   762  CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY3gPB29kkdbu0mPO6J0efagQhSiXB
   763  9OyDuLf5sMk6CVDWVWal5hISkyBmw/lXgF7qC2XFKivpJOrcGQd5Ep9otBqyJLzI
   764  b0IWdXuPIrVnXDwcdWr86ybX2iC42zKWfbXgjzGijeAVpl0UJLKBj+fk5q6NvkRL
   765  5FUL6TRV7Krn9mrmnrV9J5IqV15pTd9W2aVJ6IqWvIPCACtZKulqWn4707uy2X2W
   766  1Stq/5qnp1pDshiGk1VPyxCwQ6yw3iEcgecbYo3vQfhWcv7Q8LpSIM9ZYpXu6OmF
   767  +czqRZS9gERl+wipmmrN1MdYVrTuQem21C/PNZ4jo4XUk1SFx6JrcA+lAgMBAAGj
   768  gfUwgfIwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSe
   769  Cl9WV3BjGCwmS/KrDSLRjfwyqjAfBgNVHSMEGDAWgBTrirz4lBtOoh5EVwDnjIlH
   770  QXxxcjA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAKGH2h0dHA6Ly8xMjcuMC4w
   771  LjE6ODIwMC92MS9wa2kvY2EwIQYDVR0RBBowGIIQY2VydC5teXZhdWx0LmNvbYcE
   772  fwAAATAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vMTI3LjAuMC4xOjgyMDAvdjEv
   773  cGtpL2NybDANBgkqhkiG9w0BAQsFAAOCAQEAWGholPN8buDYwKbUiDavbzjsxUIX
   774  lU4MxEqOHw7CD3qIYIauPboLvB9EldBQwhgOOy607Yvdg3rtyYwyBFwPhHo/hK3Z
   775  6mn4hc6TF2V+AUdHBvGzp2dbYLeo8noVoWbQ/lBulggwlIHNNF6+a3kALqsqk1Ch
   776  f/hzsjFnDhAlNcYFgG8TgfE2lE/FckvejPqBffo7Q3I+wVAw0buqiz5QL81NOT+D
   777  Y2S9LLKLRaCsWo9wRU1Az4Rhd7vK5SEMh16jJ82GyEODWPvuxOTI1MnzfnbWyLYe
   778  TTp6YBjGMVf1I6NEcWNur7U17uIOiQjMZ9krNvoMJ1A/cxCoZ98QHgcIPg==
   779  -----END CERTIFICATE-----`
   780  
   781  	TestClusterServerKey = `-----BEGIN RSA PRIVATE KEY-----
   782  MIIEpAIBAAKCAQEA2N4DwdvZJHW7tJjzuidHn2oEIUolwfTsg7i3+bDJOglQ1lVm
   783  peYSEpMgZsP5V4Be6gtlxSor6STq3BkHeRKfaLQasiS8yG9CFnV7jyK1Z1w8HHVq
   784  /Osm19oguNsyln214I8xoo3gFaZdFCSygY/n5Oaujb5ES+RVC+k0Veyq5/Zq5p61
   785  fSeSKldeaU3fVtmlSeiKlryDwgArWSrpalp+O9O7stl9ltUrav+ap6daQ7IYhpNV
   786  T8sQsEOssN4hHIHnG2KN70H4VnL+0PC6UiDPWWKV7ujphfnM6kWUvYBEZfsIqZpq
   787  zdTHWFa07kHpttQvzzWeI6OF1JNUhceia3APpQIDAQABAoIBAQCH3vEzr+3nreug
   788  RoPNCXcSJXXY9X+aeT0FeeGqClzIg7Wl03OwVOjVwl/2gqnhbIgK0oE8eiNwurR6
   789  mSPZcxV0oAJpwiKU4T/imlCDaReGXn86xUX2l82KRxthNdQH/VLKEmzij0jpx4Vh
   790  bWx5SBPdkbmjDKX1dmTiRYWIn/KjyNPvNvmtwdi8Qluhf4eJcNEUr2BtblnGOmfL
   791  FdSu+brPJozpoQ1QdDnbAQRgqnh7Shl0tT85whQi0uquqIj1gEOGVjmBvDDnL3GV
   792  WOENTKqsmIIoEzdZrql1pfmYTk7WNaD92bfpN128j8BF7RmAV4/DphH0pvK05y9m
   793  tmRhyHGxAoGBAOV2BBocsm6xup575VqmFN+EnIOiTn+haOvfdnVsyQHnth63fOQx
   794  PNtMpTPR1OMKGpJ13e2bV0IgcYRsRkScVkUtoa/17VIgqZXffnJJ0A/HT67uKBq3
   795  8o7RrtyK5N20otw0lZHyqOPhyCdpSsurDhNON1kPVJVYY4N1RiIxfut/AoGBAPHz
   796  HfsJ5ZkyELE9N/r4fce04lprxWH+mQGK0/PfjS9caXPhj/r5ZkVMvzWesF3mmnY8
   797  goE5S35TuTvV1+6rKGizwlCFAQlyXJiFpOryNWpLwCmDDSzLcm+sToAlML3tMgWU
   798  jM3dWHx3C93c3ft4rSWJaUYI9JbHsMzDW6Yh+GbbAoGBANIbKwxh5Hx5XwEJP2yu
   799  kIROYCYkMy6otHLujgBdmPyWl+suZjxoXWoMl2SIqR8vPD+Jj6mmyNJy9J6lqf3f
   800  DRuQ+fEuBZ1i7QWfvJ+XuN0JyovJ5Iz6jC58D1pAD+p2IX3y5FXcVQs8zVJRFjzB
   801  p0TEJOf2oqORaKWRd6ONoMKvAoGALKu6aVMWdQZtVov6/fdLIcgf0pn7Q3CCR2qe
   802  X3Ry2L+zKJYIw0mwvDLDSt8VqQCenB3n6nvtmFFU7ds5lvM67rnhsoQcAOaAehiS
   803  rl4xxoJd5Ewx7odRhZTGmZpEOYzFo4odxRSM9c30/u18fqV1Mm0AZtHYds4/sk6P
   804  aUj0V+kCgYBMpGrJk8RSez5g0XZ35HfpI4ENoWbiwB59FIpWsLl2LADEh29eC455
   805  t9Muq7MprBVBHQo11TMLLFxDIjkuMho/gcKgpYXCt0LfiNm8EZehvLJUXH+3WqUx
   806  we6ywrbFCs6LaxaOCtTiLsN+GbZCatITL0UJaeBmTAbiw0KQjUuZPQ==
   807  -----END RSA PRIVATE KEY-----`
   808  )