github.com/tetratelabs/proxy-wasm-go-sdk@v0.23.1-0.20240517021853-021aa9cf78e8/proxywasm/proxytest/http_test.go (about)

     1  package proxytest
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
    10  	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/internal"
    11  	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
    12  )
    13  
    14  type testPlugin struct {
    15  	types.DefaultVMContext
    16  	buffered bool
    17  }
    18  
    19  type testPluginContext struct {
    20  	types.DefaultPluginContext
    21  	buffered bool
    22  }
    23  
    24  type testHttpContext struct {
    25  	types.DefaultHttpContext
    26  	buffered bool
    27  }
    28  
    29  // NewPluginContext implements the same method on types.VMContext.
    30  func (p *testPlugin) NewPluginContext(uint32) types.PluginContext {
    31  	return &testPluginContext{buffered: p.buffered}
    32  }
    33  
    34  // NewPluginContext implements the same method on types.PluginContext.
    35  func (p *testPluginContext) NewHttpContext(uint32) types.HttpContext {
    36  	return &testHttpContext{buffered: p.buffered}
    37  }
    38  
    39  // OnHttpRequestBody implements the same method on types.HttpContext.
    40  func (h *testHttpContext) OnHttpRequestBody(bodySize int, endOfStream bool) types.Action {
    41  	if !endOfStream {
    42  		if h.buffered {
    43  			return types.ActionPause
    44  		} else {
    45  			return types.ActionContinue
    46  		}
    47  	}
    48  
    49  	body, err := proxywasm.GetHttpRequestBody(0, bodySize)
    50  	if err != nil {
    51  		panic(err)
    52  	}
    53  	proxywasm.LogInfo(fmt.Sprintf("request body:%s", string(body)))
    54  
    55  	return types.ActionContinue
    56  }
    57  
    58  // OnHttpResponseBody implements the same method on types.HttpContext.
    59  func (h *testHttpContext) OnHttpResponseBody(bodySize int, endOfStream bool) types.Action {
    60  	if !endOfStream {
    61  		if h.buffered {
    62  			return types.ActionPause
    63  		} else {
    64  			return types.ActionContinue
    65  		}
    66  	}
    67  
    68  	body, err := proxywasm.GetHttpResponseBody(0, bodySize)
    69  	if err != nil {
    70  		panic(err)
    71  	}
    72  	proxywasm.LogInfo(fmt.Sprintf("response body:%s", string(body)))
    73  
    74  	return types.ActionContinue
    75  }
    76  
    77  func TestBodyBuffering(t *testing.T) {
    78  	tests := []struct {
    79  		name     string
    80  		buffered bool
    81  		action   types.Action
    82  		logged   string
    83  	}{
    84  		{
    85  			name:     "buffered",
    86  			buffered: true,
    87  			action:   types.ActionPause,
    88  			// The first chunk has been buffered, therefore it will be retrieved when calling GetHttpRequestBody at the end of stream.
    89  			logged: "1111122222",
    90  		},
    91  		{
    92  			name:     "unbuffered",
    93  			buffered: false,
    94  			action:   types.ActionContinue,
    95  			// The first chunk has not been buffered, therefore it will not be retrieved when calling GetHttpRequestBody at the end of stream.
    96  			logged: "22222",
    97  		},
    98  	}
    99  
   100  	for _, tc := range tests {
   101  		tt := tc
   102  		t.Run(tt.name, func(t *testing.T) {
   103  			host, reset := NewHostEmulator(NewEmulatorOption().WithVMContext(&testPlugin{buffered: tt.buffered}))
   104  			defer reset()
   105  
   106  			id := host.InitializeHttpContext()
   107  
   108  			action := host.CallOnRequestBody(id, []byte("11111"), false)
   109  			require.Equal(t, tt.action, action)
   110  
   111  			action = host.CallOnRequestBody(id, []byte("22222"), true)
   112  			require.Equal(t, types.ActionContinue, action)
   113  
   114  			action = host.CallOnResponseBody(id, []byte("11111"), false)
   115  			require.Equal(t, tt.action, action)
   116  
   117  			action = host.CallOnResponseBody(id, []byte("22222"), true)
   118  			require.Equal(t, types.ActionContinue, action)
   119  
   120  			logs := host.GetInfoLogs()
   121  			require.Contains(t, logs, fmt.Sprintf("request body:%s", tt.logged))
   122  			require.Contains(t, logs, fmt.Sprintf("response body:%s", tt.logged))
   123  		})
   124  	}
   125  }
   126  
   127  func TestProperties(t *testing.T) {
   128  	t.Run("Set and get properties", func(t *testing.T) {
   129  		host, reset := NewHostEmulator(NewEmulatorOption().WithVMContext(&testPlugin{}))
   130  		defer reset()
   131  
   132  		_ = host.InitializeHttpContext()
   133  
   134  		propertyPath := []string{
   135  			"route_metadata",
   136  			"filter_metadata",
   137  			"envoy.filters.http.wasm",
   138  			"hello",
   139  		}
   140  		propertyData := []byte("world")
   141  
   142  		err := host.SetProperty(propertyPath, propertyData)
   143  		require.Equal(t, err, nil)
   144  
   145  		data, err := host.GetProperty(propertyPath)
   146  		require.Equal(t, err, nil)
   147  		require.Equal(t, data, propertyData)
   148  
   149  		_, err = host.GetProperty([]string{"non-existent path"})
   150  		require.Equal(t, err, internal.StatusToError(internal.StatusNotFound))
   151  	})
   152  }