import util.CommandLineMatcher import util.JenkinsLockRule import util.JenkinsWithEnvRule import util.JenkinsWriteFileRule import static org.hamcrest.Matchers.allOf import static org.hamcrest.Matchers.containsString import static org.hamcrest.Matchers.equalTo import static org.hamcrest.Matchers.hasItem import static org.hamcrest.Matchers.is import static org.hamcrest.Matchers.subString import static org.junit.Assert.assertThat import org.hamcrest.Matchers import org.junit.Assert import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import org.junit.rules.RuleChain import com.sap.piper.JenkinsUtils import com.sap.piper.Utils import util.BasePiperTest import util.JenkinsCredentialsRule import util.JenkinsReadYamlRule import util.JenkinsShellCallRule import util.JenkinsStepRule import util.Rules class FioriOnCloudPlatformPipelineTest extends BasePiperTest { /* This scenario builds a fiori app and deploys it into an neo account. The build is performed using mta, which delegates to grunt. grunt in turn makes use of the 'sap/grunt-sapui5-bestpractice-build' plugin. The dependencies are resolved via npm. In order to run the scenario the project needs to fulfill these prerequisites: Build tools: * mta.jar available * npm installed Project configuration: * sap registry `@sap:registry=https://npm.sap.com` configured in .npmrc (either in the project or on any other suitable level) * dependency to `@sap/grunt-sapui5-bestpractice-build` declared in package.json * npmTask `@sap/grunt-sapui5-bestpractice-build` loaded inside Gruntfile.js and configure default tasks (e.g. lint, clean, build) * mta.yaml */ private ExpectedException thrown = new ExpectedException().none() JenkinsStepRule stepRule = new JenkinsStepRule(this) JenkinsReadYamlRule readYamlRule = new JenkinsReadYamlRule(this) JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this) JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this) private JenkinsLockRule jlr = new JenkinsLockRule(this) @Rule public RuleChain ruleChain = Rules .getCommonRules(this) .around(readYamlRule) .around(thrown) .around(stepRule) .around(shellRule) .around(jlr) .around(writeFileRule) .around(new JenkinsWithEnvRule(this)) .around(new JenkinsCredentialsRule(this) .withCredentials('CI_CREDENTIALS_ID', 'foo', 'terceSpot')) private writeInfluxMap = [:] class JenkinsUtilsMock extends JenkinsUtils { def isJobStartedByUser() { return true } } @Before void setup() { // // needed since we have dockerExecute inside neoDeploy JenkinsUtils.metaClass.static.isPluginActive = {def s -> false} // // there is a check for the mta.yaml file and for the deployable test.mtar file helper.registerAllowedMethod('fileExists', [String],{ it -> // called inside neo deploy, this file gets deployed it == 'test.mtar' }) helper.registerAllowedMethod("deleteDir",[], null) binding.setVariable('scm', null) helper.registerAllowedMethod('pwd', [], { return "./" }) helper.registerAllowedMethod('mtaBuild', [Map], { m -> m.script.commonPipelineEnvironment.mtarFilePath = 'test.mtar' }) Utils.metaClass.echo = { def m -> } helper.registerAllowedMethod('influxWriteData', [Map.class], { m -> writeInfluxMap = m }) UUID.metaClass.static.randomUUID = { -> 1 } } @After public void tearDown() { Utils.metaClass = null UUID.metaClass = null } @Test void straightForwardTestNeo() { nullScript .commonPipelineEnvironment .configuration = [steps: [mtaBuild: [ platform: 'NEO' ], neoDeploy: [neo: [ host: 'hana.example.com', account: 'myTestAccount', ] ] ] ] stepRule.step.fioriOnCloudPlatformPipeline(script: nullScript) // // the deployable is exchanged between the involved steps via this property: // From the presence of this value we can conclude that mtaBuild has been called // this value is set on the commonPipelineEnvironment in the corresponding mock. assertThat(nullScript.commonPipelineEnvironment.getMtarFilePath(), is(equalTo('test.mtar'))) // // the neo deploy call: Assert.assertThat(shellRule.shell, new CommandLineMatcher() .hasProlog("neo.sh deploy-mta") .hasSingleQuotedOption('host', 'hana\\.example\\.com') .hasSingleQuotedOption('account', 'myTestAccount') .hasSingleQuotedOption('password', 'terceSpot') .hasSingleQuotedOption('user', 'foo') .hasSingleQuotedOption('source', 'test.mtar') .hasArgument('synchronous')) } @Test void straightForwardTestCF() { def calledStep helper.registerAllowedMethod('piperExecuteBin', [Map, String, String, List], { Map parameters, String stepName, String metadataFile, List credentialInfo -> calledStep = stepName }) nullScript .commonPipelineEnvironment .configuration = [steps: [mtaBuild: [ platform: 'CF' ], cloudFoundryDeploy: [ deployTool: 'mtaDeployPlugin', cloudFoundry: [ apiEndpoint: 'https://api.cf.hana.example.com', org: 'testOrg', space: 'testSpace', credentialsId: 'CI_CREDENTIALS_ID' ] ] ] ] stepRule.step.fioriOnCloudPlatformPipeline( script: nullScript, ) assertThat(calledStep, is('cloudFoundryDeploy')) } @Test void errorNoTargetDefined() { nullScript .commonPipelineEnvironment .configuration = [steps: [neoDeploy: [neo: [ host: 'hana.example.com', account: 'myTestAccount', ] ] ] ] thrown.expect(Exception) thrown.expectMessage('Deployment failed: no valid deployment target defined') stepRule.step.fioriOnCloudPlatformPipeline(script: nullScript) } @Test void errorUnknownTargetDefined() { nullScript .commonPipelineEnvironment .configuration = [steps: [mtaBuild: [ platform: 'UNKNOWN' ] ] ] thrown.expect(Exception) thrown.expectMessage('Deployment failed: no valid deployment target defined') stepRule.step.fioriOnCloudPlatformPipeline(script: nullScript) } }