1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/xsDeploy_test.go
Marcus Holl 9ee2926018
xs deploy go (#931)
introduce xs deploy
2019-12-05 14:22:38 +01:00

284 lines
7.5 KiB
Go

package cmd
import (
"bytes"
"errors"
"fmt"
"github.com/stretchr/testify/assert"
"io"
"io/ioutil"
"strings"
"sync"
"testing"
)
func TestDeploy(t *testing.T) {
myXsDeployOptions := xsDeployOptions{
APIURL: "https://example.org:12345",
User: "me",
Password: "secretPassword",
Org: "myOrg",
Space: "mySpace",
LoginOpts: "--skip-ssl-validation",
DeployOpts: "--dummy-deploy-opts",
XsSessionFile: ".xs_session",
Mode: "DEPLOY",
Action: "NONE",
MtaPath: "dummy.mtar",
OperationIDLogPattern: `^.*xs bg-deploy -i (.*) -a.*$`,
}
s := shellMockRunner{}
var copiedFiles []string
var removedFiles []string
fExists := func(path string) bool {
return path == "dummy.mtar" || path == ".xs_session"
}
fCopy := func(src, dest string) (int64, error) {
copiedFiles = append(copiedFiles, fmt.Sprintf("%s->%s", src, dest))
return 0, nil
}
fRemove := func(path string) error {
removedFiles = append(removedFiles, path)
return nil
}
var stdout string
t.Run("Standard deploy succeeds", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
stdout = ""
}()
rStdout, wStdout := io.Pipe()
var wg sync.WaitGroup
wg.Add(1)
go func() {
buf := new(bytes.Buffer)
io.Copy(buf, rStdout)
stdout = buf.String()
wg.Done()
}()
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, wStdout)
wStdout.Close()
wg.Wait()
checkErr(t, e, "")
t.Run("Standard checks", func(t *testing.T) {
// Contains --> we do not check for the shebang
assert.Contains(t, s.calls[0], "xs login -a https://example.org:12345 -u me -p 'secretPassword' -o myOrg -s mySpace --skip-ssl-validation")
assert.Contains(t, s.calls[1], "xs deploy dummy.mtar --dummy-deploy-opts")
assert.Contains(t, s.calls[2], "xs logout")
assert.Len(t, s.calls, 3)
// xs session file needs to be removed at end during a normal deployment
assert.Len(t, removedFiles, 1)
assert.Contains(t, removedFiles, ".xs_session")
assert.Len(t, copiedFiles, 2)
// We copy the xs session file to the workspace in order to be able to use the file later.
// This happens directly after login
// We copy the xs session file from the workspace to the home folder in order to be able to
// use that file. This is important in case we rely on a login which happend e
assert.Contains(t, copiedFiles[0], "/.xs_session->.xs_session")
assert.Contains(t, copiedFiles[1], ".xs_session->")
assert.Contains(t, copiedFiles[1], "/.xs_session")
})
t.Run("Password not exposed", func(t *testing.T) {
assert.NotEmpty(t, stdout)
assert.NotContains(t, stdout, myXsDeployOptions.Password)
})
})
t.Run("Standard deploy fails, deployable missing", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
}()
oldMtaPath := myXsDeployOptions.MtaPath
defer func() {
myXsDeployOptions.MtaPath = oldMtaPath
}()
// this file is not denoted in the file exists mock
myXsDeployOptions.MtaPath = "doesNotExist"
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "Deployable 'doesNotExist' does not exist")
})
t.Run("Standard deploy fails, action provided", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
}()
myXsDeployOptions.Action = "RETRY"
defer func() {
myXsDeployOptions.Action = "NONE"
}()
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "Cannot perform action 'RETRY' in mode 'DEPLOY'. Only action 'NONE' is allowed.")
})
t.Run("Standard deploy fails, error from underlying process", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
s.shouldFailWith = nil
}()
s.shouldFailWith = errors.New("Error from underlying process")
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "Error from underlying process")
})
t.Run("BG deploy succeeds", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
}()
oldMode := myXsDeployOptions.Mode
defer func() {
myXsDeployOptions.Mode = oldMode
}()
myXsDeployOptions.Mode = "BG_DEPLOY"
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "")
assert.Contains(t, s.calls[0], "xs login")
assert.Contains(t, s.calls[1], "xs bg-deploy dummy.mtar --dummy-deploy-opts")
assert.Len(t, s.calls, 2) // There are two entries --> no logout in this case.
})
t.Run("BG deploy abort succeeds", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
}()
oldMode := myXsDeployOptions.Mode
oldAction := myXsDeployOptions.Action
defer func() {
myXsDeployOptions.Mode = oldMode
myXsDeployOptions.Action = oldAction
myXsDeployOptions.OperationID = ""
}()
myXsDeployOptions.Mode = "BG_DEPLOY"
myXsDeployOptions.Action = "ABORT"
myXsDeployOptions.OperationID = "12345"
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "")
assert.Contains(t, s.calls[0], "xs bg-deploy -i 12345 -a abort")
assert.Contains(t, s.calls[1], "xs logout")
assert.Len(t, s.calls, 2) // There is no login --> we have two calls
})
t.Run("BG deploy abort fails due to missing operationId", func(t *testing.T) {
defer func() {
copiedFiles = nil
removedFiles = nil
s.calls = nil
}()
oldMode := myXsDeployOptions.Mode
oldAction := myXsDeployOptions.Action
defer func() {
myXsDeployOptions.Mode = oldMode
myXsDeployOptions.Action = oldAction
}()
myXsDeployOptions.Mode = "BG_DEPLOY"
myXsDeployOptions.Action = "ABORT"
e := runXsDeploy(myXsDeployOptions, &s, fExists, fCopy, fRemove, ioutil.Discard)
checkErr(t, e, "OperationID was not provided")
})
}
func TestRetrieveOperationID(t *testing.T) {
operationID := retrieveOperationID(`
Uploading 1 files:
myFolder/dummy.mtar
File upload finished
Detected MTA schema version: "3.1.0"
Detected deploy target as "myOrg mySpace"
Detected deployed MTA with ID "my_mta" and version "0.0.1"
Deployed MTA color: blue
New MTA color: green
Detected new MTA version: "0.0.1"
Deployed MTA version: 0.0.1
Service "xxx" is not modified and will not be updated
Creating application "db-green" from MTA module "xx"...
Uploading application "xx-green"...
Staging application "xx-green"...
Application "xx-green" staged
Executing task "deploy" on application "xx-green"...
Task execution status: succeeded
Process has entered validation phase. After testing your new deployment you can resume or abort the process.
Use "xs bg-deploy -i 1234 -a resume" to resume the process.
Use "xs bg-deploy -i 1234 -a abort" to abort the process.
Hint: Use the '--no-confirm' option of the bg-deploy command to skip this phase.
`, `^.*xs bg-deploy -i (.*) -a.*$`)
assert.Equal(t, "1234", operationID)
}
func checkErr(t *testing.T, e error, message string) {
expectError := len(message) > 0
if expectError {
if e == nil {
t.Errorf("Expected error not received. Expected: '%s'.", message)
} else {
if !strings.Contains(e.Error(), message) {
t.Errorf("Unexpected error message received: '%s'. Expected: '%s'.", e.Error(), message)
}
}
} else {
if e != nil {
t.Errorf("No error expected, but error received: %s", e.Error())
}
}
}