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 }