mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-02-09 13:47:31 +02:00
[TMS] Reimplement tmsUpload step in Go (#3399)
* Initially generated tmsUpload<...> files * First provisioning of parameters supported by tmsUpload step * Refer to Go step from tmsUpload.groovy * Initial client implementation * Reverting line delimiters in tmsUpoad.groovy back to Unix ones * Temporarily remove when-condition for Release stage * Define useGoStep parameter in tmsUpload.groovy * Unstash buildResult if useGoStep is true * No unstashing and empty credentials, when using go step * Register TmsUploadCommand in piper.go * Cleanup groovy-related changes - they will be temporarily implemented in a different repo * Make getting OAuth token success * Look through the code and cleanup it a bit * Read service key from Jenkins credentials store * Provide initial set of unit tests for methods in /pkg/tms/tms.go file * Minor improvements on logging response on http call error * Check, if positive HTTP status code is as expected * Cleanup tms.yaml file, provide additional unit test for tms.go * Provide unit test for the case, when request body contains spaces * Specify nodeExtDescriptorMapping parameter as of type map in tms.yaml * Implement client method for getting nodes * Write tests for GetNodes method * Add GetMtaExtDescriptor client method and cover it with unit tests * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide UploadFile and UploadFileToNode client methods * Provide tests for Update- and UploadMtaExtDescriptor client methods * Write tests for FileUpload and FileUploadToNode client methods * Minor corrections * Remove some TODO comments * Rename some of response structures * Revert change for line delimiters in cmd/piper.go * Add uploadType string parameter to UploadFile and UploadRequest methods of uploader mock to reflect the changed Uploader implementation * Start to implement execution logic in tmsUpload.go * Changes in tms.yaml file - remove resources from inputs in tms.yaml and implement mtaPath parameter settings in the yaml file the same way, as it is done in cloudFoundryDeploy.yaml - rename tms.yaml to tmsUpload.yaml, since some generation policy changed meanwhile * Rename tms.yaml to tmsUpload.yaml and do go generate * Use provided proxy on communication with UAA and TMS * Set proxy even before getting OAuth token * Further implementation of tmsUpload.go * Continuation on implementing the tmsUpload.go executor * Get mtarFilePath and git commitId from commonPipelineEnvironment, if they are missing in configuration file + minor changes * Implement a happy path test for tmsUpload logic * Cover with unit tests main happy and error paths of tmsUpload.go logic * Extend set of unit tests for tmsUpload.go * Eliminate some TODOs, extend unit tests for tmsUpload.go * Delete some TODOs * Remove a couple of more TODOs from tms_test.go file * Provide additional unit test for error due unexpected positive http status code on upload * Revert back line delimiters in cmd/piper.go * Comment out file uploading calls in tmsUpload.go * Run go generate to update generated files * Convert line delimiters in tmsUpload.yaml to Unix ones, as well as provide new line character in the end of the file, plus minor fix for logging in tmsUpload.go file (pipeline complained) * Correct description of a parameter in tmsUpload.yaml, extend unit tests to check for trimming a slash in the end of TMS url for client methods that do upload * [minor] Add a comment in the test code * Add stashContent parameter to do unstashing in tmsUpload.groovy, remove some of the clarified TODOs * Uncomment uploading file calls in tmsUpload.go, declare buildResult stash in tmsUpload.yaml * Remove clarified TODOs from the tmsUpload.go file * Run go fmt for jenkins-library/pkg/tms * Do not get explicitly values from common pipeline environment - all configurations are provided in yaml file * Remove unused struct from tmsUpload_test.go * Run go fmt jenkins-library\pkg\tms * Revise descriptions of parameters provided in tmsUpload.yaml file * Specify STAGES scope for tmsUpload parameters * Provide STAGES scope for the tmsUpload parameters, provide default value for stashContent parameter * Remove trailing space from tmsUpload.yaml * Provide unit tests for proxy-related changes in http.go file * Improve proxy implementation in tmsUpload.go file * Make tmsServiceKey again a mandatory parameter * Run go generate command to make the generated files correspond the yaml state * Change line delimiters back to Unix ones (were switched while resolving the conflicts) * Remove trailing spaces from tmsUpload.yaml * Minor change in a comment to trigger pipelines with commit * Improve checks for zero-structs and for empty maps, as well as use different package to read files in the tests * Revert line endings in http.go * Revert comments formatting changes in files that do not belong to the tmsUpload step
This commit is contained in:
parent
402c6085c9
commit
4b257377ec
@ -100,6 +100,7 @@ func GetAllStepMetadata() map[string]config.StepData {
|
||||
"shellExecute": shellExecuteMetadata(),
|
||||
"sonarExecuteScan": sonarExecuteScanMetadata(),
|
||||
"terraformExecute": terraformExecuteMetadata(),
|
||||
"tmsUpload": tmsUploadMetadata(),
|
||||
"transportRequestDocIDFromGit": transportRequestDocIDFromGitMetadata(),
|
||||
"transportRequestReqIDFromGit": transportRequestReqIDFromGitMetadata(),
|
||||
"transportRequestUploadCTS": transportRequestUploadCTSMetadata(),
|
||||
|
@ -191,6 +191,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(ApiProxyListCommand())
|
||||
rootCmd.AddCommand(AnsSendEventCommand())
|
||||
rootCmd.AddCommand(ApiProviderListCommand())
|
||||
rootCmd.AddCommand(TmsUploadCommand())
|
||||
|
||||
addRootFlags(rootCmd)
|
||||
|
||||
|
7
cmd/testdata/TestRunTmsUpload/invalid/missing_extends_parameter.mtaext
vendored
Normal file
7
cmd/testdata/TestRunTmsUpload/invalid/missing_extends_parameter.mtaext
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
_schema-version: "3.1.0"
|
||||
ID: com.sap.tms.upload.test_ext
|
||||
|
||||
modules:
|
||||
- name: "openui5-sample-app"
|
||||
parameters:
|
||||
version: 1.0.0-${timestamp}
|
13
cmd/testdata/TestRunTmsUpload/invalid/mta_no_id_and_version_parameters.yaml
vendored
Normal file
13
cmd/testdata/TestRunTmsUpload/invalid/mta_no_id_and_version_parameters.yaml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
_schema-version: "2.0.0"
|
||||
|
||||
parameters:
|
||||
hcp-deployer-version: "1.0.0"
|
||||
|
||||
modules:
|
||||
- name: "openui5-sample-app"
|
||||
type: html5
|
||||
path: .
|
||||
parameters:
|
||||
version: "1.0.0"
|
||||
build-parameters:
|
||||
builder: grunt
|
1
cmd/testdata/TestRunTmsUpload/invalid/mta_not_a_yaml.yaml
vendored
Normal file
1
cmd/testdata/TestRunTmsUpload/invalid/mta_not_a_yaml.yaml
vendored
Normal file
@ -0,0 +1 @@
|
||||
The content does not correspond to yaml syntax.
|
1
cmd/testdata/TestRunTmsUpload/invalid/wrong_content.mtaext
vendored
Normal file
1
cmd/testdata/TestRunTmsUpload/invalid/wrong_content.mtaext
vendored
Normal file
@ -0,0 +1 @@
|
||||
The content does not correspond to yaml syntax.
|
8
cmd/testdata/TestRunTmsUpload/invalid/wrong_extends_parameter.mtaext
vendored
Normal file
8
cmd/testdata/TestRunTmsUpload/invalid/wrong_extends_parameter.mtaext
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
_schema-version: "3.1.0"
|
||||
ID: com.sap.tms.upload.test_ext
|
||||
extends: com.sap.tms.upload.test.wrong.extends.parameter
|
||||
|
||||
modules:
|
||||
- name: "openui5-sample-app"
|
||||
parameters:
|
||||
version: 1.0.0-${timestamp}
|
15
cmd/testdata/TestRunTmsUpload/valid/mta.yaml
vendored
Normal file
15
cmd/testdata/TestRunTmsUpload/valid/mta.yaml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
_schema-version: "2.0.0"
|
||||
ID: "com.sap.tms.upload.test"
|
||||
version: 1.0.0
|
||||
|
||||
parameters:
|
||||
hcp-deployer-version: "1.0.0"
|
||||
|
||||
modules:
|
||||
- name: "openui5-sample-app"
|
||||
type: html5
|
||||
path: .
|
||||
parameters:
|
||||
version: "1.0.0"
|
||||
build-parameters:
|
||||
builder: grunt
|
8
cmd/testdata/TestRunTmsUpload/valid/test.mtaext
vendored
Normal file
8
cmd/testdata/TestRunTmsUpload/valid/test.mtaext
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
_schema-version: "3.1.0"
|
||||
ID: com.sap.tms.upload.test_ext
|
||||
extends: com.sap.tms.upload.test
|
||||
|
||||
modules:
|
||||
- name: "openui5-sample-app"
|
||||
parameters:
|
||||
version: 1.0.0-${timestamp}
|
288
cmd/tmsUpload.go
Normal file
288
cmd/tmsUpload.go
Normal file
@ -0,0 +1,288 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/SAP/jenkins-library/pkg/tms"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type uaa struct {
|
||||
Url string `json:"url"`
|
||||
ClientId string `json:"clientid"`
|
||||
ClientSecret string `json:"clientsecret"`
|
||||
}
|
||||
|
||||
type serviceKey struct {
|
||||
Uaa uaa `json:"uaa"`
|
||||
Uri string `json:"uri"`
|
||||
}
|
||||
|
||||
type tmsUploadUtils interface {
|
||||
command.ExecRunner
|
||||
|
||||
FileExists(filename string) (bool, error)
|
||||
FileRead(path string) ([]byte, error)
|
||||
|
||||
// Add more methods here, or embed additional interfaces, or remove/replace as required.
|
||||
// The tmsUploadUtils interface should be descriptive of your runtime dependencies,
|
||||
// i.e. include everything you need to be able to mock in tests.
|
||||
// Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies.
|
||||
}
|
||||
|
||||
type tmsUploadUtilsBundle struct {
|
||||
*command.Command
|
||||
*piperutils.Files
|
||||
|
||||
// Embed more structs as necessary to implement methods or interfaces you add to tmsUploadUtils.
|
||||
// Structs embedded in this way must each have a unique set of methods attached.
|
||||
// If there is no struct which implements the method you need, attach the method to
|
||||
// tmsUploadUtilsBundle and forward to the implementation of the dependency.
|
||||
}
|
||||
|
||||
func newTmsUploadUtils() tmsUploadUtils {
|
||||
utils := tmsUploadUtilsBundle{
|
||||
Command: &command.Command{},
|
||||
Files: &piperutils.Files{},
|
||||
}
|
||||
// Reroute command output to logging framework
|
||||
utils.Stdout(log.Writer())
|
||||
utils.Stderr(log.Writer())
|
||||
return &utils
|
||||
}
|
||||
|
||||
func tmsUpload(config tmsUploadOptions, telemetryData *telemetry.CustomData, influx *tmsUploadInflux) {
|
||||
// Utils can be used wherever the command.ExecRunner interface is expected.
|
||||
// It can also be used for example as a mavenExecRunner.
|
||||
utils := newTmsUploadUtils()
|
||||
client := &piperHttp.Client{}
|
||||
proxy := config.Proxy
|
||||
if proxy != "" {
|
||||
transportProxy, err := url.Parse(proxy)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatalf("Failed to parse proxy string %v into a URL structure", proxy)
|
||||
}
|
||||
|
||||
options := piperHttp.ClientOptions{TransportProxy: transportProxy}
|
||||
client.SetOptions(options)
|
||||
if GeneralConfig.Verbose {
|
||||
log.Entry().Infof("HTTP client instructed to use %v proxy", proxy)
|
||||
}
|
||||
}
|
||||
|
||||
serviceKey, err := unmarshalServiceKey(config.TmsServiceKey)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("Failed to unmarshal TMS service key")
|
||||
}
|
||||
|
||||
if GeneralConfig.Verbose {
|
||||
log.Entry().Info("Will be used for communication:")
|
||||
log.Entry().Infof("- client id: %v", serviceKey.Uaa.ClientId)
|
||||
log.Entry().Infof("- TMS URL: %v", serviceKey.Uri)
|
||||
log.Entry().Infof("- UAA URL: %v", serviceKey.Uaa.Url)
|
||||
}
|
||||
|
||||
communicationInstance, err := tms.NewCommunicationInstance(client, serviceKey.Uri, serviceKey.Uaa.Url, serviceKey.Uaa.ClientId, serviceKey.Uaa.ClientSecret, GeneralConfig.Verbose)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("Failed to prepare client for talking with TMS")
|
||||
}
|
||||
|
||||
if err := runTmsUpload(config, communicationInstance, utils); err != nil {
|
||||
log.Entry().WithError(err).Fatal("Failed to run tmsUpload step")
|
||||
}
|
||||
}
|
||||
|
||||
func runTmsUpload(config tmsUploadOptions, communicationInstance tms.CommunicationInterface, utils tmsUploadUtils) error {
|
||||
mtaPath := config.MtaPath
|
||||
exists, _ := utils.FileExists(mtaPath)
|
||||
if !exists {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return fmt.Errorf("mta file %s not found", mtaPath)
|
||||
}
|
||||
|
||||
description := config.CustomDescription
|
||||
namedUser := config.NamedUser
|
||||
nodeName := config.NodeName
|
||||
mtaVersion := config.MtaVersion
|
||||
nodeNameExtDescriptorMapping := config.NodeExtDescriptorMapping
|
||||
|
||||
if GeneralConfig.Verbose {
|
||||
log.Entry().Info("The step will use the following values:")
|
||||
log.Entry().Infof("- description: %v", description)
|
||||
|
||||
if len(nodeNameExtDescriptorMapping) > 0 {
|
||||
log.Entry().Infof("- mapping between node names and MTA extension descriptor file paths: %v", nodeNameExtDescriptorMapping)
|
||||
}
|
||||
log.Entry().Infof("- MTA path: %v", mtaPath)
|
||||
log.Entry().Infof("- MTA version: %v", mtaVersion)
|
||||
if namedUser != "" {
|
||||
log.Entry().Infof("- named user: %v", namedUser)
|
||||
}
|
||||
log.Entry().Infof("- node name: %v", nodeName)
|
||||
}
|
||||
|
||||
if len(nodeNameExtDescriptorMapping) > 0 {
|
||||
nodes, errGetNodes := communicationInstance.GetNodes()
|
||||
if errGetNodes != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to get nodes: %w", errGetNodes)
|
||||
}
|
||||
|
||||
mtaYamlMap, errGetMtaYamlAsMap := getYamlAsMap(utils, "mta.yaml")
|
||||
if errGetMtaYamlAsMap != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return fmt.Errorf("failed to get mta.yaml as map: %w", errGetMtaYamlAsMap)
|
||||
}
|
||||
_, isIdParameterInMap := mtaYamlMap["ID"]
|
||||
_, isVersionParameterInMap := mtaYamlMap["version"]
|
||||
if !isIdParameterInMap || !isVersionParameterInMap {
|
||||
var errorMessage string
|
||||
if !isIdParameterInMap {
|
||||
errorMessage += "parameter 'ID' is not found in mta.yaml\n"
|
||||
}
|
||||
if !isVersionParameterInMap {
|
||||
errorMessage += "parameter 'version' is not found in mta.yaml\n"
|
||||
}
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errors.New(errorMessage)
|
||||
}
|
||||
|
||||
// validate the whole mapping and then throw errors together, so that user can get them after a single pipeline run
|
||||
nodeIdExtDescriptorMapping, errGetNodeIdExtDescriptorMapping := formNodeIdExtDescriptorMappingWithValidation(utils, nodeNameExtDescriptorMapping, nodes, mtaYamlMap, mtaVersion)
|
||||
if errGetNodeIdExtDescriptorMapping != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return errGetNodeIdExtDescriptorMapping
|
||||
}
|
||||
|
||||
for nodeId, mtaExtDescriptorPath := range nodeIdExtDescriptorMapping {
|
||||
obtainedMtaExtDescriptor, errGetMtaExtDescriptor := communicationInstance.GetMtaExtDescriptor(nodeId, fmt.Sprintf("%v", mtaYamlMap["ID"]), mtaVersion)
|
||||
if errGetMtaExtDescriptor != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to get MTA extension descriptor: %w", errGetMtaExtDescriptor)
|
||||
}
|
||||
|
||||
if obtainedMtaExtDescriptor != (tms.MtaExtDescriptor{}) {
|
||||
_, errUpdateMtaExtDescriptor := communicationInstance.UpdateMtaExtDescriptor(nodeId, obtainedMtaExtDescriptor.Id, mtaExtDescriptorPath, mtaVersion, description, namedUser)
|
||||
if errUpdateMtaExtDescriptor != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to update MTA extension descriptor: %w", errUpdateMtaExtDescriptor)
|
||||
}
|
||||
} else {
|
||||
_, errUploadMtaExtDescriptor := communicationInstance.UploadMtaExtDescriptorToNode(nodeId, mtaExtDescriptorPath, mtaVersion, description, namedUser)
|
||||
if errUploadMtaExtDescriptor != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to upload MTA extension descriptor to node: %w", errUploadMtaExtDescriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo, errUploadFile := communicationInstance.UploadFile(mtaPath, namedUser)
|
||||
if errUploadFile != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to upload file: %w", errUploadFile)
|
||||
}
|
||||
|
||||
_, errUploadFileToNode := communicationInstance.UploadFileToNode(nodeName, strconv.FormatInt(fileInfo.Id, 10), description, namedUser)
|
||||
if errUploadFileToNode != nil {
|
||||
log.SetErrorCategory(log.ErrorService)
|
||||
return fmt.Errorf("failed to upload file to node: %w", errUploadFileToNode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func formNodeIdExtDescriptorMappingWithValidation(utils tmsUploadUtils, nodeNameExtDescriptorMapping map[string]interface{}, nodes []tms.Node, mtaYamlMap map[string]interface{}, mtaVersion string) (map[int64]string, error) {
|
||||
var wrongMtaIdExtDescriptors []string
|
||||
var wrongExtDescriptorPaths []string
|
||||
var wrongNodeNames []string
|
||||
var errorMessage string
|
||||
|
||||
nodeIdExtDescriptorMapping := make(map[int64]string)
|
||||
for nodeName, mappedValue := range nodeNameExtDescriptorMapping {
|
||||
mappedValueString := fmt.Sprintf("%v", mappedValue)
|
||||
exists, _ := utils.FileExists(mappedValueString)
|
||||
if exists {
|
||||
extDescriptorMap, errGetYamlAsMap := getYamlAsMap(utils, mappedValueString)
|
||||
if errGetYamlAsMap == nil {
|
||||
if fmt.Sprintf("%v", mtaYamlMap["ID"]) != fmt.Sprintf("%v", extDescriptorMap["extends"]) {
|
||||
wrongMtaIdExtDescriptors = append(wrongMtaIdExtDescriptors, mappedValueString)
|
||||
}
|
||||
} else {
|
||||
wrappedErr := errors.Wrapf(errGetYamlAsMap, "tried to parse %v as yaml, but got an error", mappedValueString)
|
||||
errorMessage += fmt.Sprintf("%v\n", wrappedErr)
|
||||
}
|
||||
} else {
|
||||
wrongExtDescriptorPaths = append(wrongExtDescriptorPaths, mappedValueString)
|
||||
}
|
||||
|
||||
isNodeFound := false
|
||||
for _, node := range nodes {
|
||||
if node.Name == nodeName {
|
||||
nodeIdExtDescriptorMapping[node.Id] = mappedValueString
|
||||
isNodeFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isNodeFound {
|
||||
wrongNodeNames = append(wrongNodeNames, nodeName)
|
||||
}
|
||||
}
|
||||
|
||||
if mtaVersion != "*" && mtaVersion != mtaYamlMap["version"] {
|
||||
errorMessage += "parameter 'mtaVersion' does not match the MTA version in mta.yaml\n"
|
||||
}
|
||||
|
||||
if len(wrongMtaIdExtDescriptors) > 0 || len(wrongExtDescriptorPaths) > 0 || len(wrongNodeNames) > 0 {
|
||||
if len(wrongMtaIdExtDescriptors) > 0 {
|
||||
sort.Strings(wrongMtaIdExtDescriptors)
|
||||
errorMessage += fmt.Sprintf("parameter 'extends' in MTA extension descriptor files %v is not the same as MTA ID or is missing at all\n", wrongMtaIdExtDescriptors)
|
||||
}
|
||||
if len(wrongExtDescriptorPaths) > 0 {
|
||||
sort.Strings(wrongExtDescriptorPaths)
|
||||
errorMessage += fmt.Sprintf("MTA extension descriptor files %v do not exist\n", wrongExtDescriptorPaths)
|
||||
}
|
||||
if len(wrongNodeNames) > 0 {
|
||||
sort.Strings(wrongNodeNames)
|
||||
errorMessage += fmt.Sprintf("nodes %v do not exist. Please check node names provided in 'nodeExtDescriptorMapping' parameter or create these nodes\n", wrongNodeNames)
|
||||
}
|
||||
}
|
||||
|
||||
if errorMessage == "" {
|
||||
return nodeIdExtDescriptorMapping, nil
|
||||
} else {
|
||||
return nil, errors.New(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func getYamlAsMap(utils tmsUploadUtils, yamlPath string) (map[string]interface{}, error) {
|
||||
var result map[string]interface{}
|
||||
bytes, err := utils.FileRead(yamlPath)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
err = yaml.Unmarshal(bytes, &result)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func unmarshalServiceKey(serviceKeyJson string) (serviceKey serviceKey, err error) {
|
||||
err = json.Unmarshal([]byte(serviceKeyJson), &serviceKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
311
cmd/tmsUpload_generated.go
Normal file
311
cmd/tmsUpload_generated.go
Normal file
@ -0,0 +1,311 @@
|
||||
// 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/SAP/jenkins-library/pkg/validation"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type tmsUploadOptions struct {
|
||||
TmsServiceKey string `json:"tmsServiceKey,omitempty"`
|
||||
CustomDescription string `json:"customDescription,omitempty"`
|
||||
NamedUser string `json:"namedUser,omitempty"`
|
||||
NodeName string `json:"nodeName,omitempty"`
|
||||
MtaPath string `json:"mtaPath,omitempty"`
|
||||
MtaVersion string `json:"mtaVersion,omitempty"`
|
||||
NodeExtDescriptorMapping map[string]interface{} `json:"nodeExtDescriptorMapping,omitempty"`
|
||||
Proxy string `json:"proxy,omitempty"`
|
||||
StashContent []string `json:"stashContent,omitempty"`
|
||||
}
|
||||
|
||||
type tmsUploadInflux struct {
|
||||
step_data struct {
|
||||
fields struct {
|
||||
tms bool
|
||||
}
|
||||
tags struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *tmsUploadInflux) persist(path, resourceName string) {
|
||||
measurementContent := []struct {
|
||||
measurement string
|
||||
valType string
|
||||
name string
|
||||
value interface{}
|
||||
}{
|
||||
{valType: config.InfluxField, measurement: "step_data", name: "tms", value: i.step_data.fields.tms},
|
||||
}
|
||||
|
||||
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().Error("failed to persist Influx environment")
|
||||
}
|
||||
}
|
||||
|
||||
// TmsUploadCommand This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
|
||||
func TmsUploadCommand() *cobra.Command {
|
||||
const STEP_NAME = "tmsUpload"
|
||||
|
||||
metadata := tmsUploadMetadata()
|
||||
var stepConfig tmsUploadOptions
|
||||
var startTime time.Time
|
||||
var influx tmsUploadInflux
|
||||
var logCollector *log.CollectorHook
|
||||
var splunkClient *splunk.Splunk
|
||||
telemetryClient := &telemetry.Telemetry{}
|
||||
|
||||
var createTmsUploadCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.",
|
||||
Long: `This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
|
||||
|
||||
TMS lets you manage transports between SAP Business Technology Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts.
|
||||
For more information, see [official documentation of SAP Cloud Transport Management service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE)
|
||||
|
||||
!!! note "Prerequisites"
|
||||
* You have subscribed to and set up TMS, as described in [Initial Setup](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file.
|
||||
* A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store or provided as value of tmsServiceKey parameter.`,
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
|
||||
|
||||
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
|
||||
}
|
||||
log.RegisterSecret(stepConfig.TmsServiceKey)
|
||||
|
||||
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 {
|
||||
splunkClient = &splunk.Splunk{}
|
||||
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
|
||||
log.RegisterHook(logCollector)
|
||||
}
|
||||
|
||||
if err = log.RegisterANSHookIfConfigured(GeneralConfig.CorrelationID); err != nil {
|
||||
log.Entry().WithError(err).Warn("failed to set up SAP Alert Notification Service log hook")
|
||||
}
|
||||
|
||||
validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = validation.ValidateStruct(stepConfig); err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
stepTelemetryData := telemetry.CustomData{}
|
||||
stepTelemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
influx.persist(GeneralConfig.EnvRootPath, "influx")
|
||||
config.RemoveVaultSecretFiles()
|
||||
stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
|
||||
stepTelemetryData.PiperCommitHash = GitCommit
|
||||
telemetryClient.SetData(&stepTelemetryData)
|
||||
telemetryClient.Send()
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunkClient.Send(telemetryClient.GetData(), logCollector)
|
||||
}
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunkClient.Initialize(GeneralConfig.CorrelationID,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Dsn,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Token,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Index,
|
||||
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
|
||||
}
|
||||
tmsUpload(stepConfig, &stepTelemetryData, &influx)
|
||||
stepTelemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addTmsUploadFlags(createTmsUploadCmd, &stepConfig)
|
||||
return createTmsUploadCmd
|
||||
}
|
||||
|
||||
func addTmsUploadFlags(cmd *cobra.Command, stepConfig *tmsUploadOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.TmsServiceKey, "tmsServiceKey", os.Getenv("PIPER_tmsServiceKey"), "Service key JSON string to access the SAP Cloud Transport Management service instance APIs. If not specified and if pipeline is running on Jenkins, service key, stored under ID provided with credentialsId parameter, is used.")
|
||||
cmd.Flags().StringVar(&stepConfig.CustomDescription, "customDescription", os.Getenv("PIPER_customDescription"), "Can be used as the description of a transport request. Will overwrite the default, which is corresponding Git commit ID.")
|
||||
cmd.Flags().StringVar(&stepConfig.NamedUser, "namedUser", `Piper-Pipeline`, "Defines the named user to execute transport request with. The default value is 'Piper-Pipeline'. If pipeline is running on Jenkins, the name of the user, who started the job, is tried to be used at first.")
|
||||
cmd.Flags().StringVar(&stepConfig.NodeName, "nodeName", os.Getenv("PIPER_nodeName"), "Defines the name of the node to which the *.mtar file should be uploaded.")
|
||||
cmd.Flags().StringVar(&stepConfig.MtaPath, "mtaPath", os.Getenv("PIPER_mtaPath"), "Defines the relative path to *.mtar file for the upload to the SAP Cloud Transport Management service. If not specified, it will use the *.mtar file created in mtaBuild.")
|
||||
cmd.Flags().StringVar(&stepConfig.MtaVersion, "mtaVersion", `*`, "Defines the version of the MTA for which the MTA extension descriptor will be used. You can use an asterisk (*) to accept any MTA version, or use a specific version compliant with SemVer 2.0, e.g. 1.0.0 (see semver.org). If the parameter is not configured, an asterisk is used.")
|
||||
|
||||
cmd.Flags().StringVar(&stepConfig.Proxy, "proxy", os.Getenv("PIPER_proxy"), "Proxy URL which should be used for communication with the SAP Cloud Transport Management service backend.")
|
||||
cmd.Flags().StringSliceVar(&stepConfig.StashContent, "stashContent", []string{`buildResult`}, "If specific stashes should be considered during Jenkins execution, their names need to be passed as a list via this parameter, e.g. stashContent: [\"deployDescriptor\", \"buildResult\"]. By default, the build result is considered.")
|
||||
|
||||
cmd.MarkFlagRequired("tmsServiceKey")
|
||||
cmd.MarkFlagRequired("nodeName")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func tmsUploadMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "tmsUpload",
|
||||
Aliases: []config.Alias{},
|
||||
Description: "This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.",
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Secrets: []config.StepSecrets{
|
||||
{Name: "credentialsId", Description: "Jenkins 'Secret text' credentials ID containing service key for SAP Cloud Transport Management service.", Type: "jenkins"},
|
||||
},
|
||||
Resources: []config.StepResources{
|
||||
{Name: "buildResult", Type: "stash"},
|
||||
},
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "tmsServiceKey",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "credentialsId",
|
||||
Param: "tmsServiceKey",
|
||||
Type: "secret",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_tmsServiceKey"),
|
||||
},
|
||||
{
|
||||
Name: "customDescription",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "git/commitId",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_customDescription"),
|
||||
},
|
||||
{
|
||||
Name: "namedUser",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: `Piper-Pipeline`,
|
||||
},
|
||||
{
|
||||
Name: "nodeName",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_nodeName"),
|
||||
},
|
||||
{
|
||||
Name: "mtaPath",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "mtarFilePath",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_mtaPath"),
|
||||
},
|
||||
{
|
||||
Name: "mtaVersion",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: `*`,
|
||||
},
|
||||
{
|
||||
Name: "nodeExtDescriptorMapping",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "map[string]interface{}",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "proxy",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_proxy"),
|
||||
},
|
||||
{
|
||||
Name: "stashContent",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "[]string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: []string{`buildResult`},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outputs: config.StepOutputs{
|
||||
Resources: []config.StepResources{
|
||||
{
|
||||
Name: "influx",
|
||||
Type: "influx",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"name": "step_data", "fields": []map[string]string{{"name": "tms"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
17
cmd/tmsUpload_generated_test.go
Normal file
17
cmd/tmsUpload_generated_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTmsUploadCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCmd := TmsUploadCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procedure
|
||||
assert.Equal(t, "tmsUpload", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
493
cmd/tmsUpload_test.go
Normal file
493
cmd/tmsUpload_test.go
Normal file
@ -0,0 +1,493 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/SAP/jenkins-library/pkg/tms"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const NODE_ID = 777
|
||||
const ID_OF_MTA_EXT_DESCRIPTOR = 456
|
||||
const FILE_ID = 333
|
||||
const NODE_NAME = "TEST_NODE"
|
||||
const MTA_PATH_LOCAL = "example.mtar"
|
||||
const MTA_NAME = "example.mtar"
|
||||
const MTA_ID = "com.sap.tms.upload.test"
|
||||
const MTA_EXT_ID = "com.sap.tms.upload.test_ext"
|
||||
const MTA_YAML_PATH_LOCAL = "mta.yaml"
|
||||
const MTA_YAML_PATH = "./testdata/TestRunTmsUpload/valid/mta.yaml"
|
||||
const INVALID_MTA_YAML_PATH = "./testdata/TestRunTmsUpload/invalid/mta_not_a_yaml.yaml"
|
||||
const INVALID_MTA_YAML_PATH_2 = "./testdata/TestRunTmsUpload/invalid/mta_no_id_and_version_parameters.yaml"
|
||||
const MTA_EXT_DESCRIPTOR_PATH_LOCAL = "test.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL = "wrong_content.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_2 = "wrong_extends_parameter.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_3 = "missing_extends_parameter.mtaext"
|
||||
const MTA_EXT_DESCRIPTOR_PATH = "./testdata/TestRunTmsUpload/valid/test.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH = "./testdata/TestRunTmsUpload/invalid/wrong_content.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH_2 = "./testdata/TestRunTmsUpload/invalid/wrong_extends_parameter.mtaext"
|
||||
const INVALID_MTA_EXT_DESCRIPTOR_PATH_3 = "./testdata/TestRunTmsUpload/invalid/missing_extends_parameter.mtaext"
|
||||
const CUSTOM_DESCRIPTION = "This is a test description"
|
||||
const NAMED_USER = "techUser"
|
||||
const MTA_VERSION = "1.0.0"
|
||||
const WRONG_MTA_VERSION = "3.2.1"
|
||||
const LAST_CHANGED_AT = "2021-11-16T13:06:05.711Z"
|
||||
const INVALID_INPUT_MSG = "Invalid input parameter(s) when getting MTA extension descriptor"
|
||||
|
||||
type tmsUploadMockUtils struct {
|
||||
*mock.ExecMockRunner
|
||||
*mock.FilesMock
|
||||
}
|
||||
|
||||
func newTmsUploadTestsUtils() tmsUploadMockUtils {
|
||||
utils := tmsUploadMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
return utils
|
||||
}
|
||||
|
||||
type communicationInstanceMock struct {
|
||||
getNodesResponse []tms.Node
|
||||
getMtaExtDescriptorResponse tms.MtaExtDescriptor
|
||||
updateMtaExtDescriptorResponse tms.MtaExtDescriptor
|
||||
uploadMtaExtDescriptorToNodeResponse tms.MtaExtDescriptor
|
||||
uploadFileResponse tms.FileInfo
|
||||
uploadFileToNodeResponse tms.NodeUploadResponseEntity
|
||||
isErrorOnGetNodes bool
|
||||
isErrorOnGetMtaExtDescriptor bool
|
||||
isErrorOnUpdateMtaExtDescriptor bool
|
||||
isErrorOnUploadMtaExtDescriptorToNode bool
|
||||
isErrorOnUploadFile bool
|
||||
isErrorOnUploadFileToNode bool
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) GetNodes() ([]tms.Node, error) {
|
||||
if cim.isErrorOnGetNodes {
|
||||
var nodes []tms.Node
|
||||
return nodes, errors.New("Something went wrong on getting nodes")
|
||||
} else {
|
||||
return cim.getNodesResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) GetMtaExtDescriptor(nodeId int64, mtaId, mtaVersion string) (tms.MtaExtDescriptor, error) {
|
||||
var mtaExtDescriptor tms.MtaExtDescriptor
|
||||
if mtaVersion != MTA_VERSION || nodeId != NODE_ID || mtaId != MTA_ID {
|
||||
return mtaExtDescriptor, errors.New(INVALID_INPUT_MSG)
|
||||
}
|
||||
|
||||
if cim.isErrorOnGetMtaExtDescriptor {
|
||||
return mtaExtDescriptor, errors.New("Something went wrong on getting MTA extension descriptor")
|
||||
} else {
|
||||
return cim.getMtaExtDescriptorResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor int64, file, mtaVersion, description, namedUser string) (tms.MtaExtDescriptor, error) {
|
||||
var mtaExtDescriptor tms.MtaExtDescriptor
|
||||
if mtaVersion != MTA_VERSION || description != CUSTOM_DESCRIPTION || nodeId != NODE_ID || idOfMtaExtDescriptor != ID_OF_MTA_EXT_DESCRIPTOR || file != MTA_EXT_DESCRIPTOR_PATH_LOCAL || namedUser != NAMED_USER {
|
||||
return mtaExtDescriptor, errors.New(INVALID_INPUT_MSG)
|
||||
}
|
||||
|
||||
if cim.isErrorOnUpdateMtaExtDescriptor {
|
||||
return mtaExtDescriptor, errors.New("Something went wrong on updating MTA extension descriptor")
|
||||
} else {
|
||||
return cim.updateMtaExtDescriptorResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) UploadMtaExtDescriptorToNode(nodeId int64, file, mtaVersion, description, namedUser string) (tms.MtaExtDescriptor, error) {
|
||||
var mtaExtDescriptor tms.MtaExtDescriptor
|
||||
if mtaVersion != MTA_VERSION || description != CUSTOM_DESCRIPTION || nodeId != NODE_ID || file != MTA_EXT_DESCRIPTOR_PATH_LOCAL || namedUser != NAMED_USER {
|
||||
return mtaExtDescriptor, errors.New(INVALID_INPUT_MSG)
|
||||
}
|
||||
|
||||
if cim.isErrorOnUploadMtaExtDescriptorToNode {
|
||||
return mtaExtDescriptor, errors.New("Something went wrong on uploading MTA extension descriptor to node")
|
||||
} else {
|
||||
return cim.uploadMtaExtDescriptorToNodeResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) UploadFile(file, namedUser string) (tms.FileInfo, error) {
|
||||
var fileInfo tms.FileInfo
|
||||
if file != MTA_PATH_LOCAL || namedUser != NAMED_USER {
|
||||
return fileInfo, errors.New(INVALID_INPUT_MSG)
|
||||
}
|
||||
|
||||
if cim.isErrorOnUploadFile {
|
||||
return fileInfo, errors.New("Something went wrong on uploading file")
|
||||
} else {
|
||||
return cim.uploadFileResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cim *communicationInstanceMock) UploadFileToNode(nodeName, fileId, description, namedUser string) (tms.NodeUploadResponseEntity, error) {
|
||||
var nodeUploadResponseEntity tms.NodeUploadResponseEntity
|
||||
if description != CUSTOM_DESCRIPTION || nodeName != NODE_NAME || fileId != strconv.FormatInt(FILE_ID, 10) || namedUser != NAMED_USER {
|
||||
return nodeUploadResponseEntity, errors.New(INVALID_INPUT_MSG)
|
||||
}
|
||||
|
||||
if cim.isErrorOnUploadFileToNode {
|
||||
return nodeUploadResponseEntity, errors.New("Something went wrong on uploading file to node")
|
||||
} else {
|
||||
return cim.uploadFileToNodeResponse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunTmsUpload(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("happy path: 1. get nodes 2. get MTA ext descriptor -> nothing obtained 3. upload MTA ext descriptor to node 4. upload file 5. upload file to node", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
fileInfo := tms.FileInfo{Id: FILE_ID, Name: MTA_NAME}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, uploadFileResponse: fileInfo}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("happy path: no mapping between node nmaes and MTA extension descriptors is provided -> only upload file and upload file to node calls will be executed", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
fileInfo := tms.FileInfo{Id: FILE_ID, Name: MTA_NAME}
|
||||
communicationInstance := communicationInstanceMock{uploadFileResponse: fileInfo}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("happy path: 1. get nodes 2. get MTA ext descriptor 3. update the MTA ext descriptor 4. upload file 5. upload file to node", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
mtaExtDescriptor := tms.MtaExtDescriptor{Id: ID_OF_MTA_EXT_DESCRIPTOR, Description: "Some existing description", MtaId: MTA_ID, MtaExtId: MTA_EXT_ID, MtaVersion: MTA_VERSION, LastChangedAt: LAST_CHANGED_AT}
|
||||
fileInfo := tms.FileInfo{Id: FILE_ID, Name: MTA_NAME}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, getMtaExtDescriptorResponse: mtaExtDescriptor, uploadFileResponse: fileInfo}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("error path: MTA file does not exist", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
communicationInstance := communicationInstanceMock{}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, fmt.Sprintf("mta file %s not found", MTA_PATH_LOCAL))
|
||||
})
|
||||
|
||||
t.Run("error path: error while getting nodes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
communicationInstance := communicationInstanceMock{isErrorOnGetNodes: true}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to get nodes: Something went wrong on getting nodes")
|
||||
})
|
||||
|
||||
t.Run("error path: cannot read mta.yaml (the file is missing)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to get mta.yaml as map: could not read 'mta.yaml'")
|
||||
})
|
||||
|
||||
t.Run("error path: cannot unmarshal mta.yaml (the file does not represent a yaml)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(INVALID_MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to get mta.yaml as map: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}")
|
||||
})
|
||||
|
||||
t.Run("error path: no 'ID' and 'version' parameters found in mta.yaml", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(INVALID_MTA_YAML_PATH_2)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
var expectedErrorMessage string
|
||||
expectedErrorMessage += "parameter 'ID' is not found in mta.yaml\n"
|
||||
expectedErrorMessage += "parameter 'version' is not found in mta.yaml\n"
|
||||
|
||||
assert.EqualError(t, err, expectedErrorMessage)
|
||||
})
|
||||
|
||||
t.Run("error path: errors on validating the mapping between node names and MTA extension descriptor paths", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
invalidMtaExtDescriptorBytes, _ := ioutil.ReadFile(INVALID_MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL, invalidMtaExtDescriptorBytes)
|
||||
|
||||
invalidMtaExtDescriptorBytes2, _ := ioutil.ReadFile(INVALID_MTA_EXT_DESCRIPTOR_PATH_2)
|
||||
utils.AddFile(INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_2, invalidMtaExtDescriptorBytes2)
|
||||
|
||||
invalidMtaExtDescriptorBytes3, _ := ioutil.ReadFile(INVALID_MTA_EXT_DESCRIPTOR_PATH_3)
|
||||
utils.AddFile(INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_3, invalidMtaExtDescriptorBytes3)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL, "UNEXISTING_NODE": "unexisting.mtaext", "ONE_MORE_UNEXISTING_NODE": INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL, "ONE_MORE_UNEXISTING_NODE_2": INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_2, "ONE_MORE_UNEXISTING_NODE_3": INVALID_MTA_EXT_DESCRIPTOR_PATH_LOCAL_3}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: WRONG_MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
var expectedErrorMessage string
|
||||
expectedErrorMessage += "tried to parse wrong_content.mtaext as yaml, but got an error: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}\n"
|
||||
expectedErrorMessage += "parameter 'mtaVersion' does not match the MTA version in mta.yaml\n"
|
||||
expectedErrorMessage += "parameter 'extends' in MTA extension descriptor files [missing_extends_parameter.mtaext wrong_extends_parameter.mtaext] is not the same as MTA ID or is missing at all\n"
|
||||
expectedErrorMessage += "MTA extension descriptor files [unexisting.mtaext] do not exist\n"
|
||||
expectedErrorMessage += "nodes [ONE_MORE_UNEXISTING_NODE ONE_MORE_UNEXISTING_NODE_2 ONE_MORE_UNEXISTING_NODE_3 UNEXISTING_NODE] do not exist. Please check node names provided in 'nodeExtDescriptorMapping' parameter or create these nodes\n"
|
||||
assert.EqualError(t, err, expectedErrorMessage)
|
||||
})
|
||||
|
||||
t.Run("error path: error while getting MTA extension descriptor", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, isErrorOnGetMtaExtDescriptor: true}
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to get MTA extension descriptor: Something went wrong on getting MTA extension descriptor")
|
||||
})
|
||||
|
||||
t.Run("error path: error while updating MTA extension descriptor", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
mtaExtDescriptor := tms.MtaExtDescriptor{Id: ID_OF_MTA_EXT_DESCRIPTOR, Description: "Some existing description", MtaId: MTA_ID, MtaExtId: MTA_EXT_ID, MtaVersion: MTA_VERSION, LastChangedAt: LAST_CHANGED_AT}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, getMtaExtDescriptorResponse: mtaExtDescriptor, isErrorOnUpdateMtaExtDescriptor: true}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to update MTA extension descriptor: Something went wrong on updating MTA extension descriptor")
|
||||
})
|
||||
|
||||
t.Run("error path: error while uploading MTA extension descriptor to node", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, isErrorOnUploadMtaExtDescriptorToNode: true}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to upload MTA extension descriptor to node: Something went wrong on uploading MTA extension descriptor to node")
|
||||
})
|
||||
|
||||
t.Run("error path: error while uploading file", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, isErrorOnUploadFile: true}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to upload file: Something went wrong on uploading file")
|
||||
})
|
||||
|
||||
t.Run("error path: error while uploading file to node", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// init
|
||||
nodes := []tms.Node{{Id: NODE_ID, Name: NODE_NAME}}
|
||||
fileInfo := tms.FileInfo{Id: FILE_ID, Name: MTA_NAME}
|
||||
communicationInstance := communicationInstanceMock{getNodesResponse: nodes, uploadFileResponse: fileInfo, isErrorOnUploadFileToNode: true}
|
||||
|
||||
utils := newTmsUploadTestsUtils()
|
||||
utils.AddFile(MTA_PATH_LOCAL, []byte("dummy content"))
|
||||
|
||||
mtaYamlBytes, _ := ioutil.ReadFile(MTA_YAML_PATH)
|
||||
utils.AddFile(MTA_YAML_PATH_LOCAL, mtaYamlBytes)
|
||||
|
||||
mtaExtDescriptorBytes, _ := ioutil.ReadFile(MTA_EXT_DESCRIPTOR_PATH)
|
||||
utils.AddFile(MTA_EXT_DESCRIPTOR_PATH_LOCAL, mtaExtDescriptorBytes)
|
||||
|
||||
nodeNameExtDescriptorMapping := map[string]interface{}{NODE_NAME: MTA_EXT_DESCRIPTOR_PATH_LOCAL}
|
||||
config := tmsUploadOptions{MtaPath: MTA_PATH_LOCAL, CustomDescription: CUSTOM_DESCRIPTION, NamedUser: NAMED_USER, NodeName: NODE_NAME, MtaVersion: MTA_VERSION, NodeExtDescriptorMapping: nodeNameExtDescriptorMapping}
|
||||
|
||||
// test
|
||||
err := runTmsUpload(config, &communicationInstance, utils)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "failed to upload file to node: Something went wrong on uploading file to node")
|
||||
})
|
||||
}
|
@ -13,6 +13,7 @@ import (
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -32,6 +33,7 @@ type Client struct {
|
||||
maxRetries int
|
||||
transportTimeout time.Duration
|
||||
transportSkipVerification bool
|
||||
transportProxy *url.URL
|
||||
username string
|
||||
password string
|
||||
token string
|
||||
@ -56,6 +58,7 @@ type ClientOptions struct {
|
||||
// used for the transport layer and duration of handshakes and such.
|
||||
TransportTimeout time.Duration
|
||||
TransportSkipVerification bool
|
||||
TransportProxy *url.URL
|
||||
Username string
|
||||
Password string
|
||||
Token string
|
||||
@ -236,6 +239,7 @@ func (c *Client) SetOptions(options ClientOptions) {
|
||||
c.useDefaultTransport = options.UseDefaultTransport
|
||||
c.transportTimeout = options.TransportTimeout
|
||||
c.transportSkipVerification = options.TransportSkipVerification
|
||||
c.transportProxy = options.TransportProxy
|
||||
c.maxRequestDuration = options.MaxRequestDuration
|
||||
c.username = options.Username
|
||||
c.password = options.Password
|
||||
@ -277,6 +281,7 @@ func (c *Client) initialize() *http.Client {
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: c.transportTimeout,
|
||||
}).DialContext,
|
||||
Proxy: http.ProxyURL(c.transportProxy),
|
||||
ResponseHeaderTimeout: c.transportTimeout,
|
||||
ExpectContinueTimeout: c.transportTimeout,
|
||||
TLSHandshakeTimeout: c.transportTimeout,
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -59,6 +60,24 @@ func TestSend(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
})
|
||||
t.Run("failure when calling via proxy", func(t *testing.T) {
|
||||
// given
|
||||
httpmock.Activate()
|
||||
defer httpmock.DeactivateAndReset()
|
||||
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewStringResponder(200, `OK`))
|
||||
|
||||
client := Client{}
|
||||
transportProxy, _ := url.Parse("https://proxy.dummy.sap.com")
|
||||
client.SetOptions(ClientOptions{MaxRetries: -1, TransportProxy: transportProxy})
|
||||
|
||||
// when
|
||||
response, err := client.Send(request)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "lookup proxy.dummy.sap.com: no such host")
|
||||
assert.Nil(t, response)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultTransport(t *testing.T) {
|
||||
@ -178,10 +197,12 @@ func TestSendRequest(t *testing.T) {
|
||||
|
||||
func TestSetOptions(t *testing.T) {
|
||||
c := Client{}
|
||||
opts := ClientOptions{MaxRetries: -1, TransportTimeout: 10, MaxRequestDuration: 5, Username: "TestUser", Password: "TestPassword", Token: "TestToken", Logger: log.Entry().WithField("package", "github.com/SAP/jenkins-library/pkg/http")}
|
||||
transportProxy, _ := url.Parse("https://proxy.dummy.sap.com")
|
||||
opts := ClientOptions{MaxRetries: -1, TransportTimeout: 10, TransportProxy: transportProxy, MaxRequestDuration: 5, Username: "TestUser", Password: "TestPassword", Token: "TestToken", Logger: log.Entry().WithField("package", "github.com/SAP/jenkins-library/pkg/http")}
|
||||
c.SetOptions(opts)
|
||||
|
||||
assert.Equal(t, opts.TransportTimeout, c.transportTimeout)
|
||||
assert.Equal(t, opts.TransportProxy, c.transportProxy)
|
||||
assert.Equal(t, opts.TransportSkipVerification, c.transportSkipVerification)
|
||||
assert.Equal(t, opts.MaxRequestDuration, c.maxRequestDuration)
|
||||
assert.Equal(t, opts.Username, c.username)
|
||||
|
8
pkg/tms/resources/cf_example.mtaext
Normal file
8
pkg/tms/resources/cf_example.mtaext
Normal file
@ -0,0 +1,8 @@
|
||||
_schema-version: "3.1"
|
||||
ID: fs-storage-ext
|
||||
extends: fs-storage
|
||||
|
||||
modules:
|
||||
- name: anatz
|
||||
parameters:
|
||||
memory: 32M
|
BIN
pkg/tms/resources/cf_example.mtar
Normal file
BIN
pkg/tms/resources/cf_example.mtar
Normal file
Binary file not shown.
414
pkg/tms/tms.go
Normal file
414
pkg/tms/tms.go
Normal file
@ -0,0 +1,414 @@
|
||||
package tms
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type AuthToken struct {
|
||||
TokenType string `json:"token_type"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
type CommunicationInstance struct {
|
||||
tmsUrl string
|
||||
uaaUrl string
|
||||
clientId string
|
||||
clientSecret string
|
||||
httpClient piperHttp.Uploader
|
||||
logger *logrus.Entry
|
||||
isVerbose bool
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type nodes struct {
|
||||
Nodes []Node `json:"nodes"`
|
||||
}
|
||||
|
||||
type MtaExtDescriptor struct {
|
||||
Id int64 `json:"id"`
|
||||
Description string `json:"description"`
|
||||
MtaId string `json:"mtaId"`
|
||||
MtaExtId string `json:"mtaExtId"`
|
||||
MtaVersion string `json:"mtaVersion"`
|
||||
LastChangedAt string `json:"lastChangedAt"`
|
||||
}
|
||||
|
||||
type mtaExtDescriptors struct {
|
||||
MtaExtDescriptors []MtaExtDescriptor `json:"mtaExtDescriptors"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Id int64 `json:"fileId"`
|
||||
Name string `json:"fileName"`
|
||||
}
|
||||
|
||||
type NodeUploadResponseEntity struct {
|
||||
TransportRequestId int64 `json:"transportRequestId"`
|
||||
TransportRequestDescription string `json:"transportRequestDescription"`
|
||||
QueueEntries []QueueEntry `json:"queueEntries"`
|
||||
}
|
||||
|
||||
type QueueEntry struct {
|
||||
Id int64 `json:"queueId"`
|
||||
NodeId int64 `json:"nodeId"`
|
||||
NodeName string `json:"nodeName"`
|
||||
}
|
||||
|
||||
type NodeUploadRequestEntity struct {
|
||||
ContentType string `json:"contentType"`
|
||||
StorageType string `json:"storageType"`
|
||||
NodeName string `json:"nodeName"`
|
||||
Description string `json:"description"`
|
||||
NamedUser string `json:"namedUser"`
|
||||
Entries []Entry `json:"entries"`
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
Uri string `json:"uri"`
|
||||
}
|
||||
|
||||
type CommunicationInterface interface {
|
||||
GetNodes() ([]Node, error)
|
||||
GetMtaExtDescriptor(nodeId int64, mtaId, mtaVersion string) (MtaExtDescriptor, error)
|
||||
UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor int64, file, mtaVersion, description, namedUser string) (MtaExtDescriptor, error)
|
||||
UploadMtaExtDescriptorToNode(nodeId int64, file, mtaVersion, description, namedUser string) (MtaExtDescriptor, error)
|
||||
UploadFile(file, namedUser string) (FileInfo, error)
|
||||
UploadFileToNode(nodeName, fileId, description, namedUser string) (NodeUploadResponseEntity, error)
|
||||
}
|
||||
|
||||
// NewCommunicationInstance returns CommunicationInstance structure with http client prepared for communication with TMS backend
|
||||
func NewCommunicationInstance(httpClient piperHttp.Uploader, tmsUrl, uaaUrl, clientId, clientSecret string, isVerbose bool) (*CommunicationInstance, error) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms")
|
||||
|
||||
communicationInstance := &CommunicationInstance{
|
||||
tmsUrl: tmsUrl,
|
||||
uaaUrl: uaaUrl,
|
||||
clientId: clientId,
|
||||
clientSecret: clientSecret,
|
||||
httpClient: httpClient,
|
||||
logger: logger,
|
||||
isVerbose: isVerbose,
|
||||
}
|
||||
|
||||
token, err := communicationInstance.getOAuthToken()
|
||||
if err != nil {
|
||||
return communicationInstance, errors.Wrap(err, "Error fetching OAuth token")
|
||||
}
|
||||
log.RegisterSecret(token)
|
||||
|
||||
options := piperHttp.ClientOptions{
|
||||
Token: token,
|
||||
}
|
||||
communicationInstance.httpClient.SetOptions(options)
|
||||
|
||||
return communicationInstance, nil
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) getOAuthToken() (string, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("OAuth token retrieval started")
|
||||
communicationInstance.logger.Infof("uaaUrl: %v, clientId: %v", communicationInstance.uaaUrl, communicationInstance.clientId)
|
||||
}
|
||||
|
||||
encodedUsernameColonPassword := b64.StdEncoding.EncodeToString([]byte(communicationInstance.clientId + ":" + communicationInstance.clientSecret))
|
||||
header := http.Header{}
|
||||
header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
header.Add("Authorization", "Basic "+encodedUsernameColonPassword)
|
||||
|
||||
urlFormData := url.Values{
|
||||
"username": {communicationInstance.clientId},
|
||||
"password": {communicationInstance.clientSecret},
|
||||
"grant_type": {"password"},
|
||||
}
|
||||
|
||||
data, err := sendRequest(communicationInstance, http.MethodPost, "/oauth/token/?grant_type=client_credentials&response_type=token", strings.NewReader(urlFormData.Encode()), header, http.StatusOK, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var token AuthToken
|
||||
json.Unmarshal(data, &token)
|
||||
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("OAuth Token retrieved successfully")
|
||||
}
|
||||
return token.TokenType + " " + token.AccessToken, nil
|
||||
}
|
||||
|
||||
func sendRequest(communicationInstance *CommunicationInstance, method, urlPathAndQuery string, body io.Reader, header http.Header, expectedStatusCode int, isTowardsUaa bool) ([]byte, error) {
|
||||
var requestBody io.Reader
|
||||
if body != nil {
|
||||
closer := ioutil.NopCloser(body)
|
||||
bodyBytes, _ := ioutil.ReadAll(closer)
|
||||
requestBody = bytes.NewBuffer(bodyBytes)
|
||||
defer closer.Close()
|
||||
}
|
||||
|
||||
url := communicationInstance.tmsUrl
|
||||
if isTowardsUaa {
|
||||
url = communicationInstance.uaaUrl
|
||||
}
|
||||
url = strings.TrimSuffix(url, "/")
|
||||
|
||||
response, err := communicationInstance.httpClient.SendRequest(method, fmt.Sprintf("%v%v", url, urlPathAndQuery), requestBody, header, nil)
|
||||
|
||||
// err is not nil for HTTP status codes >= 300
|
||||
if err != nil {
|
||||
communicationInstance.logger.Errorf("HTTP request failed with error: %s", err)
|
||||
communicationInstance.logResponseBody(response)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != expectedStatusCode {
|
||||
return nil, fmt.Errorf("unexpected positive HTTP status code %v, while it was expected %v", response.StatusCode, expectedStatusCode)
|
||||
}
|
||||
|
||||
data, _ := ioutil.ReadAll(response.Body)
|
||||
if !isTowardsUaa && communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Debugf("Valid response body: %v", string(data))
|
||||
}
|
||||
defer response.Body.Close()
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) logResponseBody(response *http.Response) {
|
||||
if response != nil && response.Body != nil {
|
||||
data, _ := ioutil.ReadAll(response.Body)
|
||||
communicationInstance.logger.Errorf("Response body: %s", data)
|
||||
response.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) GetNodes() ([]Node, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Obtaining nodes started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v", communicationInstance.tmsUrl)
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
header.Add("Content-Type", "application/json")
|
||||
|
||||
var aNodes []Node
|
||||
var data []byte
|
||||
data, err := sendRequest(communicationInstance, http.MethodGet, "/v2/nodes", nil, header, http.StatusOK, false)
|
||||
if err != nil {
|
||||
return aNodes, err
|
||||
}
|
||||
|
||||
var getNodesResponse nodes
|
||||
json.Unmarshal(data, &getNodesResponse)
|
||||
aNodes = getNodesResponse.Nodes
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Nodes obtained successfully")
|
||||
}
|
||||
return aNodes, nil
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) GetMtaExtDescriptor(nodeId int64, mtaId, mtaVersion string) (MtaExtDescriptor, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Get MTA extension descriptor started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v, nodeId: %v, mtaId: %v, mtaVersion: %v", communicationInstance.tmsUrl, nodeId, mtaId, mtaVersion)
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
header.Add("Content-Type", "application/json")
|
||||
|
||||
var mtaExtDescriptor MtaExtDescriptor
|
||||
var data []byte
|
||||
data, err := sendRequest(communicationInstance, http.MethodGet, fmt.Sprintf("/v2/nodes/%v/mtaExtDescriptors?mtaId=%v&mtaVersion=%v", nodeId, mtaId, mtaVersion), nil, header, http.StatusOK, false)
|
||||
if err != nil {
|
||||
return mtaExtDescriptor, err
|
||||
}
|
||||
|
||||
var getMtaExtDescriptorsResponse mtaExtDescriptors
|
||||
json.Unmarshal(data, &getMtaExtDescriptorsResponse)
|
||||
if len(getMtaExtDescriptorsResponse.MtaExtDescriptors) > 0 {
|
||||
mtaExtDescriptor = getMtaExtDescriptorsResponse.MtaExtDescriptors[0]
|
||||
}
|
||||
|
||||
if communicationInstance.isVerbose {
|
||||
if mtaExtDescriptor != (MtaExtDescriptor{}) {
|
||||
communicationInstance.logger.Info("MTA extension descriptor obtained successfully")
|
||||
} else {
|
||||
communicationInstance.logger.Warn("No MTA extension descriptor found")
|
||||
}
|
||||
}
|
||||
return mtaExtDescriptor, nil
|
||||
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) UploadFileToNode(nodeName, fileId, description, namedUser string) (NodeUploadResponseEntity, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Node upload started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v, nodeName: %v, fileId: %v, description: %v, namedUser: %v", communicationInstance.tmsUrl, nodeName, fileId, description, namedUser)
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
header.Add("Content-Type", "application/json")
|
||||
|
||||
var nodeUploadResponseEntity NodeUploadResponseEntity
|
||||
entry := Entry{Uri: fileId}
|
||||
body := NodeUploadRequestEntity{ContentType: "MTA", StorageType: "FILE", NodeName: nodeName, Description: description, NamedUser: namedUser, Entries: []Entry{entry}}
|
||||
bodyBytes, errMarshaling := json.Marshal(body)
|
||||
if errMarshaling != nil {
|
||||
return nodeUploadResponseEntity, errors.Wrapf(errMarshaling, "unable to marshal request body %v", body)
|
||||
}
|
||||
|
||||
data, errSendRequest := sendRequest(communicationInstance, http.MethodPost, "/v2/nodes/upload", bytes.NewReader(bodyBytes), header, http.StatusOK, false)
|
||||
if errSendRequest != nil {
|
||||
return nodeUploadResponseEntity, errSendRequest
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &nodeUploadResponseEntity)
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Node upload executed successfully")
|
||||
}
|
||||
return nodeUploadResponseEntity, nil
|
||||
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor int64, file, mtaVersion, description, namedUser string) (MtaExtDescriptor, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Update of MTA extension descriptor started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v, nodeId: %v, mtaExtDescriptorId: %v, file: %v, mtaVersion: %v, description: %v, namedUser: %v", communicationInstance.tmsUrl, nodeId, idOfMtaExtDescriptor, file, mtaVersion, description, namedUser)
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
header.Add("tms-named-user", namedUser)
|
||||
|
||||
tmsUrl := strings.TrimSuffix(communicationInstance.tmsUrl, "/")
|
||||
url := fmt.Sprintf("%v/v2/nodes/%v/mtaExtDescriptors/%v", tmsUrl, nodeId, idOfMtaExtDescriptor)
|
||||
formFields := map[string]string{"mtaVersion": mtaVersion, "description": description}
|
||||
|
||||
var mtaExtDescriptor MtaExtDescriptor
|
||||
fileHandle, errOpenFile := os.Open(file)
|
||||
if errOpenFile != nil {
|
||||
return mtaExtDescriptor, errors.Wrapf(errOpenFile, "unable to locate file %v", file)
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
uploadRequestData := piperHttp.UploadRequestData{Method: http.MethodPut, URL: url, File: file, FileFieldName: "file", FormFields: formFields, FileContent: fileHandle, Header: header, Cookies: nil}
|
||||
|
||||
var data []byte
|
||||
data, errUpload := upload(communicationInstance, uploadRequestData, http.StatusOK)
|
||||
if errUpload != nil {
|
||||
return mtaExtDescriptor, errUpload
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &mtaExtDescriptor)
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("MTA extension descriptor updated successfully")
|
||||
}
|
||||
return mtaExtDescriptor, nil
|
||||
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) UploadMtaExtDescriptorToNode(nodeId int64, file, mtaVersion, description, namedUser string) (MtaExtDescriptor, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Upload of MTA extension descriptor started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v, nodeId: %v, file: %v, mtaVersion: %v, description: %v, namedUser: %v", communicationInstance.tmsUrl, nodeId, file, mtaVersion, description, namedUser)
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
header.Add("tms-named-user", namedUser)
|
||||
|
||||
tmsUrl := strings.TrimSuffix(communicationInstance.tmsUrl, "/")
|
||||
url := fmt.Sprintf("%v/v2/nodes/%v/mtaExtDescriptors", tmsUrl, nodeId)
|
||||
formFields := map[string]string{"mtaVersion": mtaVersion, "description": description}
|
||||
|
||||
var mtaExtDescriptor MtaExtDescriptor
|
||||
fileHandle, errOpenFile := os.Open(file)
|
||||
if errOpenFile != nil {
|
||||
return mtaExtDescriptor, errors.Wrapf(errOpenFile, "unable to locate file %v", file)
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
uploadRequestData := piperHttp.UploadRequestData{Method: http.MethodPost, URL: url, File: file, FileFieldName: "file", FormFields: formFields, FileContent: fileHandle, Header: header, Cookies: nil}
|
||||
|
||||
var data []byte
|
||||
data, errUpload := upload(communicationInstance, uploadRequestData, http.StatusCreated)
|
||||
if errUpload != nil {
|
||||
return mtaExtDescriptor, errUpload
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &mtaExtDescriptor)
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("MTA extension descriptor uploaded successfully")
|
||||
}
|
||||
return mtaExtDescriptor, nil
|
||||
|
||||
}
|
||||
|
||||
func (communicationInstance *CommunicationInstance) UploadFile(file, namedUser string) (FileInfo, error) {
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("Upload of file started")
|
||||
communicationInstance.logger.Infof("tmsUrl: %v, file: %v, namedUser: %v", communicationInstance.tmsUrl, file, namedUser)
|
||||
}
|
||||
|
||||
tmsUrl := strings.TrimSuffix(communicationInstance.tmsUrl, "/")
|
||||
url := fmt.Sprintf("%v/v2/files/upload", tmsUrl)
|
||||
formFields := map[string]string{"namedUser": namedUser}
|
||||
|
||||
var fileInfo FileInfo
|
||||
fileHandle, errOpenFile := os.Open(file)
|
||||
if errOpenFile != nil {
|
||||
return fileInfo, errors.Wrapf(errOpenFile, "unable to locate file %v", file)
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
uploadRequestData := piperHttp.UploadRequestData{Method: http.MethodPost, URL: url, File: file, FileFieldName: "file", FormFields: formFields, FileContent: fileHandle, Header: http.Header{}, Cookies: nil}
|
||||
|
||||
var data []byte
|
||||
data, errUpload := upload(communicationInstance, uploadRequestData, http.StatusCreated)
|
||||
if errUpload != nil {
|
||||
return fileInfo, errUpload
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &fileInfo)
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Info("File uploaded successfully")
|
||||
}
|
||||
return fileInfo, nil
|
||||
|
||||
}
|
||||
|
||||
func upload(communicationInstance *CommunicationInstance, uploadRequestData piperHttp.UploadRequestData, expectedStatusCode int) ([]byte, error) {
|
||||
response, err := communicationInstance.httpClient.Upload(uploadRequestData)
|
||||
|
||||
// err is not nil for HTTP status codes >= 300
|
||||
if err != nil {
|
||||
communicationInstance.logger.Errorf("HTTP request failed with error: %s", err)
|
||||
communicationInstance.logResponseBody(response)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != expectedStatusCode {
|
||||
return nil, fmt.Errorf("unexpected positive HTTP status code %v, while it was expected %v", response.StatusCode, expectedStatusCode)
|
||||
}
|
||||
|
||||
data, _ := ioutil.ReadAll(response.Body)
|
||||
if communicationInstance.isVerbose {
|
||||
communicationInstance.logger.Debugf("Valid response body: %v", string(data))
|
||||
}
|
||||
defer response.Body.Close()
|
||||
return data, nil
|
||||
}
|
620
pkg/tms/tms_test.go
Normal file
620
pkg/tms/tms_test.go
Normal file
@ -0,0 +1,620 @@
|
||||
package tms
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type uploaderMock struct {
|
||||
token string
|
||||
httpMethod string
|
||||
httpStatusCode int
|
||||
urlCalled string
|
||||
requestBody string
|
||||
responseBody string
|
||||
filePath string
|
||||
fileFieldName string
|
||||
fileContentString string
|
||||
header http.Header
|
||||
isTechnicalErrorExpected bool
|
||||
formFields map[string]string
|
||||
}
|
||||
|
||||
func (um *uploaderMock) SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
||||
if um.isTechnicalErrorExpected {
|
||||
return nil, errors.New("Provoked technical error")
|
||||
}
|
||||
um.httpMethod = method
|
||||
um.urlCalled = url
|
||||
um.header = header
|
||||
if body != nil {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(body)
|
||||
um.requestBody = buf.String()
|
||||
}
|
||||
var httpError error
|
||||
if um.httpStatusCode >= 300 {
|
||||
httpError = fmt.Errorf("http error %v", um.httpStatusCode)
|
||||
}
|
||||
return &http.Response{StatusCode: um.httpStatusCode, Body: ioutil.NopCloser(strings.NewReader(um.responseBody))}, httpError
|
||||
}
|
||||
|
||||
func (um *uploaderMock) UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) {
|
||||
um.httpMethod = http.MethodPost
|
||||
um.urlCalled = url
|
||||
um.header = header
|
||||
return &http.Response{StatusCode: um.httpStatusCode, Body: ioutil.NopCloser(bytes.NewReader([]byte(um.responseBody)))}, nil
|
||||
}
|
||||
|
||||
func (um *uploaderMock) UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) {
|
||||
um.httpMethod = http.MethodPost
|
||||
um.urlCalled = url
|
||||
um.header = header
|
||||
return &http.Response{StatusCode: um.httpStatusCode, Body: ioutil.NopCloser(bytes.NewReader([]byte(um.responseBody)))}, nil
|
||||
}
|
||||
|
||||
func (um *uploaderMock) Upload(uploadRequestData piperHttp.UploadRequestData) (*http.Response, error) {
|
||||
if um.isTechnicalErrorExpected {
|
||||
return nil, errors.New("Provoked technical error")
|
||||
}
|
||||
um.httpMethod = uploadRequestData.Method
|
||||
um.urlCalled = uploadRequestData.URL
|
||||
um.header = uploadRequestData.Header
|
||||
um.filePath = uploadRequestData.File
|
||||
um.fileFieldName = uploadRequestData.FileFieldName
|
||||
um.formFields = uploadRequestData.FormFields
|
||||
if uploadRequestData.FileContent != nil {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(uploadRequestData.FileContent)
|
||||
um.fileContentString = buf.String()
|
||||
}
|
||||
var httpError error
|
||||
if um.httpStatusCode >= 300 {
|
||||
httpError = fmt.Errorf("http error %v", um.httpStatusCode)
|
||||
}
|
||||
return &http.Response{StatusCode: um.httpStatusCode, Body: ioutil.NopCloser(strings.NewReader(um.responseBody))}, httpError
|
||||
}
|
||||
|
||||
func (um *uploaderMock) SetOptions(options piperHttp.ClientOptions) {
|
||||
um.token = options.Token
|
||||
}
|
||||
|
||||
func TestGetOAuthToken(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"token_type":"bearer","access_token":"testOAuthToken","expires_in":54321}`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", clientId: "testClientId", clientSecret: "testClientSecret", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
token, err := communicationInstance.getOAuthToken()
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://dummy.sap.com/oauth/token/?grant_type=client_credentials&response_type=token", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/x-www-form-urlencoded"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
assert.Equal(t, []string{"Basic dGVzdENsaWVudElkOnRlc3RDbGllbnRTZWNyZXQ="}, uploaderMock.header[http.CanonicalHeaderKey("authorization")], "Authorizatoin header incorrect")
|
||||
assert.Equal(t, "grant_type=password&password=testClientSecret&username=testClientId", uploaderMock.requestBody, "Request body incorrect")
|
||||
assert.Equal(t, "bearer testOAuthToken", token, "Obtained token incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", clientId: "testClientId", clientSecret: "testClientSecret", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := communicationInstance.getOAuthToken()
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://dummy.sap.com/oauth/token/?grant_type=client_credentials&response_type=token", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/x-www-form-urlencoded"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
assert.Equal(t, []string{"Basic dGVzdENsaWVudElkOnRlc3RDbGllbnRTZWNyZXQ="}, uploaderMock.header[http.CanonicalHeaderKey("authorization")], "Authorizatoin header incorrect")
|
||||
assert.Equal(t, "grant_type=password&password=testClientSecret&username=testClientId", uploaderMock.requestBody, "Request body incorrect")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetNodes(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
getNodesResponse := `{"nodes": [{"id": 1,"name": "TEST_NODE"}]}`
|
||||
uploaderMock := uploaderMock{responseBody: getNodesResponse, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodes, err := communicationInstance.GetNodes()
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/nodes", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodGet, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
assert.Equal(t, 1, len(nodes), "Length of nodes list incorrect")
|
||||
assert.Equal(t, int64(1), nodes[0].Id, "Id of node at position 0 in the list incorrect")
|
||||
assert.Equal(t, "TEST_NODE", nodes[0].Name, "Name of node at position 0 in the list incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := communicationInstance.GetNodes()
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/nodes", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodGet, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestGetMtaExtDescriptor(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
id := int64(777)
|
||||
mtaExtDescription := "This is a test description"
|
||||
mtaId := "test.mta.id"
|
||||
mtaExtId := "test.mta.id_ext"
|
||||
mtaVersion := "1.0.0"
|
||||
lastChangedAt := "2021-11-16T13:06:05.711Z"
|
||||
|
||||
getMtaExtDescriptorResponse := fmt.Sprintf(`{"mtaExtDescriptors": [{"id": %v,"description": "%v","mtaId": "%v","mtaExtId": "%v","mtaVersion": "%v","lastChangedAt": "%v"}]}`, id, mtaExtDescription, mtaId, mtaExtId, mtaVersion, lastChangedAt)
|
||||
uploaderMock := uploaderMock{responseBody: getMtaExtDescriptorResponse, httpStatusCode: http.StatusOK}
|
||||
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
mtaExtDescriptor, err := communicationInstance.GetMtaExtDescriptor(nodeId, mtaId, mtaVersion)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors?mtaId=%v&mtaVersion=%v", nodeId, mtaId, mtaVersion), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodGet, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
assert.Equal(t, id, mtaExtDescriptor.Id, "MTA extension descriptor Id field incorrect")
|
||||
assert.Equal(t, mtaExtDescription, mtaExtDescriptor.Description, "MTA extension descriptor Description field incorrect")
|
||||
assert.Equal(t, mtaId, mtaExtDescriptor.MtaId, "MTA extension descriptor MtaId field incorrect")
|
||||
assert.Equal(t, mtaExtId, mtaExtDescriptor.MtaExtId, "MTA extension descriptor MtaExtId field incorrect")
|
||||
assert.Equal(t, mtaVersion, mtaExtDescriptor.MtaVersion, "MTA extension descriptor MtaVersion field incorrect")
|
||||
assert.Equal(t, lastChangedAt, mtaExtDescriptor.LastChangedAt, "MTA extension descriptor LastChangedAt field incorrect")
|
||||
})
|
||||
|
||||
t.Run("test success, no MTA extension descriptor found", func(t *testing.T) {
|
||||
getMtaExtDescriptorResponse := `{"mtaExtDescriptors": []}`
|
||||
uploaderMock := uploaderMock{responseBody: getMtaExtDescriptorResponse, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
mtaId := "test.mta.id"
|
||||
mtaVersion := "1.0.1"
|
||||
mtaExtDescriptor, err := communicationInstance.GetMtaExtDescriptor(nodeId, mtaId, mtaVersion)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors?mtaId=%v&mtaVersion=%v", nodeId, mtaId, mtaVersion), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodGet, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
assert.Equal(t, MtaExtDescriptor{}, mtaExtDescriptor, "Initialized mtaExtDescriptor structure received, but a zero-valued expected")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
mtaId := "test.mta.id"
|
||||
mtaVersion := "1.0.1"
|
||||
_, err := communicationInstance.GetMtaExtDescriptor(nodeId, mtaId, mtaVersion)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors?mtaId=%v&mtaVersion=%v", nodeId, mtaId, mtaVersion), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodGet, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestUpdateMtaExtDescriptor(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success with trimming url slash in the end", func(t *testing.T) {
|
||||
idOfMtaExtDescriptor := int64(777)
|
||||
mtaExtDescription := "This is an updated description"
|
||||
mtaId := "fs-storage"
|
||||
mtaExtId := "fs-storage-ext"
|
||||
mtaVersion := "1.0.0"
|
||||
lastChangedAt := "2021-11-16T13:06:05.711Z"
|
||||
|
||||
updateMtaExtDescriptorResponse := fmt.Sprintf(`{"id": %v,"description": "%v","mtaId": "%v","mtaExtId": "%v","mtaVersion": "%v","lastChangedAt": "%v"}`, idOfMtaExtDescriptor, mtaExtDescription, mtaId, mtaExtId, mtaVersion, lastChangedAt)
|
||||
uploaderMock := uploaderMock{responseBody: updateMtaExtDescriptorResponse, httpStatusCode: http.StatusOK}
|
||||
|
||||
// the slash in the end of the url will be trimmed
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com/", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
filePath := "./resources/cf_example.mtaext"
|
||||
namedUser := "testUser"
|
||||
mtaExtDescriptor, err := communicationInstance.UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors/%v", nodeId, idOfMtaExtDescriptor), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPut, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{namedUser}, uploaderMock.header[http.CanonicalHeaderKey("tms-named-user")], "tms-named-user header incorrect")
|
||||
assert.Equal(t, filePath, uploaderMock.filePath, "File path incorrect")
|
||||
assert.Equal(t, "file", uploaderMock.fileFieldName, "File field name incorrect")
|
||||
assert.Equal(t, map[string]string{"mtaVersion": mtaVersion, "description": mtaExtDescription}, uploaderMock.formFields, "Form field(s) incorrect")
|
||||
|
||||
fileHandle, _ := os.Open(filePath)
|
||||
defer fileHandle.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(fileHandle)
|
||||
fileContentString := buf.String()
|
||||
assert.Equal(t, fileContentString, uploaderMock.fileContentString, "File content incorrect")
|
||||
|
||||
assert.Equal(t, idOfMtaExtDescriptor, mtaExtDescriptor.Id, "MTA extension descriptor Id field incorrect")
|
||||
assert.Equal(t, mtaExtDescription, mtaExtDescriptor.Description, "MTA extension descriptor Description field incorrect")
|
||||
assert.Equal(t, mtaId, mtaExtDescriptor.MtaId, "MTA extension descriptor MtaId field incorrect")
|
||||
assert.Equal(t, mtaExtId, mtaExtDescriptor.MtaExtId, "MTA extension descriptor MtaExtId field incorrect")
|
||||
assert.Equal(t, mtaVersion, mtaExtDescriptor.MtaVersion, "MTA extension descriptor MtaVersion field incorrect")
|
||||
assert.Equal(t, lastChangedAt, mtaExtDescriptor.LastChangedAt, "MTA extension descriptor LastChangedAt field incorrect")
|
||||
})
|
||||
|
||||
t.Run("test upload error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
idOfMtaExtDescriptor := int64(777)
|
||||
filePath := "./resources/cf_example.mtaext"
|
||||
mtaVersion := "1.0.0"
|
||||
mtaExtDescription := "This is an updated description"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors/%v", nodeId, idOfMtaExtDescriptor), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error on opening file", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Some response`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
idOfMtaExtDescriptor := int64(777)
|
||||
filePath := "./resources/not_existing.mtaext"
|
||||
mtaVersion := "1.0.0"
|
||||
mtaExtDescription := "This is an updated description"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UpdateMtaExtDescriptor(nodeId, idOfMtaExtDescriptor, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Contains(t, err.Error(), fmt.Sprintf("unable to locate file %v", filePath), "Error text does not contain expected string")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadMtaExtDescriptorToNode(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success with trimming url slash in the end", func(t *testing.T) {
|
||||
idOfMtaExtDescriptor := int64(777)
|
||||
mtaExtDescription := "This is a test description"
|
||||
mtaId := "fs-storage"
|
||||
mtaExtId := "fs-storage-ext"
|
||||
mtaVersion := "1.0.0"
|
||||
lastChangedAt := "2021-11-16T13:06:05.711Z"
|
||||
|
||||
uploadMtaExtDescriptorResponse := fmt.Sprintf(`{"id": %v,"description": "%v","mtaId": "%v","mtaExtId": "%v","mtaVersion": "%v","lastChangedAt": "%v"}`, idOfMtaExtDescriptor, mtaExtDescription, mtaId, mtaExtId, mtaVersion, lastChangedAt)
|
||||
uploaderMock := uploaderMock{responseBody: uploadMtaExtDescriptorResponse, httpStatusCode: http.StatusCreated}
|
||||
|
||||
// the slash in the end of the url will be trimmed
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com/", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
filePath := "./resources/cf_example.mtaext"
|
||||
namedUser := "testUser"
|
||||
mtaExtDescriptor, err := communicationInstance.UploadMtaExtDescriptorToNode(nodeId, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors", nodeId), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{namedUser}, uploaderMock.header[http.CanonicalHeaderKey("tms-named-user")], "tms-named-user header incorrect")
|
||||
assert.Equal(t, filePath, uploaderMock.filePath, "File path incorrect")
|
||||
assert.Equal(t, "file", uploaderMock.fileFieldName, "File field name incorrect")
|
||||
assert.Equal(t, map[string]string{"mtaVersion": mtaVersion, "description": mtaExtDescription}, uploaderMock.formFields, "Form field(s) incorrect")
|
||||
|
||||
fileHandle, _ := os.Open(filePath)
|
||||
defer fileHandle.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(fileHandle)
|
||||
fileContentString := buf.String()
|
||||
assert.Equal(t, fileContentString, uploaderMock.fileContentString, "File content incorrect")
|
||||
|
||||
assert.Equal(t, idOfMtaExtDescriptor, mtaExtDescriptor.Id, "MTA extension descriptor Id field incorrect")
|
||||
assert.Equal(t, mtaExtDescription, mtaExtDescriptor.Description, "MTA extension descriptor Description field incorrect")
|
||||
assert.Equal(t, mtaId, mtaExtDescriptor.MtaId, "MTA extension descriptor MtaId field incorrect")
|
||||
assert.Equal(t, mtaExtId, mtaExtDescriptor.MtaExtId, "MTA extension descriptor MtaExtId field incorrect")
|
||||
assert.Equal(t, mtaVersion, mtaExtDescriptor.MtaVersion, "MTA extension descriptor MtaVersion field incorrect")
|
||||
assert.Equal(t, lastChangedAt, mtaExtDescriptor.LastChangedAt, "MTA extension descriptor LastChangedAt field incorrect")
|
||||
})
|
||||
|
||||
t.Run("test upload error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
filePath := "./resources/cf_example.mtaext"
|
||||
mtaVersion := "1.0.0"
|
||||
mtaExtDescription := "This is a test description"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadMtaExtDescriptorToNode(nodeId, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, fmt.Sprintf("https://tms.dummy.sap.com/v2/nodes/%v/mtaExtDescriptors", nodeId), uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error on opening file", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Some response`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeId := int64(111)
|
||||
filePath := "./resources/not_existing.mtaext"
|
||||
mtaVersion := "1.0.0"
|
||||
mtaExtDescription := "This is a test description"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadMtaExtDescriptorToNode(nodeId, filePath, mtaVersion, mtaExtDescription, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Contains(t, err.Error(), fmt.Sprintf("unable to locate file %v", filePath), "Error text does not contain expected string")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadFile(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success with trimming url slash in the end", func(t *testing.T) {
|
||||
fileId := int64(333)
|
||||
fileName := "cf_example.mtar"
|
||||
|
||||
uploadFileResponse := fmt.Sprintf(`{"fileId": %v,"fileName": "%v"}`, fileId, fileName)
|
||||
uploaderMock := uploaderMock{responseBody: uploadFileResponse, httpStatusCode: http.StatusCreated}
|
||||
|
||||
// the slash in the end of the url will be trimmed
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com/", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
filePath := "./resources/cf_example.mtar"
|
||||
namedUser := "testUser"
|
||||
fileInfo, err := communicationInstance.UploadFile(filePath, namedUser)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/files/upload", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, filePath, uploaderMock.filePath, "File path incorrect")
|
||||
assert.Equal(t, "file", uploaderMock.fileFieldName, "File field name incorrect")
|
||||
assert.Equal(t, map[string]string{"namedUser": namedUser}, uploaderMock.formFields, "Form field incorrect")
|
||||
|
||||
fileHandle, _ := os.Open(filePath)
|
||||
defer fileHandle.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(fileHandle)
|
||||
fileContentString := buf.String()
|
||||
assert.Equal(t, fileContentString, uploaderMock.fileContentString, "File content incorrect")
|
||||
|
||||
assert.Equal(t, fileId, fileInfo.Id, "Id field of file info incorrect")
|
||||
assert.Equal(t, fileName, fileInfo.Name, "Name field of file info incorrect")
|
||||
})
|
||||
|
||||
t.Run("test upload error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
filePath := "./resources/cf_example.mtar"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadFile(filePath, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/files/upload", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error on opening file", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Some response`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
filePath := "./resources/not_existing.mtar"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadFile(filePath, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Contains(t, err.Error(), fmt.Sprintf("unable to locate file %v", filePath), "Error text does not contain expected string")
|
||||
})
|
||||
|
||||
t.Run("test error due unexpected positive http status code", func(t *testing.T) {
|
||||
fileId := int64(333)
|
||||
fileName := "cf_example.mtar"
|
||||
|
||||
uploadFileResponse := fmt.Sprintf(`{"fileId": %v,"fileName": "%v"}`, fileId, fileName)
|
||||
uploaderMock := uploaderMock{responseBody: uploadFileResponse, httpStatusCode: http.StatusOK}
|
||||
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
filePath := "./resources/cf_example.mtar"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadFile(filePath, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/files/upload", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "unexpected positive HTTP status code 200, while it was expected 201", err.Error(), "Error text incorrect")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadFileToNode(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
transportRequestId := int64(555)
|
||||
transportRequestDescription := "This is a test description"
|
||||
queueId := int64(123)
|
||||
nodeId := int64(456)
|
||||
nodeName := "TEST_NODE"
|
||||
queueEntryString := fmt.Sprintf(`{"queueId": %v,"nodeId": %v,"nodeName": "%v"}`, queueId, nodeId, nodeName)
|
||||
|
||||
uploadFileToNodeResponse := fmt.Sprintf(`{"transportRequestId": %v,"transportRequestDescription": "%v","queueEntries": [%v]}`, transportRequestId, transportRequestDescription, queueEntryString)
|
||||
uploaderMock := uploaderMock{responseBody: uploadFileToNodeResponse, httpStatusCode: http.StatusOK}
|
||||
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
fileId := "111"
|
||||
namedUser := "testUser"
|
||||
nodeUploadResponseEntity, err := communicationInstance.UploadFileToNode(nodeName, fileId, transportRequestDescription, namedUser)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/nodes/upload", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, []string{"application/json"}, uploaderMock.header[http.CanonicalHeaderKey("content-type")], "Content-Type header incorrect")
|
||||
|
||||
entryString := fmt.Sprintf(`{"uri":"%v"}`, fileId)
|
||||
assert.Equal(t, fmt.Sprintf(`{"contentType":"MTA","storageType":"FILE","nodeName":"%v","description":"%v","namedUser":"%v","entries":[%v]}`, nodeName, transportRequestDescription, namedUser, entryString), uploaderMock.requestBody, "Request body incorrect")
|
||||
|
||||
assert.Equal(t, transportRequestId, nodeUploadResponseEntity.TransportRequestId, "TransportRequestId field of node upload response incorrect")
|
||||
assert.Equal(t, transportRequestDescription, nodeUploadResponseEntity.TransportRequestDescription, "TransportRequestDescription field of node upload response incorrect")
|
||||
assert.Equal(t, 1, len(nodeUploadResponseEntity.QueueEntries), "Queue entries amount in node upload response incorrect")
|
||||
assert.Equal(t, queueId, nodeUploadResponseEntity.QueueEntries[0].Id, "Queue entry Id field incorrect")
|
||||
assert.Equal(t, nodeId, nodeUploadResponseEntity.QueueEntries[0].NodeId, "Queue entry NodeId field incorrect")
|
||||
assert.Equal(t, nodeName, nodeUploadResponseEntity.QueueEntries[0].NodeName, "Queue entry NodeName field incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
nodeName := "TEST_NODE"
|
||||
fileId := "111"
|
||||
transportRequestDescription := "This is a test description"
|
||||
namedUser := "testUser"
|
||||
_, err := communicationInstance.UploadFileToNode(nodeName, fileId, transportRequestDescription, namedUser)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/v2/nodes/upload", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSendRequest(t *testing.T) {
|
||||
logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/tms_test")
|
||||
t.Run("test success against uaa", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
urlFormData := url.Values{
|
||||
"key1": {"value1"},
|
||||
}
|
||||
header := http.Header{}
|
||||
header.Add("Authorization", "Basic dGVzdENsaWVudElkOnRlc3RDbGllbnRTZWNyZXQ=")
|
||||
data, err := sendRequest(&communicationInstance, http.MethodPost, "/test/?param1=value1", strings.NewReader(urlFormData.Encode()), header, http.StatusOK, true)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://dummy.sap.com/test/?param1=value1", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, http.MethodPost, uploaderMock.httpMethod, "Http method incorrect")
|
||||
assert.Equal(t, 1, len(uploaderMock.header), "Length of headers map incorrect")
|
||||
assert.Equal(t, []string{"Basic dGVzdENsaWVudElkOnRlc3RDbGllbnRTZWNyZXQ="}, uploaderMock.header[http.CanonicalHeaderKey("authorization")], "Authorizatoin header incorrect")
|
||||
assert.Equal(t, "key1=value1", uploaderMock.requestBody, "Request body incorrect")
|
||||
assert.Equal(t, []byte(uploaderMock.responseBody), data, "Response body incorrect")
|
||||
})
|
||||
|
||||
t.Run("test success against tms", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := sendRequest(&communicationInstance, http.MethodGet, "/test", nil, nil, http.StatusOK, false)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/test", uploaderMock.urlCalled, "Called url incorrect")
|
||||
})
|
||||
|
||||
t.Run("test success with trimming url slash in the end", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusOK}
|
||||
|
||||
// the slash in the end of the used url will be trimmed
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com/", tmsUrl: "https://tms.dummy.sap.com/", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := sendRequest(&communicationInstance, http.MethodGet, "/test", nil, nil, http.StatusOK, false)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/test", uploaderMock.urlCalled, "Called url incorrect")
|
||||
})
|
||||
|
||||
t.Run("test success with body values containing spaces", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
urlFormData := url.Values{
|
||||
"key1": {"value with spaces"},
|
||||
}
|
||||
_, err := sendRequest(&communicationInstance, http.MethodPost, "/test/?param1=value1", strings.NewReader(urlFormData.Encode()), nil, http.StatusOK, true)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://dummy.sap.com/test/?param1=value1", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "key1=value+with+spaces", uploaderMock.requestBody, "Request body incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusBadRequest}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := sendRequest(&communicationInstance, http.MethodGet, "/test", nil, nil, http.StatusOK, false)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/test", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error due unexpected positive http status code", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"someKey": "someValue"}`, httpStatusCode: http.StatusCreated}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
_, err := sendRequest(&communicationInstance, http.MethodPost, "/test", nil, nil, http.StatusOK, false)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "https://tms.dummy.sap.com/test", uploaderMock.urlCalled, "Called url incorrect")
|
||||
assert.Equal(t, "unexpected positive HTTP status code 201, while it was expected 200", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
t.Run("test technical error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{isTechnicalErrorExpected: true}
|
||||
communicationInstance := CommunicationInstance{uaaUrl: "https://dummy.sap.com", tmsUrl: "https://tms.dummy.sap.com", httpClient: &uploaderMock, logger: logger, isVerbose: false}
|
||||
|
||||
data, err := sendRequest(&communicationInstance, http.MethodGet, "/test", nil, nil, http.StatusOK, false)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Nil(t, data, "Nil result expected, but was not")
|
||||
assert.Equal(t, "Provoked technical error", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestNewCommunicationInstance(t *testing.T) {
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `{"token_type":"bearer","access_token":"testOAuthToken","expires_in":54321}`, httpStatusCode: http.StatusOK}
|
||||
communicationInstance, err := NewCommunicationInstance(&uploaderMock, "https://tms.dummy.sap.com", "https://dummy.sap.com", "testClientId", "testClientSecret", false)
|
||||
|
||||
assert.NoError(t, err, "Error occurred, but none expected")
|
||||
assert.Equal(t, "https://dummy.sap.com", communicationInstance.uaaUrl, "uaaUrl field of communication instance incorrect")
|
||||
assert.Equal(t, "testClientId", communicationInstance.clientId, "clientId field of communication instance incorrect")
|
||||
assert.Equal(t, "testClientSecret", communicationInstance.clientSecret, "clientSecret field of communication instance incorrect")
|
||||
assert.Equal(t, false, communicationInstance.isVerbose, "isVerbose field of communication instance incorrect")
|
||||
assert.Equal(t, "bearer testOAuthToken", uploaderMock.token, "Obtained token incorrect")
|
||||
})
|
||||
|
||||
t.Run("test error", func(t *testing.T) {
|
||||
uploaderMock := uploaderMock{responseBody: `Bad request provided`, httpStatusCode: http.StatusBadRequest}
|
||||
_, err := NewCommunicationInstance(&uploaderMock, "https://tms.dummy.sap.com", "https://dummy.sap.com", "testClientId", "testClientSecret", false)
|
||||
|
||||
assert.Error(t, err, "Error expected, but none occurred")
|
||||
assert.Equal(t, "Error fetching OAuth token: http error 400", err.Error(), "Error text incorrect")
|
||||
})
|
||||
|
||||
}
|
110
resources/metadata/tmsUpload.yaml
Normal file
110
resources/metadata/tmsUpload.yaml
Normal file
@ -0,0 +1,110 @@
|
||||
metadata:
|
||||
name: tmsUpload
|
||||
description: This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
|
||||
longDescription: |-
|
||||
This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Transport Management service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
|
||||
|
||||
TMS lets you manage transports between SAP Business Technology Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts.
|
||||
For more information, see [official documentation of SAP Cloud Transport Management service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE)
|
||||
|
||||
!!! note "Prerequisites"
|
||||
* You have subscribed to and set up TMS, as described in [Initial Setup](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file.
|
||||
* A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store or provided as value of tmsServiceKey parameter.
|
||||
spec:
|
||||
inputs:
|
||||
secrets:
|
||||
- name: credentialsId
|
||||
description: Jenkins 'Secret text' credentials ID containing service key for SAP Cloud Transport Management service.
|
||||
type: jenkins
|
||||
resources:
|
||||
- name: buildResult
|
||||
type: stash
|
||||
params:
|
||||
- name: tmsServiceKey
|
||||
type: string
|
||||
description: Service key JSON string to access the SAP Cloud Transport Management service instance APIs. If not specified and if pipeline is running on Jenkins, service key, stored under ID provided with credentialsId parameter, is used.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
mandatory: true
|
||||
secret: true
|
||||
resourceRef:
|
||||
- name: credentialsId
|
||||
type: secret
|
||||
param: tmsServiceKey
|
||||
- name: customDescription
|
||||
type: string
|
||||
description: Can be used as the description of a transport request. Will overwrite the default, which is corresponding Git commit ID.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: git/commitId
|
||||
- name: namedUser
|
||||
type: string
|
||||
description: Defines the named user to execute transport request with. The default value is 'Piper-Pipeline'. If pipeline is running on Jenkins, the name of the user, who started the job, is tried to be used at first.
|
||||
default: Piper-Pipeline
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
- name: nodeName
|
||||
type: string
|
||||
description: Defines the name of the node to which the *.mtar file should be uploaded.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
mandatory: true
|
||||
- name: mtaPath
|
||||
type: string
|
||||
description: Defines the relative path to *.mtar file for the upload to the SAP Cloud Transport Management service. If not specified, it will use the *.mtar file created in mtaBuild.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: mtarFilePath
|
||||
- name: mtaVersion
|
||||
type: string
|
||||
description: Defines the version of the MTA for which the MTA extension descriptor will be used. You can use an asterisk (*) to accept any MTA version, or use a specific version compliant with SemVer 2.0, e.g. 1.0.0 (see semver.org). If the parameter is not configured, an asterisk is used.
|
||||
default: "*"
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
- name: nodeExtDescriptorMapping
|
||||
type: map[string]interface{}
|
||||
description: 'Available only for transports in Cloud Foundry environment. Defines a mapping between a transport node name and an MTA extension descriptor file path that you want to use for the transport node, e.g. nodeExtDescriptorMapping: {"nodeName": "example.mtaext", "nodeName2": "example2.mtaext"}.'
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
- name: proxy
|
||||
type: string
|
||||
description: Proxy URL which should be used for communication with the SAP Cloud Transport Management service backend.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
- name: stashContent
|
||||
type: '[]string'
|
||||
description: 'If specific stashes should be considered during Jenkins execution, their names need to be passed as a list via this parameter, e.g. stashContent: ["deployDescriptor", "buildResult"]. By default, the build result is considered.'
|
||||
default: ["buildResult"]
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
outputs:
|
||||
resources:
|
||||
- name: influx
|
||||
type: influx
|
||||
params:
|
||||
- name: step_data
|
||||
fields:
|
||||
- name: tms
|
||||
type: bool
|
Loading…
x
Reference in New Issue
Block a user