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

     1  // Copyright 2021 Tetrate
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package proxywasm
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"wa-lang.org/wazero/imports/proxywasm/internal"
    23  )
    24  
    25  type logHost struct {
    26  	internal.DefaultProxyWAMSHost
    27  	t           *testing.T
    28  	expMessage  string
    29  	expLogLevel internal.LogLevel
    30  }
    31  
    32  func (l logHost) ProxyLog(logLevel internal.LogLevel, messageData *byte, messageSize int) internal.Status {
    33  	actual := internal.RawBytePtrToString(messageData, messageSize)
    34  	require.Equal(l.t, l.expMessage, actual)
    35  	require.Equal(l.t, l.expLogLevel, logLevel)
    36  	return internal.StatusOK
    37  }
    38  
    39  func TestHostCall_ForeignFunction(t *testing.T) {
    40  	defer internal.RegisterMockWasmHost(internal.DefaultProxyWAMSHost{})()
    41  
    42  	ret, err := CallForeignFunction("testFunc", []byte(""))
    43  	require.NoError(t, err)
    44  	require.Equal(t, []byte(nil), ret)
    45  }
    46  
    47  func TestHostCall_Logging(t *testing.T) {
    48  	t.Run("trace", func(t *testing.T) {
    49  		release := internal.RegisterMockWasmHost(logHost{
    50  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
    51  			t:                    t,
    52  			expMessage:           "trace",
    53  			expLogLevel:          internal.LogLevelTrace,
    54  		})
    55  		defer release()
    56  		LogTrace("trace")
    57  	})
    58  
    59  	t.Run("tracef", func(t *testing.T) {
    60  		release := internal.RegisterMockWasmHost(logHost{
    61  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
    62  			t:                    t,
    63  			expMessage:           "trace: log",
    64  			expLogLevel:          internal.LogLevelTrace,
    65  		})
    66  		defer release()
    67  		LogTracef("trace: %s", "log")
    68  	})
    69  
    70  	t.Run("debug", func(t *testing.T) {
    71  		release := internal.RegisterMockWasmHost(logHost{
    72  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
    73  			t:                    t,
    74  			expMessage:           "abc",
    75  			expLogLevel:          internal.LogLevelDebug,
    76  		})
    77  		defer release()
    78  		LogDebug("abc")
    79  	})
    80  
    81  	t.Run("debugf", func(t *testing.T) {
    82  		release := internal.RegisterMockWasmHost(logHost{
    83  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
    84  			t:                    t,
    85  			expMessage:           "debug: log",
    86  			expLogLevel:          internal.LogLevelDebug,
    87  		})
    88  		defer release()
    89  		LogDebugf("debug: %s", "log")
    90  	})
    91  
    92  	t.Run("info", func(t *testing.T) {
    93  		release := internal.RegisterMockWasmHost(logHost{
    94  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
    95  			t:                    t,
    96  			expMessage:           "info",
    97  			expLogLevel:          internal.LogLevelInfo,
    98  		})
    99  		defer release()
   100  		LogInfo("info")
   101  	})
   102  
   103  	t.Run("infof", func(t *testing.T) {
   104  		release := internal.RegisterMockWasmHost(logHost{
   105  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   106  			t:                    t,
   107  			expMessage:           "info: log: 10",
   108  			expLogLevel:          internal.LogLevelInfo,
   109  		})
   110  		defer release()
   111  		LogInfof("info: %s: %d", "log", 10)
   112  	})
   113  
   114  	t.Run("warn", func(t *testing.T) {
   115  		release := internal.RegisterMockWasmHost(logHost{
   116  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   117  			t:                    t,
   118  			expMessage:           "warn",
   119  			expLogLevel:          internal.LogLevelWarn,
   120  		})
   121  		defer release()
   122  		LogWarn("warn")
   123  	})
   124  
   125  	t.Run("warnf", func(t *testing.T) {
   126  		release := internal.RegisterMockWasmHost(logHost{
   127  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   128  			t:                    t,
   129  			expMessage:           "warn: log: 10",
   130  			expLogLevel:          internal.LogLevelWarn,
   131  		})
   132  		defer release()
   133  		LogWarnf("warn: %s: %d", "log", 10)
   134  	})
   135  
   136  	t.Run("error", func(t *testing.T) {
   137  		release := internal.RegisterMockWasmHost(logHost{
   138  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   139  			t:                    t,
   140  			expMessage:           "error",
   141  			expLogLevel:          internal.LogLevelError,
   142  		})
   143  		defer release()
   144  		LogError("error")
   145  	})
   146  
   147  	t.Run("warnf", func(t *testing.T) {
   148  		release := internal.RegisterMockWasmHost(logHost{
   149  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   150  			t:                    t,
   151  			expMessage:           "warn: log: 10",
   152  			expLogLevel:          internal.LogLevelWarn,
   153  		})
   154  		defer release()
   155  		LogWarnf("warn: %s: %d", "log", 10)
   156  	})
   157  
   158  	t.Run("critical", func(t *testing.T) {
   159  		release := internal.RegisterMockWasmHost(logHost{
   160  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   161  			t:                    t,
   162  			expMessage:           "critical error",
   163  			expLogLevel:          internal.LogLevelCritical,
   164  		})
   165  		defer release()
   166  		LogCritical("critical error")
   167  	})
   168  
   169  	t.Run("criticalf", func(t *testing.T) {
   170  		release := internal.RegisterMockWasmHost(logHost{
   171  			DefaultProxyWAMSHost: internal.DefaultProxyWAMSHost{},
   172  			t:                    t,
   173  			expMessage:           "critical: log: 10",
   174  			expLogLevel:          internal.LogLevelCritical,
   175  		})
   176  		defer release()
   177  		LogCriticalf("critical: %s: %d", "log", 10)
   178  	})
   179  }
   180  
   181  type metricProxyWasmHost struct {
   182  	internal.DefaultProxyWAMSHost
   183  	idToValue map[uint32]uint64
   184  	idToType  map[uint32]internal.MetricType
   185  	nameToID  map[string]uint32
   186  }
   187  
   188  func (m metricProxyWasmHost) ProxyDefineMetric(metricType internal.MetricType,
   189  	metricNameData *byte, metricNameSize int, returnMetricIDPtr *uint32) internal.Status {
   190  	name := internal.RawBytePtrToString(metricNameData, metricNameSize)
   191  	id, ok := m.nameToID[name]
   192  	if !ok {
   193  		id = uint32(len(m.nameToID))
   194  		m.nameToID[name] = id
   195  		m.idToValue[id] = 0
   196  		m.idToType[id] = metricType
   197  	}
   198  	*returnMetricIDPtr = id
   199  	return internal.StatusOK
   200  }
   201  
   202  func (m metricProxyWasmHost) ProxyIncrementMetric(metricID uint32, offset int64) internal.Status {
   203  	val, ok := m.idToValue[metricID]
   204  	if !ok {
   205  		return internal.StatusBadArgument
   206  	}
   207  
   208  	m.idToValue[metricID] = val + uint64(offset)
   209  	return internal.StatusOK
   210  }
   211  
   212  func (m metricProxyWasmHost) ProxyRecordMetric(metricID uint32, value uint64) internal.Status {
   213  	_, ok := m.idToValue[metricID]
   214  	if !ok {
   215  		return internal.StatusBadArgument
   216  	}
   217  	m.idToValue[metricID] = value
   218  	return internal.StatusOK
   219  }
   220  
   221  func (m metricProxyWasmHost) ProxyGetMetric(metricID uint32, returnMetricValue *uint64) internal.Status {
   222  	value, ok := m.idToValue[metricID]
   223  	if !ok {
   224  		return internal.StatusBadArgument
   225  	}
   226  	*returnMetricValue = value
   227  	return internal.StatusOK
   228  }
   229  
   230  func TestHostCall_Metric(t *testing.T) {
   231  	host := metricProxyWasmHost{
   232  		internal.DefaultProxyWAMSHost{},
   233  		map[uint32]uint64{},
   234  		map[uint32]internal.MetricType{},
   235  		map[string]uint32{},
   236  	}
   237  	release := internal.RegisterMockWasmHost(host)
   238  	defer release()
   239  
   240  	t.Run("counter", func(t *testing.T) {
   241  		for _, c := range []struct {
   242  			name   string
   243  			offset uint64
   244  		}{
   245  			{name: "requests", offset: 100},
   246  		} {
   247  			t.Run(c.name, func(t *testing.T) {
   248  				// define metric
   249  				m := DefineCounterMetric(c.name)
   250  
   251  				// increment
   252  				m.Increment(c.offset)
   253  
   254  				// get
   255  				require.Equal(t, c.offset, m.Value())
   256  			})
   257  		}
   258  	})
   259  
   260  	t.Run("gauge", func(t *testing.T) {
   261  		for _, c := range []struct {
   262  			name   string
   263  			offset int64
   264  		}{
   265  			{name: "rate", offset: -50},
   266  		} {
   267  			t.Run(c.name, func(t *testing.T) {
   268  				// define metric
   269  				m := DefineGaugeMetric(c.name)
   270  
   271  				// increment
   272  				m.Add(c.offset)
   273  
   274  				// get
   275  				require.Equal(t, c.offset, m.Value())
   276  			})
   277  		}
   278  	})
   279  
   280  	t.Run("histogram", func(t *testing.T) {
   281  		for _, c := range []struct {
   282  			name  string
   283  			value uint64
   284  		}{
   285  			{name: "request count", value: 10000},
   286  		} {
   287  			t.Run(c.name, func(t *testing.T) {
   288  				// define metric
   289  				m := DefineHistogramMetric(c.name)
   290  
   291  				// record
   292  				m.Record(c.value)
   293  
   294  				// get
   295  				require.Equal(t, c.value, m.Value())
   296  			})
   297  		}
   298  	})
   299  }