github.com/keys-pub/mattermost-server@v4.10.10+incompatible/plugin/rpcplugin/hooks_test.go (about)

     1  package rpcplugin
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"strings"
     9  	"sync"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/mattermost/mattermost-server/model"
    17  	"github.com/mattermost/mattermost-server/plugin"
    18  	"github.com/mattermost/mattermost-server/plugin/plugintest"
    19  )
    20  
    21  func testHooksRPC(hooks interface{}, f func(*RemoteHooks)) error {
    22  	r1, w1 := io.Pipe()
    23  	r2, w2 := io.Pipe()
    24  
    25  	c1 := NewMuxer(NewReadWriteCloser(r1, w2), false)
    26  	defer c1.Close()
    27  
    28  	c2 := NewMuxer(NewReadWriteCloser(r2, w1), true)
    29  	defer c2.Close()
    30  
    31  	id, server := c1.Serve()
    32  	go ServeHooks(hooks, server, c1)
    33  
    34  	remote, err := ConnectHooks(c2.Connect(id), c2, "plugin_id")
    35  	if err != nil {
    36  		return err
    37  	}
    38  	defer remote.Close()
    39  
    40  	f(remote)
    41  	return nil
    42  }
    43  
    44  func TestHooks(t *testing.T) {
    45  	var api plugintest.API
    46  	var hooks plugintest.Hooks
    47  	defer hooks.AssertExpectations(t)
    48  
    49  	assert.NoError(t, testHooksRPC(&hooks, func(remote *RemoteHooks) {
    50  		hooks.On("OnActivate", mock.AnythingOfType("*rpcplugin.RemoteAPI")).Return(nil)
    51  		assert.NoError(t, remote.OnActivate(&api))
    52  
    53  		hooks.On("OnDeactivate").Return(nil)
    54  		assert.NoError(t, remote.OnDeactivate())
    55  
    56  		hooks.On("OnConfigurationChange").Return(nil)
    57  		assert.NoError(t, remote.OnConfigurationChange())
    58  
    59  		hooks.On("ServeHTTP", mock.AnythingOfType("*rpcplugin.RemoteHTTPResponseWriter"), mock.AnythingOfType("*http.Request")).Run(func(args mock.Arguments) {
    60  			w := args.Get(0).(http.ResponseWriter)
    61  			r := args.Get(1).(*http.Request)
    62  			assert.Equal(t, "/foo", r.URL.Path)
    63  			assert.Equal(t, "POST", r.Method)
    64  			body, err := ioutil.ReadAll(r.Body)
    65  			assert.NoError(t, err)
    66  			assert.Equal(t, "asdf", string(body))
    67  			assert.Equal(t, "header", r.Header.Get("Test-Header"))
    68  			w.Write([]byte("bar"))
    69  		})
    70  
    71  		w := httptest.NewRecorder()
    72  		r, err := http.NewRequest("POST", "/foo", strings.NewReader("asdf"))
    73  		r.Header.Set("Test-Header", "header")
    74  		assert.NoError(t, err)
    75  		remote.ServeHTTP(w, r)
    76  
    77  		resp := w.Result()
    78  		defer resp.Body.Close()
    79  		assert.Equal(t, http.StatusOK, resp.StatusCode)
    80  		body, err := ioutil.ReadAll(resp.Body)
    81  		assert.NoError(t, err)
    82  		assert.Equal(t, "bar", string(body))
    83  
    84  		hooks.On("ExecuteCommand", &model.CommandArgs{
    85  			Command: "/foo",
    86  		}).Return(&model.CommandResponse{
    87  			Text: "bar",
    88  		}, nil)
    89  		commandResponse, appErr := hooks.ExecuteCommand(&model.CommandArgs{
    90  			Command: "/foo",
    91  		})
    92  		assert.Equal(t, "bar", commandResponse.Text)
    93  		assert.Nil(t, appErr)
    94  	}))
    95  }
    96  
    97  func TestHooks_Concurrency(t *testing.T) {
    98  	var hooks plugintest.Hooks
    99  	defer hooks.AssertExpectations(t)
   100  
   101  	assert.NoError(t, testHooksRPC(&hooks, func(remote *RemoteHooks) {
   102  		ch := make(chan bool)
   103  
   104  		hooks.On("ServeHTTP", mock.AnythingOfType("*rpcplugin.RemoteHTTPResponseWriter"), mock.AnythingOfType("*http.Request")).Run(func(args mock.Arguments) {
   105  			r := args.Get(1).(*http.Request)
   106  			if r.URL.Path == "/1" {
   107  				<-ch
   108  			} else {
   109  				ch <- true
   110  			}
   111  		})
   112  
   113  		rec := httptest.NewRecorder()
   114  
   115  		wg := sync.WaitGroup{}
   116  		wg.Add(2)
   117  
   118  		go func() {
   119  			req, err := http.NewRequest("GET", "/1", nil)
   120  			require.NoError(t, err)
   121  			remote.ServeHTTP(rec, req)
   122  			wg.Done()
   123  		}()
   124  
   125  		go func() {
   126  			req, err := http.NewRequest("GET", "/2", nil)
   127  			require.NoError(t, err)
   128  			remote.ServeHTTP(rec, req)
   129  			wg.Done()
   130  		}()
   131  
   132  		wg.Wait()
   133  	}))
   134  }
   135  
   136  type testHooks struct {
   137  	mock.Mock
   138  }
   139  
   140  func (h *testHooks) OnActivate(api plugin.API) error {
   141  	return h.Called(api).Error(0)
   142  }
   143  
   144  func TestHooks_PartiallyImplemented(t *testing.T) {
   145  	var api plugintest.API
   146  	var hooks testHooks
   147  	defer hooks.AssertExpectations(t)
   148  
   149  	assert.NoError(t, testHooksRPC(&hooks, func(remote *RemoteHooks) {
   150  		implemented, err := remote.Implemented()
   151  		assert.NoError(t, err)
   152  		assert.Equal(t, []string{"OnActivate"}, implemented)
   153  
   154  		hooks.On("OnActivate", mock.AnythingOfType("*rpcplugin.RemoteAPI")).Return(nil)
   155  		assert.NoError(t, remote.OnActivate(&api))
   156  
   157  		assert.NoError(t, remote.OnDeactivate())
   158  	}))
   159  }
   160  
   161  type benchmarkHooks struct{}
   162  
   163  func (*benchmarkHooks) OnDeactivate() error { return nil }
   164  
   165  func (*benchmarkHooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   166  	ioutil.ReadAll(r.Body)
   167  	w.Header().Set("Foo-Header", "foo")
   168  	http.Error(w, "foo", http.StatusBadRequest)
   169  }
   170  
   171  func BenchmarkHooks_OnDeactivate(b *testing.B) {
   172  	var hooks benchmarkHooks
   173  
   174  	if err := testHooksRPC(&hooks, func(remote *RemoteHooks) {
   175  		b.ResetTimer()
   176  		for n := 0; n < b.N; n++ {
   177  			remote.OnDeactivate()
   178  		}
   179  		b.StopTimer()
   180  	}); err != nil {
   181  		b.Fatal(err.Error())
   182  	}
   183  }
   184  
   185  func BenchmarkHooks_ServeHTTP(b *testing.B) {
   186  	var hooks benchmarkHooks
   187  
   188  	if err := testHooksRPC(&hooks, func(remote *RemoteHooks) {
   189  		b.ResetTimer()
   190  		for n := 0; n < b.N; n++ {
   191  			w := httptest.NewRecorder()
   192  			r, _ := http.NewRequest("POST", "/foo", strings.NewReader("12345678901234567890"))
   193  			remote.ServeHTTP(w, r)
   194  		}
   195  		b.StopTimer()
   196  	}); err != nil {
   197  		b.Fatal(err.Error())
   198  	}
   199  }
   200  
   201  func BenchmarkHooks_Unimplemented(b *testing.B) {
   202  	var hooks testHooks
   203  
   204  	if err := testHooksRPC(&hooks, func(remote *RemoteHooks) {
   205  		b.ResetTimer()
   206  		for n := 0; n < b.N; n++ {
   207  			remote.OnDeactivate()
   208  		}
   209  		b.StopTimer()
   210  	}); err != nil {
   211  		b.Fatal(err.Error())
   212  	}
   213  }