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

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package plugin
     5  
     6  import (
     7  	"bytes"
     8  	"io"
     9  	"os"
    10  	"sync"
    11  	"testing"
    12  	"time"
    13  
    14  	hclog "github.com/hashicorp/go-hclog"
    15  )
    16  
    17  func TestClient_App(t *testing.T) {
    18  	pluginLogger := hclog.New(&hclog.LoggerOptions{
    19  		Level:      hclog.Trace,
    20  		Output:     os.Stderr,
    21  		JSONFormat: true,
    22  	})
    23  
    24  	testPlugin := &testInterfaceImpl{
    25  		logger: pluginLogger,
    26  	}
    27  
    28  	client, _ := TestPluginRPCConn(t, map[string]Plugin{
    29  		"test": &testInterfacePlugin{Impl: testPlugin},
    30  	}, nil)
    31  	defer client.Close()
    32  
    33  	raw, err := client.Dispense("test")
    34  	if err != nil {
    35  		t.Fatalf("err: %s", err)
    36  	}
    37  
    38  	impl, ok := raw.(testInterface)
    39  	if !ok {
    40  		t.Fatalf("bad: %#v", raw)
    41  	}
    42  
    43  	result := impl.Double(21)
    44  	if result != 42 {
    45  		t.Fatalf("bad: %#v", result)
    46  	}
    47  }
    48  
    49  func TestClient_syncStreams(t *testing.T) {
    50  	// Create streams for the server that we can talk to
    51  	stdout_r, stdout_w := io.Pipe()
    52  	stderr_r, stderr_w := io.Pipe()
    53  
    54  	client, _ := TestPluginRPCConn(t, map[string]Plugin{}, &TestOptions{
    55  		ServerStdout: stdout_r,
    56  		ServerStderr: stderr_r,
    57  	})
    58  
    59  	// Start the data copying
    60  	var stdout_out, stderr_out safeBuffer
    61  	stdout := &safeBuffer{
    62  		b: bytes.NewBufferString("stdouttest"),
    63  	}
    64  	stderr := &safeBuffer{
    65  		b: bytes.NewBufferString("stderrtest"),
    66  	}
    67  	go client.SyncStreams(&stdout_out, &stderr_out)
    68  	go io.Copy(stdout_w, stdout)
    69  	go io.Copy(stderr_w, stderr)
    70  
    71  	// Unfortunately I can't think of a better way to make sure all the
    72  	// copies above go through so let's just exit.
    73  	time.Sleep(100 * time.Millisecond)
    74  
    75  	// Close everything, and lets test the result
    76  	client.Close()
    77  	stdout_w.Close()
    78  	stderr_w.Close()
    79  
    80  	if v := stdout_out.String(); v != "stdouttest" {
    81  		t.Fatalf("bad: %q", v)
    82  	}
    83  	if v := stderr_out.String(); v != "stderrtest" {
    84  		t.Fatalf("bad: %q", v)
    85  	}
    86  }
    87  
    88  type safeBuffer struct {
    89  	sync.Mutex
    90  	b *bytes.Buffer
    91  }
    92  
    93  func (s *safeBuffer) Write(p []byte) (n int, err error) {
    94  	s.Lock()
    95  	defer s.Unlock()
    96  	if s.b == nil {
    97  		s.b = new(bytes.Buffer)
    98  	}
    99  	return s.b.Write(p)
   100  }
   101  
   102  func (s *safeBuffer) Read(p []byte) (n int, err error) {
   103  	s.Lock()
   104  	defer s.Unlock()
   105  	if s.b == nil {
   106  		s.b = new(bytes.Buffer)
   107  	}
   108  	return s.b.Read(p)
   109  }
   110  
   111  func (s *safeBuffer) String() string {
   112  	s.Lock()
   113  	defer s.Unlock()
   114  	if s.b == nil {
   115  		s.b = new(bytes.Buffer)
   116  	}
   117  	return s.b.String()
   118  }