github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/it/impl_bootstrap_test.go (about) 1 /* 2 * Copyright (c) 2024-present unTill Software Development Group B.V. 3 * @author Denis Gribanov 4 */ 5 6 package sys_it 7 8 import ( 9 "fmt" 10 "testing" 11 "testing/fstest" 12 13 "github.com/stretchr/testify/require" 14 "github.com/voedger/voedger/pkg/appparts" 15 "github.com/voedger/voedger/pkg/apps" 16 "github.com/voedger/voedger/pkg/apps/sys/clusterapp" 17 "github.com/voedger/voedger/pkg/btstrp" 18 "github.com/voedger/voedger/pkg/cluster" 19 "github.com/voedger/voedger/pkg/extensionpoints" 20 "github.com/voedger/voedger/pkg/iblobstoragestg" 21 "github.com/voedger/voedger/pkg/istorage" 22 "github.com/voedger/voedger/pkg/istorage/mem" 23 "github.com/voedger/voedger/pkg/istructs" 24 "github.com/voedger/voedger/pkg/istructsmem" 25 payloads "github.com/voedger/voedger/pkg/itokens-payloads" 26 "github.com/voedger/voedger/pkg/parser" 27 "github.com/voedger/voedger/pkg/sys" 28 "github.com/voedger/voedger/pkg/sys/authnz" 29 "github.com/voedger/voedger/pkg/sys/smtp" 30 coreutils "github.com/voedger/voedger/pkg/utils" 31 it "github.com/voedger/voedger/pkg/vit" 32 "github.com/voedger/voedger/pkg/vvm" 33 dbcertcache "github.com/voedger/voedger/pkg/vvm/db_cert_cache" 34 ) 35 36 func TestBoostrap_BasicUsage(t *testing.T) { 37 require := require.New(t) 38 memStorage := mem.Provide() 39 keyspacePrefix := t.Name() 40 41 // launch the VVM with an app with a certain NumParts and NumAppWorkspaces 42 numParts := istructs.NumAppPartitions(42) 43 numAppWS := istructs.NumAppWorkspaces(43) 44 cfg := getTestCfg(numParts, numAppWS, memStorage, keyspacePrefix) 45 vit := it.NewVIT(t, &cfg) 46 47 var clusterApp btstrp.ClusterBuiltInApp 48 otherApps := []appparts.BuiltInApp{} 49 for _, app := range vit.BuiltInAppsPackages { 50 if app.Name == istructs.AppQName_sys_cluster { 51 clusterApp = btstrp.ClusterBuiltInApp(app.BuiltInApp) 52 } else { 53 otherApps = append(otherApps, app.BuiltInApp) 54 } 55 } 56 57 t.Run("basic usage", func(t *testing.T) { 58 appParts, cleanup, err := appparts.New(vit.IAppStructsProvider) 59 require.NoError(err) 60 defer cleanup() 61 blobStorage := iblobstoragestg.BlobAppStoragePtr(new(istorage.IAppStorage)) 62 routerStorage := dbcertcache.RouterAppStoragePtr(new(istorage.IAppStorage)) 63 err = btstrp.Bootstrap(vit.IFederation, vit.IAppStructsProvider, vit.TimeFunc, appParts, clusterApp, otherApps, vit.ITokens, vit.IAppStorageProvider, 64 blobStorage, routerStorage) 65 require.NoError(err) 66 require.NotNil(*blobStorage) 67 require.NotNil(*routerStorage) 68 }) 69 70 t.Run("panic on NumPartitions change", func(t *testing.T) { 71 appParts, cleanup, err := appparts.New(vit.IAppStructsProvider) 72 require.NoError(err) 73 defer cleanup() 74 otherApps[0].AppDeploymentDescriptor.NumParts++ 75 defer func() { 76 otherApps[0].AppDeploymentDescriptor.NumParts-- 77 }() 78 blobStorage := iblobstoragestg.BlobAppStoragePtr(new(istorage.IAppStorage)) 79 routerStorage := dbcertcache.RouterAppStoragePtr(new(istorage.IAppStorage)) 80 require.PanicsWithValue(fmt.Sprintf("failed to deploy app %[1]s: status 409: num partitions changed: app %[1]s declaring NumPartitions=%d but was previously deployed with NumPartitions=%d", 81 otherApps[0].Name, otherApps[0].AppDeploymentDescriptor.NumParts, otherApps[0].AppDeploymentDescriptor.NumParts-1), func() { 82 btstrp.Bootstrap(vit.IFederation, vit.IAppStructsProvider, vit.TimeFunc, appParts, clusterApp, otherApps, vit.ITokens, vit.IAppStorageProvider, 83 blobStorage, routerStorage) 84 }) 85 }) 86 87 t.Run("panic on NumAppPartitions change", func(t *testing.T) { 88 appParts, cleanup, err := appparts.New(vit.IAppStructsProvider) 89 require.NoError(err) 90 defer cleanup() 91 otherApps[0].AppDeploymentDescriptor.NumAppWorkspaces++ 92 defer func() { 93 otherApps[0].AppDeploymentDescriptor.NumAppWorkspaces-- 94 }() 95 96 require.PanicsWithValue(fmt.Sprintf("failed to deploy app %[1]s: status 409: num application workspaces changed: app %[1]s declaring NumAppWorkspaces=%d but was previously deployed with NumAppWorksaces=%d", 97 otherApps[0].Name, otherApps[0].AppDeploymentDescriptor.NumAppWorkspaces, otherApps[0].AppDeploymentDescriptor.NumAppWorkspaces-1), func() { 98 blobStorage := iblobstoragestg.BlobAppStoragePtr(new(istorage.IAppStorage)) 99 routerStorage := dbcertcache.RouterAppStoragePtr(new(istorage.IAppStorage)) 100 btstrp.Bootstrap(vit.IFederation, vit.IAppStructsProvider, vit.TimeFunc, appParts, clusterApp, otherApps, vit.ITokens, 101 vit.IAppStorageProvider, blobStorage, routerStorage) 102 }) 103 }) 104 } 105 106 func getTestCfg(numParts istructs.NumAppPartitions, numAppWS istructs.NumAppWorkspaces, storage istorage.IAppStorageFactory, testName string) it.VITConfig { 107 fs := fstest.MapFS{ 108 "app.vsql": &fstest.MapFile{ 109 Data: []byte(`APPLICATION app1();`), 110 }, 111 } 112 app1PackageFS := parser.PackageFS{ 113 Path: it.App1PkgPath, 114 FS: fs, 115 } 116 return it.NewOwnVITConfig( 117 it.WithApp(istructs.AppQName_test1_app1, func(apis apps.APIs, cfg *istructsmem.AppConfigType, ep extensionpoints.IExtensionPoint) apps.BuiltInAppDef { 118 sysPkg := sys.Provide(cfg, smtp.Cfg{}, ep, nil, apis.TimeFunc, apis.ITokens, apis.IFederation, apis.IAppStructsProvider, apis.IAppTokensFactory, 119 nil, apis.IAppStorageProvider) 120 return apps.BuiltInAppDef{ 121 AppDeploymentDescriptor: appparts.AppDeploymentDescriptor{ 122 NumParts: numParts, 123 EnginePoolSize: it.DefaultTestAppEnginesPool, 124 NumAppWorkspaces: numAppWS, 125 }, 126 AppQName: istructs.AppQName_test1_app1, 127 Packages: []parser.PackageFS{sysPkg, app1PackageFS}, 128 } 129 }), 130 it.WithVVMConfig(func(cfg *vvm.VVMConfig) { 131 // use predefined storage 132 cfg.StorageFactory = func() (provider istorage.IAppStorageFactory, err error) { 133 return storage, nil 134 } 135 cfg.KeyspaceNameSuffix = testName 136 }), 137 ) 138 } 139 140 func TestDeployAppErrors(t *testing.T) { 141 require := require.New(t) 142 vit := it.NewVIT(t, &it.SharedConfig_App1) 143 defer vit.TearDown() 144 145 sysToken, err := payloads.GetSystemPrincipalToken(vit.ITokens, istructs.AppQName_sys_cluster) 146 require.NoError(err) 147 148 t.Run("sys/cluster can not be deployed by c.cluster.DeployApp", func(t *testing.T) { 149 body := fmt.Sprintf(`{"args":{"AppQName":"%s","NumPartitions":1,"NumAppWorkspaces":1}}`, istructs.AppQName_sys_cluster) 150 vit.PostApp(istructs.AppQName_sys_cluster, clusterapp.ClusterAppPseudoWSID, "c.cluster.DeployApp", body, 151 coreutils.WithAuthorizeBy(sysToken), coreutils.Expect400()).Println() 152 }) 153 154 var test1App1DeploymentDescriptor appparts.AppDeploymentDescriptor 155 for _, app := range vit.BuiltInAppsPackages { 156 if app.Name == istructs.AppQName_test1_app1 { 157 test1App1DeploymentDescriptor = app.AppDeploymentDescriptor 158 break 159 } 160 } 161 162 t.Run("409 conflict on try to deploy with different NumPartitions", func(t *testing.T) { 163 body := fmt.Sprintf(`{"args":{"AppQName":"%s","NumPartitions":%d,"NumAppWorkspaces":%d}}`, 164 istructs.AppQName_test1_app1, 165 test1App1DeploymentDescriptor.NumParts+1, test1App1DeploymentDescriptor.NumAppWorkspaces) 166 resp := vit.PostApp(istructs.AppQName_sys_cluster, clusterapp.ClusterAppPseudoWSID, "c.cluster.DeployApp", body, 167 coreutils.WithAuthorizeBy(sysToken), 168 coreutils.Expect409(), 169 ) 170 resp.Println() 171 require.Empty(resp.NewIDs) 172 }) 173 174 t.Run("409 conflict on try to deploy with different NumAppPartitions", func(t *testing.T) { 175 body := fmt.Sprintf(`{"args":{"AppQName":"%s","NumPartitions":%d,"NumAppWorkspaces":%d}}`, 176 istructs.AppQName_test1_app1, 177 test1App1DeploymentDescriptor.NumParts, test1App1DeploymentDescriptor.NumAppWorkspaces+1) 178 resp := vit.PostApp(istructs.AppQName_sys_cluster, clusterapp.ClusterAppPseudoWSID, "c.cluster.DeployApp", body, 179 coreutils.WithAuthorizeBy(sysToken), 180 coreutils.Expect409(), 181 ) 182 resp.Println() 183 require.Empty(resp.NewIDs) 184 }) 185 186 t.Run("400 bad request on wrong appQName", func(t *testing.T) { 187 body := `{"args":{"AppQName":"wrong","NumPartitions":1,"NumAppWorkspaces":1}}` 188 vit.PostApp(istructs.AppQName_sys_cluster, clusterapp.ClusterAppPseudoWSID, "c.cluster.DeployApp", body, 189 coreutils.WithAuthorizeBy(sysToken), 190 coreutils.Expect400(), 191 ).Println() 192 }) 193 } 194 195 func TestAppWSInitIndempotency(t *testing.T) { 196 require := require.New(t) 197 vit := it.NewVIT(t, &it.SharedConfig_App1) 198 defer vit.TearDown() 199 200 checkCDocsWSDesc(vit.VVMConfig, vit.VVM, require) 201 202 // init app ws again (first is done on NewVIT()) -> expect no errors + assume next tests will work as well 203 for _, app := range vit.BuiltInAppsPackages { 204 as, err := vit.AppStructs(app.Name) 205 require.NoError(err) 206 initedWSIDs, err := cluster.InitAppWSes(as, as.NumAppWorkspaces(), app.NumParts, istructs.UnixMilli(vit.TimeFunc().UnixMilli())) 207 require.NoError(err) 208 require.Empty(initedWSIDs) 209 } 210 } 211 212 func checkCDocsWSDesc(vvmCfg *vvm.VVMConfig, vvm *vvm.VVM, require *require.Assertions) { 213 for appQName := range vvmCfg.VVMAppsBuilder { 214 as, err := vvm.AppStructs(appQName) 215 require.NoError(err) 216 for wsNum := 0; istructs.NumAppWorkspaces(wsNum) < as.NumAppWorkspaces(); wsNum++ { 217 appWSID := istructs.NewWSID(istructs.MainClusterID, istructs.WSID(wsNum+int(istructs.FirstBaseAppWSID))) 218 existingCDocWSDesc, err := as.Records().GetSingleton(appWSID, authnz.QNameCDocWorkspaceDescriptor) 219 require.NoError(err) 220 require.Equal(authnz.QNameCDocWorkspaceDescriptor, existingCDocWSDesc.QName()) 221 } 222 } 223 }