mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
fd568c9174
* do not swallow exception triggered inside SWA handling --> write it to the log The real change is in src/com/sap/piper/Utils.groovy All the changes in the tests are dealing with mocking the echo method used in the Utils class mentioned above.
506 lines
19 KiB
Groovy
506 lines
19 KiB
Groovy
import com.sap.piper.k8s.ContainerMap
|
|
|
|
import com.sap.piper.JenkinsUtils
|
|
import com.sap.piper.SidecarUtils
|
|
import com.sap.piper.Utils
|
|
import org.junit.After
|
|
import org.junit.Before
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.junit.rules.RuleChain
|
|
|
|
import util.BasePiperTest
|
|
import util.JenkinsLoggingRule
|
|
import util.JenkinsReadYamlRule
|
|
import util.JenkinsShellCallRule
|
|
import util.JenkinsStepRule
|
|
import util.PluginMock
|
|
import util.Rules
|
|
|
|
import static org.hamcrest.Matchers.*
|
|
import static org.junit.Assert.assertThat
|
|
import static org.junit.Assert.assertTrue
|
|
import static org.junit.Assert.assertEquals
|
|
import static org.junit.Assert.assertFalse
|
|
|
|
class DockerExecuteTest extends BasePiperTest {
|
|
private DockerMock docker
|
|
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
|
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
|
private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this)
|
|
|
|
@Rule
|
|
public RuleChain ruleChain = Rules
|
|
.getCommonRules(this)
|
|
.around(new JenkinsReadYamlRule(this))
|
|
.around(loggingRule)
|
|
.around(stepRule)
|
|
.around(shellRule)
|
|
|
|
def bodyExecuted
|
|
def containerName
|
|
|
|
@Before
|
|
void init() {
|
|
bodyExecuted = false
|
|
docker = new DockerMock()
|
|
JenkinsUtils.metaClass.static.isPluginActive = { def s -> new PluginMock(s).isActive() }
|
|
binding.setVariable('docker', docker)
|
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, "docker .*", 0)
|
|
Utils.metaClass.echo = { def m -> }
|
|
}
|
|
|
|
@After
|
|
public void tearDown() {
|
|
Utils.metaClass = null
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsideContainerOfExistingPod() throws Exception {
|
|
List usedDockerEnvVars
|
|
helper.registerAllowedMethod('container', [String.class, Closure.class], { String container, Closure body ->
|
|
containerName = container
|
|
body()
|
|
})
|
|
helper.registerAllowedMethod('withEnv', [List.class, Closure.class], { List envVars, Closure body ->
|
|
usedDockerEnvVars = envVars
|
|
body()
|
|
})
|
|
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
|
ContainerMap.instance.setMap(['testpod': ['maven:3.5-jdk-8-alpine': 'mavenexec']])
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Executing inside a Kubernetes Container'))
|
|
assertEquals('mavenexec', containerName)
|
|
assertEquals(usedDockerEnvVars[0].toString(), "http_proxy=http://proxy:8000")
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsideNewlyCreatedPod() throws Exception {
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
|
binding.setVariable('env', [ON_K8S: 'true'])
|
|
ContainerMap.instance.setMap(['testpod': ['maven:3.5-jdk-8-alpine': 'mavenexec']])
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Executing inside a Kubernetes Pod'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsidePodWithEmptyContainerMap() throws Exception {
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
|
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
|
ContainerMap.instance.setMap([:])
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Executing inside a Kubernetes Pod'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsidePodWithStageKeyEmptyValue() throws Exception {
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body -> body() })
|
|
binding.setVariable('env', [POD_NAME: 'testpod', ON_K8S: 'true'])
|
|
ContainerMap.instance.setMap(['testpod': [:]])
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Executing inside a Kubernetes Pod'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsidePodWithCustomCommandAndShell() throws Exception {
|
|
Map kubernetesConfig = [:]
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { Map config, Closure body ->
|
|
kubernetesConfig = config
|
|
return body()
|
|
})
|
|
binding.setVariable('env', [ON_K8S: 'true'])
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
containerCommand: '/busybox/tail -f /dev/null',
|
|
containerShell: '/busybox/sh',
|
|
dockerImage: 'maven:3.5-jdk-8-alpine'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Executing inside a Kubernetes Pod'))
|
|
assertThat(kubernetesConfig.containerCommand, is('/busybox/tail -f /dev/null'))
|
|
assertThat(kubernetesConfig.containerShell, is('/busybox/sh'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsideDockerContainer() throws Exception {
|
|
stepRule.step.dockerExecute(script: nullScript, dockerImage: 'maven:3.5-jdk-8-alpine') {
|
|
bodyExecuted = true
|
|
}
|
|
assertEquals('maven:3.5-jdk-8-alpine', docker.getImageNames()[0])
|
|
assertTrue(docker.isImagePulled())
|
|
assertEquals('--env http_proxy --env https_proxy --env no_proxy --env HTTP_PROXY --env HTTPS_PROXY --env NO_PROXY', docker.getParameters().trim())
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testSkipDockerImagePull() throws Exception {
|
|
nullScript.commonPipelineEnvironment.configuration = [steps: [dockerExecute: [dockerPullImage: false]]]
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertThat(docker.imagePullCount, is(0))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testPullSidecarWithDedicatedCredentialsAndRegistry() {
|
|
nullScript.commonPipelineEnvironment.configuration =
|
|
[
|
|
steps: [
|
|
dockerExecute: [
|
|
dockerRegistry: 'https://registry.example.org',
|
|
dockerRegistryCredentials: 'mySecrets',
|
|
dockerSidecarRegistry: 'https://sidecarregistry.example.org',
|
|
dockerSidecarRegistryCredentials: 'mySidecarRegistryCredentials',
|
|
]
|
|
]
|
|
]
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerRegistryCredentials: 'mySecrets',
|
|
sidecarImage: 'ubuntu',
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
// not clear which image has been pulled with which registry, but at least
|
|
// both registries are involved.
|
|
assertThat(docker.registriesWithCredentials, is([
|
|
[
|
|
registry: 'https://registry.example.org',
|
|
credentialsId: 'mySecrets',
|
|
],
|
|
[
|
|
registry: 'https://sidecarregistry.example.org',
|
|
credentialsId: 'mySidecarRegistryCredentials',
|
|
]
|
|
]))
|
|
assertThat(docker.imagePullCount, is(2))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testPullSidecarWithSameCredentialsAndRegistryLikeBaseImageWhenNothingElseIsSpecified() {
|
|
nullScript.commonPipelineEnvironment.configuration =
|
|
[
|
|
steps: [
|
|
dockerExecute: [
|
|
dockerRegistry: 'https://registry.example.org',
|
|
]
|
|
]
|
|
]
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerRegistryCredentials: 'mySecrets',
|
|
sidecarImage: 'ubuntu',
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
// from getting an empty list we derive withRegistry has not been called
|
|
// if it would have been called we would have the registry provided above.
|
|
assertThat(docker.registriesWithCredentials, is([
|
|
[
|
|
registry: 'https://registry.example.org',
|
|
credentialsId: 'mySecrets',
|
|
],
|
|
[
|
|
registry: 'https://registry.example.org',
|
|
credentialsId: 'mySecrets',
|
|
],
|
|
]))
|
|
assertThat(docker.imagePullCount, is(2))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testPullWithoutCredentialsHappensWithoutRegistryCall() {
|
|
nullScript.commonPipelineEnvironment.configuration =
|
|
[
|
|
steps: [
|
|
dockerExecute: [
|
|
dockerRegistry: 'https://registry.example.org',
|
|
]
|
|
]
|
|
]
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
// from getting an empty list we derive withRegistry has not been called
|
|
// if it would have been called we would have the registry provided above.
|
|
assertThat(docker.registriesWithCredentials, is([]))
|
|
assertThat(docker.imagePullCount, is(1))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testPullWithCredentials() throws Exception {
|
|
|
|
nullScript.commonPipelineEnvironment.configuration =
|
|
[
|
|
steps: [
|
|
dockerExecute: [
|
|
dockerRegistry: 'https://registry.example.org',
|
|
dockerRegistryCredentials: 'mySecrets',
|
|
]
|
|
]
|
|
]
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine'
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertThat(docker.registriesWithCredentials, is([
|
|
[
|
|
registry: 'https://registry.example.org',
|
|
credentialsId: 'mySecrets',
|
|
]
|
|
]))
|
|
assertThat(docker.imagePullCount, is(1))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testSkipSidecarImagePull() throws Exception {
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerName: 'maven',
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
sidecarEnvVars: ['testEnv': 'testVal'],
|
|
sidecarImage: 'selenium/standalone-chrome',
|
|
sidecarVolumeBind: ['/dev/shm': '/dev/shm'],
|
|
sidecarName: 'testAlias',
|
|
sidecarPorts: ['4444': '4444', '1111': '1111'],
|
|
sidecarPullImage: false
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertThat(docker.imagePullCount, is(1))
|
|
assertThat(bodyExecuted, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsideDockerContainerWithParameters() throws Exception {
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerOptions: '-description=lorem ipsum',
|
|
dockerVolumeBind: ['my_vol': '/my_vol'],
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(docker.getParameters().contains('--env https_proxy '))
|
|
assertTrue(docker.getParameters().contains('--env http_proxy=http://proxy:8000'))
|
|
assertTrue(docker.getParameters().contains('description=lorem\\ ipsum'))
|
|
assertTrue(docker.getParameters().contains('--volume my_vol:/my_vol'))
|
|
assertTrue(bodyExecuted)
|
|
}
|
|
|
|
@Test
|
|
void testExecuteInsideDockerContainerWithDockerOptionsList() throws Exception {
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerOptions: ['-it', '--network=my-network', 'description=lorem ipsum'],
|
|
dockerEnvVars: ['http_proxy': 'http://proxy:8000']) {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(docker.getParameters().contains('--env http_proxy=http://proxy:8000'))
|
|
assertTrue(docker.getParameters().contains('-it'))
|
|
assertTrue(docker.getParameters().contains('--network=my-network'))
|
|
assertTrue(docker.getParameters().contains('description=lorem\\ ipsum'))
|
|
}
|
|
|
|
@Test
|
|
void testDockerNotInstalledResultsInLocalExecution() throws Exception {
|
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, "docker .*", 1)
|
|
stepRule.step.dockerExecute(script: nullScript,
|
|
dockerOptions: '-it') {
|
|
bodyExecuted = true
|
|
}
|
|
assertTrue(loggingRule.log.contains('Cannot connect to docker daemon'))
|
|
assertTrue(loggingRule.log.contains('Running on local environment'))
|
|
assertTrue(bodyExecuted)
|
|
assertFalse(docker.isImagePulled())
|
|
}
|
|
|
|
@Test
|
|
void testSidecarDefault() {
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerName: 'maven',
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
sidecarEnvVars: ['testEnv': 'testVal'],
|
|
sidecarImage: 'selenium/standalone-chrome',
|
|
sidecarVolumeBind: ['/dev/shm': '/dev/shm'],
|
|
sidecarName: 'testAlias',
|
|
sidecarPorts: ['4444': '4444', '1111': '1111']
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
|
|
assertThat(bodyExecuted, is(true))
|
|
assertThat(docker.imagePullCount, is(2))
|
|
assertThat(docker.sidecarParameters, allOf(
|
|
containsString('--env testEnv=testVal'),
|
|
containsString('--volume /dev/shm:/dev/shm'),
|
|
containsString('--network sidecar-'),
|
|
containsString('--network-alias testAlias')
|
|
))
|
|
assertThat(docker.parameters, allOf(
|
|
containsString('--network sidecar-'),
|
|
containsString('--network-alias maven')
|
|
))
|
|
}
|
|
|
|
@Test
|
|
void testSidecarHealthCheck() {
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
sidecarImage: 'selenium/standalone-chrome',
|
|
sidecarName: 'testAlias',
|
|
sidecarReadyCommand: "isReady.sh"
|
|
) {}
|
|
assertThat(shellRule.shell, hasItem("docker exec uniqueId isReady.sh"))
|
|
}
|
|
|
|
@Test
|
|
void testSidecarKubernetes() {
|
|
boolean dockerExecuteOnKubernetesCalled = false
|
|
binding.setVariable('env', [ON_K8S: 'true'])
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { params, body ->
|
|
dockerExecuteOnKubernetesCalled = true
|
|
assertThat(params.dockerImage, is('maven:3.5-jdk-8-alpine'))
|
|
assertThat(params.containerName, is('maven'))
|
|
assertThat(params.sidecarEnvVars, is(['testEnv': 'testVal']))
|
|
assertThat(params.sidecarName, is('selenium'))
|
|
assertThat(params.sidecarImage, is('selenium/standalone-chrome'))
|
|
assertThat(params.containerName, is('maven'))
|
|
assertThat(params.containerPortMappings['selenium/standalone-chrome'], hasItem(allOf(hasEntry('containerPort', 4444), hasEntry('hostPort', 4444))))
|
|
assertThat(params.dockerWorkspace, is('/home/piper'))
|
|
body()
|
|
})
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
containerPortMappings: [
|
|
'selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]
|
|
],
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
dockerName: 'maven',
|
|
dockerWorkspace: '/home/piper',
|
|
sidecarEnvVars: ['testEnv': 'testVal'],
|
|
sidecarImage: 'selenium/standalone-chrome',
|
|
sidecarName: 'selenium',
|
|
sidecarVolumeBind: ['/dev/shm': '/dev/shm']
|
|
) {
|
|
bodyExecuted = true
|
|
}
|
|
assertThat(bodyExecuted, is(true))
|
|
assertThat(dockerExecuteOnKubernetesCalled, is(true))
|
|
}
|
|
|
|
@Test
|
|
void testSidecarKubernetesHealthCheck() {
|
|
binding.setVariable('env', [ON_K8S: 'true'])
|
|
|
|
helper.registerAllowedMethod('dockerExecuteOnKubernetes', [Map.class, Closure.class], { params, body ->
|
|
body()
|
|
SidecarUtils sidecarUtils = new SidecarUtils(nullScript)
|
|
sidecarUtils.waitForSidecarReadyOnKubernetes(params.sidecarName, params.sidecarReadyCommand)
|
|
})
|
|
|
|
def containerCalled = false
|
|
helper.registerAllowedMethod('container', [Map.class, Closure.class], { params, body ->
|
|
containerCalled = true
|
|
assertThat(params.name, is('testAlias'))
|
|
body()
|
|
})
|
|
|
|
stepRule.step.dockerExecute(
|
|
script: nullScript,
|
|
dockerImage: 'maven:3.5-jdk-8-alpine',
|
|
sidecarImage: 'selenium/standalone-chrome',
|
|
sidecarName: 'testAlias',
|
|
sidecarReadyCommand: "isReady.sh"
|
|
) {}
|
|
|
|
assertThat(containerCalled, is(true))
|
|
assertThat(shellRule.shell, hasItem("isReady.sh"))
|
|
}
|
|
|
|
private class DockerMock {
|
|
private List imageNames = []
|
|
private boolean imagePulled = false
|
|
private int imagePullCount = 0
|
|
private String parameters
|
|
private String sidecarParameters
|
|
private List registriesWithCredentials = []
|
|
private String credentialsId
|
|
|
|
DockerMock image(String imageName) {
|
|
this.imageNames << imageName
|
|
return this
|
|
}
|
|
|
|
void pull() {
|
|
imagePullCount++
|
|
imagePulled = true
|
|
}
|
|
|
|
void withRegistry(String registry, String credentialsId, Closure c) {
|
|
this.registriesWithCredentials << [registry: registry, credentialsId: credentialsId]
|
|
c()
|
|
}
|
|
|
|
void inside(String parameters, body) {
|
|
this.parameters = parameters
|
|
body()
|
|
}
|
|
|
|
void withRun(String parameters, body) {
|
|
this.sidecarParameters = parameters
|
|
body([id: 'uniqueId'])
|
|
}
|
|
|
|
def getImageNames() {
|
|
return imageNames
|
|
}
|
|
|
|
boolean isImagePulled() {
|
|
return imagePulled
|
|
}
|
|
|
|
String getParameters() {
|
|
return parameters
|
|
}
|
|
}
|
|
}
|