1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-03 15:02:35 +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:
lndrschlz 2021-01-28 11:31:24 +01:00 committed by GitHub
parent 44788f1d3a
commit e60bdb94a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 444 additions and 328 deletions

View File

@ -60,6 +60,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"containerSaveImage": containerSaveImageMetadata(),
"sonarExecuteScan": sonarExecuteScanMetadata(),
"transportRequestUploadCTS": transportRequestUploadCTSMetadata(),
"uiVeri5ExecuteTests": uiVeri5ExecuteTestsMetadata(),
"vaultRotateSecretId": vaultRotateSecretIdMetadata(),
"artifactPrepareVersion": artifactPrepareVersionMetadata(),
"whitesourceExecuteScan": whitesourceExecuteScanMetadata(),

View File

@ -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())

View 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
}

View 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
}

View 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")
}

View 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")
})
}

View File

@ -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}"]
}
```

View File

@ -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
}
}

View File

@ -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)
}
})
}
}

View File

@ -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:
- './'

View 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"

View File

@ -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

View File

@ -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()
}
}

View File

@ -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)
}