github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/store_module_list_test.go (about) 1 package wasm 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/bananabytelabs/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 }