github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/wasm/store_module_list_test.go (about)

     1  package wasm
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/tetratelabs/wazero/internal/testing/require"
     9  )
    10  
    11  func TestStore_registerModule(t *testing.T) {
    12  	s := newStore()
    13  	m1 := &ModuleInstance{ModuleName: "m1"}
    14  
    15  	t.Run("adds module", func(t *testing.T) {
    16  		require.NoError(t, s.registerModule(m1))
    17  		require.Equal(t, map[string]*ModuleInstance{m1.ModuleName: m1}, s.nameToModule)
    18  		require.Equal(t, m1, s.moduleList)
    19  		require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
    20  	})
    21  
    22  	t.Run("adds second module", func(t *testing.T) {
    23  		m2 := &ModuleInstance{ModuleName: "m2"}
    24  		require.NoError(t, s.registerModule(m2))
    25  		require.Equal(t, map[string]*ModuleInstance{m1.ModuleName: m1, m2.ModuleName: m2}, s.nameToModule)
    26  		require.Equal(t, m2, s.moduleList)
    27  		require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
    28  	})
    29  
    30  	t.Run("error on duplicated non anonymous", func(t *testing.T) {
    31  		m1Second := &ModuleInstance{ModuleName: "m1"}
    32  		require.EqualError(t, s.registerModule(m1Second), "module[m1] has already been instantiated")
    33  	})
    34  
    35  	t.Run("error on closed", func(t *testing.T) {
    36  		require.NoError(t, s.CloseWithExitCode(context.Background(), 0))
    37  		require.Error(t, s.registerModule(m1))
    38  	})
    39  }
    40  
    41  func TestStore_deleteModule(t *testing.T) {
    42  	s, m1, m2 := newTestStore()
    43  
    44  	t.Run("delete one module", func(t *testing.T) {
    45  		require.NoError(t, s.deleteModule(m2))
    46  
    47  		// Leaves the other module alone.
    48  		require.Equal(t, map[string]*ModuleInstance{m1.ModuleName: m1}, s.nameToModule)
    49  		require.Equal(t, m1, s.moduleList)
    50  		require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
    51  	})
    52  
    53  	t.Run("ok if missing", func(t *testing.T) {
    54  		require.NoError(t, s.deleteModule(m2))
    55  	})
    56  
    57  	t.Run("delete last module", func(t *testing.T) {
    58  		require.NoError(t, s.deleteModule(m1))
    59  
    60  		require.Zero(t, len(s.nameToModule))
    61  		require.Nil(t, s.moduleList)
    62  		require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
    63  	})
    64  
    65  	t.Run("delete middle", func(t *testing.T) {
    66  		s := newStore()
    67  		one, two, three := &ModuleInstance{ModuleName: "1"}, &ModuleInstance{ModuleName: "2"}, &ModuleInstance{ModuleName: "3"}
    68  		require.NoError(t, s.registerModule(one))
    69  		require.NoError(t, s.registerModule(two))
    70  		require.NoError(t, s.registerModule(three))
    71  		require.Equal(t, three, s.moduleList)
    72  		require.Nil(t, three.prev)
    73  		require.Equal(t, two, three.next)
    74  		require.Equal(t, two.prev, three)
    75  		require.Equal(t, one, two.next)
    76  		require.Equal(t, one.prev, two)
    77  		require.Nil(t, one.next)
    78  		require.NoError(t, s.deleteModule(two))
    79  		require.Equal(t, three, s.moduleList)
    80  		require.Nil(t, three.prev)
    81  		require.Equal(t, one, three.next)
    82  		require.Equal(t, one.prev, three)
    83  		require.Nil(t, one.next)
    84  	})
    85  }
    86  
    87  func TestStore_module(t *testing.T) {
    88  	s, m1, _ := newTestStore()
    89  
    90  	t.Run("ok", func(t *testing.T) {
    91  		got, err := s.module(m1.ModuleName)
    92  		require.NoError(t, err)
    93  		require.Equal(t, m1, got)
    94  	})
    95  
    96  	t.Run("unknown", func(t *testing.T) {
    97  		got, err := s.module("unknown")
    98  		require.Error(t, err)
    99  		require.Nil(t, got)
   100  	})
   101  
   102  	t.Run("store closed", func(t *testing.T) {
   103  		require.NoError(t, s.CloseWithExitCode(context.Background(), 0))
   104  		got, err := s.module(m1.ModuleName)
   105  		require.Error(t, err)
   106  		require.Nil(t, got)
   107  	})
   108  }
   109  
   110  func TestStore_nameToModuleCap(t *testing.T) {
   111  	t.Run("nameToModuleCap grows beyond initial cap", func(t *testing.T) {
   112  		s := newStore()
   113  		for i := 0; i < 300; i++ {
   114  			require.NoError(t, s.registerModule(&ModuleInstance{ModuleName: fmt.Sprintf("m%d", i)}))
   115  		}
   116  
   117  		require.Equal(t, 300, s.nameToModuleCap)
   118  	})
   119  
   120  	t.Run("nameToModuleCap shrinks by half the cap", func(t *testing.T) {
   121  		s := newStore()
   122  		for i := 0; i < 400; i++ {
   123  			require.NoError(t, s.registerModule(&ModuleInstance{ModuleName: fmt.Sprintf("m%d", i)}))
   124  		}
   125  
   126  		for i := 0; i < 250; i++ {
   127  			require.NoError(t, s.deleteModule(s.nameToModule[fmt.Sprintf("m%d", i)]))
   128  		}
   129  
   130  		require.Equal(t, 200, s.nameToModuleCap)
   131  	})
   132  
   133  	t.Run("nameToModuleCap does not shrink below initial size", func(t *testing.T) {
   134  		s := newStore()
   135  		for i := 0; i < 400; i++ {
   136  			require.NoError(t, s.registerModule(&ModuleInstance{ModuleName: fmt.Sprintf("m%d", i)}))
   137  		}
   138  
   139  		for i := 0; i < 350; i++ {
   140  			require.NoError(t, s.deleteModule(s.nameToModule[fmt.Sprintf("m%d", i)]))
   141  		}
   142  
   143  		require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
   144  	})
   145  
   146  	t.Run("nameToModuleCap does not grow when if nameToModule does not grow", func(t *testing.T) {
   147  		s := newStore()
   148  		for i := 0; i < 99; i++ {
   149  			require.NoError(t, s.registerModule(&ModuleInstance{ModuleName: fmt.Sprintf("m%d", i)}))
   150  		}
   151  		for i := 0; i < 400; i++ {
   152  			require.NoError(t, s.registerModule(&ModuleInstance{ModuleName: fmt.Sprintf("m%d", i+99)}))
   153  			require.NoError(t, s.deleteModule(s.nameToModule[fmt.Sprintf("m%d", i+99)]))
   154  			require.Equal(t, nameToModuleShrinkThreshold, s.nameToModuleCap)
   155  		}
   156  	})
   157  }
   158  
   159  func TestStore_Module(t *testing.T) {
   160  	s, m1, _ := newTestStore()
   161  
   162  	t.Run("ok", func(t *testing.T) {
   163  		require.Equal(t, m1, s.Module(m1.ModuleName))
   164  	})
   165  
   166  	t.Run("unknown", func(t *testing.T) {
   167  		require.Nil(t, s.Module("unknown"))
   168  	})
   169  }
   170  
   171  // newTestStore sets up a new Store without adding test coverage its functions.
   172  func newTestStore() (*Store, *ModuleInstance, *ModuleInstance) {
   173  	s := newStore()
   174  	m1 := &ModuleInstance{ModuleName: "m1"}
   175  	m2 := &ModuleInstance{ModuleName: "m2"}
   176  
   177  	m1.prev = m2
   178  	m2.next = m1
   179  	s.nameToModule = map[string]*ModuleInstance{m1.ModuleName: m1, m2.ModuleName: m2}
   180  	s.moduleList = m2
   181  	return s, m1, m2
   182  }