You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	feat(uiVeri5): golang implmementation for uiVeri5ExecuteTests (#2394)
* added uiVeri5ExecuteTests step files * added confPath an regenerated step * added test for uiVeri5ExecuteTests * config modified * added groovy wrapper * ambiguous method fixed * uiveri5 wrapper * removed install command * fixed defaults * added testOptions as confPath arg * test set env * test npm install local * changed env settings * tests regenerated * go generate * fix code climate * overwrite groovy step * remove groovy wrapper go * unstash piper bin * test older node version * test piperExecuteBin * wip * wip * wip * wip * wip * wip * wip * refactored params * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * set testServerUrl as os env for uiveri5 * Update config.yml * fix naming of testServerUrl param * wip * refactored setEnv and fixed tests * wip * step param for NPM_CONFIG_PREFIX * fix runCommand * refactored step param, regenerate, docu, fix tests * fix groovy wrapper test * cleanup * add to CommonStepsTest field whitelist * fixed default pipeline environment vars * fix []string default * fix metadata.go bug * added test for docu metadata gen * fix metadata_test.go in doc gen * Update metadata_generated.go * Update metadata_generated.go * remove npm config prefix param; doc fix * remove tab * changed npm config prefix * removed groovy wrapper test * removed groovy step defaults * modify path variable * modified npm config prefix * fix error wrapper and tests * doc update * add testRepository support * wip * fix testRepository param * wip * add utils * init stash content * wip * wip * wip * add comment for deprecated parameters * fixed commonStepTest * fixed commonStepTest * added error category for testOptions failure * Update vars/uiVeri5ExecuteTests.groovy Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> * Update vars/uiVeri5ExecuteTests.groovy Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> * fix condition Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
This commit is contained in:
		| @@ -60,6 +60,7 @@ func GetAllStepMetadata() map[string]config.StepData { | ||||
| 		"containerSaveImage":                      containerSaveImageMetadata(), | ||||
| 		"sonarExecuteScan":                        sonarExecuteScanMetadata(), | ||||
| 		"transportRequestUploadCTS":               transportRequestUploadCTSMetadata(), | ||||
| 		"uiVeri5ExecuteTests":                     uiVeri5ExecuteTestsMetadata(), | ||||
| 		"vaultRotateSecretId":                     vaultRotateSecretIdMetadata(), | ||||
| 		"artifactPrepareVersion":                  artifactPrepareVersionMetadata(), | ||||
| 		"whitesourceExecuteScan":                  whitesourceExecuteScanMetadata(), | ||||
|   | ||||
| @@ -70,6 +70,7 @@ func Execute() { | ||||
| 	rootCmd.AddCommand(DetectExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(HadolintExecuteCommand()) | ||||
| 	rootCmd.AddCommand(KarmaExecuteTestsCommand()) | ||||
| 	rootCmd.AddCommand(UiVeri5ExecuteTestsCommand()) | ||||
| 	rootCmd.AddCommand(SonarExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(KubernetesDeployCommand()) | ||||
| 	rootCmd.AddCommand(XsDeployCommand()) | ||||
|   | ||||
							
								
								
									
										49
									
								
								cmd/uiVeri5ExecuteTests.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								cmd/uiVeri5ExecuteTests.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| func uiVeri5ExecuteTests(config uiVeri5ExecuteTestsOptions, telemetryData *telemetry.CustomData) { | ||||
| 	// for command execution use Command | ||||
| 	c := command.Command{} | ||||
| 	// reroute command output to logging framework | ||||
| 	c.Stdout(log.Writer()) | ||||
| 	c.Stderr(log.Writer()) | ||||
|  | ||||
| 	// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	err := runUIVeri5(&config, &c) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("step execution failed") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func runUIVeri5(config *uiVeri5ExecuteTestsOptions, command command.ExecRunner) error { | ||||
| 	envs := []string{"NPM_CONFIG_PREFIX=~/.npm-global"} | ||||
| 	path := "PATH=" + os.Getenv("PATH") + ":~/.npm-global/bin" | ||||
| 	envs = append(envs, path) | ||||
| 	if config.TestServerURL != "" { | ||||
| 		envs = append(envs, "TARGET_SERVER_URL="+config.TestServerURL) | ||||
| 	} | ||||
| 	command.SetEnv(envs) | ||||
|  | ||||
| 	installCommandTokens := strings.Split(config.InstallCommand, " ") | ||||
| 	if err := command.RunExecutable(installCommandTokens[0], installCommandTokens[1:]...); err != nil { | ||||
| 		return errors.Wrapf(err, "failed to execute install command: %v", config.InstallCommand) | ||||
| 	} | ||||
|  | ||||
| 	if config.TestOptions != "" { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.Errorf("parameter testOptions no longer supported, please use runOptions parameter instead.") | ||||
| 	} | ||||
| 	if err := command.RunExecutable(config.RunCommand, config.RunOptions...); err != nil { | ||||
| 		return errors.Wrapf(err, "failed to execute run command: %v %v", config.RunCommand, config.RunOptions) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										154
									
								
								cmd/uiVeri5ExecuteTests_generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								cmd/uiVeri5ExecuteTests_generated.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| // Code generated by piper's step-generator. DO NOT EDIT. | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/config" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type uiVeri5ExecuteTestsOptions struct { | ||||
| 	InstallCommand string   `json:"installCommand,omitempty"` | ||||
| 	RunCommand     string   `json:"runCommand,omitempty"` | ||||
| 	RunOptions     []string `json:"runOptions,omitempty"` | ||||
| 	TestOptions    string   `json:"testOptions,omitempty"` | ||||
| 	TestServerURL  string   `json:"testServerUrl,omitempty"` | ||||
| } | ||||
|  | ||||
| // UiVeri5ExecuteTestsCommand Executes UI5 e2e tests using uiVeri5 | ||||
| func UiVeri5ExecuteTestsCommand() *cobra.Command { | ||||
| 	const STEP_NAME = "uiVeri5ExecuteTests" | ||||
|  | ||||
| 	metadata := uiVeri5ExecuteTestsMetadata() | ||||
| 	var stepConfig uiVeri5ExecuteTestsOptions | ||||
| 	var startTime time.Time | ||||
|  | ||||
| 	var createUiVeri5ExecuteTestsCmd = &cobra.Command{ | ||||
| 		Use:   STEP_NAME, | ||||
| 		Short: "Executes UI5 e2e tests using uiVeri5", | ||||
| 		Long:  `In this step the ([UIVeri5 tests](https://github.com/SAP/ui5-uiveri5)) are executed.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName(STEP_NAME) | ||||
| 			log.SetVerbose(GeneralConfig.Verbose) | ||||
|  | ||||
| 			path, _ := os.Getwd() | ||||
| 			fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path} | ||||
| 			log.RegisterHook(fatalHook) | ||||
|  | ||||
| 			err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile) | ||||
| 			if err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { | ||||
| 				sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) | ||||
| 				log.RegisterHook(&sentryHook) | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		}, | ||||
| 		Run: func(_ *cobra.Command, _ []string) { | ||||
| 			telemetryData := telemetry.CustomData{} | ||||
| 			telemetryData.ErrorCode = "1" | ||||
| 			handler := func() { | ||||
| 				config.RemoveVaultSecretFiles() | ||||
| 				telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) | ||||
| 				telemetryData.ErrorCategory = log.GetErrorCategory().String() | ||||
| 				telemetry.Send(&telemetryData) | ||||
| 			} | ||||
| 			log.DeferExitHandler(handler) | ||||
| 			defer handler() | ||||
| 			telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME) | ||||
| 			uiVeri5ExecuteTests(stepConfig, &telemetryData) | ||||
| 			telemetryData.ErrorCode = "0" | ||||
| 			log.Entry().Info("SUCCESS") | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	addUiVeri5ExecuteTestsFlags(createUiVeri5ExecuteTestsCmd, &stepConfig) | ||||
| 	return createUiVeri5ExecuteTestsCmd | ||||
| } | ||||
|  | ||||
| func addUiVeri5ExecuteTestsFlags(cmd *cobra.Command, stepConfig *uiVeri5ExecuteTestsOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.InstallCommand, "installCommand", `npm install @ui5/uiveri5 --global --quiet`, "The command that is executed to install the uiveri5 test tool.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.RunCommand, "runCommand", `/home/node/.npm-global/bin/uiveri5`, "The command that is executed to start the tests.") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.RunOptions, "runOptions", []string{`--seleniumAddress='http://localhost:4444/wd/hub'`}, "Options to append to the runCommand, last parameter has to be path to conf.js (default if missing: ./conf.js).") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TestOptions, "testOptions", os.Getenv("PIPER_testOptions"), "Deprecated and will result in an error if set. Please use runOptions instead.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TestServerURL, "testServerUrl", os.Getenv("PIPER_testServerUrl"), "URL pointing to the deployment.") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("installCommand") | ||||
| 	cmd.MarkFlagRequired("runCommand") | ||||
| 	cmd.MarkFlagRequired("runOptions") | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| func uiVeri5ExecuteTestsMetadata() config.StepData { | ||||
| 	var theMetaData = config.StepData{ | ||||
| 		Metadata: config.StepMetadata{ | ||||
| 			Name:        "uiVeri5ExecuteTests", | ||||
| 			Aliases:     []config.Alias{}, | ||||
| 			Description: "Executes UI5 e2e tests using uiVeri5", | ||||
| 		}, | ||||
| 		Spec: config.StepSpec{ | ||||
| 			Inputs: config.StepInputs{ | ||||
| 				Parameters: []config.StepParameters{ | ||||
| 					{ | ||||
| 						Name:        "installCommand", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "runCommand", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "runOptions", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "[]string", | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "testOptions", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "testServerUrl", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
| 				{Name: "uiVeri5", Image: "node:lts-stretch", EnvVars: []config.EnvVar{{Name: "no_proxy", Value: "localhost,selenium,$no_proxy"}, {Name: "NO_PROXY", Value: "localhost,selenium,$NO_PROXY"}}, WorkingDir: "/home/node"}, | ||||
| 			}, | ||||
| 			Sidecars: []config.Container{ | ||||
| 				{Name: "selenium", Image: "selenium/standalone-chrome", EnvVars: []config.EnvVar{{Name: "NO_PROXY", Value: "localhost,selenium,$NO_PROXY"}, {Name: "no_proxy", Value: "localhost,selenium,$no_proxy"}}}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return theMetaData | ||||
| } | ||||
							
								
								
									
										17
									
								
								cmd/uiVeri5ExecuteTests_generated_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/uiVeri5ExecuteTests_generated_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestUiVeri5ExecuteTestsCommand(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	testCmd := UiVeri5ExecuteTestsCommand() | ||||
|  | ||||
| 	// only high level testing performed - details are tested in step generation procedure | ||||
| 	assert.Equal(t, "uiVeri5ExecuteTests", testCmd.Use, "command name incorrect") | ||||
|  | ||||
| } | ||||
							
								
								
									
										52
									
								
								cmd/uiVeri5ExecuteTests_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								cmd/uiVeri5ExecuteTests_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestRunUIVeri5(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		opts := &uiVeri5ExecuteTestsOptions{ | ||||
| 			InstallCommand: "npm install ui5/uiveri5", | ||||
| 			RunCommand:     "uiveri5", | ||||
| 			RunOptions:     []string{"conf.js"}, | ||||
| 			TestServerURL:  "http://path/to/deployment", | ||||
| 		} | ||||
|  | ||||
| 		e := mock.ExecMockRunner{} | ||||
| 		runUIVeri5(opts, &e) | ||||
|  | ||||
| 		assert.Equal(t, e.Env[0], "NPM_CONFIG_PREFIX=~/.npm-global", "NPM_CONFIG_PREFIX not set as expected") | ||||
| 		assert.Contains(t, e.Env[1], "PATH", "PATH not in env list") | ||||
| 		assert.Equal(t, e.Env[2], "TARGET_SERVER_URL=http://path/to/deployment", "TARGET_SERVER_URL not set as expected") | ||||
|  | ||||
| 		assert.Equal(t, e.Calls[0], mock.ExecCall{Exec: "npm", Params: []string{"install", "ui5/uiveri5"}}, "install command/params incorrect") | ||||
|  | ||||
| 		assert.Equal(t, e.Calls[1], mock.ExecCall{Exec: "uiveri5", Params: []string{"conf.js"}}, "run command/params incorrect") | ||||
|  | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case install command", func(t *testing.T) { | ||||
| 		wantError := "failed to execute install command: fail install test: error case" | ||||
|  | ||||
| 		opts := &uiVeri5ExecuteTestsOptions{InstallCommand: "fail install test", RunCommand: "uiveri5"} | ||||
|  | ||||
| 		e := mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"fail install test": errors.New("error case")}} | ||||
| 		err := runUIVeri5(opts, &e) | ||||
| 		assert.EqualErrorf(t, err, wantError, "expected comman to exit with error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case run command", func(t *testing.T) { | ||||
| 		wantError := "failed to execute run command: fail uiveri5 [testParam]: error case" | ||||
|  | ||||
| 		opts := &uiVeri5ExecuteTestsOptions{InstallCommand: "npm install ui5/uiveri5", RunCommand: "fail uiveri5", RunOptions: []string{"testParam"}} | ||||
|  | ||||
| 		e := mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"fail uiveri5": errors.New("error case")}} | ||||
| 		err := runUIVeri5(opts, &e) | ||||
| 		assert.EqualErrorf(t, err, wantError, "expected comman to exit with error") | ||||
| 	}) | ||||
| } | ||||
| @@ -12,8 +12,12 @@ | ||||
|  | ||||
| ## Exceptions | ||||
|  | ||||
| The parameter `testOptions` is deprecated and is replaced by `runOptions`. | ||||
|  | ||||
| Using the `runOptions` parameter the 'seleniumAddress' for uiveri5 can be set. For jenkins on kubernetes the host is 'localhost', in other environments, e.g. native jenkins installations, the host can be set to 'selenium'. | ||||
|  | ||||
| If you see an error like `fatal: Not a git repository (or any parent up to mount point /home/jenkins)` it is likely that your test description cannot be found.<br /> | ||||
| Please make sure to point parameter `testOptions` to your `conf.js` file like `testOptions: './path/to/my/tests/conf.js'` | ||||
| Please make sure to point parameter `runOptions` to your `conf.js` file like `runOptions: ['./path/to/my/tests/conf.js']` | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
| @@ -65,7 +69,7 @@ withCredentials([usernamePassword( | ||||
|     passwordVariable: 'password', | ||||
|     usernameVariable: 'username' | ||||
| )]) { | ||||
|     uiVeri5ExecuteTests script: this, testOptions: "./uiveri5/conf.js --params.user=\${username} --params.pass=\${password}" | ||||
|     uiVeri5ExecuteTests script: this, runOptions: ["./uiveri5/conf.js", "--params.user=\${username}", "--params.pass=\${password}"] | ||||
| } | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -41,7 +41,7 @@ func adjustMandatoryFlags(stepMetadata *config.StepData) { | ||||
| 		if parameter.Mandatory { | ||||
| 			if parameter.Default == nil || | ||||
| 				parameter.Default == "" || | ||||
| 				parameter.Type == "[]string" && len(parameter.Default.([]string)) == 0 { | ||||
| 				parameter.Type == "[]string" && interfaceArrayLength(parameter.Default) == 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			fmt.Printf("Changing mandatory flag to '%v' for parameter '%s', default value available '%v'.\n", false, parameter.Name, parameter.Default) | ||||
| @@ -75,3 +75,15 @@ func applyCustomDefaultValues(stepMetadata *config.StepData, stepConfiguration c | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // check length only if interface type is a slice | ||||
| func interfaceArrayLength(i interface{}) int { | ||||
| 	switch i.(type) { | ||||
| 	case []string: | ||||
| 		return len(i.([]string)) | ||||
| 	case []interface{}: | ||||
| 		return len(i.([]interface{})) | ||||
| 	default: | ||||
| 		return -1 | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -76,3 +76,47 @@ func Test_adjustMandatoryFlags(t *testing.T) { | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Test_interfaceArrayLength(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		i interface{} | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name string | ||||
| 		args args | ||||
| 		want int | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "empty type", | ||||
| 			args: args{}, | ||||
| 			want: -1, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "string type", | ||||
| 			args: args{"string"}, | ||||
| 			want: -1, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "empty array type", | ||||
| 			args: args{[]interface{}{}}, | ||||
| 			want: 0, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "string array type", | ||||
| 			args: args{[]interface{}{"string1", "string1"}}, | ||||
| 			want: 2, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "string array type", | ||||
| 			args: args{[]string{"string1", "string1"}}, | ||||
| 			want: 2, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			if got := interfaceArrayLength(tt.args.i); got != tt.want { | ||||
| 				t.Errorf("interfaceArrayLength() = %v, want %v", got, tt.want) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -600,16 +600,6 @@ steps: | ||||
|       verbose: false | ||||
|   transportRequestRelease: | ||||
|       verbose: false | ||||
|   uiVeri5ExecuteTests: | ||||
|     failOnError: false | ||||
|     dockerEnvVars: {} | ||||
|     installCommand: 'npm install @ui5/uiveri5 --global --quiet' | ||||
|     seleniumPort: 4444 | ||||
|     stashContent: | ||||
|       - 'buildDescriptor' | ||||
|       - 'tests' | ||||
|     testOptions: '' | ||||
|     runCommand: "uiveri5 --seleniumAddress='http://${config.seleniumHost}:${config.seleniumPort}/wd/hub'" | ||||
|   writeTemporaryCredentials: | ||||
|     credentialsDirectories: | ||||
|       - './' | ||||
|   | ||||
							
								
								
									
										80
									
								
								resources/metadata/uiVeri5ExecuteTests.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								resources/metadata/uiVeri5ExecuteTests.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| metadata: | ||||
|   name: uiVeri5ExecuteTests | ||||
|   description: Executes UI5 e2e tests using uiVeri5 | ||||
|   longDescription: | | ||||
|     In this step the ([UIVeri5 tests](https://github.com/SAP/ui5-uiveri5)) are executed. | ||||
|  | ||||
| #    The step is using `dockerExecute` step to spin up two containers in a Docker network: | ||||
| #    * a Selenium/Chrome container (`selenium/standalone-chrome`) | ||||
| #    * a NodeJS container (`node:lts-stretch`) | ||||
| #    In the Docker network, the containers can be referenced by the values provided in `dockerName` and `sidecarName`, the default values are `uiVeri5` and `selenium`. | ||||
| #   !!! note | ||||
| #        In a Kubernetes environment, the containers both need to be referenced with `localhost`. | ||||
| spec: | ||||
|   inputs: | ||||
|     params: | ||||
|       - name: installCommand | ||||
|         type: string | ||||
|         description: The command that is executed to install the uiveri5 test tool. | ||||
|         default: npm install @ui5/uiveri5 --global --quiet | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|       - name: runCommand | ||||
|         type: string | ||||
|         description: "The command that is executed to start the tests." | ||||
|         default: /home/node/.npm-global/bin/uiveri5 | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|       - name: runOptions | ||||
|         type: "[]string" | ||||
|         description: "Options to append to the runCommand, last parameter has to be path to conf.js (default if missing: ./conf.js)." | ||||
|         default: ["--seleniumAddress='http://localhost:4444/wd/hub'"] | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|       - name: testOptions | ||||
|         type: string | ||||
|         description: "Deprecated and will result in an error if set. Please use runOptions instead." | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: testServerUrl | ||||
|         type: string | ||||
|         description: "URL pointing to the deployment." | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|   containers: | ||||
|     - name: uiVeri5 | ||||
|       image: node:lts-stretch | ||||
|       env: | ||||
|         - name: no_proxy | ||||
|           value: localhost,selenium,$no_proxy | ||||
|         - name: NO_PROXY | ||||
|           value: localhost,selenium,$NO_PROXY | ||||
|       workingDir: /home/node | ||||
|   sidecars: | ||||
|     - image: selenium/standalone-chrome | ||||
|       name: selenium | ||||
|       securityContext: | ||||
|         privileged: true | ||||
|       volumeMounts: | ||||
|         - mountPath: /dev/shm | ||||
|           name: dev-shm | ||||
|       env: | ||||
|         - name: "NO_PROXY" | ||||
|           value: "localhost,selenium,$NO_PROXY" | ||||
|         - name: "no_proxy" | ||||
|           value: "localhost,selenium,$no_proxy" | ||||
| @@ -170,7 +170,9 @@ public class CommonStepsTest extends BasePiperTest{ | ||||
|         'kanikoExecute', //implementing new golang pattern without fields | ||||
|         'gitopsUpdateDeployment', //implementing new golang pattern without fields | ||||
|         'vaultRotateSecretId', //implementing new golang pattern without fields | ||||
|         'integrationArtifactDeploy', //implementing new golang pattern without fields | ||||
|         'deployIntegrationArtifact', //implementing new golang pattern without fields | ||||
|         'uiVeri5ExecuteTests', //implementing new golang pattern without fields | ||||
|         'integrationArtifactDeploy' //implementing new golang pattern without fields | ||||
|     ] | ||||
|  | ||||
|     @Test | ||||
|   | ||||
| @@ -1,186 +0,0 @@ | ||||
| import static org.hamcrest.Matchers.* | ||||
|  | ||||
| import com.sap.piper.Utils | ||||
|  | ||||
| import hudson.AbortException | ||||
|  | ||||
| import org.junit.After | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import org.junit.rules.RuleChain | ||||
| import org.junit.rules.ExpectedException | ||||
|  | ||||
| import static org.junit.Assert.assertThat | ||||
|  | ||||
| import util.BasePiperTest | ||||
| import util.JenkinsDockerExecuteRule | ||||
| import util.JenkinsLoggingRule | ||||
| import util.JenkinsReadYamlRule | ||||
| import util.JenkinsStepRule | ||||
| import util.Rules | ||||
|  | ||||
| class UiVeri5ExecuteTestsTest extends BasePiperTest { | ||||
|     private ExpectedException thrown = ExpectedException.none() | ||||
|     private JenkinsStepRule stepRule = new JenkinsStepRule(this) | ||||
|     private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this) | ||||
|     private JenkinsDockerExecuteRule dockerRule = new JenkinsDockerExecuteRule(this) | ||||
|  | ||||
|     @Rule | ||||
|     public RuleChain rules = Rules | ||||
|         .getCommonRules(this) | ||||
|         .around(thrown) | ||||
|         .around(new JenkinsReadYamlRule(this)) | ||||
|         .around(dockerRule) | ||||
|         .around(loggingRule) | ||||
|         .around(stepRule) | ||||
|  | ||||
|     def gitParams = [:] | ||||
|     def shellCommands = [] | ||||
|     def seleniumMap = [:] | ||||
|  | ||||
|     class MockBuild { | ||||
|         MockBuild(){} | ||||
|         def getRootDir(){ | ||||
|             return new MockPath() | ||||
|         } | ||||
|         class MockPath { | ||||
|             MockPath(){} | ||||
|             // return default | ||||
|             String getAbsolutePath(){ | ||||
|                 return 'myPath' | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Before | ||||
|     void init() { | ||||
|  | ||||
|         binding.setVariable('currentBuild', [ | ||||
|             result: 'SUCCESS', | ||||
|             rawBuild: new MockBuild() | ||||
|         ]) | ||||
|  | ||||
|         helper.registerAllowedMethod("git", [Map.class], { map -> gitParams = map}) | ||||
|         helper.registerAllowedMethod("stash", [String.class], null) | ||||
|         helper.registerAllowedMethod("unstash", [String.class], { s -> return [s]}) | ||||
|         helper.registerAllowedMethod("sh", [String.class], { s -> | ||||
|             if (s.contains('failure')) throw new RuntimeException('Test Error') | ||||
|             shellCommands.add(s.toString()) | ||||
|         }) | ||||
|         helper.registerAllowedMethod("sh", [Map.class], { map -> | ||||
|             return 'available' | ||||
|         }) | ||||
|         helper.registerAllowedMethod('seleniumExecuteTests', [Map.class, Closure.class], { m, body -> | ||||
|             seleniumMap = m | ||||
|             return body() | ||||
|         }) | ||||
|         Utils.metaClass.echo = { def m -> } | ||||
|     } | ||||
|  | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Utils.metaClass = null | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testDefault() throws Exception { | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             script: nullScript, | ||||
|             juStabUtils: utils, | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertThat(shellCommands, hasItem(containsString('npm install @ui5/uiveri5 --global --quiet'))) | ||||
|         assertThat(shellCommands, hasItem(containsString('uiveri5 --seleniumAddress=\'http://selenium:4444/wd/hub\''))) | ||||
|         assertThat(seleniumMap.dockerImage, isEmptyOrNullString()) | ||||
|         assertThat(seleniumMap.dockerWorkspace, isEmptyOrNullString()) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testDefaultOnK8s() throws Exception { | ||||
|         // prepare | ||||
|         binding.variables.env.ON_K8S = 'true' | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             script: nullScript, | ||||
|             juStabUtils: utils, | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertThat(shellCommands, hasItem(containsString('npm install @ui5/uiveri5 --global --quiet'))) | ||||
|         assertThat(shellCommands, hasItem(containsString('uiveri5 --seleniumAddress=\'http://localhost:4444/wd/hub\''))) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testWithCustomSidecar() throws Exception { | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             script: nullScript, | ||||
|             juStabUtils: utils, | ||||
|             sidecarEnvVars: [myEnv: 'testValue'], | ||||
|             sidecarImage: 'myImage' | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertThat(seleniumMap.sidecarImage, is('myImage')) | ||||
|         assertThat(seleniumMap.sidecarEnvVars.myEnv, is('testValue')) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testWithTestRepository() throws Exception { | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             script: nullScript, | ||||
|             juStabUtils: utils, | ||||
|             testRepository: 'git@myGitUrl' | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertThat(seleniumMap, hasKey('stashContent')) | ||||
|         assertThat(seleniumMap.stashContent, hasItem(startsWith('testContent-'))) | ||||
|         assertThat(gitParams, hasEntry('url', 'git@myGitUrl')) | ||||
|         assertThat(gitParams, not(hasKey('credentialsId'))) | ||||
|         assertThat(gitParams, not(hasKey('branch'))) | ||||
|         assertJobStatusSuccess() | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testWithTestRepositoryWithGitBranchAndCredentials() throws Exception { | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             script: nullScript, | ||||
|             juStabUtils: utils, | ||||
|             testRepository: 'git@myGitUrl', | ||||
|             gitSshKeyCredentialsId: 'myCredentials', | ||||
|             gitBranch: 'myBranch' | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertThat(gitParams, hasEntry('url', 'git@myGitUrl')) | ||||
|         assertThat(gitParams, hasEntry('credentialsId', 'myCredentials')) | ||||
|         assertThat(gitParams, hasEntry('branch', 'myBranch')) | ||||
|         assertJobStatusSuccess() | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testWithFailOnError() throws Exception { | ||||
|         thrown.expect(AbortException) | ||||
|         thrown.expectMessage('ERROR: The execution of the uiveri5 tests failed, see the log for details.') | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             juStabUtils: utils, | ||||
|             failOnError: true, | ||||
|             testOptions: 'failure', | ||||
|             script: nullScript | ||||
|         ]) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testWithoutFailOnError() throws Exception { | ||||
|         // execute test | ||||
|         stepRule.step.uiVeri5ExecuteTests([ | ||||
|             juStabUtils: utils, | ||||
|             testOptions: 'failure', | ||||
|             script: nullScript | ||||
|         ]) | ||||
|         // asserts | ||||
|         assertJobStatusSuccess() | ||||
|     } | ||||
| } | ||||
| @@ -1,147 +1,43 @@ | ||||
| import com.sap.piper.ConfigurationHelper | ||||
| import com.sap.piper.GenerateDocumentation | ||||
| import com.sap.piper.GitUtils | ||||
| import com.sap.piper.Utils | ||||
|  | ||||
| import groovy.text.GStringTemplateEngine | ||||
| import groovy.transform.Field | ||||
|  | ||||
| import static com.sap.piper.Prerequisites.checkScript | ||||
|  | ||||
| @Field String STEP_NAME = getClass().getName() | ||||
| @Field String METADATA_FILE = 'metadata/uiVeri5ExecuteTests.yaml' | ||||
|  | ||||
| @Field Set GENERAL_CONFIG_KEYS = [ | ||||
|     /** @see seleniumExecuteTests */ | ||||
|     'gitSshKeyCredentialsId' | ||||
| ] | ||||
| @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([ | ||||
|     /** @see dockerExecute */ | ||||
|     'dockerEnvVars', | ||||
|     /** @see dockerExecute */ | ||||
|     'dockerImage', | ||||
|     /** @see dockerExecute */ | ||||
|     'dockerWorkspace', | ||||
|     /** | ||||
|      * With `failOnError` the behavior in case tests fail can be defined. | ||||
|      * @possibleValues `true`, `false` | ||||
|      */ | ||||
|     'failOnError', | ||||
|     /** @see seleniumExecuteTests */ | ||||
|     'gitBranch', | ||||
|     /** | ||||
|      * The command that is executed to install the test tool. | ||||
|      */ | ||||
|     'installCommand', | ||||
|     /** | ||||
|      * The command that is executed to start the tests. | ||||
|      */ | ||||
|     'runCommand', | ||||
|     /** | ||||
|      * The host of the selenium hub, this is set automatically to `localhost` in a Kubernetes environment (determined by the `ON_K8S` environment variable) of to `selenium` in any other case. The value is only needed for the `runCommand`. | ||||
|      */ | ||||
|     'seleniumHost', | ||||
|     /** @see seleniumExecuteTests */ | ||||
|     'seleniumHubCredentialsId', | ||||
|     /** | ||||
|      * The port of the selenium hub. The value is only needed for the `runCommand`. | ||||
|      */ | ||||
|     'seleniumPort', | ||||
|     /** @see dockerExecute */ | ||||
|     'sidecarEnvVars', | ||||
|     /** @see dockerExecute */ | ||||
|     'sidecarImage', | ||||
|     /** @see dockerExecute */ | ||||
|     'stashContent', | ||||
|     /** | ||||
|      * This allows to set specific options for the UIVeri5 execution. Details can be found [in the UIVeri5 documentation](https://github.com/SAP/ui5-uiveri5/blob/master/docs/config/config.md#configuration). | ||||
|      */ | ||||
|     'testOptions', | ||||
|     /** @see seleniumExecuteTests */ | ||||
|     'testRepository', | ||||
|     /** | ||||
|      * The `testServerUrl` is passed as environment variable `TARGET_SERVER_URL` to the test execution. | ||||
|      * The tests should read the host information from this environment variable in order to be infrastructure agnostic. | ||||
|      */ | ||||
|     'testServerUrl' | ||||
| ]) | ||||
| @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS | ||||
|  | ||||
| /** | ||||
|  * With this step [UIVeri5](https://github.com/SAP/ui5-uiveri5) tests can be executed. | ||||
| /* | ||||
|  * Parameters read from config for backwards compatibility of groovy wrapper step: | ||||
|  * | ||||
|  * UIVeri5 describes following benefits on its GitHub page: | ||||
|  * | ||||
|  * * Automatic synchronization with UI5 app rendering so there is no need to add waits and sleeps to your test. Tests are reliable by design. | ||||
|  * * Tests are written in synchronous manner, no callbacks, no promise chaining so are really simple to write and maintain. | ||||
|  * * Full power of webdriverjs, protractor and jasmine - deferred selectors, custom matchers, custom locators. | ||||
|  * * Control locators (OPA5 declarative matchers) allow locating and interacting with UI5 controls. | ||||
|  * * Does not depend on testability support in applications - works with autorefreshing views, resizing elements, animated transitions. | ||||
|  * * Declarative authentications - authentication flow over OAuth2 providers, etc. | ||||
|  * * Console operation, CI ready, fully configurable, no need for java (coming soon) or IDE. | ||||
|  * * Covers full ui5 browser matrix - Chrome,Firefox,IE,Edge,Safari,iOS,Android. | ||||
|  * * Open-source, modify to suite your specific neeeds. | ||||
|  * | ||||
|  * !!! note "Browser Matrix" | ||||
|  *     With this step and the underlying Docker image ([selenium/standalone-chrome](https://github.com/SeleniumHQ/docker-selenium/tree/master/StandaloneChrome)) only Chrome tests are possible. | ||||
|  * | ||||
|  *     Testing of further browsers can be done with using a custom Docker image. | ||||
|  * testRepository, gitBranch, gitSshKeyCredentialsId used for test repository loading | ||||
|  */ | ||||
| @GenerateDocumentation | ||||
| void call(Map parameters = [:]) { | ||||
|     handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) { | ||||
|         def script = checkScript(this, parameters) ?: this | ||||
|         def utils = parameters.juStabUtils ?: new Utils() | ||||
|         String stageName = parameters.stageName ?: env.STAGE_NAME | ||||
| @Field Set CONFIG_KEYS = [ | ||||
|     "gitBranch", | ||||
|     "gitSshKeyCredentialsId", | ||||
|     "testRepository", | ||||
| ] | ||||
|  | ||||
|         // load default & individual configuration | ||||
|         Map config = ConfigurationHelper.newInstance(this) | ||||
| void call(Map parameters = [:]) { | ||||
|     final script = checkScript(this, parameters) ?: this | ||||
|     String stageName = parameters.stageName ?: env.STAGE_NAME | ||||
|     def utils = parameters.juStabUtils ?: new Utils() | ||||
|     Map config = ConfigurationHelper.newInstance(this) | ||||
|             .loadStepDefaults([:], stageName) | ||||
|             .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) | ||||
|             .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) | ||||
|             .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS) | ||||
|             .mixin(parameters, PARAMETER_KEYS) | ||||
|             .addIfEmpty('seleniumHost', isKubernetes()?'localhost':'selenium') | ||||
|             .mixinGeneralConfig(script.commonPipelineEnvironment, CONFIG_KEYS) | ||||
|             .mixinStepConfig(script.commonPipelineEnvironment, CONFIG_KEYS) | ||||
|             .mixinStageConfig(script.commonPipelineEnvironment, stageName, CONFIG_KEYS) | ||||
|             .mixin(parameters, CONFIG_KEYS) | ||||
|             .use() | ||||
|  | ||||
|         utils.pushToSWA([ | ||||
|             step: STEP_NAME, | ||||
|             stepParamKey1: 'scriptMissing', | ||||
|             stepParam1: parameters?.script == null | ||||
|         ], config) | ||||
|  | ||||
|         config.stashContent = config.testRepository ? [GitUtils.handleTestRepository(this, config)] : utils.unstashAll(config.stashContent) | ||||
|         config.installCommand = GStringTemplateEngine.newInstance().createTemplate(config.installCommand).make([config: config]).toString() | ||||
|         config.runCommand = GStringTemplateEngine.newInstance().createTemplate(config.runCommand).make([config: config]).toString() | ||||
|         config.dockerEnvVars.TARGET_SERVER_URL = config.dockerEnvVars.TARGET_SERVER_URL ?: config.testServerUrl | ||||
|  | ||||
|         seleniumExecuteTests( | ||||
|             script: script, | ||||
|             buildTool: 'npm', | ||||
|             dockerEnvVars: config.dockerEnvVars, | ||||
|             dockerImage: config.dockerImage, | ||||
|             dockerName: config.dockerName, | ||||
|             dockerWorkspace: config.dockerWorkspace, | ||||
|             seleniumHubCredentialsId: config.seleniumHubCredentialsId, | ||||
|             sidecarEnvVars: config.sidecarEnvVars, | ||||
|             sidecarImage: config.sidecarImage, | ||||
|             stashContent: config.stashContent | ||||
|         ) { | ||||
|             sh returnStatus: true, script: """ | ||||
|                 node --version | ||||
|                 npm --version | ||||
|             """ | ||||
|             try { | ||||
|                 sh "NPM_CONFIG_PREFIX=~/.npm-global ${config.installCommand}" | ||||
|                 sh "PATH=\$PATH:~/.npm-global/bin ${config.runCommand} ${config.testOptions}" | ||||
|             } catch (err) { | ||||
|                 echo "[${STEP_NAME}] Test execution failed" | ||||
|                 script.currentBuild.result = 'UNSTABLE' | ||||
|                 if (config.failOnError) error "[${STEP_NAME}] ERROR: The execution of the uiveri5 tests failed, see the log for details." | ||||
|             } | ||||
|         } | ||||
|     if (parameters.testRepository || config.testRepository ) { | ||||
|         parameters.stashContent = GitUtils.handleTestRepository(this, [gitBranch: config.gitBranch, gitSshKeyCredentialsId: config.gitSshKeyCredentialsId, testRepository: config.testRepository]) | ||||
|     } | ||||
| } | ||||
|  | ||||
| boolean isKubernetes() { | ||||
|     return Boolean.valueOf(env.ON_K8S) | ||||
|     List credentials = [ | ||||
|         [type: 'usernamePassword', id: 'seleniumHubCredentialsId', env: ['PIPER_SELENIUM_HUB_USER', 'PIPER_SELENIUM_HUB_PASSWORD']], | ||||
|     ] | ||||
|     piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user