wa-lang.org/wazero@v1.0.2/imports/proxywasm/_proxytest/timing_on_test.go (about)

     1  //go:build proxywasm_timing
     2  
     3  package proxytest
     4  
     5  import (
     6  	"fmt"
     7  	"regexp"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
    14  )
    15  
    16  type timedPlugin struct {
    17  	types.DefaultVMContext
    18  	tcp bool
    19  }
    20  
    21  // NewPluginContext implements the same method on types.DefaultVMContext.
    22  func (p *timedPlugin) NewPluginContext(uint32) types.PluginContext {
    23  	time.Sleep(1 * time.Millisecond)
    24  	return &timedPluginContext{tcp: p.tcp}
    25  }
    26  
    27  type timedPluginContext struct {
    28  	types.DefaultPluginContext
    29  	tcp bool
    30  }
    31  
    32  // OnPluginStart implements the same method on types.PluginContext.
    33  func (p *timedPluginContext) OnPluginStart(int) types.OnPluginStartStatus {
    34  	time.Sleep(1 * time.Millisecond)
    35  	return true
    36  }
    37  
    38  // NewHttpContext implements the same method on types.DefaultPluginContext.
    39  func (p *timedPluginContext) NewHttpContext(uint32) types.HttpContext {
    40  	time.Sleep(1 * time.Millisecond)
    41  	if !p.tcp {
    42  		return &timedHttpContext{}
    43  	}
    44  	return nil
    45  }
    46  
    47  // NewTcpContext implements the same method on types.DefaultPluginContext.
    48  func (p *timedPluginContext) NewTcpContext(uint32) types.TcpContext {
    49  	time.Sleep(1 * time.Millisecond)
    50  	if p.tcp {
    51  		return &timedTcpContext{}
    52  	}
    53  	return nil
    54  }
    55  
    56  type timedHttpContext struct {
    57  }
    58  
    59  // OnHttpRequestHeaders implements the same method on types.HttpContext.
    60  func (c *timedHttpContext) OnHttpRequestHeaders(int, bool) types.Action {
    61  	time.Sleep(1 * time.Millisecond)
    62  	return types.ActionContinue
    63  }
    64  
    65  // OnHttpRequestBody implements the same method on types.HttpContext.
    66  func (c *timedHttpContext) OnHttpRequestBody(int, bool) types.Action {
    67  	time.Sleep(1 * time.Millisecond)
    68  	return types.ActionContinue
    69  }
    70  
    71  // OnHttpRequestTrailers implements the same method on types.HttpContext.
    72  func (c *timedHttpContext) OnHttpRequestTrailers(int) types.Action {
    73  	time.Sleep(1 * time.Millisecond)
    74  	return types.ActionContinue
    75  }
    76  
    77  // OnHttpResponseHeaders implements the same method on types.HttpContext.
    78  func (c *timedHttpContext) OnHttpResponseHeaders(int, bool) types.Action {
    79  	time.Sleep(1 * time.Millisecond)
    80  	return types.ActionContinue
    81  }
    82  
    83  // OnHttpResponseBody implements the same method on types.HttpContext.
    84  func (c *timedHttpContext) OnHttpResponseBody(int, bool) types.Action {
    85  	time.Sleep(1 * time.Millisecond)
    86  	return types.ActionContinue
    87  }
    88  
    89  // OnHttpResponseTrailers implements the same method on types.HttpContext.
    90  func (c *timedHttpContext) OnHttpResponseTrailers(int) types.Action {
    91  	time.Sleep(1 * time.Millisecond)
    92  	return types.ActionContinue
    93  }
    94  
    95  // OnHttpStreamDone implements the same method on types.HttpContext.
    96  func (c *timedHttpContext) OnHttpStreamDone() {
    97  	time.Sleep(1 * time.Millisecond)
    98  }
    99  
   100  type timedTcpContext struct {
   101  }
   102  
   103  // OnNewConnection implements the same method on types.TcpContext.
   104  func (t timedTcpContext) OnNewConnection() types.Action {
   105  	time.Sleep(1 * time.Millisecond)
   106  	return types.ActionContinue
   107  }
   108  
   109  // OnDownstreamData implements the same method on types.TcpContext.
   110  func (t timedTcpContext) OnDownstreamData(int, bool) types.Action {
   111  	time.Sleep(1 * time.Millisecond)
   112  	return types.ActionContinue
   113  }
   114  
   115  // OnDownstreamClose implements the same method on types.TcpContext.
   116  func (t timedTcpContext) OnDownstreamClose(types.PeerType) {
   117  	time.Sleep(1 * time.Millisecond)
   118  }
   119  
   120  // OnUpstreamData implements the same method on types.TcpContext.
   121  func (t timedTcpContext) OnUpstreamData(int, bool) types.Action {
   122  	time.Sleep(1 * time.Millisecond)
   123  	return types.ActionContinue
   124  }
   125  
   126  // OnUpstreamClose implements the same method on types.TcpContext.
   127  func (t timedTcpContext) OnUpstreamClose(types.PeerType) {
   128  	time.Sleep(1 * time.Millisecond)
   129  }
   130  
   131  // OnStreamDone implements the same method on types.TcpContext.
   132  func (t timedTcpContext) OnStreamDone() {
   133  	time.Sleep(1 * time.Millisecond)
   134  }
   135  
   136  // Execute lifecycle methods, there should be logs for the no-op plugin.
   137  func TestTimingOn(t *testing.T) {
   138  	t.Run("http", func(t *testing.T) {
   139  		host, reset := NewHostEmulator(NewEmulatorOption().WithVMContext(&timedPlugin{}))
   140  		defer reset()
   141  
   142  		require.Equal(t, types.OnPluginStartStatusOK, host.StartPlugin())
   143  		id := host.InitializeHttpContext()
   144  
   145  		require.Equal(t, types.ActionContinue, host.CallOnRequestHeaders(id, nil, false))
   146  		require.Equal(t, types.ActionContinue, host.CallOnRequestBody(id, nil, false))
   147  		require.Equal(t, types.ActionContinue, host.CallOnRequestTrailers(id, nil))
   148  		require.Equal(t, types.ActionContinue, host.CallOnResponseHeaders(id, nil, false))
   149  		require.Equal(t, types.ActionContinue, host.CallOnResponseBody(id, nil, false))
   150  		require.Equal(t, types.ActionContinue, host.CallOnResponseTrailers(id, nil))
   151  		host.CompleteHttpContext(id)
   152  
   153  		host.GetDebugLogs()
   154  		requireLogged(t, "proxyOnContextCreate", host.GetDebugLogs())
   155  		requireLogged(t, "proxyOnConfigure", host.GetDebugLogs())
   156  		requireLogged(t, "proxyOnContextCreate", host.GetDebugLogs())
   157  		requireLogged(t, "proxyOnRequestHeaders", host.GetDebugLogs())
   158  		requireLogged(t, "proxyOnRequestBody", host.GetDebugLogs())
   159  		requireLogged(t, "proxyOnRequestTrailers", host.GetDebugLogs())
   160  		requireLogged(t, "proxyOnResponseHeaders", host.GetDebugLogs())
   161  		requireLogged(t, "proxyOnResponseBody", host.GetDebugLogs())
   162  		requireLogged(t, "proxyOnResponseTrailers", host.GetDebugLogs())
   163  		requireLogged(t, "proxyOnLog", host.GetDebugLogs())
   164  		requireLogged(t, "proxyOnDelete", host.GetDebugLogs())
   165  	})
   166  
   167  	t.Run("tcp", func(t *testing.T) {
   168  		host, reset := NewHostEmulator(NewEmulatorOption().WithVMContext(&timedPlugin{tcp: true}))
   169  		defer reset()
   170  
   171  		require.Equal(t, types.OnPluginStartStatusOK, host.StartPlugin())
   172  		id, action := host.InitializeConnection()
   173  		require.Equal(t, types.ActionContinue, action)
   174  
   175  		require.Equal(t, types.ActionContinue, host.CallOnDownstreamData(id, nil))
   176  		require.Equal(t, types.ActionContinue, host.CallOnUpstreamData(id, nil))
   177  		host.CompleteConnection(id)
   178  
   179  		requireLogged(t, "proxyOnContextCreate", host.GetDebugLogs())
   180  		requireLogged(t, "proxyOnConfigure", host.GetDebugLogs())
   181  		requireLogged(t, "proxyOnContextCreate", host.GetDebugLogs())
   182  		requireLogged(t, "proxyOnNewConnection", host.GetDebugLogs())
   183  		requireLogged(t, "proxyOnDownstreamData", host.GetDebugLogs())
   184  		requireLogged(t, "proxyOnUpstreamData", host.GetDebugLogs())
   185  		requireLogged(t, "proxyOnLog", host.GetDebugLogs())
   186  		requireLogged(t, "proxyOnDelete", host.GetDebugLogs())
   187  	})
   188  }
   189  
   190  func requireLogged(t *testing.T, msg string, logs []string) {
   191  	t.Helper()
   192  	re := regexp.MustCompile(fmt.Sprintf(`%s took \d+`, msg))
   193  	for _, l := range logs {
   194  		if re.MatchString(l) {
   195  			// While we can't make reliable assertions on the actual time took, it is inconceivable to have a time of
   196  			// 0 since we add a small sleep in each function, while bugs like forgetting "defer" might cause it. So do
   197  			// a special check for it.
   198  			require.NotContains(t, l, "took 0s")
   199  			return
   200  		}
   201  	}
   202  	require.Failf(t, "unexpected log", "expected log %s, got %v", msg, logs)
   203  }