github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istructsmem/internal/qnames/impl_test.go (about) 1 /* 2 * Copyright (c) 2021-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package qnames 7 8 import ( 9 "errors" 10 "fmt" 11 "testing" 12 13 "github.com/stretchr/testify/mock" 14 "github.com/stretchr/testify/require" 15 16 "github.com/voedger/voedger/pkg/appdef" 17 "github.com/voedger/voedger/pkg/istorage/mem" 18 istorageimpl "github.com/voedger/voedger/pkg/istorage/provider" 19 "github.com/voedger/voedger/pkg/istructs" 20 "github.com/voedger/voedger/pkg/istructsmem/internal/consts" 21 "github.com/voedger/voedger/pkg/istructsmem/internal/teststore" 22 "github.com/voedger/voedger/pkg/istructsmem/internal/utils" 23 "github.com/voedger/voedger/pkg/istructsmem/internal/vers" 24 ) 25 26 func TestQNames(t *testing.T) { 27 require := require.New(t) 28 29 sp := istorageimpl.Provide(mem.Provide()) 30 storage, err := sp.AppStorage(istructs.AppQName_test1_app1) 31 require.NoError(err) 32 33 versions := vers.New() 34 if err := versions.Prepare(storage); err != nil { 35 panic(err) 36 } 37 38 defName := appdef.NewQName("test", "doc") 39 40 resourceName := appdef.NewQName("test", "resource") 41 r := mockResources{} 42 r.On("Resources", mock.AnythingOfType("func(appdef.QName)")). 43 Run(func(args mock.Arguments) { 44 cb := args.Get(0).(func(appdef.QName)) 45 cb(resourceName) 46 }) 47 48 names := New() 49 if err := names.Prepare(storage, versions, 50 func() appdef.IAppDef { 51 adb := appdef.New() 52 adb.AddPackage("test", "test.com/test") 53 adb.AddCDoc(defName) 54 appDef, err := adb.Build() 55 require.NoError(err) 56 return appDef 57 }(), 58 &r); err != nil { 59 panic(err) 60 } 61 62 t.Run("basic QNames methods", func(t *testing.T) { 63 64 check := func(names *QNames, name appdef.QName) QNameID { 65 id, err := names.ID(name) 66 require.NoError(err) 67 require.NotEqual(NullQNameID, id) 68 69 n, err := names.QName(id) 70 require.NoError(err) 71 require.Equal(name, n) 72 73 return id 74 } 75 76 sID := check(names, defName) 77 rID := check(names, resourceName) 78 79 t.Run("must be ok to load early stored names", func(t *testing.T) { 80 versions1 := vers.New() 81 if err := versions1.Prepare(storage); err != nil { 82 panic(err) 83 } 84 85 names1 := New() 86 if err := names1.Prepare(storage, versions, nil, nil); err != nil { 87 panic(err) 88 } 89 90 require.Equal(sID, check(names1, defName)) 91 require.Equal(rID, check(names1, resourceName)) 92 }) 93 94 t.Run("must be ok to redeclare names", func(t *testing.T) { 95 versions2 := vers.New() 96 if err := versions2.Prepare(storage); err != nil { 97 panic(err) 98 } 99 100 names2 := New() 101 if err := names2.Prepare(storage, versions, 102 func() appdef.IAppDef { 103 adb := appdef.New() 104 adb.AddPackage("test", "test.com/test") 105 adb.AddCDoc(defName) 106 appDef, err := adb.Build() 107 require.NoError(err) 108 return appDef 109 }(), 110 nil); err != nil { 111 panic(err) 112 } 113 114 require.Equal(sID, check(names2, defName)) 115 require.Equal(rID, check(names2, resourceName)) 116 }) 117 }) 118 119 t.Run("must be error if unknown name", func(t *testing.T) { 120 id, err := names.ID(appdef.NewQName("test", "unknown")) 121 require.Equal(NullQNameID, id) 122 require.ErrorIs(err, ErrNameNotFound) 123 }) 124 125 t.Run("must be error if unknown id", func(t *testing.T) { 126 n, err := names.QName(QNameID(MaxAvailableQNameID)) 127 require.Equal(appdef.NullQName, n) 128 require.ErrorIs(err, ErrIDNotFound) 129 }) 130 } 131 132 func TestQNamesPrepareErrors(t *testing.T) { 133 require := require.New(t) 134 135 t.Run("must be error if unknown system view version", func(t *testing.T) { 136 sp := istorageimpl.Provide(mem.Provide()) 137 storage, _ := sp.AppStorage(istructs.AppQName_test1_app1) 138 139 versions := vers.New() 140 if err := versions.Prepare(storage); err != nil { 141 panic(err) 142 } 143 144 versions.Put(vers.SysQNamesVersion, latestVersion+1) 145 146 names := New() 147 err := names.Prepare(storage, versions, nil, nil) 148 require.ErrorIs(err, vers.ErrorInvalidVersion) 149 }) 150 151 t.Run("must be error if invalid QName loaded from system view ", func(t *testing.T) { 152 sp := istorageimpl.Provide(mem.Provide()) 153 storage, _ := sp.AppStorage(istructs.AppQName_test1_app1) 154 155 versions := vers.New() 156 if err := versions.Prepare(storage); err != nil { 157 panic(err) 158 } 159 160 versions.Put(vers.SysQNamesVersion, latestVersion) 161 const badName = "-test.error.qname-" 162 storage.Put(utils.ToBytes(consts.SysView_QNames, ver01), []byte(badName), utils.ToBytes(QNameID(512))) 163 164 names := New() 165 err := names.Prepare(storage, versions, nil, nil) 166 require.ErrorIs(err, appdef.ErrConvertError) 167 require.ErrorContains(err, badName) 168 }) 169 170 t.Run("must be ok if deleted QName loaded from system view ", func(t *testing.T) { 171 sp := istorageimpl.Provide(mem.Provide()) 172 storage, _ := sp.AppStorage(istructs.AppQName_test1_app1) 173 174 versions := vers.New() 175 if err := versions.Prepare(storage); err != nil { 176 panic(err) 177 } 178 179 versions.Put(vers.SysQNamesVersion, latestVersion) 180 storage.Put(utils.ToBytes(consts.SysView_QNames, ver01), []byte("test.deleted"), utils.ToBytes(NullQNameID)) 181 182 names := New() 183 err := names.Prepare(storage, versions, nil, nil) 184 require.NoError(err) 185 }) 186 187 t.Run("must be error if invalid (small) QNameID loaded from system view ", func(t *testing.T) { 188 sp := istorageimpl.Provide(mem.Provide()) 189 storage, _ := sp.AppStorage(istructs.AppQName_test1_app1) 190 191 versions := vers.New() 192 if err := versions.Prepare(storage); err != nil { 193 panic(err) 194 } 195 196 versions.Put(vers.SysQNamesVersion, latestVersion) 197 storage.Put(utils.ToBytes(consts.SysView_QNames, ver01), []byte(istructs.QNameForError.String()), utils.ToBytes(QNameIDForError)) 198 199 names := New() 200 err := names.Prepare(storage, versions, nil, nil) 201 require.ErrorIs(err, ErrWrongQNameID) 202 require.ErrorContains(err, fmt.Sprintf("unexpected ID (%v)", QNameIDForError)) 203 }) 204 205 t.Run("must be error if too many QNames", func(t *testing.T) { 206 sp := istorageimpl.Provide(mem.Provide()) 207 storage, _ := sp.AppStorage(istructs.AppQName_test1_app1) 208 209 versions := vers.New() 210 if err := versions.Prepare(storage); err != nil { 211 panic(err) 212 } 213 214 names := New() 215 err := names.Prepare(storage, versions, 216 func() appdef.IAppDef { 217 adb := appdef.New() 218 adb.AddPackage("test", "test.com/test") 219 for i := 0; i <= MaxAvailableQNameID; i++ { 220 adb.AddObject(appdef.NewQName("test", fmt.Sprintf("name_%d", i))) 221 } 222 appDef, err := adb.Build() 223 require.NoError(err) 224 return appDef 225 }(), 226 nil) 227 require.ErrorIs(err, ErrQNameIDsExceeds) 228 }) 229 230 t.Run("must be error if write to storage failed", func(t *testing.T) { 231 qName := appdef.NewQName("test", "test") 232 writeError := errors.New("storage write error") 233 234 t.Run("must be error if write some name failed", func(t *testing.T) { 235 storage := teststore.NewStorage() 236 237 versions := vers.New() 238 if err := versions.Prepare(storage); err != nil { 239 panic(err) 240 } 241 242 storage.SchedulePutError(writeError, utils.ToBytes(consts.SysView_QNames, ver01), []byte(qName.String())) 243 244 names := New() 245 err := names.Prepare(storage, versions, 246 func() appdef.IAppDef { 247 adb := appdef.New() 248 adb.AddPackage("test", "test.com/test") 249 adb.AddObject(qName) 250 appDef, err := adb.Build() 251 require.NoError(err) 252 return appDef 253 }(), 254 nil) 255 require.ErrorIs(err, writeError) 256 }) 257 258 t.Run("must be error if write system view version failed", func(t *testing.T) { 259 storage := teststore.NewStorage() 260 261 versions := vers.New() 262 if err := versions.Prepare(storage); err != nil { 263 panic(err) 264 } 265 266 storage.SchedulePutError(writeError, utils.ToBytes(consts.SysView_Versions), utils.ToBytes(vers.SysQNamesVersion)) 267 268 names := New() 269 err := names.Prepare(storage, versions, 270 func() appdef.IAppDef { 271 adb := appdef.New() 272 adb.AddPackage("test", "test.com/test") 273 adb.AddObject(qName) 274 appDef, err := adb.Build() 275 require.NoError(err) 276 return appDef 277 }(), 278 nil) 279 require.ErrorIs(err, writeError) 280 }) 281 }) 282 } 283 284 type mockResources struct { 285 mock.Mock 286 } 287 288 func (r *mockResources) QueryResource(resource appdef.QName) istructs.IResource { 289 return r.Called(resource).Get(0).(istructs.IResource) 290 } 291 292 func (r *mockResources) Resources(cb func(appdef.QName)) { 293 r.Called(cb) 294 }