From af9030a38393a9e8088d076ef42fffedd32d0c75 Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Thu, 25 May 2023 20:24:20 +0530 Subject: [PATCH] Change for multiple resources paths (#1276) * Initial change for multiple resources paths for normal run Signed-off-by: Pravin Pushkar * multi app run changes for multiple resource paths Signed-off-by: Pravin Pushkar * correct file paths for windows Signed-off-by: Pravin Pushkar * remove checking duplicates Signed-off-by: Pravin Pushkar * addressed review comments Signed-off-by: Pravin Pushkar * Fix tests Signed-off-by: Pravin Pushkar --------- Signed-off-by: Pravin Pushkar --- cmd/run.go | 8 +- go.mod | 6 +- go.sum | 12 +- pkg/standalone/run.go | 36 +++--- .../runfileconfig/run_file_config_parser.go | 39 ++++++- .../run_file_config_parser_test.go | 109 +++++++++++++----- ...t_run_config_multiple_resources_paths.yaml | 19 +++ ...t_run_config_precedence_rule_dapr_dir.yaml | 2 +- tests/e2e/standalone/run_test.go | 16 +++ .../additional_resources/test-statestore.yaml | 8 ++ 10 files changed, 195 insertions(+), 60 deletions(-) create mode 100644 pkg/standalone/testdata/runfileconfig/test_run_config_multiple_resources_paths.yaml create mode 100644 tests/e2e/testdata/additional_resources/test-statestore.yaml diff --git a/cmd/run.go b/cmd/run.go index 41388c034..d603a6a73 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -49,7 +49,7 @@ var ( logLevel string protocol string componentsPath string - resourcesPath string + resourcesPaths []string appSSL bool metricsPort int maxRequestBodySize int @@ -160,7 +160,7 @@ dapr run --run-file /path/to/directory AppProtocol: protocol, PlacementHostAddr: viper.GetString("placement-host-address"), ComponentsPath: componentsPath, - ResourcesPath: resourcesPath, + ResourcesPaths: resourcesPaths, AppSSL: appSSL, MaxRequestBodySize: maxRequestBodySize, HTTPReadBufferSize: readBufferSize, @@ -435,8 +435,8 @@ func init() { RunCmd.Flags().StringVarP(&logLevel, "log-level", "", "info", "The log verbosity. Valid values are: debug, info, warn, error, fatal, or panic") RunCmd.Flags().IntVarP(&maxConcurrency, "app-max-concurrency", "", -1, "The concurrency level of the application, otherwise is unlimited") RunCmd.Flags().StringVarP(&protocol, "app-protocol", "P", "http", "The protocol (grpc, grpcs, http, https, h2c) Dapr uses to talk to the application") - RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", "", "The path for components directory") - RunCmd.Flags().StringVarP(&resourcesPath, "resources-path", "", "", "The path for resources directory") + RunCmd.Flags().StringVarP(&componentsPath, "components-path", "d", "", "The path for components directory. Default is $HOME/.dapr/components or %USERPROFILE%\\.dapr\\components") + RunCmd.Flags().StringSliceVarP(&resourcesPaths, "resources-path", "", []string{}, "The path for resources directory") // TODO: Remove below line once the flag is removed in the future releases. // By marking this as deprecated, the flag will be hidden from the help menu, but will continue to work. It will show a warning message when used. RunCmd.Flags().MarkDeprecated("components-path", "This flag is deprecated and will be removed in the future releases. Use \"resources-path\" flag instead") diff --git a/go.mod b/go.mod index 35aa5b55d..394a13771 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect github.com/Pallinder/sillyname-go v0.0.0-20130730142914-97aeae9e6ba1 github.com/briandowns/spinner v1.19.0 - github.com/dapr/dapr v1.11.0-rc.1 + github.com/dapr/dapr v1.11.0-rc.4 github.com/dapr/go-sdk v1.6.0 github.com/docker/docker v20.10.21+incompatible github.com/fatih/color v1.15.0 @@ -72,7 +72,7 @@ require ( github.com/containerd/containerd v1.6.18 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect - github.com/dapr/components-contrib v1.11.0-rc.4 // indirect + github.com/dapr/components-contrib v1.11.0-rc.6 // indirect github.com/dapr/kit v0.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect @@ -147,7 +147,7 @@ require ( github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microsoft/durabletask-go v0.2.1 // indirect + github.com/microsoft/durabletask-go v0.2.3 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect diff --git a/go.sum b/go.sum index f80c65497..8ee190a33 100644 --- a/go.sum +++ b/go.sum @@ -336,10 +336,10 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= -github.com/dapr/components-contrib v1.11.0-rc.4 h1:+MexV5pqeBxqCWcmAMwHCENl8DosAZhND9UDiLBK15A= -github.com/dapr/components-contrib v1.11.0-rc.4/go.mod h1:AwbfpZkJttIxPGGtg4tDyXz7izzjca0xfHbzixazLmw= -github.com/dapr/dapr v1.11.0-rc.1 h1:GlQI3xwwMdfbICltsnMjSwPeSn9IXhERwoQwoWYu5Po= -github.com/dapr/dapr v1.11.0-rc.1/go.mod h1:fBzcrk4+o6pdGOHaFp0fsEM7gL/swfH78NYw2hCvsbM= +github.com/dapr/components-contrib v1.11.0-rc.6 h1:sJiILsy/UVVeDeYp7tfG41Jw/kut3B98yWPKnxFO0tI= +github.com/dapr/components-contrib v1.11.0-rc.6/go.mod h1:esIqaJSvemBfMVoO9PVNCKZBEX38SVKRd22RI7XLWOA= +github.com/dapr/dapr v1.11.0-rc.4 h1:orrtDE0QSLGy5JbKvnZpAjuLTc3iERVKzHRLePpZW4o= +github.com/dapr/dapr v1.11.0-rc.4/go.mod h1:BZI1EBRrjVUgF9be++d92AnX3RzPrzuaMpEF6YoqveI= github.com/dapr/go-sdk v1.6.0 h1:jg5A2khSCHF8bGZsig5RWN/gD0jjitszc2V6Uq2pPdY= github.com/dapr/go-sdk v1.6.0/go.mod h1:KLQBltoD9K0w5hKTihdcyg9Epob9gypwL5dYcQzPro4= github.com/dapr/kit v0.0.5 h1:BbjO6LksdXAv6iuTVZiHJNkXj9Ii1gS2wA1u785Ypsg= @@ -822,8 +822,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/microsoft/durabletask-go v0.2.1 h1:ZSEJi43KOEALwWOlj0oJI2LezEgwQeUsITyTUbH2DYQ= -github.com/microsoft/durabletask-go v0.2.1/go.mod h1:UtJXHmKalksdccRiN9Y16cHJYYtZN0bqmqOSiy56V8g= +github.com/microsoft/durabletask-go v0.2.3 h1:Qrwij52Y1qf2jVPEETBZEOoRK69ZMZl5VqwVNKEJh7w= +github.com/microsoft/durabletask-go v0.2.3/go.mod h1:UtJXHmKalksdccRiN9Y16cHJYYtZN0bqmqOSiy56V8g= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= diff --git a/pkg/standalone/run.go b/pkg/standalone/run.go index c39903fb7..d8ac1db97 100644 --- a/pkg/standalone/run.go +++ b/pkg/standalone/run.go @@ -59,8 +59,9 @@ type SharedRunConfig struct { LogLevel string `arg:"log-level" yaml:"logLevel"` MaxConcurrency int `arg:"app-max-concurrency" yaml:"appMaxConcurrency" default:"-1"` PlacementHostAddr string `arg:"placement-host-address" yaml:"placementHostAddress"` - ComponentsPath string `arg:"components-path"` - ResourcesPath string `arg:"resources-path" yaml:"resourcesPath"` + ComponentsPath string `arg:"components-path"` // Deprecated in run template file: use ResourcesPaths instead. + ResourcesPath string `yaml:"resourcesPath"` // Deprecated in run template file: use ResourcesPaths instead. + ResourcesPaths []string `arg:"resources-path" yaml:"resourcesPaths"` AppSSL bool `arg:"app-ssl" yaml:"appSSL"` MaxRequestBodySize int `arg:"dapr-http-max-request-size" yaml:"daprHTTPMaxRequestSize" default:"-1"` HTTPReadBufferSize int `arg:"dapr-http-read-buffer-size" yaml:"daprHTTPReadBufferSize" default:"-1"` @@ -83,17 +84,18 @@ func (meta *DaprMeta) newAppID() string { } } -func (config *RunConfig) validateResourcesPath() error { - dirPath := config.ResourcesPath - if dirPath == "" { - dirPath = config.ComponentsPath +func (config *RunConfig) validateResourcesPaths() error { + dirPath := config.ResourcesPaths + if len(dirPath) == 0 { + dirPath = []string{config.ComponentsPath} } - _, err := os.Stat(dirPath) - if err != nil { - return fmt.Errorf("error validating resources path %q : %w", dirPath, err) + for _, path := range dirPath { + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("error validating resources path %q : %w", dirPath, err) + } } - componentsLoader := components.NewLocalComponents(dirPath) - _, err = componentsLoader.LoadComponents() + componentsLoader := components.NewLocalComponents(dirPath...) + _, err := componentsLoader.LoadComponents() if err != nil { return fmt.Errorf("error validating components in resources path %q : %w", dirPath, err) } @@ -142,12 +144,12 @@ func (config *RunConfig) Validate() error { config.AppID = meta.newAppID() } - err = config.validateResourcesPath() + err = config.validateResourcesPaths() if err != nil { return err } - if config.ResourcesPath != "" { + if len(config.ResourcesPaths) > 0 { config.ComponentsPath = "" } @@ -286,11 +288,17 @@ func getArgsFromSchema(schema reflect.Value, args []string) []string { ifneq, hasIfneq := typeField.Tag.Lookup("ifneq") - switch valueField.(type) { + switch vType := valueField.(type) { case bool: if valueField == true { args = append(args, key) } + case []string: + if len(vType) > 0 { + for _, val := range vType { + args = append(args, key, val) + } + } default: value := fmt.Sprintf("%v", reflect.ValueOf(valueField)) if len(value) != 0 && (!hasIfneq || value != ifneq) { diff --git a/pkg/standalone/runfileconfig/run_file_config_parser.go b/pkg/standalone/runfileconfig/run_file_config_parser.go index 42cf39c27..6f0a90716 100644 --- a/pkg/standalone/runfileconfig/run_file_config_parser.go +++ b/pkg/standalone/runfileconfig/run_file_config_parser.go @@ -56,6 +56,20 @@ func (a *RunFileConfig) validateRunConfig(runFilePath string) error { if err != nil { return err } + + // Resolves common's section ResourcesPaths to absolute paths and validates them. + for i := range a.Common.ResourcesPaths { + err := a.resolvePathToAbsAndValidate(baseDir, &a.Common.ResourcesPaths[i]) + if err != nil { + return err + } + } + + // Merge common's section ResourcesPaths and ResourcePath. ResourcesPaths will be single source of truth for resources to be loaded. + if len(strings.TrimSpace(a.Common.ResourcesPath)) > 0 { + a.Common.ResourcesPaths = append(a.Common.ResourcesPaths, a.Common.ResourcesPath) + } + for i := 0; i < len(a.Apps); i++ { if a.Apps[i].AppDirPath == "" { return errors.New("required field 'appDirPath' not found in the provided app config file") @@ -70,6 +84,19 @@ func (a *RunFileConfig) validateRunConfig(runFilePath string) error { if err != nil { return err } + + // Resolves ResourcesPaths to absolute paths and validates them. + for j := range a.Apps[i].ResourcesPaths { + err := a.resolvePathToAbsAndValidate(a.Apps[i].AppDirPath, &a.Apps[i].ResourcesPaths[j]) + if err != nil { + return err + } + } + + // Merge app's section ResourcesPaths and ResourcePath. ResourcesPaths will be single source of truth for resources to be loaded. + if len(strings.TrimSpace(a.Apps[i].ResourcesPath)) > 0 { + a.Apps[i].ResourcesPaths = append(a.Apps[i].ResourcesPaths, a.Apps[i].ResourcesPath) + } } return nil } @@ -231,22 +258,22 @@ func (a *RunFileConfig) mergeCommonAndAppsEnv() { } // resolveResourcesFilePath resolves the resources path for the app. -// Precedence order for resourcesPath -> apps[i].resourcesPath > apps[i].appDirPath/.dapr/resources > common.resourcesPath > dapr default resources path. +// Precedence order for resourcesPaths -> apps[i].resourcesPaths > apps[i].appDirPath/.dapr/resources > common.resourcesPaths > dapr default resources path. func (a *RunFileConfig) resolveResourcesFilePath(app *App) error { - if app.ResourcesPath != "" { + if len(app.ResourcesPaths) > 0 { return nil } localResourcesDir := filepath.Join(app.AppDirPath, standalone.DefaultDaprDirName, standalone.DefaultResourcesDirName) if err := utils.ValidateFilePath(localResourcesDir); err == nil { - app.ResourcesPath = localResourcesDir - } else if len(strings.TrimSpace(a.Common.ResourcesPath)) > 0 { - app.ResourcesPath = a.Common.ResourcesPath + app.ResourcesPaths = []string{localResourcesDir} + } else if len(a.Common.ResourcesPaths) > 0 { + app.ResourcesPaths = append(app.ResourcesPaths, a.Common.ResourcesPaths...) } else { daprDirPath, err := standalone.GetDaprRuntimePath(app.DaprdInstallPath) if err != nil { return fmt.Errorf("error getting dapr install path: %w", err) } - app.ResourcesPath = standalone.GetDaprComponentsPath(daprDirPath) + app.ResourcesPaths = []string{standalone.GetDaprComponentsPath(daprDirPath)} } return nil } diff --git a/pkg/standalone/runfileconfig/run_file_config_parser_test.go b/pkg/standalone/runfileconfig/run_file_config_parser_test.go index bc8bc952a..7527a4c2f 100644 --- a/pkg/standalone/runfileconfig/run_file_config_parser_test.go +++ b/pkg/standalone/runfileconfig/run_file_config_parser_test.go @@ -16,6 +16,7 @@ package runfileconfig import ( "os" "path/filepath" + "strings" "testing" "github.com/dapr/cli/pkg/standalone" @@ -30,6 +31,7 @@ var ( runFileForPrecedenceRule = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_precedence_rule.yaml") runFileForPrecedenceRuleDaprDir = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_precedence_rule_dapr_dir.yaml") runFileForLogDestination = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_log_destination.yaml") + runFileForMultiResourcePaths = filepath.Join("..", "testdata", "runfileconfig", "test_run_config_multiple_resources_paths.yaml") ) func TestRunConfigFile(t *testing.T) { @@ -71,17 +73,17 @@ func TestRunConfigFile(t *testing.T) { assert.Equal(t, "/tmp/test-socket", apps[1].UnixDomainSocket) // test resourcesPath and configPath after precedence order logic. - assert.Equal(t, filepath.Join(apps[0].AppDirPath, "resources"), apps[0].ResourcesPath) - assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPath) + assert.Equal(t, filepath.Join(apps[0].AppDirPath, "resources"), apps[0].ResourcesPaths[0]) + assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPaths[0]) assert.Equal(t, filepath.Join(apps[0].AppDirPath, "config.yaml"), apps[0].ConfigFile) assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "config.yaml"), apps[1].ConfigFile) // temporarily set apps[0].ResourcesPath to empty string to test it is getting picked from common section. - apps[0].ResourcesPath = "" + apps[0].ResourcesPaths = []string{} config.resolveResourcesAndConfigFilePaths() - assert.Equal(t, config.Common.ResourcesPath, apps[0].ResourcesPath) - assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPath) + assert.Equal(t, config.Common.ResourcesPaths[0], apps[0].ResourcesPaths[0]) + assert.Equal(t, filepath.Join(apps[1].AppDirPath, ".dapr", "resources"), apps[1].ResourcesPaths[0]) // test merged envs from common and app sections. assert.Equal(t, 2, len(apps[0].Env)) @@ -104,45 +106,39 @@ func TestRunConfigFile(t *testing.T) { err = config.validateRunConfig(runFileForPrecedenceRule) assert.NoError(t, err) + // test precedence logic for resourcesPath and configPath. + err = config.resolveResourcesAndConfigFilePaths() + assert.NoError(t, err) + testcases := []struct { name string - disableCommonSection bool expectedResourcesPath string expectedConfigFilePath string appIndex int }{ { - name: "resourcesPath and configPath are set in app section", - disableCommonSection: false, + name: "resourcesPaths and configPath are set in app section", expectedResourcesPath: filepath.Join(config.Apps[0].AppDirPath, "resources"), expectedConfigFilePath: filepath.Join(config.Apps[0].AppDirPath, "config.yaml"), appIndex: 0, }, { - name: "resourcesPath and configPath present in .dapr directory under appDirPath", - disableCommonSection: false, + name: "resourcesPaths and configPath present in .dapr directory under appDirPath", expectedResourcesPath: filepath.Join(config.Apps[1].AppDirPath, ".dapr", "resources"), expectedConfigFilePath: filepath.Join(config.Apps[1].AppDirPath, ".dapr", "config.yaml"), appIndex: 1, }, { - name: "resourcesPath and configPath are resolved from common's section", - disableCommonSection: false, - expectedResourcesPath: config.Common.ResourcesPath, // from common section. - expectedConfigFilePath: config.Common.ConfigFile, // from common section. + name: "resourcesPaths and configPath are resolved from common's section", + expectedResourcesPath: config.Common.ResourcesPaths[0], // from common section. + expectedConfigFilePath: config.Common.ConfigFile, // from common section. appIndex: 2, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - if tc.disableCommonSection { - config.Common.ResourcesPath = "" - config.Common.ConfigFile = "" - } - // test precedence logic for resourcesPath and configPath. - config.resolveResourcesAndConfigFilePaths() - assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPath) + assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0]) assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile) }) } @@ -163,6 +159,11 @@ func TestRunConfigFile(t *testing.T) { app2Data := getResourcesAndConfigFilePaths(t, config.Apps[1].DaprdInstallPath) app2ResourcesPath := app2Data[0] app2ConfigFilePath := app2Data[1] + + // test precedence logic for resourcesPath and configPath. + err = config.resolveResourcesAndConfigFilePaths() + assert.NoError(t, err) + testcases := []struct { name string expectedResourcesPath string @@ -170,13 +171,13 @@ func TestRunConfigFile(t *testing.T) { appIndex int }{ { - name: "resourcesPath and configPath are resolved from dapr's default installation path.", + name: "resourcesPaths and configPath are resolved from dapr's default installation path.", expectedResourcesPath: app1ResourcesPath, expectedConfigFilePath: app1ConfigFilePath, appIndex: 0, }, { - name: "resourcesPath and configPath are resolved from dapr's custom installation path.", + name: "resourcesPaths and configPath are resolved from dapr's custom installation path.", expectedResourcesPath: app2ResourcesPath, expectedConfigFilePath: app2ConfigFilePath, appIndex: 1, @@ -185,9 +186,7 @@ func TestRunConfigFile(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - // test precedence logic for resourcesPath and configPath. - config.resolveResourcesAndConfigFilePaths() - assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPath) + assert.Equal(t, tc.expectedResourcesPath, config.Apps[tc.appIndex].ResourcesPaths[0]) assert.Equal(t, tc.expectedConfigFilePath, config.Apps[tc.appIndex].ConfigFile) }) } @@ -252,6 +251,64 @@ func TestRunConfigFile(t *testing.T) { }) } +func TestMultiResourcePathsResolution(t *testing.T) { + config := RunFileConfig{} + + err := config.parseAppsConfig(runFileForMultiResourcePaths) + assert.NoError(t, err) + err = config.validateRunConfig(runFileForMultiResourcePaths) + assert.NoError(t, err) + + // test precedence logic for multiple resources paths. + err = config.resolveResourcesAndConfigFilePaths() + assert.NoError(t, err) + + testcases := []struct { + name string + expectedNoOfResources int + expectedResourcesPathsContains string + appIndex int + }{ + { + name: "resourcesPaths should have 2 paths", + expectedNoOfResources: 2, + expectedResourcesPathsContains: filepath.Join(config.Apps[0].AppDirPath, "resources"), + appIndex: 0, + }, + { + name: "resourcesPaths should have 2 paths", + expectedNoOfResources: 2, + expectedResourcesPathsContains: filepath.Join("backend", ".dapr", "resources"), + appIndex: 0, + }, + { + name: "resourcesPaths should have 2 path from common section", + expectedNoOfResources: 2, + expectedResourcesPathsContains: filepath.Join("app", "resources"), + appIndex: 1, + }, + { + name: "resourcesPaths should have 1 path from .dapr's folder", + expectedNoOfResources: 1, + expectedResourcesPathsContains: filepath.Join("backend", ".dapr", "resources"), + appIndex: 2, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expectedNoOfResources, len(config.Apps[tc.appIndex].ResourcesPaths)) + var rsrcFound bool + for _, resourcePath := range config.Apps[tc.appIndex].ResourcesPaths { + if rsrcFound = strings.Contains(resourcePath, tc.expectedResourcesPathsContains); rsrcFound { + break + } + } + assert.True(t, rsrcFound) + }) + } +} + func TestGetBasePathFromAbsPath(t *testing.T) { testcases := []struct { name string diff --git a/pkg/standalone/testdata/runfileconfig/test_run_config_multiple_resources_paths.yaml b/pkg/standalone/testdata/runfileconfig/test_run_config_multiple_resources_paths.yaml new file mode 100644 index 000000000..8f624dfd0 --- /dev/null +++ b/pkg/standalone/testdata/runfileconfig/test_run_config_multiple_resources_paths.yaml @@ -0,0 +1,19 @@ +version: 1 +common: +# resourcesPath and resourcesPaths should be combined into resourcesPaths and should contain 1 path to load resources from. + resourcesPath: ./app/resources + resourcesPaths: + - ./app/resources + configFilePath: ./app/config.yaml +apps: +# resourcesPaths should contain 2 paths to load resources from. + - appDirPath: ./webapp/ + resourcesPath: ./resources + resourcesPaths: + - ../backend/.dapr/resources +# resourcesPaths should be resolved from common's section and should contain 1 path to load resources from. + - appDirPath: ./webapp/ + appID: webapp_1 +# resourcesPaths resolved from app/.dapr folder and should contain 1 path to load resources from. + - appID: backend + appDirPath: ./backend/ \ No newline at end of file diff --git a/pkg/standalone/testdata/runfileconfig/test_run_config_precedence_rule_dapr_dir.yaml b/pkg/standalone/testdata/runfileconfig/test_run_config_precedence_rule_dapr_dir.yaml index f706c4439..9073e6afa 100644 --- a/pkg/standalone/testdata/runfileconfig/test_run_config_precedence_rule_dapr_dir.yaml +++ b/pkg/standalone/testdata/runfileconfig/test_run_config_precedence_rule_dapr_dir.yaml @@ -7,4 +7,4 @@ apps: # tests resourcesPath and config_file resolved from dapr's custom installation directory. - appID: app_custom_dapr_dir appDirPath: ./app_precedence_rule/ - daprPath: ../custom_dapr_dir \ No newline at end of file + runtimePath: ../custom_dapr_dir \ No newline at end of file diff --git a/tests/e2e/standalone/run_test.go b/tests/e2e/standalone/run_test.go index d831c8c51..35992ccdc 100644 --- a/tests/e2e/standalone/run_test.go +++ b/tests/e2e/standalone/run_test.go @@ -178,6 +178,22 @@ func TestStandaloneRun(t *testing.T) { assert.Contains(t, output, "Exited Dapr successfully") }) + t.Run("check run with multiple resources-path", func(t *testing.T) { + args := []string{ + "--app-id", "testapp", + "--resources-path", "../testdata/resources", + "--resources-path", "../testdata/additional_resources", + "--", "bash", "-c", "echo 'test'", + } + output, err := cmdRun("", args...) + t.Log(output) + require.NoError(t, err, "run failed") + assert.Contains(t, output, "Component loaded: test-statestore (state.in-memory/v1)") + assert.Contains(t, output, "Component loaded: test-statestore-additional-resource (state.in-memory/v1)") + assert.Contains(t, output, "Exited App successfully") + assert.Contains(t, output, "Exited Dapr successfully") + }) + t.Run("run with unknown flags", func(t *testing.T) { output, err := cmdRun("", "--flag") require.Error(t, err, "expected error on run unknown flag") diff --git a/tests/e2e/testdata/additional_resources/test-statestore.yaml b/tests/e2e/testdata/additional_resources/test-statestore.yaml new file mode 100644 index 000000000..2182f6cf7 --- /dev/null +++ b/tests/e2e/testdata/additional_resources/test-statestore.yaml @@ -0,0 +1,8 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: test-statestore-additional-resource +spec: + type: state.in-memory + version: v1 + metadata: