mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
feat(gauge): migrate gaugeExecuteTests to go implementation (#2775)
* gaugeExecuteTests converted to golang * rewrited gaugeExecuteTests to cross-platform implementation. Now gauge uses npm * regenerated * groovy file import fix Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
parent
3b2e7dc53d
commit
c38d231820
118
cmd/gaugeExecuteTests.go
Normal file
118
cmd/gaugeExecuteTests.go
Normal file
@ -0,0 +1,118 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var ErrorGaugeInstall error = errors.New("error installing gauge")
|
||||
var ErrorGaugeRunnerInstall error = errors.New("error installing runner")
|
||||
var ErrorGaugeRun error = errors.New("error running gauge")
|
||||
|
||||
type gaugeExecuteTestsUtils interface {
|
||||
FileExists(filename string) (bool, error)
|
||||
MkdirAll(path string, perm os.FileMode) error
|
||||
SetEnv([]string)
|
||||
RunExecutable(executable string, params ...string) error
|
||||
Stdout(io.Writer)
|
||||
Getenv(key string) string
|
||||
}
|
||||
|
||||
type gaugeExecuteTestsUtilsBundle struct {
|
||||
*command.Command
|
||||
*piperutils.Files
|
||||
}
|
||||
|
||||
func newGaugeExecuteTestsUtils() gaugeExecuteTestsUtils {
|
||||
utils := gaugeExecuteTestsUtilsBundle{
|
||||
Command: &command.Command{},
|
||||
Files: &piperutils.Files{},
|
||||
}
|
||||
utils.Stdout(log.Writer())
|
||||
utils.Stderr(log.Writer())
|
||||
return &utils
|
||||
}
|
||||
|
||||
func gaugeExecuteTests(config gaugeExecuteTestsOptions, telemetryData *telemetry.CustomData, influx *gaugeExecuteTestsInflux) {
|
||||
utils := newGaugeExecuteTestsUtils()
|
||||
|
||||
influx.step_data.fields.gauge = false
|
||||
err := runGaugeExecuteTests(&config, telemetryData, utils)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
influx.step_data.fields.gauge = true
|
||||
}
|
||||
|
||||
func runGaugeExecuteTests(config *gaugeExecuteTestsOptions, telemetryData *telemetry.CustomData, utils gaugeExecuteTestsUtils) error {
|
||||
if config.InstallCommand != "" {
|
||||
err := installGauge(config.InstallCommand, utils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.LanguageRunner != "" {
|
||||
err := installLanguageRunner(config.LanguageRunner, utils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := runGauge(config, utils)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run gauge: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installGauge(gaugeInstallCommand string, utils gaugeExecuteTestsUtils) error {
|
||||
installGaugeTokens := strings.Split(gaugeInstallCommand, " ")
|
||||
installGaugeTokens = append(installGaugeTokens, "--prefix=~/.npm-global")
|
||||
err := utils.RunExecutable(installGaugeTokens[0], installGaugeTokens[1:]...)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.Wrap(ErrorGaugeInstall, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installLanguageRunner(languageRunner string, utils gaugeExecuteTestsUtils) error {
|
||||
installParams := []string{"install", languageRunner}
|
||||
gaugePath := filepath.Join(utils.Getenv("HOME"), "/.npm-global/bin/gauge")
|
||||
err := utils.RunExecutable(gaugePath, installParams...)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.Wrap(ErrorGaugeRunnerInstall, err.Error())
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func runGauge(config *gaugeExecuteTestsOptions, utils gaugeExecuteTestsUtils) error {
|
||||
runCommandTokens := strings.Split(config.RunCommand, " ")
|
||||
if config.TestOptions != "" {
|
||||
runCommandTokens = append(runCommandTokens, strings.Split(config.TestOptions, " ")...)
|
||||
}
|
||||
gaugePath := filepath.Join(utils.Getenv("HOME"), "/.npm-global/bin/gauge")
|
||||
err := utils.RunExecutable(gaugePath, runCommandTokens...)
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrorGaugeRun, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (utils gaugeExecuteTestsUtilsBundle) Getenv(key string) string {
|
||||
return os.Getenv(key)
|
||||
}
|
221
cmd/gaugeExecuteTests_generated.go
Normal file
221
cmd/gaugeExecuteTests_generated.go
Normal file
@ -0,0 +1,221 @@
|
||||
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||
"github.com/SAP/jenkins-library/pkg/splunk"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type gaugeExecuteTestsOptions struct {
|
||||
InstallCommand string `json:"installCommand,omitempty"`
|
||||
LanguageRunner string `json:"languageRunner,omitempty"`
|
||||
RunCommand string `json:"runCommand,omitempty"`
|
||||
TestOptions string `json:"testOptions,omitempty"`
|
||||
}
|
||||
|
||||
type gaugeExecuteTestsInflux struct {
|
||||
step_data struct {
|
||||
fields struct {
|
||||
gauge bool
|
||||
}
|
||||
tags struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *gaugeExecuteTestsInflux) persist(path, resourceName string) {
|
||||
measurementContent := []struct {
|
||||
measurement string
|
||||
valType string
|
||||
name string
|
||||
value interface{}
|
||||
}{
|
||||
{valType: config.InfluxField, measurement: "step_data", name: "gauge", value: i.step_data.fields.gauge},
|
||||
}
|
||||
|
||||
errCount := 0
|
||||
for _, metric := range measurementContent {
|
||||
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Error("Error persisting influx environment.")
|
||||
errCount++
|
||||
}
|
||||
}
|
||||
if errCount > 0 {
|
||||
log.Entry().Fatal("failed to persist Influx environment")
|
||||
}
|
||||
}
|
||||
|
||||
// GaugeExecuteTestsCommand Installs gauge and executes specified gauge tests.
|
||||
func GaugeExecuteTestsCommand() *cobra.Command {
|
||||
const STEP_NAME = "gaugeExecuteTests"
|
||||
|
||||
metadata := gaugeExecuteTestsMetadata()
|
||||
var stepConfig gaugeExecuteTestsOptions
|
||||
var startTime time.Time
|
||||
var influx gaugeExecuteTestsInflux
|
||||
var logCollector *log.CollectorHook
|
||||
|
||||
var createGaugeExecuteTestsCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "Installs gauge and executes specified gauge tests.",
|
||||
Long: `In this step Gauge ([getgauge.io](https://getgauge.io)) acceptance tests are executed. Using Gauge it will be possible to have a three-tier test layout:
|
||||
|
||||
Acceptance Criteria
|
||||
Test implemenation layer
|
||||
Application driver layer
|
||||
|
||||
This layout is propagated by Jez Humble and Dave Farley in their book "Continuous Delivery" as a way to create maintainable acceptance test suites (see "Continuous Delivery", p. 190ff).
|
||||
|
||||
Using Gauge it is possible to write test specifications in [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) and therefore allow e.g. product owners to write the relevant acceptance test specifications. At the same time it allows the developer to implement the steps described in the specification in her development environment.
|
||||
|
||||
You can use the [sample projects](https://github.com/getgauge/gauge-mvn-archetypes) of Gauge.`,
|
||||
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)
|
||||
}
|
||||
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
|
||||
log.RegisterHook(logCollector)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
telemetryData := telemetry.CustomData{}
|
||||
telemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
config.RemoveVaultSecretFiles()
|
||||
influx.persist(GeneralConfig.EnvRootPath, "influx")
|
||||
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
telemetryData.ErrorCategory = log.GetErrorCategory().String()
|
||||
telemetry.Send(&telemetryData)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunk.Send(&telemetryData, logCollector)
|
||||
}
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunk.Initialize(GeneralConfig.CorrelationID,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Dsn,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Token,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Index,
|
||||
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
|
||||
}
|
||||
gaugeExecuteTests(stepConfig, &telemetryData, &influx)
|
||||
telemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addGaugeExecuteTestsFlags(createGaugeExecuteTestsCmd, &stepConfig)
|
||||
return createGaugeExecuteTestsCmd
|
||||
}
|
||||
|
||||
func addGaugeExecuteTestsFlags(cmd *cobra.Command, stepConfig *gaugeExecuteTestsOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.InstallCommand, "installCommand", os.Getenv("PIPER_installCommand"), "Defines the command for installing Gauge. Gauge should be installed using npm. Example: npm install -g @getgauge/cli@1.2.1")
|
||||
cmd.Flags().StringVar(&stepConfig.LanguageRunner, "languageRunner", os.Getenv("PIPER_languageRunner"), "Defines the Gauge language runner to be used. Example: java")
|
||||
cmd.Flags().StringVar(&stepConfig.RunCommand, "runCommand", os.Getenv("PIPER_runCommand"), "Defines the command which is used for executing Gauge. Example: run -s -p specs/")
|
||||
cmd.Flags().StringVar(&stepConfig.TestOptions, "testOptions", os.Getenv("PIPER_testOptions"), "Allows to set specific options for the Gauge execution. Details can be found for example [in the Gauge Maven plugin documentation](https://github.com/getgauge-contrib/gauge-maven-plugin#executing-specs)")
|
||||
|
||||
cmd.MarkFlagRequired("runCommand")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func gaugeExecuteTestsMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "gaugeExecuteTests",
|
||||
Aliases: []config.Alias{},
|
||||
Description: "Installs gauge and executes specified gauge tests.",
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Resources: []config.StepResources{
|
||||
{Name: "buildDescriptor", Type: "stash"},
|
||||
{Name: "tests", Type: "stash"},
|
||||
},
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "installCommand",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "languageRunner",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "runCommand",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "testOptions",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
{Name: "gauge", 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"}}},
|
||||
},
|
||||
Outputs: config.StepOutputs{
|
||||
Resources: []config.StepResources{
|
||||
{
|
||||
Name: "influx",
|
||||
Type: "influx",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"Name": "step_data"}, {"fields": []map[string]string{{"name": "gauge"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
17
cmd/gaugeExecuteTests_generated_test.go
Normal file
17
cmd/gaugeExecuteTests_generated_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGaugeExecuteTestsCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCmd := GaugeExecuteTestsCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procedure
|
||||
assert.Equal(t, "gaugeExecuteTests", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
112
cmd/gaugeExecuteTests_test.go
Normal file
112
cmd/gaugeExecuteTests_test.go
Normal file
@ -0,0 +1,112 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type gaugeExecuteTestsMockUtils struct {
|
||||
*mock.ExecMockRunner
|
||||
*mock.FilesMock
|
||||
}
|
||||
|
||||
func (utils gaugeExecuteTestsMockUtils) Getenv(key string) string {
|
||||
if key == "HOME" {
|
||||
return "/home/node"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func TestRunGaugeExecuteTests(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allFineConfig := gaugeExecuteTestsOptions{
|
||||
InstallCommand: "npm install -g @getgauge/cli",
|
||||
LanguageRunner: "java",
|
||||
RunCommand: "run",
|
||||
TestOptions: "specs",
|
||||
}
|
||||
gaugeBin := "home/node/.npm-global/bin/gauge"
|
||||
|
||||
t.Run("success case", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
mockUtils := gaugeExecuteTestsMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
|
||||
err := runGaugeExecuteTests(&allFineConfig, nil, &mockUtils)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Exec, "npm")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Params, []string{"install", "-g", "@getgauge/cli", "--prefix=~/.npm-global"})
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Exec, "/home/node/.npm-global/bin/gauge")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Params, []string{"install", "java"})
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[2].Exec, "/home/node/.npm-global/bin/gauge")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[2].Params, []string{"run", "specs"})
|
||||
})
|
||||
|
||||
t.Run("fail on installation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
badInstallConfig := allFineConfig
|
||||
badInstallConfig.InstallCommand = "npm install -g @wronggauge/cli"
|
||||
|
||||
mockUtils := gaugeExecuteTestsMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"npm install -g @wronggauge/cli": errors.New("cannot find module")}},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
|
||||
err := runGaugeExecuteTests(&badInstallConfig, nil, &mockUtils)
|
||||
assert.True(t, errors.Is(err, ErrorGaugeInstall))
|
||||
|
||||
assert.Equal(t, len(mockUtils.ExecMockRunner.Calls), 1)
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Exec, "npm")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Params, []string{"install", "-g", "@wronggauge/cli", "--prefix=~/.npm-global"})
|
||||
})
|
||||
|
||||
t.Run("fail on installing language runner", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
badInstallConfig := allFineConfig
|
||||
badInstallConfig.LanguageRunner = "wrong"
|
||||
|
||||
mockUtils := gaugeExecuteTestsMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{gaugeBin + " install wrong": errors.New("error installing runner")}},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
|
||||
err := runGaugeExecuteTests(&badInstallConfig, nil, &mockUtils)
|
||||
assert.True(t, errors.Is(err, ErrorGaugeRunnerInstall))
|
||||
|
||||
assert.Equal(t, len(mockUtils.ExecMockRunner.Calls), 2)
|
||||
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Exec, "npm")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Params, []string{"install", "-g", "@getgauge/cli", "--prefix=~/.npm-global"})
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Exec, "/home/node/.npm-global/bin/gauge")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Params, []string{"install", "wrong"})
|
||||
})
|
||||
t.Run("fail on gauge run", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
mockUtils := gaugeExecuteTestsMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{gaugeBin + " run specs": errors.New("error running gauge")}},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
|
||||
err := runGaugeExecuteTests(&allFineConfig, nil, &mockUtils)
|
||||
assert.True(t, errors.Is(err, ErrorGaugeRun))
|
||||
|
||||
assert.Equal(t, len(mockUtils.ExecMockRunner.Calls), 3)
|
||||
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Exec, "npm")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[0].Params, []string{"install", "-g", "@getgauge/cli", "--prefix=~/.npm-global"})
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Exec, "/home/node/.npm-global/bin/gauge")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[1].Params, []string{"install", "java"})
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[2].Exec, "/home/node/.npm-global/bin/gauge")
|
||||
assert.Equal(t, mockUtils.ExecMockRunner.Calls[2].Params, []string{"run", "specs"})
|
||||
})
|
||||
}
|
@ -33,6 +33,7 @@ func GetAllStepMetadata() map[string]config.StepData {
|
||||
"containerExecuteStructureTests": containerExecuteStructureTestsMetadata(),
|
||||
"detectExecuteScan": detectExecuteScanMetadata(),
|
||||
"fortifyExecuteScan": fortifyExecuteScanMetadata(),
|
||||
"gaugeExecuteTests": gaugeExecuteTestsMetadata(),
|
||||
"gctsCloneRepository": gctsCloneRepositoryMetadata(),
|
||||
"gctsCreateRepository": gctsCreateRepositoryMetadata(),
|
||||
"gctsDeploy": gctsDeployMetadata(),
|
||||
|
@ -147,6 +147,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(IntegrationArtifactUploadCommand())
|
||||
rootCmd.AddCommand(TerraformExecuteCommand())
|
||||
rootCmd.AddCommand(ContainerExecuteStructureTestsCommand())
|
||||
rootCmd.AddCommand(GaugeExecuteTestsCommand())
|
||||
rootCmd.AddCommand(BatsExecuteTestsCommand())
|
||||
rootCmd.AddCommand(PipelineCreateScanSummaryCommand())
|
||||
rootCmd.AddCommand(TransportRequestDocIDFromGitCommand())
|
||||
|
81
integration/integration_gauge_test.go
Normal file
81
integration/integration_gauge_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
// +build integration
|
||||
// can be execute with go test -tags=integration ./integration/...
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
const (
|
||||
installCommand string = "npm install -g @getgauge/cli --prefix=~/.npm-global --unsafe-perm" //option --unsafe-perm need to install gauge in docker container. See this issue: https://github.com/getgauge/gauge/issues/1470
|
||||
)
|
||||
|
||||
func runTest(t *testing.T, languageRunner string) {
|
||||
ctx := context.Background()
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
assert.NoError(t, err, "Getting current working directory failed.")
|
||||
pwd = filepath.Dir(pwd)
|
||||
|
||||
// using custom createTmpDir function to avoid issues with symlinks on Docker for Mac
|
||||
tempDir, err := createTmpDir("")
|
||||
defer os.RemoveAll(tempDir) // clean up
|
||||
assert.NoError(t, err, "Error when creating temp dir")
|
||||
|
||||
err = copyDir(filepath.Join(pwd, "integration", "testdata", "TestGaugeIntegration", "gauge-"+languageRunner), tempDir)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to copy test project.")
|
||||
}
|
||||
|
||||
//workaround to use test script util it is possible to set workdir for Exec call
|
||||
testScript := fmt.Sprintf(`#!/bin/sh
|
||||
cd /test
|
||||
/piperbin/piper gaugeExecuteTests --installCommand="%v" --languageRunner=%v --runCommand="run" >test-log.txt 2>&1
|
||||
`, installCommand, languageRunner)
|
||||
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
|
||||
|
||||
reqNode := testcontainers.ContainerRequest{
|
||||
Image: "getgauge/gocd-jdk-mvn-node",
|
||||
Cmd: []string{"tail", "-f"},
|
||||
BindMounts: map[string]string{
|
||||
pwd: "/piperbin",
|
||||
tempDir: "/test",
|
||||
},
|
||||
}
|
||||
|
||||
nodeContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: reqNode,
|
||||
Started: true,
|
||||
})
|
||||
|
||||
code, err := nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, code)
|
||||
|
||||
content, err := ioutil.ReadFile(filepath.Join(tempDir, "/test-log.txt"))
|
||||
if err != nil {
|
||||
t.Fatal("Could not read test-log.txt.", err)
|
||||
}
|
||||
output := string(content)
|
||||
assert.Contains(t, output, "info gaugeExecuteTests - Scenarios: 2 executed 2 passed 0 failed 0 skipped")
|
||||
assert.Contains(t, output, "info gaugeExecuteTests - SUCCESS")
|
||||
}
|
||||
|
||||
func TestGaugeJava(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest(t, "java")
|
||||
}
|
||||
|
||||
func TestGaugeJS(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest(t, "js")
|
||||
}
|
7
integration/testdata/TestGaugeIntegration/gauge-java/.dockerignore
vendored
Normal file
7
integration/testdata/TestGaugeIntegration/gauge-java/.dockerignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
logs
|
||||
Dockerfile
|
||||
reports
|
||||
.gauge
|
||||
README.md
|
||||
gauge_bin
|
||||
.gitignore
|
11
integration/testdata/TestGaugeIntegration/gauge-java/.gitignore
vendored
Normal file
11
integration/testdata/TestGaugeIntegration/gauge-java/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Gauge - metadata dir
|
||||
.gauge
|
||||
|
||||
# Gauge - log files dir
|
||||
logs
|
||||
|
||||
# Gauge - java class output directory
|
||||
gauge_bin
|
||||
|
||||
# Gauge - reports generated by reporting plugins
|
||||
reports
|
24
integration/testdata/TestGaugeIntegration/gauge-java/Dockerfile
vendored
Normal file
24
integration/testdata/TestGaugeIntegration/gauge-java/Dockerfile
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Building the image
|
||||
# docker build -t gauge-java .
|
||||
# Running the image
|
||||
# docker run --rm -it -v ${PWD}/reports:/gauge/reports gauge-java
|
||||
|
||||
# This image uses the official openjdk base image.
|
||||
|
||||
FROM openjdk
|
||||
|
||||
# Install gauge
|
||||
RUN microdnf install -y unzip \
|
||||
&& curl -Ssl https://downloads.gauge.org/stable | sh
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /gauge
|
||||
|
||||
# Copy the local source folder
|
||||
COPY . .
|
||||
|
||||
# Install gauge plugins
|
||||
RUN gauge install \
|
||||
&& gauge install screenshot
|
||||
|
||||
CMD ["gauge", "run", "specs"]
|
28
integration/testdata/TestGaugeIntegration/gauge-java/env/default/default.properties
vendored
Normal file
28
integration/testdata/TestGaugeIntegration/gauge-java/env/default/default.properties
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# default.properties
|
||||
# properties set here will be available to the test execution as environment variables
|
||||
|
||||
# sample_key = sample_value
|
||||
|
||||
# The path to the gauge reports directory. Should be either relative to the project directory or an absolute path
|
||||
gauge_reports_dir = reports
|
||||
|
||||
# Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.
|
||||
overwrite_reports = true
|
||||
|
||||
# Set to false to disable screenshots on failure in reports.
|
||||
screenshot_on_failure = true
|
||||
|
||||
# The path to the gauge logs directory. Should be either relative to the project directory or an absolute path
|
||||
logs_directory = logs
|
||||
|
||||
# Set to true to use multithreading for parallel execution
|
||||
enable_multithreading = false
|
||||
|
||||
# The path the gauge specifications directory. Takes a comma separated list of specification files/directories.
|
||||
gauge_specs_dir = specs
|
||||
|
||||
# The default delimiter used read csv files.
|
||||
csv_delimiter = ,
|
||||
|
||||
# Allows steps to be written in multiline
|
||||
allow_multiline_step = false
|
22
integration/testdata/TestGaugeIntegration/gauge-java/env/default/java.properties
vendored
Normal file
22
integration/testdata/TestGaugeIntegration/gauge-java/env/default/java.properties
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
# Specify an alternate Java home if you want to use a custom version
|
||||
gauge_java_home =
|
||||
|
||||
# IntelliJ and Eclipse out directory will be usually autodetected
|
||||
# Use the below property if you need to override the build path
|
||||
gauge_custom_build_path =
|
||||
|
||||
# specify the directory where additional libs are kept
|
||||
# you can specify multiple directory names separated with a comma (,)
|
||||
gauge_additional_libs = libs/*
|
||||
|
||||
# JVM arguments passed to java while launching. Enter multiple values separated by comma (,) eg. Xmx1024m, Xms128m
|
||||
gauge_jvm_args =
|
||||
|
||||
# specify the directory containing java files to be compiled
|
||||
# you can specify multiple directory names separated with a comma (,)
|
||||
gauge_custom_compile_dir =
|
||||
|
||||
# specify the level at which the objects should be cleared
|
||||
# Possible values are suite, spec and scenario. Default value is scenario.
|
||||
gauge_clear_state_level = scenario
|
0
integration/testdata/TestGaugeIntegration/gauge-java/libs/.gitkeep
vendored
Normal file
0
integration/testdata/TestGaugeIntegration/gauge-java/libs/.gitkeep
vendored
Normal file
6
integration/testdata/TestGaugeIntegration/gauge-java/manifest.json
vendored
Normal file
6
integration/testdata/TestGaugeIntegration/gauge-java/manifest.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"Language": "java",
|
||||
"Plugins": [
|
||||
"html-report"
|
||||
]
|
||||
}
|
32
integration/testdata/TestGaugeIntegration/gauge-java/specs/example.spec
vendored
Normal file
32
integration/testdata/TestGaugeIntegration/gauge-java/specs/example.spec
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# Specification Heading
|
||||
|
||||
This is an executable specification file. This file follows markdown syntax.
|
||||
Every heading in this file denotes a scenario. Every bulleted point denotes a step.
|
||||
|
||||
To execute this specification, run
|
||||
gauge run specs
|
||||
|
||||
|
||||
* Vowels in English language are "aeiou".
|
||||
|
||||
## Vowel counts in single word
|
||||
|
||||
tags: single word
|
||||
|
||||
* The word "gauge" has "3" vowels.
|
||||
|
||||
|
||||
## Vowel counts in multiple word
|
||||
|
||||
This is the second scenario in this specification
|
||||
|
||||
Here's a step that takes a table
|
||||
|
||||
* Almost all words have vowels
|
||||
|Word |Vowel Count|
|
||||
|------|-----------|
|
||||
|Gauge |3 |
|
||||
|Mingle|2 |
|
||||
|Snap |1 |
|
||||
|GoCD |1 |
|
||||
|Rhythm|0 |
|
47
integration/testdata/TestGaugeIntegration/gauge-java/src/test/java/StepImplementation.java
vendored
Normal file
47
integration/testdata/TestGaugeIntegration/gauge-java/src/test/java/StepImplementation.java
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
import com.thoughtworks.gauge.Step;
|
||||
import com.thoughtworks.gauge.Table;
|
||||
import com.thoughtworks.gauge.TableRow;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class StepImplementation {
|
||||
|
||||
private HashSet<Character> vowels;
|
||||
|
||||
@Step("Vowels in English language are <vowelString>.")
|
||||
public void setLanguageVowels(String vowelString) {
|
||||
vowels = new HashSet<>();
|
||||
for (char ch : vowelString.toCharArray()) {
|
||||
vowels.add(ch);
|
||||
}
|
||||
}
|
||||
|
||||
@Step("The word <word> has <expectedCount> vowels.")
|
||||
public void verifyVowelsCountInWord(String word, int expectedCount) {
|
||||
int actualCount = countVowels(word);
|
||||
assertThat(expectedCount).isEqualTo(actualCount);
|
||||
}
|
||||
|
||||
@Step("Almost all words have vowels <wordsTable>")
|
||||
public void verifyVowelsCountInMultipleWords(Table wordsTable) {
|
||||
for (TableRow row : wordsTable.getTableRows()) {
|
||||
String word = row.getCell("Word");
|
||||
int expectedCount = Integer.parseInt(row.getCell("Vowel Count"));
|
||||
int actualCount = countVowels(word);
|
||||
|
||||
assertThat(expectedCount).isEqualTo(actualCount);
|
||||
}
|
||||
}
|
||||
|
||||
private int countVowels(String word) {
|
||||
int count = 0;
|
||||
for (char ch : word.toCharArray()) {
|
||||
if (vowels.contains(ch)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
5
integration/testdata/TestGaugeIntegration/gauge-js/.dockerignore
vendored
Normal file
5
integration/testdata/TestGaugeIntegration/gauge-js/.dockerignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
logs
|
||||
Dockerfile
|
||||
reports
|
||||
README.md
|
36
integration/testdata/TestGaugeIntegration/gauge-js/.gitignore
vendored
Normal file
36
integration/testdata/TestGaugeIntegration/gauge-js/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
# Gauge - metadata dir
|
||||
.gauge
|
||||
|
||||
# Gauge - log files dir
|
||||
logs
|
||||
|
||||
# Gauge - reports dir
|
||||
reports
|
||||
|
||||
# Gauge - JavaScript node dependencies
|
||||
node_modules
|
||||
# Gauge - metadata dir
|
||||
.gauge
|
||||
|
||||
# Gauge - log files dir
|
||||
logs
|
||||
|
||||
# Gauge - reports dir
|
||||
reports
|
||||
|
||||
# Gauge - JavaScript node dependencies
|
||||
node_modules
|
||||
# Gauge - metadata dir
|
||||
.gauge
|
||||
|
||||
# Gauge - log files dir
|
||||
logs
|
||||
|
||||
# Gauge - reports dir
|
||||
reports
|
||||
|
||||
# Gauge - JavaScript node dependencies
|
||||
node_modules
|
||||
.DS_Store
|
||||
|
||||
|
22
integration/testdata/TestGaugeIntegration/gauge-js/env/default/default.properties
vendored
Normal file
22
integration/testdata/TestGaugeIntegration/gauge-js/env/default/default.properties
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
# default.properties
|
||||
# properties set here will be available to the test execution as environment variables
|
||||
|
||||
# sample_key = sample_value
|
||||
|
||||
#The path to the gauge reports directory. Should be either relative to the project directory or an absolute path
|
||||
gauge_reports_dir = reports
|
||||
|
||||
#Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.
|
||||
overwrite_reports = true
|
||||
|
||||
# Set to false to disable screenshots on failure in reports.
|
||||
screenshot_on_failure = true
|
||||
|
||||
# The path to the gauge logs directory. Should be either relative to the project directory or an absolute path
|
||||
logs_directory = logs
|
||||
|
||||
# The path the gauge specifications directory. Takes a comma separated list of specification files/directories.
|
||||
gauge_specs_dir = specs
|
||||
|
||||
# The default delimiter used read csv files.
|
||||
csv_delimiter = ,
|
10
integration/testdata/TestGaugeIntegration/gauge-js/env/default/js.properties
vendored
Normal file
10
integration/testdata/TestGaugeIntegration/gauge-js/env/default/js.properties
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#js.properties
|
||||
#settings related to gauge-js.
|
||||
|
||||
test_timeout = 10000
|
||||
|
||||
# Change this to true to enable debugging support
|
||||
DEBUG = false
|
||||
|
||||
# Comma seperated list of dirs. path should be relative to project root.
|
||||
STEP_IMPL_DIR = tests
|
6
integration/testdata/TestGaugeIntegration/gauge-js/manifest.json
vendored
Normal file
6
integration/testdata/TestGaugeIntegration/gauge-js/manifest.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"Language": "js",
|
||||
"Plugins": [
|
||||
"html-report"
|
||||
]
|
||||
}
|
11
integration/testdata/TestGaugeIntegration/gauge-js/package-lock.json
generated
vendored
Normal file
11
integration/testdata/TestGaugeIntegration/gauge-js/package-lock.json
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "gauge-js-template",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gauge-js-template"
|
||||
}
|
||||
}
|
||||
}
|
7
integration/testdata/TestGaugeIntegration/gauge-js/package.json
vendored
Normal file
7
integration/testdata/TestGaugeIntegration/gauge-js/package.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "gauge-js-template",
|
||||
"description": "Starter template for writing JavaScript tests for Gauge",
|
||||
"scripts": {
|
||||
"test": "gauge run specs/"
|
||||
}
|
||||
}
|
32
integration/testdata/TestGaugeIntegration/gauge-js/specs/example.spec
vendored
Normal file
32
integration/testdata/TestGaugeIntegration/gauge-js/specs/example.spec
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# Specification Heading
|
||||
|
||||
This is an executable specification file. This file follows markdown syntax.
|
||||
Every heading in this file denotes a scenario. Every bulleted point denotes a step.
|
||||
|
||||
To execute this specification, run
|
||||
|
||||
gauge run specs
|
||||
|
||||
|
||||
* Vowels in English language are "aeiou".
|
||||
|
||||
## Vowel counts in single word
|
||||
tags: single word
|
||||
|
||||
* The word "gauge" has "3" vowels.
|
||||
|
||||
## Vowel counts in multiple word
|
||||
|
||||
This is the second scenario in this specification
|
||||
|
||||
Here's a step that takes a table
|
||||
|
||||
* Almost all words have vowels
|
||||
|Word |Vowel Count|
|
||||
|------|-----------|
|
||||
|Gauge |3 |
|
||||
|Mingle|2 |
|
||||
|Snap |1 |
|
||||
|GoCD |1 |
|
||||
|Rhythm|0 |
|
||||
|
42
integration/testdata/TestGaugeIntegration/gauge-js/tests/step_implementation.js
vendored
Normal file
42
integration/testdata/TestGaugeIntegration/gauge-js/tests/step_implementation.js
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/* globals gauge*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var vowels = ["a", "e", "i", "o", "u"];
|
||||
|
||||
var numberOfVowels = function (word) {
|
||||
var vowelArr = word.split("").filter(function (elem) { return vowels.indexOf(elem) > -1; });
|
||||
return vowelArr.length;
|
||||
};
|
||||
|
||||
// --------------------------
|
||||
// Gauge step implementations
|
||||
// --------------------------
|
||||
|
||||
step("Vowels in English language are <vowels>.", function(vowelsGiven) {
|
||||
assert.equal(vowelsGiven, vowels.join(""));
|
||||
});
|
||||
|
||||
step("The word <word> has <number> vowels.", function(word, number) {
|
||||
assert.equal(number, numberOfVowels(word));
|
||||
});
|
||||
|
||||
step("Almost all words have vowels <table>", function(table) {
|
||||
table.rows.forEach(function (row) {
|
||||
assert.equal(numberOfVowels(row.cells[0]), parseInt(row.cells[1]));
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------
|
||||
// Execution Hooks
|
||||
// ---------------
|
||||
|
||||
beforeScenario(function () {
|
||||
assert.equal(vowels.join(""), "aeiou");
|
||||
});
|
||||
|
||||
beforeScenario(function () {
|
||||
assert.equal(vowels[0], "a");
|
||||
}, { tags: [ "single word" ]});
|
91
resources/metadata/gauge.yaml
Normal file
91
resources/metadata/gauge.yaml
Normal file
@ -0,0 +1,91 @@
|
||||
metadata:
|
||||
name: gaugeExecuteTests
|
||||
description: Installs gauge and executes specified gauge tests.
|
||||
longDescription: |
|
||||
In this step Gauge ([getgauge.io](https://getgauge.io)) acceptance tests are executed. Using Gauge it will be possible to have a three-tier test layout:
|
||||
|
||||
Acceptance Criteria
|
||||
Test implemenation layer
|
||||
Application driver layer
|
||||
|
||||
This layout is propagated by Jez Humble and Dave Farley in their book "Continuous Delivery" as a way to create maintainable acceptance test suites (see "Continuous Delivery", p. 190ff).
|
||||
|
||||
Using Gauge it is possible to write test specifications in [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) and therefore allow e.g. product owners to write the relevant acceptance test specifications. At the same time it allows the developer to implement the steps described in the specification in her development environment.
|
||||
|
||||
You can use the [sample projects](https://github.com/getgauge/gauge-mvn-archetypes) of Gauge.
|
||||
|
||||
spec:
|
||||
inputs:
|
||||
secrets:
|
||||
- name: seleniumHubCredentialsId
|
||||
type: jenkins
|
||||
description: "Defines the id of the user/password credentials to be used to connect to a Selenium Hub. The credentials are provided in the environment variables `PIPER_SELENIUM_HUB_USER` and `PIPER_SELENIUM_HUB_PASSWORD`."
|
||||
resources:
|
||||
- name: buildDescriptor
|
||||
type: stash
|
||||
- name: tests
|
||||
type: stash
|
||||
params:
|
||||
- name: installCommand
|
||||
type: string
|
||||
description: 'Defines the command for installing Gauge. Gauge should be installed using npm. Example: npm install -g @getgauge/cli@1.2.1'
|
||||
scope:
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
- name: languageRunner
|
||||
type: string
|
||||
description: 'Defines the Gauge language runner to be used. Example: java'
|
||||
scope:
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
- name: runCommand
|
||||
type: string
|
||||
description: 'Defines the command which is used for executing Gauge. Example: run -s -p specs/'
|
||||
scope:
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
mandatory: true
|
||||
- name: testOptions
|
||||
type: string
|
||||
description: "Allows to set specific options for the Gauge execution. Details can be found for example [in the Gauge Maven plugin documentation](https://github.com/getgauge-contrib/gauge-maven-plugin#executing-specs)"
|
||||
scope:
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
outputs:
|
||||
resources:
|
||||
- name: influx
|
||||
type: influx
|
||||
params:
|
||||
- name: step_data
|
||||
fields:
|
||||
- name: gauge
|
||||
type: bool
|
||||
containers:
|
||||
- name: gauge
|
||||
image: node:lts-stretch
|
||||
env:
|
||||
- name: no_proxy
|
||||
value: localhost,selenium,$no_proxy
|
||||
- name: NO_PROXY
|
||||
value: localhost,selenium,$NO_PROXY
|
||||
workingDir: /home/node
|
||||
volumeMounts:
|
||||
- mountPath: /dev/shm
|
||||
name: dev-shm
|
||||
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"
|
@ -186,6 +186,7 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
'integrationArtifactUpload', //implementing new golang pattern without fields
|
||||
'containerExecuteStructureTests', //implementing new golang pattern without fields
|
||||
'transportRequestUploadSOLMAN', //implementing new golang pattern without fields
|
||||
'gaugeExecuteTests', //implementing new golang pattern without fields
|
||||
'batsExecuteTests', //implementing new golang pattern without fields
|
||||
]
|
||||
|
||||
|
@ -1,163 +0,0 @@
|
||||
import hudson.AbortException
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class GaugeExecuteTestsTest extends BasePiperTest {
|
||||
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
||||
private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this)
|
||||
private JenkinsEnvironmentRule environmentRule = new JenkinsEnvironmentRule(this)
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(shellRule)
|
||||
.around(loggingRule)
|
||||
.around(environmentRule)
|
||||
.around(stepRule)
|
||||
.around(thrown)
|
||||
|
||||
def gitParams = [:]
|
||||
def seleniumParams = [:]
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
helper.registerAllowedMethod("git", [Map.class], { map -> gitParams = map })
|
||||
helper.registerAllowedMethod("unstash", [String.class], { s -> return [s]})
|
||||
|
||||
helper.registerAllowedMethod('seleniumExecuteTests', [Map.class, Closure.class], {map, body ->
|
||||
seleniumParams = map
|
||||
return body()
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeDefaultSuccess() throws Exception {
|
||||
stepRule.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
testServerUrl: 'http://test.url'
|
||||
)
|
||||
assertThat(shellRule.shell, hasItem(stringContainsInOrder([
|
||||
'export HOME=${HOME:-$(pwd)}',
|
||||
'if [ "$HOME" = "/" ]; then export HOME=$(pwd); fi',
|
||||
'export PATH=$HOME/bin/gauge:$PATH',
|
||||
'mkdir -p $HOME/bin/gauge',
|
||||
'curl -SsL https://downloads.gauge.org/stable | sh -s -- --location=$HOME/bin/gauge',
|
||||
'gauge telemetry off',
|
||||
'gauge install java',
|
||||
'gauge install html-report',
|
||||
'gauge install xml-report',
|
||||
'mvn test-compile gauge:execute -DspecsDir=specs'
|
||||
])))
|
||||
assertThat(seleniumParams.dockerImage, is('maven:3.5-jdk-8'))
|
||||
assertThat(seleniumParams.dockerEnvVars, hasEntry('TARGET_SERVER_URL', 'http://test.url'))
|
||||
assertThat(seleniumParams.dockerName, is('maven'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is(''))
|
||||
assertThat(seleniumParams.stashContent, hasSize(2))
|
||||
assertThat(seleniumParams.stashContent, allOf(hasItem('buildDescriptor'), hasItem('tests')))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDockerFromCustomStepConfiguration() {
|
||||
|
||||
def expectedImage = 'image:test'
|
||||
def expectedEnvVars = ['HUB':'', 'HUB_URL':'', 'env1': 'value1', 'env2': 'value2']
|
||||
def expectedOptions = '--opt1=val1 --opt2=val2 --opt3'
|
||||
def expectedWorkspace = '/path/to/workspace'
|
||||
|
||||
nullScript.commonPipelineEnvironment.configuration = [steps:[gaugeExecuteTests:[
|
||||
dockerImage: expectedImage,
|
||||
dockerOptions: expectedOptions,
|
||||
dockerEnvVars: expectedEnvVars,
|
||||
dockerWorkspace: expectedWorkspace
|
||||
]]]
|
||||
|
||||
stepRule.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils
|
||||
)
|
||||
|
||||
assert expectedImage == seleniumParams.dockerImage
|
||||
assert expectedOptions == seleniumParams.dockerOptions
|
||||
assert expectedEnvVars.equals(seleniumParams.dockerEnvVars)
|
||||
assert expectedWorkspace == seleniumParams.dockerWorkspace
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeNode() throws Exception {
|
||||
stepRule.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
buildTool: 'npm',
|
||||
dockerEnvVars: ['TARGET_SERVER_URL':'http://custom.url'],
|
||||
juStabUtils: utils,
|
||||
testOptions: 'testSpec'
|
||||
)
|
||||
assertThat(shellRule.shell, hasItem(stringContainsInOrder([
|
||||
'gauge install js',
|
||||
'gauge run testSpec'
|
||||
])))
|
||||
assertThat(seleniumParams.dockerImage, is('node:lts-stretch'))
|
||||
assertThat(seleniumParams.dockerEnvVars, hasEntry('TARGET_SERVER_URL', 'http://custom.url'))
|
||||
assertThat(seleniumParams.dockerName, is('npm'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is('/home/node'))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteCustomWithError() throws Exception {
|
||||
helper.registerAllowedMethod("sh", [String.class], { s ->
|
||||
throw new RuntimeException('Test Error')
|
||||
})
|
||||
thrown.expect(AbortException)
|
||||
thrown.expectMessage('ERROR: The execution of the gauge tests failed, see the log for details.')
|
||||
try {
|
||||
stepRule.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
dockerImage: 'testImage',
|
||||
dockerName: 'testImageName',
|
||||
dockerWorkspace: '/home/test',
|
||||
failOnError: true,
|
||||
stashContent: ['testStash'],
|
||||
)
|
||||
|
||||
} finally{
|
||||
assertThat(seleniumParams.dockerImage, is('testImage'))
|
||||
assertThat(seleniumParams.dockerName, is('testImageName'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is('/home/test'))
|
||||
assertThat(seleniumParams.stashContent, hasSize(1))
|
||||
assertThat(loggingRule.log, containsString('[gaugeExecuteTests] One or more tests failed'))
|
||||
assertThat(nullScript.currentBuild.result, is('UNSTABLE'))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeCustomRepo() throws Exception {
|
||||
helper.registerAllowedMethod('git', [String.class], null)
|
||||
helper.registerAllowedMethod('stash', [String.class], null)
|
||||
|
||||
stepRule.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
testRepository: 'myTestRepo',
|
||||
failOnError: true
|
||||
)
|
||||
|
||||
// nested matchers do not work correctly
|
||||
assertThat(seleniumParams.stashContent, hasItem(startsWith('testContent-')))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
}
|
@ -1,167 +1,13 @@
|
||||
import static com.sap.piper.Prerequisites.checkScript
|
||||
|
||||
import com.sap.piper.GenerateDocumentation
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.GitUtils
|
||||
import com.sap.piper.analytics.InfluxData
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
@Field String METADATA_FILE = 'metadata/gauge.yaml'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = []
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
/**
|
||||
* Defines the build tool to be used for the test execution.
|
||||
* @possibleValues `maven`, `npm`, `bundler`
|
||||
*/
|
||||
'buildTool',
|
||||
/** @see dockerExecute*/
|
||||
'dockerEnvVars',
|
||||
/** @see dockerExecute*/
|
||||
'dockerImage',
|
||||
/** @see dockerExecute*/
|
||||
'dockerName',
|
||||
/** @see dockerExecute */
|
||||
'dockerOptions',
|
||||
/** @see dockerExecute*/
|
||||
'dockerWorkspace',
|
||||
/**
|
||||
* Defines the behavior in case tests fail. When this is set to `true` test results cannot be recorded using the `publishTestResults` step afterwards.
|
||||
* @possibleValues `true`, `false`
|
||||
*/
|
||||
'failOnError',
|
||||
/** Defines the command for installing Gauge. In case the `dockerImage` already contains Gauge it can be set to empty: ``.*/
|
||||
'installCommand',
|
||||
/** Defines the Gauge language runner to be used.*/
|
||||
'languageRunner',
|
||||
/** Defines the command which is used for executing Gauge.*/
|
||||
'runCommand',
|
||||
/** Defines if specific stashes should be considered for the tests.*/
|
||||
'stashContent',
|
||||
/** Allows to set specific options for the Gauge execution. Details can be found for example [in the Gauge Maven plugin documentation](https://github.com/getgauge/gauge-maven-plugin#executing-specs)*/
|
||||
'testOptions',
|
||||
/** Defines the repository containing the tests, in case the test implementation is stored in a different repository than the code itself.*/
|
||||
'testRepository',
|
||||
/** Defines the branch containing the tests, in case the test implementation is stored in a different repository and a different branch than master.*/
|
||||
'gitBranch',
|
||||
/**
|
||||
* Defines the credentials for the repository containing the tests, in case the test implementation is stored in a different and protected repository than the code itself.
|
||||
* For protected repositories the `testRepository` needs to contain the ssh git url.
|
||||
*/
|
||||
'gitSshKeyCredentialsId',
|
||||
/** It is passed as environment variable `TARGET_SERVER_URL` to the test execution. Tests running against the system should read the host information from this environment variable in order to be infrastructure agnostic.*/
|
||||
'testServerUrl'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
/**
|
||||
* In this step Gauge ([getgauge.io](http:getgauge.io)) acceptance tests are executed.
|
||||
* Using Gauge it will be possible to have a three-tier test layout:
|
||||
*
|
||||
* * Acceptance Criteria
|
||||
* * Test implemenation layer
|
||||
* * Application driver layer
|
||||
*
|
||||
* This layout is propagated by Jez Humble and Dave Farley in their book "Continuous Delivery" as a way to create maintainable acceptance test suites (see "Continuous Delivery", p. 190ff).
|
||||
*
|
||||
* Using Gauge it is possible to write test specifications in [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) and therefore allow e.g. product owners to write the relevant acceptance test specifications. At the same time it allows the developer to implement the steps described in the specification in her development environment.
|
||||
*
|
||||
* You can use the [sample projects](https://github.com/getgauge/gauge-mvn-archetypes) of Gauge.
|
||||
*
|
||||
* !!! note "Make sure to run against a Selenium Hub configuration"
|
||||
* In the test example of _gauge-archetype-selenium_ please make sure to allow it to run against a Selenium hub:
|
||||
*
|
||||
* Please extend DriverFactory.java for example in following way:
|
||||
*
|
||||
* ``` java
|
||||
* String hubUrl = System.getenv("HUB_URL");
|
||||
* //when running on a Docker deamon (and not using Kubernetes plugin), Docker images will be linked
|
||||
* //in this case hubUrl will be http://selenium:4444/wd/hub due to the linking of the containers
|
||||
* hubUrl = (hubUrl == null) ? "http://localhost:4444/wd/hub" : hubUrl;
|
||||
* Capabilities chromeCapabilities = DesiredCapabilities.chrome();
|
||||
* System.out.println("Running on Selenium Hub: " + hubUrl);
|
||||
* return new RemoteWebDriver(new URL(hubUrl), chromeCapabilities);
|
||||
* ```
|
||||
*/
|
||||
@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
|
||||
|
||||
InfluxData.addField('step_data', 'gauge', false)
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults([:], stageName)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.dependingOn('buildTool').mixin('dockerImage')
|
||||
.dependingOn('buildTool').mixin('dockerName')
|
||||
.dependingOn('buildTool').mixin('dockerOptions')
|
||||
.dependingOn('buildTool').mixin('dockerEnvVars')
|
||||
.dependingOn('buildTool').mixin('dockerWorkspace')
|
||||
.dependingOn('buildTool').mixin('languageRunner')
|
||||
.dependingOn('buildTool').mixin('runCommand')
|
||||
.dependingOn('buildTool').mixin('testOptions')
|
||||
.use()
|
||||
|
||||
utils.pushToSWA([
|
||||
step: STEP_NAME,
|
||||
stepParamKey1: 'buildTool',
|
||||
stepParam1: config.buildTool,
|
||||
stepParamKey2: 'dockerName',
|
||||
stepParam2: config.dockerName
|
||||
], config)
|
||||
|
||||
if(!config.dockerEnvVars.TARGET_SERVER_URL && config.testServerUrl)
|
||||
config.dockerEnvVars.TARGET_SERVER_URL = config.testServerUrl
|
||||
|
||||
if (config.testRepository) {
|
||||
// handle separate test repository
|
||||
config.stashContent = [GitUtils.handleTestRepository(this, config)]
|
||||
} else {
|
||||
config.stashContent = utils.unstashAll(config.stashContent)
|
||||
}
|
||||
|
||||
seleniumExecuteTests (
|
||||
script: script,
|
||||
buildTool: config.buildTool,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerName: config.dockerName,
|
||||
dockerEnvVars: config.dockerEnvVars,
|
||||
dockerOptions: config.dockerOptions,
|
||||
dockerWorkspace: config.dockerWorkspace,
|
||||
stashContent: config.stashContent
|
||||
) {
|
||||
String gaugeScript = ''
|
||||
if (config.installCommand) {
|
||||
gaugeScript = '''export HOME=${HOME:-$(pwd)}
|
||||
if [ "$HOME" = "/" ]; then export HOME=$(pwd); fi
|
||||
export PATH=$HOME/bin/gauge:$PATH
|
||||
mkdir -p $HOME/bin/gauge
|
||||
''' + config.installCommand + '''
|
||||
gauge telemetry off
|
||||
gauge install ''' + config.languageRunner + '''
|
||||
gauge install html-report
|
||||
gauge install xml-report
|
||||
'''
|
||||
}
|
||||
gaugeScript += config.runCommand
|
||||
|
||||
try {
|
||||
sh "${gaugeScript} ${config.testOptions}"
|
||||
InfluxData.addField('step_data', 'gauge', true)
|
||||
} catch (err) {
|
||||
echo "[${STEP_NAME}] One or more tests failed"
|
||||
script.currentBuild.result = 'UNSTABLE'
|
||||
if (config.failOnError) error "[${STEP_NAME}] ERROR: The execution of the gauge tests failed, see the log for details."
|
||||
}
|
||||
}
|
||||
}
|
||||
List credentials = [
|
||||
[type: 'usernamePassword', id: 'seleniumHubCredentialsId', env: ['PIPER_SELENIUM_HUB_USER', 'PIPER_SELENIUM_HUB_PASSWORD']],
|
||||
]
|
||||
final script = checkScript(this, parameters) ?: this
|
||||
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user