├── .gitignore
├── Jenkinsfile
├── Jenkinsfile-arquillian
├── Jenkinsfile-basic
├── Jenkinsfile-declarative
├── Jenkinsfile-declarative-one-agent
├── Jenkinsfile-declarative-restricted
├── Jenkinsfile-declarative-runas
├── Jenkinsfile-jnlp-base
├── Jenkinsfile-mavenlocalrepo
├── Jenkinsfile-yaml
├── LICENSE
├── README.md
├── app-users
├── README.md
├── application-local.properties
├── bootstrap.properties
├── configuration
│ └── settings.xml
├── pom.xml
├── run.sh
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── mycompany
│ │ │ └── k8sit
│ │ │ ├── Application.java
│ │ │ ├── model
│ │ │ ├── Address.java
│ │ │ └── User.java
│ │ │ └── route
│ │ │ └── UserRoute.java
│ └── resources
│ │ ├── application-arquillian.properties
│ │ ├── application-k8sit.properties
│ │ ├── application.properties
│ │ ├── bootstrap.properties
│ │ └── spring
│ │ └── application-context.xml
│ └── test
│ ├── java
│ └── com
│ │ └── mycompany
│ │ └── k8sit
│ │ └── ApplicationTest.java
│ └── resources
│ ├── application-unittest.properties
│ ├── bootstrap.properties
│ ├── data.sql
│ └── schema.sql
├── arquillian-test
├── README.md
├── podtemplate-arquillian.xml
├── pom.xml
└── src
│ └── test
│ ├── java
│ └── com
│ │ └── mycompany
│ │ └── k8sit
│ │ └── ArquillianTest.java
│ └── resources
│ ├── after-namespace.sh
│ ├── app-users-test.yaml
│ ├── arquillian.xml
│ ├── logback.xml
│ └── sql
│ └── sql-load.sql
├── configuration
└── settings.xml
├── integration-test
├── mockserver
│ ├── setup.sh
│ ├── testRetry@test.com.err
│ └── testSucc@test.com.ok
├── pom.xml
├── run.sh
├── sql
│ ├── create-tables.sql
│ ├── load-data.sql
│ └── setup.sh
└── src
│ └── test
│ └── java
│ └── com
│ └── mycompany
│ └── k8sit
│ ├── IntegrationTest.java
│ └── SpringConfiguration.java
└── pod.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | **/target
2 | **/.settings
3 | **/.project
4 | **/.classpath
5 | **/*.iml
6 | **/.idea
7 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | podTemplate(
2 | name: 'app-users-it',
3 | label: 'app-users-it',
4 | cloud: 'openshift',
5 | containers: [
6 | //Java agent, test executor
7 | containerTemplate(name: 'jnlp',
8 | image: 'registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9',
9 | resourceLimitMemory: '512Mi',
10 | workingDir: '/home/jenkins',
11 | command: '/bin/sh -c',
12 | args: '"umask 0000; /usr/local/bin/run-jnlp-client ${computer.jnlpmac} ${computer.name}"',
13 | alwaysPullImage: false,
14 | envVars: [
15 | //Heap for jnlp is 1/2, for mvn and surefire process is 1/4 of resourceLimitMemory by default
16 | envVar(key: 'JNLP_MAX_HEAP_UPPER_BOUND_MB', value: '64')
17 | ]),
18 | //App under test
19 | containerTemplate(name: 'app-users',
20 | image: '172.30.1.1:5000/myproject/app-users:latest',
21 | resourceLimitMemory: '512Mi',
22 | alwaysPullImage: true,
23 | envVars: [
24 | envVar(key: 'SPRING_PROFILES_ACTIVE', value: 'k8sit'),
25 | envVar(key: 'SPRING_CLOUD_KUBERNETES_ENABLED', value: 'false')
26 | ]),
27 | //DB
28 | containerTemplate(name: 'mariadb',
29 | image: 'registry.access.redhat.com/rhscl/mariadb-102-rhel7:1',
30 | resourceLimitMemory: '256Mi',
31 | alwaysPullImage: false,
32 | envVars: [
33 | envVar(key: 'MYSQL_USER', value: 'myuser'),
34 | envVar(key: 'MYSQL_PASSWORD', value: 'mypassword'),
35 | envVar(key: 'MYSQL_DATABASE', value: 'testdb'),
36 | envVar(key: 'MYSQL_ROOT_PASSWORD', value: 'secret')
37 | ]),
38 | //AMQ
39 | containerTemplate(name: 'amq',
40 | image: 'registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3',
41 | resourceLimitMemory: '256Mi',
42 | alwaysPullImage: false,
43 | envVars: [
44 | envVar(key: 'AMQ_USER', value: 'test'),
45 | envVar(key: 'AMQ_PASSWORD', value: 'secret')
46 | ]),
47 | //External API Third party (provided by mockserver)
48 | containerTemplate(name: 'mockserver',
49 | image: 'jamesdbloom/mockserver:mockserver-5.3.0',
50 | resourceLimitMemory: '256Mi',
51 | alwaysPullImage: false,
52 | envVars: [
53 | envVar(key: 'LOG_LEVEL', value: 'INFO'),
54 | envVar(key: 'JVM_OPTIONS', value: '-Xmx128m'),
55 | ])
56 | ]
57 | )
58 | {
59 | node('maven'){
60 | stage('Pull source') {
61 | checkout scm //git url: 'https://github.com/bszeti/kubernetes-integration-test.git'
62 | }
63 |
64 | dir ("app-users") {
65 | stage('Build app') {
66 | sh "mvn -B -s ../configuration/settings.xml -DskipTests package"
67 | }
68 |
69 | stage('Build Image') {
70 | // Requires: minishift config set insecure-registry 172.30.0.0/16
71 | sh "oc new-build --name=app-users --docker-image=registry.access.redhat.com/fuse7/fuse-java-openshift:latest --binary=true --labels=app=app-users || true"
72 | sh 'rm -rf oc-build && mkdir -p oc-build/deployments'
73 | sh 'cp target/*.jar oc-build/deployments'
74 |
75 | openshift.withCluster() {
76 | openshift.withProject('myproject') {
77 | openshift.selector('bc', 'app-users').startBuild('--from-dir=oc-build', '--wait=true').logs('-f')
78 | }
79 |
80 | }
81 | }
82 | }
83 |
84 | }
85 |
86 | node('app-users-it') {
87 | stage('Pull source') {
88 | checkout scm
89 | }
90 | dir ("integration-test") {
91 | stage('Prepare test') {
92 | container('mariadb') {
93 | //requires mysql
94 | sh 'sql/setup.sh'
95 | }
96 | container('jnlp') {
97 | //requires curl and python
98 | sh 'mockserver/setup.sh'
99 | }
100 | }
101 |
102 | //These env vars are used the tests to send message to users.in queue
103 | withEnv(['AMQ_USER=test',
104 | 'AMQ_PASSWORD=secret']) {
105 | stage('Build and run test') {
106 | try {
107 | sh 'mvn -s ../configuration/settings.xml -B clean test'
108 | } finally {
109 | junit 'target/surefire-reports/*.xml'
110 | }
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Jenkinsfile-arquillian:
--------------------------------------------------------------------------------
1 | //See README.md under arquillian-test how to prepare Jenkins build
2 | node('arquillian'){
3 | stage('Pull source') {
4 | checkout scm
5 | }
6 |
7 | dir ("arquillian-test") {
8 | try {
9 | stage('Build app') {
10 | sh "mvn -B -s ../configuration/settings.xml test"
11 | }
12 | } finally {
13 | archiveArtifacts artifacts: 'target/surefire-reports/*.log'
14 | junit 'target/surefire-reports/*.xml'
15 | }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/Jenkinsfile-basic:
--------------------------------------------------------------------------------
1 | podTemplate(
2 | label: 'app-users-it',
3 | cloud: 'openshift',
4 | containers: [
5 | //Java agent, test executor
6 | containerTemplate(name: 'jnlp',
7 | image: 'registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9',
8 | resourceLimitMemory: '512Mi',
9 | command: '/bin/sh -c',
10 | args: '"umask 0000; /usr/local/bin/run-jnlp-client ${computer.jnlpmac} ${computer.name}"',
11 | envVars: [
12 | //Heap for jnlp is 1/2, for mvn and surefire process is 1/4 of resourceLimitMemory by default
13 | envVar(key: 'JNLP_MAX_HEAP_UPPER_BOUND_MB', value: '64')
14 | ]),
15 | //App under test
16 | containerTemplate(name: 'app-users',
17 | image: '172.30.1.1:5000/myproject/app-users:latest',
18 | resourceLimitMemory: '512Mi',
19 | envVars: [
20 | envVar(key: 'SPRING_PROFILES_ACTIVE', value: 'k8sit'),
21 | envVar(key: 'SPRING_CLOUD_KUBERNETES_ENABLED', value: 'false')
22 | ]),
23 | //DB
24 | containerTemplate(name: 'mariadb',
25 | image: 'registry.access.redhat.com/rhscl/mariadb-102-rhel7:1',
26 | resourceLimitMemory: '256Mi',
27 | envVars: [
28 | envVar(key: 'MYSQL_USER', value: 'myuser'),
29 | envVar(key: 'MYSQL_PASSWORD', value: 'mypassword'),
30 | envVar(key: 'MYSQL_DATABASE', value: 'testdb'),
31 | envVar(key: 'MYSQL_ROOT_PASSWORD', value: 'secret')
32 | ]),
33 | //AMQ
34 | containerTemplate(name: 'amq',
35 | image: 'registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3',
36 | resourceLimitMemory: '256Mi',
37 | envVars: [
38 | envVar(key: 'AMQ_USER', value: 'test'),
39 | envVar(key: 'AMQ_PASSWORD', value: 'secret')
40 | ]),
41 | //External API Third party (provided by mockserver)
42 | containerTemplate(name: 'mockserver',
43 | image: 'jamesdbloom/mockserver:mockserver-5.3.0',
44 | resourceLimitMemory: '256Mi',
45 | envVars: [
46 | envVar(key: 'LOG_LEVEL', value: 'INFO'),
47 | envVar(key: 'JVM_OPTIONS', value: '-Xmx128m'),
48 | ])
49 | ]
50 | )
51 | {
52 | node('app-users-it') {
53 | stage('Pull source') {
54 | checkout scm
55 | }
56 | dir ("integration-test") {
57 | stage('Prepare test') {
58 | container('mariadb') {
59 | //requires mysql
60 | sh 'sql/setup.sh'
61 | }
62 | //requires curl and python
63 | sh 'mockserver/setup.sh'
64 | }
65 |
66 | //These env vars are used the tests to send message to users.in queue
67 | withEnv(['AMQ_USER=test',
68 | 'AMQ_PASSWORD=secret']) {
69 | stage('Build and run test') {
70 | try {
71 | sh 'mvn -s ../configuration/settings.xml -B clean test'
72 | } finally {
73 | junit 'target/surefire-reports/*.xml'
74 | }
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Jenkinsfile-declarative:
--------------------------------------------------------------------------------
1 | //Update kubernetes-plugin to 1.7
2 | pipeline {
3 | agent none //Using different agent for each stage
4 | stages {
5 |
6 | /********
7 | * Build the jar and the docker image using the default 'maven' node
8 | ********/
9 | stage('Build App and Image') {
10 | agent{ label 'maven' }
11 | steps {
12 | dir ("app-users") {
13 | sh "mvn -B -s ../configuration/settings.xml -DskipTests package"
14 |
15 | // Requires: minishift config set insecure-registry 172.30.0.0/16
16 | sh "oc new-build --name=app-users --docker-image=registry.access.redhat.com/fuse7/fuse-java-openshift:latest --binary=true --labels=app=app-users || true"
17 | sh 'rm -rf oc-build && mkdir -p oc-build/deployments'
18 | sh 'cp target/*.jar oc-build/deployments'
19 |
20 | script {
21 | openshift.withCluster() {
22 | openshift.withProject('myproject') {
23 | openshift.selector('bc', 'app-users').startBuild('--from-dir=oc-build', '--wait=true').logs('-f')
24 | }
25 |
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 |
33 | /********
34 | * Run the integration test with the custom pod defined with a yaml
35 | ********/
36 | stage('Run integration test') {
37 | agent{
38 | kubernetes {
39 | label 'app-users-it'
40 | cloud 'openshift'
41 | defaultContainer 'jnlp'
42 | yaml '''
43 | apiVersion: v1
44 | kind: Pod
45 | metadata:
46 | labels:
47 | app: app-users
48 | spec:
49 | containers:
50 | #Java agent, test executor
51 | - name: jnlp
52 | image: registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9
53 | command:
54 | - /bin/sh
55 | args:
56 | - -c
57 | - umask 0000; /usr/local/bin/run-jnlp-client $(JENKINS_SECRET) $(JENKINS_NAME)
58 | resources:
59 | limits:
60 | memory: 512Mi
61 | workingDir: /home/jenkins
62 | env:
63 | - name: JNLP_MAX_HEAP_UPPER_BOUND_MB
64 | value: 64
65 | #App under test
66 | - name: app-users
67 | image: 172.30.1.1:5000/myproject/app-users:latest
68 | resources:
69 | limits:
70 | memory: 512Mi
71 | env:
72 | - name: SPRING_PROFILES_ACTIVE
73 | value: k8sit
74 | - name: SPRING_CLOUD_KUBERNETES_ENABLED
75 | value: false
76 | #DB
77 | - name: mariadb
78 | image: registry.access.redhat.com/rhscl/mariadb-102-rhel7:1
79 | resources:
80 | limits:
81 | memory: 256Mi
82 | env:
83 | - name: MYSQL_USER
84 | value: myuser
85 | - name: MYSQL_PASSWORD
86 | value: mypassword
87 | - name: MYSQL_DATABASE
88 | value: testdb
89 | - name: MYSQL_ROOT_PASSWORD
90 | value: secret
91 | readinessProbe:
92 | tcpSocket:
93 | port: 3306
94 | initialDelaySeconds: 5
95 | #AMQ
96 | - name: amq
97 | image: registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3
98 | resources:
99 | limits:
100 | memory: 256Mi
101 | env:
102 | - name: AMQ_USER
103 | value: test
104 | - name: AMQ_PASSWORD
105 | value: secret
106 | readinessProbe:
107 | tcpSocket:
108 | port: 61616
109 | initialDelaySeconds: 5
110 | #External API Third party (provided by mockserver)
111 | - name: mockserver
112 | image: jamesdbloom/mockserver:mockserver-5.3.0
113 | resources:
114 | limits:
115 | memory: 256Mi
116 | env:
117 | - name: LOG_LEVEL
118 | value: INFO
119 | - name: JVM_OPTIONS
120 | value: -Xmx128m
121 | readinessProbe:
122 | tcpSocket:
123 | port: 1080
124 | initialDelaySeconds: 5
125 | '''
126 | }
127 | }
128 | environment {
129 | //These env vars are used the tests to send message to users.in queue
130 | AMQ_USER = 'test'
131 | AMQ_PASSWORD = 'secret'
132 | }
133 | steps {
134 | dir ("integration-test") {
135 | container('mariadb') {
136 | //requires mysql
137 | sh 'sql/setup.sh'
138 | }
139 |
140 | // Default container 'jnlp'
141 | // this script requires curl and python.
142 | sh 'mockserver/setup.sh'
143 |
144 | //Run the tests.
145 | //Somehow simply "mvn ..." doesn't work here
146 | sh '/bin/bash -c "mvn -s ../configuration/settings.xml -B clean test"'
147 | }
148 | }
149 | post {
150 | always {
151 | junit testResults: 'integration-test/target/surefire-reports/*.xml', allowEmptyResults: true
152 | }
153 | }
154 | }
155 |
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/Jenkinsfile-declarative-one-agent:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent{
3 | kubernetes {
4 | label 'app-users-it'
5 | cloud 'openshift'
6 | defaultContainer 'jnlp'
7 | yaml '''
8 | apiVersion: v1
9 | kind: Pod
10 | metadata:
11 | labels:
12 | app: app-users
13 | spec:
14 | containers:
15 | #Java agent, test executor
16 | - name: jnlp
17 | image: registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9
18 | command:
19 | - /bin/sh
20 | args:
21 | - -c
22 | - umask 0000; /usr/local/bin/run-jnlp-client $(JENKINS_SECRET) $(JENKINS_NAME)
23 | resources:
24 | limits:
25 | memory: 512Mi
26 | workingDir: /home/jenkins
27 | env:
28 | - name: JNLP_MAX_HEAP_UPPER_BOUND_MB
29 | value: 64
30 | #App under test
31 | - name: app-users
32 | image: 172.30.1.1:5000/myproject/app-users:latest
33 | resources:
34 | limits:
35 | memory: 512Mi
36 | env:
37 | - name: SPRING_PROFILES_ACTIVE
38 | value: k8sit
39 | - name: SPRING_CLOUD_KUBERNETES_ENABLED
40 | value: false
41 | #DB
42 | - name: mariadb
43 | image: registry.access.redhat.com/rhscl/mariadb-102-rhel7:1
44 | resources:
45 | limits:
46 | memory: 256Mi
47 | env:
48 | - name: MYSQL_USER
49 | value: myuser
50 | - name: MYSQL_PASSWORD
51 | value: mypassword
52 | - name: MYSQL_DATABASE
53 | value: testdb
54 | - name: MYSQL_ROOT_PASSWORD
55 | value: secret
56 | readinessProbe:
57 | tcpSocket:
58 | port: 3306
59 | initialDelaySeconds: 5
60 | #AMQ
61 | - name: amq
62 | image: registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3
63 | resources:
64 | limits:
65 | memory: 256Mi
66 | env:
67 | - name: AMQ_USER
68 | value: test
69 | - name: AMQ_PASSWORD
70 | value: secret
71 | readinessProbe:
72 | tcpSocket:
73 | port: 61616
74 | initialDelaySeconds: 5
75 | #External API Third party (provided by mockserver)
76 | - name: mockserver
77 | image: jamesdbloom/mockserver:mockserver-5.3.0
78 | resources:
79 | limits:
80 | memory: 256Mi
81 | env:
82 | - name: LOG_LEVEL
83 | value: INFO
84 | - name: JVM_OPTIONS
85 | value: -Xmx128m
86 | readinessProbe:
87 | tcpSocket:
88 | port: 1080
89 | initialDelaySeconds: 5
90 | '''
91 | }
92 | }
93 |
94 | stages {
95 |
96 | /********
97 | * Run the integration test with the custom pod defined with a yaml
98 | ********/
99 | stage('Run integration test') {
100 |
101 | environment {
102 | //These env vars are used the tests to send message to users.in queue
103 | AMQ_USER = 'test'
104 | AMQ_PASSWORD = 'secret'
105 | }
106 | steps {
107 | dir ("integration-test") {
108 | container('mariadb') {
109 | //requires mysql
110 | sh 'sql/setup.sh'
111 | }
112 |
113 | // Default container 'jnlp'
114 | // this script requires curl and python.
115 | sh 'mockserver/setup.sh'
116 |
117 | //Run the tests.
118 | //Somehow simply "mvn ..." doesn't work here
119 | sh '/bin/bash -c "mvn -s ../configuration/settings.xml -B clean test"'
120 | }
121 | }
122 | post {
123 | always {
124 | junit testResults: 'integration-test/target/surefire-reports/*.xml', allowEmptyResults: true
125 | }
126 | }
127 | }
128 |
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/Jenkinsfile-declarative-restricted:
--------------------------------------------------------------------------------
1 | //Update kubernetes-plugin to 1.7
2 | pipeline {
3 | agent none //Using different agent for each stage
4 | stages {
5 |
6 | /********
7 | * Run the integration test with the custom pod defined with a yaml
8 | ********/
9 | stage('Run integration test') {
10 | agent{
11 | kubernetes {
12 | label 'app-users-it'
13 | cloud 'openshift'
14 | defaultContainer 'jnlp'
15 | yaml '''
16 | apiVersion: v1
17 | kind: Pod
18 | metadata:
19 | labels:
20 | app: app-users
21 | spec:
22 | #To resolve the file permission problem of /home/jenkins/workspace we have to make sure that all the containers are using the same runAsUser. fsGroup or supplementalGroups are not enough.
23 | #If the jenkins serviceaccount has access only to 'restricted' scc, the same random uid will be enforced on the containers, so we should not set runAsUser here.
24 | containers:
25 | #Java agent, test executor
26 | - name: jnlp
27 | image: registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9
28 | command:
29 | - /usr/local/bin/run-jnlp-client
30 | args:
31 | - $(JENKINS_SECRET)
32 | - $(JENKINS_NAME)
33 | resources:
34 | limits:
35 | memory: 512Mi
36 | workingDir: /home/jenkins
37 | env:
38 | - name: JNLP_MAX_HEAP_UPPER_BOUND_MB
39 | value: 64
40 | #App under test
41 | - name: app-users
42 | image: 172.30.1.1:5000/myproject/app-users:latest
43 | resources:
44 | limits:
45 | memory: 512Mi
46 | env:
47 | - name: SPRING_PROFILES_ACTIVE
48 | value: k8sit
49 | - name: SPRING_CLOUD_KUBERNETES_ENABLED
50 | value: false
51 | #DB
52 | - name: mariadb
53 | image: registry.access.redhat.com/rhscl/mariadb-102-rhel7:1
54 | resources:
55 | limits:
56 | memory: 256Mi
57 | env:
58 | - name: MYSQL_USER
59 | value: myuser
60 | - name: MYSQL_PASSWORD
61 | value: mypassword
62 | - name: MYSQL_DATABASE
63 | value: testdb
64 | - name: MYSQL_ROOT_PASSWORD
65 | value: secret
66 | readinessProbe:
67 | tcpSocket:
68 | port: 3306
69 | initialDelaySeconds: 5
70 | #AMQ
71 | - name: amq
72 | image: registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3
73 | resources:
74 | limits:
75 | memory: 256Mi
76 | env:
77 | - name: AMQ_USER
78 | value: test
79 | - name: AMQ_PASSWORD
80 | value: secret
81 | readinessProbe:
82 | tcpSocket:
83 | port: 61616
84 | initialDelaySeconds: 5
85 | #External API Third party (provided by mockserver)
86 | - name: mockserver
87 | image: jamesdbloom/mockserver:mockserver-5.3.0
88 | resources:
89 | limits:
90 | memory: 256Mi
91 | env:
92 | - name: LOG_LEVEL
93 | value: INFO
94 | - name: JVM_OPTIONS
95 | value: -Xmx128m
96 | readinessProbe:
97 | tcpSocket:
98 | port: 1080
99 | initialDelaySeconds: 5
100 | '''
101 | }
102 | }
103 | environment {
104 | //These env vars are used the tests to send message to users.in queue
105 | AMQ_USER = 'test'
106 | AMQ_PASSWORD = 'secret'
107 | }
108 | steps {
109 | dir ("integration-test") {
110 | container('mariadb') {
111 | //requires mysql
112 | sh 'sql/setup.sh'
113 | }
114 |
115 | // Default container 'jnlp'
116 | // this script requires curl and python.
117 | sh 'mockserver/setup.sh'
118 |
119 | //Run the tests.
120 | //Somehow simply "mvn ..." doesn't work here
121 | sh '/bin/bash -c "mvn -s ../configuration/settings.xml -B clean test"'
122 | }
123 | }
124 | post {
125 | always {
126 | junit testResults: 'integration-test/target/surefire-reports/*.xml', allowEmptyResults: true
127 | }
128 | }
129 | }
130 |
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/Jenkinsfile-declarative-runas:
--------------------------------------------------------------------------------
1 | //Update kubernetes-plugin to 1.7
2 | pipeline {
3 | agent none //Using different agent for each stage
4 | stages {
5 |
6 | /********
7 | * Build the jar and the docker image using the default 'maven' node
8 | ********/
9 | stage('Build App and Image') {
10 | agent{ label 'maven' }
11 | steps {
12 | dir ("app-users") {
13 | sh "mvn -B -s ../configuration/settings.xml -DskipTests package"
14 |
15 | // Requires: minishift config set insecure-registry 172.30.0.0/16
16 | sh "oc new-build --name=app-users --docker-image=registry.access.redhat.com/fuse7/fuse-java-openshift:latest --binary=true --labels=app=app-users || true"
17 | sh 'rm -rf oc-build && mkdir -p oc-build/deployments'
18 | sh 'cp target/*.jar oc-build/deployments'
19 |
20 | script {
21 | openshift.withCluster() {
22 | openshift.withProject('myproject') {
23 | openshift.selector('bc', 'app-users').startBuild('--from-dir=oc-build', '--wait=true').logs('-f')
24 | }
25 |
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 |
33 | /********
34 | * Run the integration test with the custom pod defined with a yaml
35 | ********/
36 | stage('Run integration test') {
37 | agent{
38 | kubernetes {
39 | label 'app-users-it'
40 | cloud 'openshift'
41 | defaultContainer 'jnlp'
42 | yaml '''
43 | apiVersion: v1
44 | kind: Pod
45 | metadata:
46 | labels:
47 | app: app-users
48 | spec:
49 | #To resolve the file permission problem of /home/jenkins/workspace we have to make sure that all the containers are using the same runAsUser. fsGroup or supplementalGroups are not enough.
50 | #If the jenkins serviceaccount has access to 'anyuid' scc, we need to set the runAsUser here to avoid having different uid in the containers.
51 | securityContext:
52 | runAsUser: 1002
53 | containers:
54 | #Java agent, test executor
55 | - name: jnlp
56 | image: registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9
57 | command:
58 | - /usr/local/bin/run-jnlp-client
59 | args:
60 | - $(JENKINS_SECRET)
61 | - $(JENKINS_NAME)
62 | resources:
63 | limits:
64 | memory: 512Mi
65 | workingDir: /home/jenkins
66 | env:
67 | - name: JNLP_MAX_HEAP_UPPER_BOUND_MB
68 | value: 64
69 | #App under test
70 | - name: app-users
71 | image: 172.30.1.1:5000/myproject/app-users:latest
72 | resources:
73 | limits:
74 | memory: 512Mi
75 | env:
76 | - name: SPRING_PROFILES_ACTIVE
77 | value: k8sit
78 | - name: SPRING_CLOUD_KUBERNETES_ENABLED
79 | value: false
80 | #DB
81 | - name: mariadb
82 | image: registry.access.redhat.com/rhscl/mariadb-102-rhel7:1
83 | resources:
84 | limits:
85 | memory: 256Mi
86 | env:
87 | - name: MYSQL_USER
88 | value: myuser
89 | - name: MYSQL_PASSWORD
90 | value: mypassword
91 | - name: MYSQL_DATABASE
92 | value: testdb
93 | - name: MYSQL_ROOT_PASSWORD
94 | value: secret
95 | readinessProbe:
96 | tcpSocket:
97 | port: 3306
98 | initialDelaySeconds: 5
99 | #AMQ
100 | - name: amq
101 | image: registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3
102 | resources:
103 | limits:
104 | memory: 256Mi
105 | env:
106 | - name: AMQ_USER
107 | value: test
108 | - name: AMQ_PASSWORD
109 | value: secret
110 | readinessProbe:
111 | tcpSocket:
112 | port: 61616
113 | initialDelaySeconds: 5
114 | #External API Third party (provided by mockserver)
115 | - name: mockserver
116 | image: jamesdbloom/mockserver:mockserver-5.3.0
117 | resources:
118 | limits:
119 | memory: 256Mi
120 | env:
121 | - name: LOG_LEVEL
122 | value: INFO
123 | - name: JVM_OPTIONS
124 | value: -Xmx128m
125 | readinessProbe:
126 | tcpSocket:
127 | port: 1080
128 | initialDelaySeconds: 5
129 | '''
130 | }
131 | }
132 | environment {
133 | //These env vars are used the tests to send message to users.in queue
134 | AMQ_USER = 'test'
135 | AMQ_PASSWORD = 'secret'
136 | }
137 | steps {
138 | dir ("integration-test") {
139 | container('mariadb') {
140 | //requires mysql
141 | sh 'sql/setup.sh'
142 | }
143 |
144 | // Default container 'jnlp'
145 | // this script requires curl and python.
146 | sh 'mockserver/setup.sh'
147 |
148 | //Run the tests.
149 | //Somehow simply "mvn ..." doesn't work here
150 | sh '/bin/bash -c "mvn -s ../configuration/settings.xml -B clean test"'
151 | }
152 | }
153 | post {
154 | always {
155 | junit testResults: 'integration-test/target/surefire-reports/*.xml', allowEmptyResults: true
156 | }
157 | }
158 | }
159 |
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/Jenkinsfile-jnlp-base:
--------------------------------------------------------------------------------
1 | podTemplate(
2 | label: 'app-users-it',
3 | cloud: 'openshift',
4 | containers: [
5 | //Jenkins agent - a jnlp container is mandatory (or added automatically)
6 | containerTemplate(name: 'jnlp',
7 | image: 'registry.access.redhat.com/openshift3/jenkins-slave-base-rhel7:v3.9',
8 | resourceLimitMemory: '256Mi',
9 | command: '/bin/sh -c',
10 | args: '"umask 0000; /usr/local/bin/run-jnlp-client ${computer.jnlpmac} ${computer.name}"'
11 | ),
12 | //Container running the test
13 | containerTemplate(name: 'it',
14 | image: 'fabric8/maven-builder:vd8fbad4',
15 | resourceLimitMemory: '512Mi',
16 | envVars: [
17 | //Manage heap, there are two java processes: maven + surefire
18 | envVar(key: 'JAVA_TOOL_OPTIONS', value: '-Xms128m -Xmx128m')
19 | ]),
20 | //App under test
21 | containerTemplate(name: 'app-users',
22 | image: '172.30.1.1:5000/myproject/app-users:latest',
23 | resourceLimitMemory: '512Mi',
24 | envVars: [
25 | envVar(key: 'SPRING_PROFILES_ACTIVE', value: 'k8sit'),
26 | envVar(key: 'SPRING_CLOUD_KUBERNETES_ENABLED', value: 'false')
27 | ]),
28 | //DB
29 | containerTemplate(name: 'mariadb',
30 | image: 'registry.access.redhat.com/rhscl/mariadb-102-rhel7:1',
31 | resourceLimitMemory: '256Mi',
32 | envVars: [
33 | envVar(key: 'MYSQL_USER', value: 'myuser'),
34 | envVar(key: 'MYSQL_PASSWORD', value: 'mypassword'),
35 | envVar(key: 'MYSQL_DATABASE', value: 'testdb'),
36 | envVar(key: 'MYSQL_ROOT_PASSWORD', value: 'secret')
37 | ]),
38 | //AMQ
39 | containerTemplate(name: 'amq',
40 | image: 'registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3',
41 | resourceLimitMemory: '256Mi',
42 | envVars: [
43 | envVar(key: 'AMQ_USER', value: 'test'),
44 | envVar(key: 'AMQ_PASSWORD', value: 'secret')
45 | ]),
46 | //External API Third party (provided by mockserver)
47 | containerTemplate(name: 'mockserver',
48 | image: 'jamesdbloom/mockserver:mockserver-5.3.0',
49 | resourceLimitMemory: '256Mi',
50 | envVars: [
51 | envVar(key: 'LOG_LEVEL', value: 'INFO'),
52 | envVar(key: 'JVM_OPTIONS', value: '-Xmx128m'),
53 | ])
54 | ]
55 | )
56 | {
57 | node('app-users-it') {
58 | stage('Pull source') {
59 | checkout scm
60 | }
61 | dir ("integration-test") {
62 | stage('Prepare test') {
63 | container('mariadb') {
64 | //requires mysql
65 | sh 'sql/setup.sh'
66 | }
67 | //requires curl and python
68 | sh 'mockserver/setup.sh'
69 | }
70 |
71 | //These env vars are used the tests to send message to users.in queue
72 | withEnv(['AMQ_USER=test',
73 | 'AMQ_PASSWORD=secret']) {
74 | stage('Build and run test') {
75 | container('it'){
76 | try {
77 | sh 'mvn -s ../configuration/settings.xml -B clean test'
78 | } finally {
79 | junit 'target/surefire-reports/*.xml'
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Jenkinsfile-mavenlocalrepo:
--------------------------------------------------------------------------------
1 | podTemplate(
2 | name: 'app-users-it',
3 | label: 'app-users-it',
4 | cloud: 'openshift',
5 | containers: [
6 | //Java agent, test executor
7 | containerTemplate(name: 'jnlp',
8 | image: 'registry.access.redhat.com/openshift3/jenkins-agent-maven-35-rhel7:v3.10',
9 | resourceLimitMemory: '512Mi',
10 | workingDir: '/home/jenkins',
11 | command: '/bin/sh -c',
12 | args: '"umask 0000; /usr/local/bin/run-jnlp-client ${computer.jnlpmac} ${computer.name}"',
13 | alwaysPullImage: false,
14 | envVars: [
15 | //Heap for jnlp is 1/2, for mvn and surefire process is 1/4 of resourceLimitMemory by default
16 | envVar(key: 'JNLP_MAX_HEAP_UPPER_BOUND_MB', value: '64')
17 | ]),
18 | //App under test
19 | containerTemplate(name: 'app-users',
20 | image: '172.30.1.1:5000/myproject/app-users:latest',
21 | resourceLimitMemory: '512Mi',
22 | alwaysPullImage: true,
23 | envVars: [
24 | envVar(key: 'SPRING_PROFILES_ACTIVE', value: 'k8sit'),
25 | envVar(key: 'SPRING_CLOUD_KUBERNETES_ENABLED', value: 'false')
26 | ]),
27 | //DB
28 | containerTemplate(name: 'mariadb',
29 | image: 'registry.access.redhat.com/rhscl/mariadb-102-rhel7:1',
30 | resourceLimitMemory: '256Mi',
31 | alwaysPullImage: false,
32 | envVars: [
33 | envVar(key: 'MYSQL_USER', value: 'myuser'),
34 | envVar(key: 'MYSQL_PASSWORD', value: 'mypassword'),
35 | envVar(key: 'MYSQL_DATABASE', value: 'testdb'),
36 | envVar(key: 'MYSQL_ROOT_PASSWORD', value: 'secret')
37 | ]),
38 | //AMQ
39 | containerTemplate(name: 'amq',
40 | image: 'registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3',
41 | resourceLimitMemory: '256Mi',
42 | alwaysPullImage: false,
43 | envVars: [
44 | envVar(key: 'AMQ_USER', value: 'test'),
45 | envVar(key: 'AMQ_PASSWORD', value: 'secret')
46 | ]),
47 | //External API Third party (provided by mockserver)
48 | containerTemplate(name: 'mockserver',
49 | image: 'jamesdbloom/mockserver:mockserver-5.3.0',
50 | resourceLimitMemory: '256Mi',
51 | alwaysPullImage: false,
52 | envVars: [
53 | envVar(key: 'LOG_LEVEL', value: 'INFO'),
54 | envVar(key: 'JVM_OPTIONS', value: '-Xmx128m'),
55 | ])
56 | ],
57 | volumes:[
58 | persistentVolumeClaim(mountPath: '/home/jenkins/.m2/repository', claimName:'mavenlocalrepo') //mounted as root drwxrwxrwx
59 | ],
60 | envVars: [
61 | envVar(key: 'ENV_NAME', value: 'my-k8sit')
62 | ]
63 | )
64 | {
65 | node('maven'){
66 | stage('Pull source') {
67 | checkout scm //git url: 'https://github.com/bszeti/kubernetes-integration-test.git'
68 | }
69 |
70 | dir ("app-users") {
71 | stage('Build app') {
72 | sh "mvn -B -s ../configuration/settings.xml -DskipTests package"
73 | }
74 |
75 | stage('Build Image') {
76 | // Requires: minishift config set insecure-registry 172.30.0.0/16
77 | sh "oc new-build --name=app-users --docker-image=registry.access.redhat.com/fuse7/fuse-java-openshift:latest --binary=true --labels=app=app-users || true"
78 | sh 'rm -rf oc-build && mkdir -p oc-build/deployments'
79 | sh 'cp target/*.jar oc-build/deployments'
80 |
81 | openshift.withCluster() {
82 | openshift.withProject('myproject') {
83 | openshift.selector('bc', 'app-users').startBuild('--from-dir=oc-build', '--wait=true').logs('-f')
84 | }
85 |
86 | }
87 | }
88 | }
89 |
90 | }
91 |
92 | node('app-users-it') {
93 | stage('Pull source') {
94 | checkout scm
95 | }
96 | dir ("integration-test") {
97 | stage('Prepare test') {
98 | container('mariadb') {
99 | //requires mysql
100 | sh 'sql/setup.sh'
101 | }
102 | container('jnlp') {
103 | //requires curl and python
104 | sh 'mockserver/setup.sh'
105 | }
106 | }
107 |
108 | //These env vars are used the tests to send message to users.in queue
109 | withEnv(['AMQ_USER=test',
110 | 'AMQ_PASSWORD=secret']) {
111 | stage('Build and run test') {
112 | try {
113 | sh 'mvn -s ../configuration/settings.xml -B clean test'
114 | } finally {
115 | junit 'target/surefire-reports/*.xml'
116 | }
117 | }
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/Jenkinsfile-yaml:
--------------------------------------------------------------------------------
1 | //Update kubernetes-plugin to 1.7
2 | node('master'){
3 | checkout scm
4 | yamlFromFile = readFile 'pod.yaml' //Read yaml file
5 | }
6 |
7 | podTemplate(
8 | name: 'app-users-it',
9 | label: 'app-users-it',
10 | cloud: 'openshift',
11 | yaml: yamlFromFile //Use the yaml read from file
12 | )
13 | {
14 | node('maven'){
15 | stage('Pull source') {
16 | checkout scm //git url: 'https://github.com/bszeti/kubernetes-integration-test.git'
17 | }
18 |
19 | dir ("app-users") {
20 | stage('Build app') {
21 | sh "mvn -B -s ../configuration/settings.xml -DskipTests package"
22 | }
23 |
24 | stage('Build Image') {
25 | // Requires: minishift config set insecure-registry 172.30.0.0/16
26 | sh "oc new-build --name=app-users --docker-image=registry.access.redhat.com/fuse7/fuse-java-openshift:latest --binary=true --labels=app=app-users || true"
27 | sh 'rm -rf oc-build && mkdir -p oc-build/deployments'
28 | sh 'cp target/*.jar oc-build/deployments'
29 |
30 | openshift.withCluster() {
31 | openshift.withProject('myproject') {
32 | openshift.selector('bc', 'app-users').startBuild('--from-dir=oc-build', '--wait=true').logs('-f')
33 | }
34 |
35 | }
36 | }
37 | }
38 |
39 | }
40 |
41 | node('app-users-it') {
42 | stage('Pull source') {
43 | checkout scm
44 | }
45 | dir ("integration-test") {
46 | stage('Prepare test') {
47 | container('mariadb') {
48 | //requires mysql
49 | sh 'sql/setup.sh'
50 | }
51 | container('jnlp') {
52 | //requires curl and python
53 | sh 'mockserver/setup.sh'
54 | }
55 | }
56 |
57 | withEnv(['AMQ_USER=test',
58 | 'AMQ_PASSWORD=secret']) {
59 | stage('Build and run test') {
60 | try {
61 | sh 'mvn -s ../configuration/settings.xml -B clean test'
62 | } finally {
63 | junit 'target/surefire-reports/*.xml'
64 | }
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Running integration tests with Kubernetes
2 |
3 | Integration test on Kubernetes with Jenkins pipeline
4 |
5 | Blog post: https://itnext.io/running-integration-tests-with-kubernetes-ae0fb71e207b
6 |
7 | ### Directories:
8 | * **app-users**: Example Red Hat Fuse 7 application that takes messages from AMQ, makes database queries and calls a REST api
9 | * **configuration/settings.xml**: Maven settings.xml with the requires repos to build
10 | * **integration-test**: Tests written in Java with Junit, can be executed with Maven
11 | * **arquillian-test**: Test with Arquillian Cube on OpenShift
12 |
13 | ### Jenkins pipelines:
14 | * **Jenkinsfile**: Builds app and executes integration test.
15 | * **Jenkinsfile-basic**: Executes integration test only. Setting only the important parameters.
16 | * **Jenkinsfile-declarative**: Using declarative syntax. Setting a different agent at stage level. Builds app and executes integration test.
17 | * **Jenkinsfile-declarative-one-agent**: Using declarative syntax. Agent is defined at the pipeline level. Executes integration test only.
18 | * **Jenkinsfile-declarative-runas**: Using declarative syntax. Pod sets runAsUser to make sure all containers are started with the same uid. No "umask 0000" is needed in the command. Requires 'anyuid' scc.
19 | * **Jenkinsfile-declarative-restricted**: Using declarative syntax. Only works if 'restricted' scc is being used, so the same random uid is set for all containers. No "umask 0000" is needed in the command.
20 | * **Jenkinsfile-jnlp-base**: Using separate container for jnlp and maven. Executes integration test only.
21 | * **Jenkinsfile-mavenlocalrepo**: Mounting a persisted volume as maven local repository to avoid downloading jars every time. Requires a 'mavenlocalrepo' persistent volume claim. Builds app and executes integration test.
22 | * **Jenkinsfile-yaml**: Reads yaml pod template from 'pod.yaml'. Builds app and executes integration test.
23 | * **Jenkinsfile-arquillian**: Run the arquillian-test integration test project. See README.md in its directory.
24 |
25 | ### App-users
26 | A Spring Boot application running a Camel route based on the Red Hat Fuse 7 stack.
27 |
28 | Steps:
29 | * Take messages from _user.in_ queue. Json :`{"email": "me@mycompany.com"}`
30 | * Query phone number from table _users_
31 | * Call a REST api to get address. E.g. https://myhost/v1/address/email/me@mycompany.com
32 | * Send the enriched user info to queue _user.out_
33 |
34 | Build and run unit tests with Maven:
35 | * Use the provided settings.xml to access the required Maven repositories:
36 |
37 | `mvn -s ../configuration/settings.xml clean package`
38 |
39 | ### Integration-test
40 |
41 | Tests written in Java using Junit5. Run with Maven: `mvn clean test`
42 |
43 | Env variables required:
44 | * AMQ_USER: AMQ connection username
45 | * AMQ_PASSWORD: AMQ connection password
46 |
47 | Test cases:
48 | * testSucc: Send message to _user.in_. Expect enriched message on _user.out_.
49 | * testRetry: Test AMQ transacted. REST api throws http 500 3x times before sending response. Send message to _user.in_. Expect enriched message on _user.out_.
50 |
51 | ### Arquillian-test
52 |
53 | Arquillian Cube based test. See README.md in its directory.
54 |
--------------------------------------------------------------------------------
/app-users/README.md:
--------------------------------------------------------------------------------
1 | ### Building
2 |
3 | The example can be built with
4 |
5 | mvn clean install
6 |
7 | ### Running on localhost
8 |
9 | mvn spring-boot:run
10 |
11 | ### Running the example in OpenShift
12 |
13 | The example can then be built and deployed using a single goal:
14 |
15 | $ mvn fabric8:deploy
16 |
17 | ### Accessing the Spring REST Actuator services
18 |
19 | curl http://localhost:8080/health
20 |
--------------------------------------------------------------------------------
/app-users/application-local.properties:
--------------------------------------------------------------------------------
1 | endpoints.enabled=true
2 |
3 | logging.level.com.mycompany=DEBUG
4 |
5 | amq.brokerUrl=tcp://localhost:61616
6 | amq.username=test
7 | amq.password=secret
8 |
9 | spring.datasource.url=jdbc:mariadb://127.0.0.1/testdb
10 | spring.datasource.username=myuser
11 | spring.datasource.password=mypassword
12 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
13 |
14 | api.url=http://localhost:1080/v1/
15 |
--------------------------------------------------------------------------------
/app-users/bootstrap.properties:
--------------------------------------------------------------------------------
1 | # Disable OpenShift integration for unit tests
2 | spring.cloud.kubernetes.enabled=false
--------------------------------------------------------------------------------
/app-users/configuration/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | redhat-repos
6 |
7 | true
8 |
9 |
10 |
11 | central
12 | http://repo1.maven.org/maven2
13 |
14 | true
15 |
16 |
17 | false
18 |
19 |
20 |
21 | redhatga
22 | Red Hat
23 | http://maven.repository.redhat.com/ga
24 |
25 |
26 | redhatea
27 | Red Hat Early Access
28 | http://maven.repository.redhat.com/earlyaccess/all
29 |
30 |
31 |
32 |
33 |
34 | central
35 | http://repo1.maven.org/maven2
36 |
37 | true
38 |
39 |
40 | false
41 |
42 |
43 |
44 | redhatga
45 | Red Hat
46 | http://maven.repository.redhat.com/ga
47 |
48 |
49 | redhatea
50 | Red Hat Early Access
51 | http://maven.repository.redhat.com/earlyaccess/all
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app-users/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.mycompany.k8sit
6 | app-users
7 | 1.0-SNAPSHOT
8 | Example :: Integration test on Kubernetes with Jenkins pipeline :: App Users
9 |
10 |
11 | UTF-8
12 |
13 |
14 | 7.0.0.fuse-000027-redhat-1
15 | 2.2.5
16 |
17 |
18 | 0.2.0.RELEASE
19 |
20 |
21 | 3.7.0
22 | 2.21.0
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | org.jboss.redhat-fuse
32 | fuse-springboot-bom
33 | ${fuse.bom.version}
34 | pom
35 | import
36 |
37 |
38 |
39 | org.mariadb.jdbc
40 | mariadb-java-client
41 | ${mariadb-java-client.version}
42 |
43 |
44 |
45 | org.springframework.cloud
46 | spring-cloud-starter-kubernetes-config
47 | ${spring-cloud-kubernetes.version}
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-web
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-tomcat
62 |
63 |
64 |
65 |
66 | org.springframework.boot
67 | spring-boot-starter-undertow
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-starter-actuator
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-starter-jdbc
76 |
77 |
78 |
79 |
80 | org.apache.camel
81 | camel-metrics-starter
82 |
83 |
84 | org.apache.camel
85 | camel-http4-starter
86 |
87 |
88 | org.apache.camel
89 | camel-jackson-starter
90 |
91 |
92 | org.fusesource
93 | camel-activemq
94 |
95 |
96 | org.apache.camel
97 | camel-sjms-starter
98 |
99 |
100 | org.apache.camel
101 | camel-bean-validator
102 |
103 |
104 | org.apache.camel
105 | camel-sql-starter
106 |
107 |
108 |
109 | org.mariadb.jdbc
110 | mariadb-java-client
111 |
112 |
113 |
114 |
115 |
116 | org.springframework.cloud
117 | spring-cloud-starter-kubernetes-config
118 |
119 |
120 |
121 |
122 | org.springframework.boot
123 | spring-boot-starter-test
124 | test
125 |
126 |
127 | org.apache.camel
128 | camel-test-spring
129 | test
130 |
131 |
132 | org.apache.camel
133 | camel-servlet-starter
134 | test
135 |
136 |
137 | org.hsqldb
138 | hsqldb
139 | test
140 |
141 |
142 | org.apache.camel
143 | camel-jsonpath
144 | test
145 |
146 |
147 |
148 |
149 |
150 | spring-boot:run
151 |
152 |
153 |
154 | maven-surefire-plugin
155 | ${maven-surefire-plugin.version}
156 |
157 |
158 | maven-compiler-plugin
159 | ${maven-compiler-plugin.version}
160 |
161 |
162 | org.jboss.redhat-fuse
163 | spring-boot-maven-plugin
164 | ${fuse.bom.version}
165 |
166 |
167 |
168 |
169 |
170 |
171 | maven-compiler-plugin
172 |
173 | 1.8
174 | 1.8
175 |
176 |
177 |
178 |
179 | org.jboss.redhat-fuse
180 | spring-boot-maven-plugin
181 |
182 |
183 |
184 | repackage
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
--------------------------------------------------------------------------------
/app-users/run.sh:
--------------------------------------------------------------------------------
1 | #sudo docker run --name mockserver -d -p 1080:1080 docker.io/jamesdbloom/mockserver
2 | #sudo docker run --name mariadb -e MYSQL_USER=myuser -e MYSQL_PASSWORD=mypassword -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=testdb -d -p 3306:3306 registry.access.redhat.com/rhscl/mariadb-102-rhel7
3 | #sudo docker run --name amq -e AMQ_USER=test -e AMQ_PASSWORD=secret -d -p 61616:61616 -p 8181:8181 registry.access.redhat.com/jboss-amq-6/amq63-openshift
4 |
5 | mvn -Dspring.profiles.active=local clean spring-boot:run
6 |
--------------------------------------------------------------------------------
/app-users/src/main/java/com/mycompany/k8sit/Application.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit;
2 |
3 | import org.apache.camel.CamelContext;
4 | import org.apache.camel.component.metrics.routepolicy.MetricsRoutePolicyFactory;
5 | import org.apache.camel.spring.boot.CamelContextConfiguration;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.boot.SpringApplication;
9 | import org.springframework.boot.autoconfigure.SpringBootApplication;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.ImportResource;
12 |
13 | @SpringBootApplication
14 | @ImportResource({"classpath:spring/application-context.xml"})
15 | public class Application {
16 | private static final Logger log = LoggerFactory.getLogger(Application.class);
17 |
18 | public static void main(String[] args) {
19 | SpringApplication.run(Application.class, args);
20 | }
21 |
22 | /***
23 | * Customize CamelContext
24 | */
25 | @Bean
26 | CamelContextConfiguration contextConfiguration() {
27 | return new CamelContextConfiguration() {
28 | @Override
29 | public void beforeApplicationStart(CamelContext context) {
30 | //Enable metrics for all routes
31 | context.addRoutePolicyFactory(new MetricsRoutePolicyFactory());
32 | }
33 |
34 | @Override
35 | public void afterApplicationStart(CamelContext context) {
36 | }
37 | };
38 | }
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app-users/src/main/java/com/mycompany/k8sit/model/Address.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit.model;
2 |
3 | public class Address {
4 | private String state;
5 | private String city;
6 | private String address;
7 | private String zip;
8 |
9 | public String getState() {
10 | return state;
11 | }
12 |
13 | public void setState(String state) {
14 | this.state = state;
15 | }
16 |
17 | public String getCity() {
18 | return city;
19 | }
20 |
21 | public void setCity(String city) {
22 | this.city = city;
23 | }
24 |
25 | public String getZip() {
26 | return zip;
27 | }
28 |
29 | public void setZip(String zip) {
30 | this.zip = zip;
31 | }
32 |
33 | public String getAddress() {
34 | return address;
35 | }
36 |
37 | public void setAddress(String address) {
38 | this.address = address;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app-users/src/main/java/com/mycompany/k8sit/model/User.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import org.hibernate.validator.constraints.Email;
5 |
6 | import javax.validation.constraints.NotNull;
7 |
8 | @JsonIgnoreProperties(ignoreUnknown = true)
9 | public class User {
10 | @NotNull
11 | @Email
12 | private String email;
13 |
14 | private String phone;
15 |
16 | private Address address;
17 |
18 | public String getEmail() {
19 | return email;
20 | }
21 |
22 | public void setEmail(String email) {
23 | this.email = email;
24 | }
25 |
26 | public String getPhone() {
27 | return phone;
28 | }
29 |
30 | public void setPhone(String phone) {
31 | this.phone = phone;
32 | }
33 |
34 | public Address getAddress() {
35 | return address;
36 | }
37 |
38 | public void setAddress(Address address) {
39 | this.address = address;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app-users/src/main/java/com/mycompany/k8sit/route/UserRoute.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit.route;
2 |
3 | import com.mycompany.k8sit.model.Address;
4 | import com.mycompany.k8sit.model.User;
5 | import org.apache.camel.Exchange;
6 | import org.apache.camel.LoggingLevel;
7 | import org.apache.camel.builder.RouteBuilder;
8 | import org.apache.camel.model.dataformat.JsonLibrary;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.stereotype.Component;
12 |
13 | @Component
14 | public class UserRoute extends RouteBuilder {
15 | private static final Logger log = LoggerFactory.getLogger(UserRoute.class);
16 |
17 | @Override
18 | public void configure() throws Exception {
19 |
20 | //There is no Camel retry enabled by default, but the endpoint is transacted, so redelivery is triggered by AMQ
21 | //Try transacted=false&synchronous=false to fail the testRetry test
22 | from("amq:user.in?consumerCount={{amq.consumerCount}}&transacted=true").routeId("user.in")
23 | .streamCaching()
24 |
25 | //Receive user email from body
26 | .log(LoggingLevel.DEBUG,log,"User received: ${body}")
27 | .unmarshal().json(JsonLibrary.Jackson,User.class)
28 | .to("bean-validator:user-in")
29 |
30 | //We populate this object during the route
31 | .setProperty("user",body())
32 |
33 | //Select phone number from database
34 | .to("sql:SELECT phone FROM users WHERE email=:#${exchangeProperty.user.email}?dataSource=#dataSource&outputType=SelectOne&outputHeader=phone")
35 | .script().simple("${exchangeProperty.user.setPhone(${header.phone})}")
36 |
37 | //Call api for address
38 | .removeHeaders("*")
39 | .setBody(constant(null))
40 | .setHeader(Exchange.HTTP_URI).constant("{{api.url}}")
41 | .setHeader(Exchange.HTTP_PATH).simple("address/email/${exchangeProperty.user.email}")
42 | .setHeader("CamelHttpMethod").constant("GET")
43 | .setHeader("Accept").simple("application/json")
44 | .to("http4:apiCall?synchronous=true")
45 | .log(LoggingLevel.DEBUG,log,"Address received: ${body}")
46 | .unmarshal().json(JsonLibrary.Jackson,Address.class)
47 | .script().simple("${exchangeProperty.user.setAddress(${body})}")
48 |
49 |
50 | //Send user with added fields to out queue
51 | .setBody(exchangeProperty("user"))
52 | .marshal().json(JsonLibrary.Jackson)
53 | .convertBodyTo(String.class)
54 |
55 | .removeHeaders("*")
56 | .log(LoggingLevel.DEBUG,log,"Send user: ${body}")
57 | .to("amq:user.out?prefillPool=false")
58 | ;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/app-users/src/main/resources/application-arquillian.properties:
--------------------------------------------------------------------------------
1 | endpoints.enabled=true
2 | management.security.enabled=false
3 |
4 | logging.level.com.mycompany=DEBUG
5 |
6 | amq.brokerUrl=tcp://amqsvc:61616
7 | amq.username=test
8 | amq.password=secret
9 |
10 | spring.datasource.url=jdbc:mariadb://mariadbsvc/testdb
11 | spring.datasource.username=myuser
12 | spring.datasource.password=mypassword
13 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
14 |
15 | api.url=http://mockserversvc/v1/
16 |
--------------------------------------------------------------------------------
/app-users/src/main/resources/application-k8sit.properties:
--------------------------------------------------------------------------------
1 | endpoints.enabled=true
2 |
3 | logging.level.com.mycompany=DEBUG
4 |
5 | amq.brokerUrl=tcp://localhost:61616
6 | amq.username=test
7 | amq.password=secret
8 |
9 | spring.datasource.url=jdbc:mariadb://127.0.0.1/testdb
10 | spring.datasource.username=myuser
11 | spring.datasource.password=mypassword
12 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
13 |
14 | api.url=http://localhost:1080/v1/
15 |
--------------------------------------------------------------------------------
/app-users/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | amq.brokerUrl=tcp://localhost:61616
2 | amq.username=admin
3 | amq.password=admin
4 | amq.consumerCount=1
5 | amq.connectionCount=1
6 |
7 | api.url=https://service.mycompany.com/v1/
--------------------------------------------------------------------------------
/app-users/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=app-users
2 |
--------------------------------------------------------------------------------
/app-users/src/main/resources/spring/application-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app-users/src/test/java/com/mycompany/k8sit/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit;
2 |
3 | import com.jayway.jsonpath.JsonPath;
4 | import org.apache.camel.*;
5 | import org.apache.camel.builder.AdviceWithRouteBuilder;
6 | import org.apache.camel.builder.RouteBuilder;
7 | import org.apache.camel.component.mock.MockEndpoint;
8 | import org.apache.camel.model.rest.RestBindingMode;
9 | import org.apache.camel.test.spring.CamelSpringBootRunner;
10 | import org.apache.camel.test.spring.MockEndpointsAndSkip;
11 | import org.apache.camel.test.spring.UseAdviceWith;
12 | import org.junit.Before;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.boot.test.context.SpringBootTest;
19 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
20 | import org.springframework.boot.test.context.TestConfiguration;
21 | import org.springframework.context.annotation.Bean;
22 | import org.springframework.http.MediaType;
23 | import org.springframework.test.annotation.DirtiesContext;
24 | import org.springframework.test.context.ActiveProfiles;
25 |
26 | import static org.junit.Assert.assertEquals;
27 |
28 | @RunWith(CamelSpringBootRunner.class)
29 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
30 | @ActiveProfiles("unittest")
31 | @UseAdviceWith
32 | @MockEndpointsAndSkip("amq:*")
33 | @DirtiesContext
34 | public class ApplicationTest {
35 | private static final Logger log = LoggerFactory.getLogger(ApplicationTest.class);
36 |
37 | @Autowired
38 | private CamelContext context;
39 |
40 | @Produce(uri = "direct:user.in")
41 | private ProducerTemplate producer;
42 |
43 | @EndpointInject(uri = "mock:amq:user.out")
44 | private MockEndpoint mockUserOut;
45 |
46 | @EndpointInject(uri = "mock:addressByEmail")
47 | private MockEndpoint addressByEmail;
48 |
49 |
50 |
51 | @TestConfiguration
52 | static class TestSpringConfiguration {
53 |
54 | @Bean
55 | public RouteBuilder addTestHttpService() {
56 | return new RouteBuilder() {
57 | @Override
58 | public void configure() throws Exception {
59 | //See ServletMappingConfiguration mapping properties: camel.component.servlet.mapping
60 | restConfiguration().component("servlet") //Requires "CamelServlet" to be registered
61 | .bindingMode(RestBindingMode.off);
62 |
63 | rest("address")
64 | .produces(MediaType.APPLICATION_JSON_VALUE)
65 | .get("email/{email}")
66 | .route().routeId("test-http")
67 | .setBody().constant("{\"address\":\"1428 Elm Street\"}")
68 | .to("mock:addressByEmail")
69 | .endRest();
70 | }
71 | };
72 | }
73 | }
74 |
75 |
76 | @Before
77 | public void before() throws Exception{
78 |
79 | if (context.getStatus()==ServiceStatus.Stopped) {
80 | //Execute adviseWith only once
81 | context.getRouteDefinition("user.in").adviceWith(context, new AdviceWithRouteBuilder() {
82 | @Override
83 | public void configure() throws Exception {
84 | replaceFromWith("direct:user.in");
85 | }
86 | });
87 |
88 |
89 | }
90 |
91 | //Reset mock endpoint
92 | mockUserOut.reset();
93 | addressByEmail.reset();
94 | }
95 |
96 | @Test
97 | public void testSucc() throws Exception{
98 | context.start();
99 | mockUserOut.expectedMessageCount(1);
100 |
101 | producer.sendBody("{\"email\":\"testSucc@test.com\"}");
102 |
103 | mockUserOut.assertIsSatisfied();
104 | Exchange sentToSync = mockUserOut.getExchanges().get(0);
105 | String response = sentToSync.getIn().getBody(String.class);
106 |
107 | assertEquals("testSucc@test.com",JsonPath.read(response,"$.email"));
108 | assertEquals("5551234567",JsonPath.read(response,"$.phone"));
109 | assertEquals("1428 Elm Street",JsonPath.read(response,"$.address.address"));
110 |
111 | }
112 |
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/app-users/src/test/resources/application-unittest.properties:
--------------------------------------------------------------------------------
1 | camel.springboot.name=CamelTest
2 |
3 | # disable all management enpoints except health
4 | endpoints.enabled=false
5 |
6 | logging.level.com.mycompany=DEBUG
7 |
8 | camel.component.servlet.mapping.context-path=/test/*
9 |
10 | #Enforce an embedded (hsql) database for unit tests
11 | spring.datasource.url=
12 | spring.datasource.driver-class-name=
13 | #spring.datasource.schema=classpath:sql/schema.sql
14 | #spring.datasource.data=classpath:sql/data.sql
15 |
16 | #We mock the component, so don't want to fill the pool
17 | amq.connectionCount=0
18 |
19 | api.url=http://localhost:{{local.server.port}}/test/
--------------------------------------------------------------------------------
/app-users/src/test/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | # Disable OpenShift integration for unit tests
2 | spring.cloud.kubernetes.enabled=false
--------------------------------------------------------------------------------
/app-users/src/test/resources/data.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO users (email, phone) VALUES ('testSucc@test.com', '5551234567');
--------------------------------------------------------------------------------
/app-users/src/test/resources/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE users (
2 | email VARCHAR(256),
3 | phone VARCHAR(64),
4 | PRIMARY KEY (email)
5 | );
--------------------------------------------------------------------------------
/arquillian-test/README.md:
--------------------------------------------------------------------------------
1 | # Integration tests with Arquillian Cube on OpenShift
2 |
3 | Arquillian Cube test project that creates a new temporary namespace with all the required containers in OpenShift. The test itself is being run outside this temporary namespace from the Jenkins' namespace (or even outside OpenShift). This was tested on Minishift with Jenkins deployed by the _jenkins-persistent_ template in the default _myproject_ namespace.
4 |
5 | ### Prepare run
6 | Preparing the right permissions is required to run this test project.
7 | * **image-puller**: The _app-users_ image should exist and be accessible from the temporary namespace. The _default_ serviceaccount should have _image-puller_ role, but we don't know the random name of the namespace in advance. Easiest is to grant permission to all service accounts from the build namespace _myproject_:
8 |
9 | `oc policy add-role-to-group system:image-puller system:serviceaccounts -n myproject`
10 |
11 | * **serviceaccount:arquillian**: Create SA that will run the test:
12 |
13 | `oc create sa arquillian -n myproject`
14 |
15 | Grant permission to create new projects:
16 |
17 | `oc adm policy add-cluster-role-to-user self-provisioner system:serviceaccount:myproject:arquillian`
18 |
19 | * **arquillian PodTemplate**: Copy the existing _maven_ PodTemplate in Jenkins Kubernetes plugin config. Use label _arquillian_ and set it to use service account _arquillian_. See _podtemplate-arquillian.xml_.
20 |
21 | After these steps a Jenkins pipeline project can be created running the _Jenkins-arquillian_ pipeline (see parent directory).
22 |
23 | ### Steps:
24 | These are the important steps of the Arquillian Cube test execution:
25 | * Create temporary namespace with random name (e.g. 'arquillian-frp71'). Prefix is set in _namespace.prefix_ property.
26 | * Run an optional script for preparation steps. In this test we need to add _view_ role for the _default_ sa in the temporary namespace to support using configMaps. See _env.setup.script.url_ property.
27 | * Apply the yaml file to create resources in the temporary namespace. See _env.config.resource.name_ property.
28 | * Populate components (database, mockserver) with initial data. See _ArquillianTest.before()_.
29 | * Run tests
30 | * Shutdown and delete the whole temporary namespace.
31 |
32 | ### Tests in ArquillianTest.class:
33 | * **testSucc**: Happy path. Send a json message to _user.in_ and expecting the enriched json on _user.out_.
34 | * **shutDownMariadb**: Tolerate temporary database issues. Delete _mariadb_ pod, send the test message then recreate _mariadb_ pod. The test message is automatically retried until the database is back online.
35 |
--------------------------------------------------------------------------------
/arquillian-test/podtemplate-arquillian.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | arquillian
4 |
5 | false
6 | false
7 | 2147483647
8 | 100
9 | 0
10 | 0
11 |
12 | arquillian
13 |
14 | NORMAL
15 | false
16 |
17 | false
18 |
19 |
20 |
21 |
22 | jnlp
23 | registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.9
24 | false
25 | false
26 | /tmp
27 |
28 | ${computer.jnlpmac} ${computer.name}
29 | false
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 0
39 | 0
40 | 0
41 | 0
42 | 0
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/arquillian-test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.mycompany.k8sit
8 | arquillian-test
9 | 1.0-SNAPSHOT
10 | Example :: Integration test on Kubernetes with Jenkins pipeline :: Arquillian Test
11 |
12 |
13 | UTF-8
14 |
15 |
16 | 1.17.1
17 |
18 | 5.0.6.RELEASE
19 | 2.4.0
20 | 5.15.4
21 | 5.3.0
22 | 1.2.3
23 |
24 | 3.7.0
25 | 2.21.0
26 |
27 |
28 |
29 |
30 |
31 | org.arquillian.cube
32 | arquillian-cube-bom
33 | ${arquillian.version}
34 | import
35 | pom
36 |
37 |
38 |
39 | org.springframework
40 | spring-framework-bom
41 | ${spring.version}
42 | pom
43 | import
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.arquillian.cube
52 | arquillian-cube-openshift-starter
53 |
54 |
55 |
56 |
57 | io.fabric8
58 | openshift-client
59 | 4.0.3
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | org.arquillian.cube
69 | arquillian-cube-requirement
70 |
71 |
72 |
73 | ch.qos.logback
74 | logback-classic
75 | ${logback.version}
76 |
77 |
78 |
79 |
80 | org.springframework
81 | spring-jms
82 |
83 |
84 |
85 | org.apache.activemq
86 | activemq-client
87 | ${activemq.version}
88 |
89 |
90 |
91 | org.mock-server
92 | mockserver-client-java
93 | ${mockserver.version}
94 |
95 |
96 |
97 | com.jayway.jsonpath
98 | json-path
99 | ${json-path.version}
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | maven-compiler-plugin
108 | ${maven-compiler-plugin.version}
109 |
110 | 1.8
111 | 1.8
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/arquillian-test/src/test/java/com/mycompany/k8sit/ArquillianTest.java:
--------------------------------------------------------------------------------
1 | package com.mycompany.k8sit;
2 |
3 | import com.jayway.jsonpath.JsonPath;
4 | import io.fabric8.kubernetes.api.model.ObjectMeta;
5 | import io.fabric8.kubernetes.api.model.Pod;
6 | import io.fabric8.kubernetes.api.model.v4_0.PodList;
7 | import io.fabric8.kubernetes.api.model.v4_0.ServiceList;
8 | import io.fabric8.kubernetes.client.dsl.ExecListener;
9 | import io.fabric8.kubernetes.client.dsl.ExecWatch;
10 | import okhttp3.Response;
11 | import org.apache.activemq.ActiveMQConnectionFactory;
12 | import org.arquillian.cube.kubernetes.annotations.Named;
13 | import org.arquillian.cube.kubernetes.annotations.PortForward;
14 | import org.arquillian.cube.kubernetes.api.Session;
15 | import org.arquillian.cube.openshift.impl.client.OpenShiftAssistant;
16 | import org.arquillian.cube.openshift.impl.enricher.RouteURL;
17 | import org.arquillian.cube.openshift.impl.requirement.RequiresOpenshift;
18 | import org.arquillian.cube.requirement.ArquillianConditionalRunner;
19 | import org.awaitility.Awaitility;
20 | import org.jboss.arquillian.test.api.ArquillianResource;
21 | import org.junit.Before;
22 | import org.junit.BeforeClass;
23 | import org.junit.Test;
24 | import org.junit.experimental.categories.Category;
25 | import org.junit.runner.RunWith;
26 | import org.mockserver.client.server.MockServerClient;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 | import org.springframework.jms.core.JmsTemplate;
30 |
31 | import javax.jms.TextMessage;
32 | import java.io.ByteArrayOutputStream;
33 | import java.io.OutputStream;
34 | import java.net.URL;
35 | import java.util.concurrent.CountDownLatch;
36 | import java.util.concurrent.TimeUnit;
37 |
38 | import static org.junit.Assert.assertEquals;
39 | import static org.junit.Assert.assertTrue;
40 | import static org.mockserver.model.HttpRequest.request;
41 | import static org.mockserver.model.HttpResponse.response;
42 |
43 | @Category(RequiresOpenshift.class)
44 | @RunWith(ArquillianConditionalRunner.class)
45 | @RequiresOpenshift
46 | //@RunWith(Arquillian.class) //Can use this simply if don't want to force condition "with OpenShift only"
47 | public class ArquillianTest {
48 | private static final Logger log = LoggerFactory.getLogger(ArquillianTest.class);
49 |
50 | @ArquillianResource
51 | io.fabric8.openshift.client.OpenShiftClient oc;
52 | @ArquillianResource
53 | io.fabric8.kubernetes.client.KubernetesClient client;
54 |
55 | //Causes: java.lang.IllegalArgumentException: Can not set io.fabric8.openshift.clnt.v4_0.OpenShiftClient field com.mycompany.k8sit.ArquillianTest.oc4 to io.fabric8.kubernetes.clnt.v4_0.DefaultKubernetesClient
56 | // @ArquillianResource
57 | // io.fabric8.kubernetes.clnt.v4_0.KubernetesClient client4;
58 | // @ArquillianResource
59 | // io.fabric8.openshift.clnt.v4_0.OpenShiftClient oc4;
60 |
61 |
62 | //Forward amq port so it's available on a localhost port.
63 | @Named("amqsvc")
64 | @PortForward
65 | @ArquillianResource
66 | URL amqsvcUrl;
67 |
68 | //We can of course do the same port-forward here, but let's use a Route instead as this service is http
69 | // @AwaitRoute //It requires a GET endpoint, but mock-server has none by default
70 | @RouteURL("mockserverroute")
71 | URL mockserver;
72 |
73 | @Named("mariadb")
74 | @ArquillianResource
75 | Pod mariadb;
76 |
77 |
78 | //Not used, these are here only for example:
79 | @ArquillianResource //Arquillian namespace: session.getNamespace() or oc.getNamespace()
80 | Session session;
81 | @ArquillianResource //Same as oc.services().list()
82 | ServiceList services;
83 | @ArquillianResource //Same as oc.pods().list()
84 | PodList pods;
85 | @ArquillianResource //Additional helper to deploy
86 | OpenShiftAssistant openShiftAssistant;
87 |
88 |
89 | @BeforeClass
90 | public static void beforeClass(){
91 | //clients are not available yet (even if static)
92 | }
93 |
94 | private boolean beforeDone = false;
95 | @Before
96 | public void before() throws Exception{
97 | if (!beforeDone){
98 |
99 | log.info("Before is running. oc client: {}",oc.getOpenshiftUrl());
100 |
101 | // Prepare database;
102 | // Run mysql client in container with oc cli tool
103 | // oc exec waits for the command to finish
104 | //Runtime rt = Runtime.getRuntime();
105 | //Process mysql = rt.exec("oc exec -i -n "+session.getNamespace()+" mariadb -- /opt/rh/rh-mariadb102/root/usr/bin/mysql -u myuser -pmypassword -h 127.0.0.1 testdb");
106 | //IOUtils.copy(this.getClass().getClassLoader().getResourceAsStream("sql/sql-load.sql"),mysql.getOutputStream() );
107 | //mysql.getOutputStream().close();
108 | //log.info("waitFor: {}",mysql.waitFor());
109 | //log.info("output: {}", IOUtils.toString(mysql.getInputStream()));
110 | //log.info("error: {}", IOUtils.toString(mysql.getErrorStream()));
111 |
112 | // Prepare database
113 | loadSql();
114 |
115 |
116 | //Prepare MockServer response for test
117 | log.info("mockserver URL: {}",mockserver);
118 | int port = mockserver.getPort() == -1 ? 80 : mockserver.getPort();
119 | log.info("mockserver {} {}",mockserver.getHost(),port);
120 | //We could use any http client to call the MockServer expectation api, but this java client is nicer
121 | MockServerClient mockServerClient = new MockServerClient(mockserver.getHost(),port);
122 | mockServerClient
123 | .when(
124 | request()
125 | .withMethod("GET")
126 | .withPath("/v1/address/email/testSucc@test.com")
127 | )
128 | .respond(
129 | response()
130 | .withBody("{\n" +
131 | "\"state\": \"Test State\",\n" +
132 | "\"city\": \"Test City\",\n" +
133 | "\"address\": \"1 Test St\",\n" +
134 | "\"zip\": \"T001\"\n" +
135 | "}\n")
136 | );
137 |
138 | beforeDone=true;
139 | }
140 | }
141 |
142 | //Happy path
143 | @Test
144 | public void testSucc() throws Exception {
145 |
146 | log.info("Test resources are in namespace:"+session.getNamespace());
147 |
148 | //OpenShift client - here for example
149 | log.info("OpenShift - getMasterUrl: {}", oc.getMasterUrl());
150 | log.info("OpenShift - getApiVersion: {}", oc.getApiVersion());
151 | log.info("OpenShift - currentUser: {}", oc.currentUser().getMetadata().getName());
152 | log.info("OpenShift - getNamespace: {}", oc.getNamespace());
153 | log.info("OpenShift - getConfiguration: {}", oc.getConfiguration());
154 | log.info("OpenShift - getClass: {}", oc.getClass());
155 |
156 | //Kubernetes client - here for example
157 | log.info("Kubernetes - getMasterUrl: {}", client.getMasterUrl());
158 | log.info("Kubernetes - getApiVersion: {}", client.getApiVersion());
159 | log.info("Kubernetes - getConfiguration: {}", client.getConfiguration());
160 | log.info("Kubernetes - getClass: {}", client.getClass());
161 |
162 | //Service in the current namespace
163 | oc.services().list().getItems().stream()
164 | .map(s->s.getMetadata().getNamespace()+" - "+s.getMetadata().getName())
165 | .forEach(s->log.info("Service: {}",s));
166 |
167 | /*************
168 | * Start test
169 | *************/
170 | //The port-foward url has http schema, but it's actually the amq 61616 port
171 | String brokerUrl = "tcp://"+ amqsvcUrl.getHost()+":"+ amqsvcUrl.getPort();
172 | log.info("brokerUrl: {}",brokerUrl);
173 | ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("test","secret",brokerUrl);
174 | JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
175 |
176 | //Send test message and receive outcome
177 | jmsTemplate.convertAndSend("user.in", "{\"email\":\"testSucc@test.com\"}");
178 | TextMessage message = (TextMessage) jmsTemplate.receive("user.out");
179 | String response = message.getText();
180 |
181 | log.info("Response: {}",response);
182 |
183 | //Asserts
184 | assertEquals("testSucc@test.com", JsonPath.read(response, "$.email"));
185 | assertEquals("5551234567", JsonPath.read(response, "$.phone"));
186 | assertEquals("Test State", JsonPath.read(response, "$.address.state"));
187 | assertEquals("Test City", JsonPath.read(response, "$.address.city"));
188 | assertEquals("1 Test St", JsonPath.read(response, "$.address.address"));
189 | assertEquals("T001", JsonPath.read(response, "$.address.zip"));
190 |
191 | }
192 |
193 | //Test verifies that the retry works in case of temporary database downtime
194 | @Test
195 | public void shutDownMariadb() throws Exception{
196 | //Delete mariadb pod
197 | log.info("mariadb: {}", oc.pods().withName("mariadb").get()); //not null
198 | log.info("Delete mariadb pod.");
199 | assertTrue( oc.pods().withName(mariadb.getMetadata().getName()).delete() );
200 | Awaitility.await().atMost(30,TimeUnit.SECONDS).until(()->oc.pods().withName("mariadb").get()==null);
201 |
202 | //The port-foward url has http schema, but it's actually the amq 61616 port
203 | String brokerUrl = "tcp://"+ amqsvcUrl.getHost()+":"+ amqsvcUrl.getPort();
204 | log.info("brokerUrl: {}",brokerUrl);
205 | ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("test","secret",brokerUrl);
206 | JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
207 |
208 | //Send test message and receive outcome
209 | jmsTemplate.convertAndSend("user.in", "{\"email\":\"testSucc@test.com\"}");
210 |
211 | //Wait a sec to make sure message fails
212 | Thread.sleep(3000);
213 |
214 | //Create mariadb Pod and load sql
215 | log.info("Create mariadb pod.");
216 | ObjectMeta emptyObjectMeta = new ObjectMeta();
217 | emptyObjectMeta.setName(mariadb.getMetadata().getName());
218 | emptyObjectMeta.setLabels(mariadb.getMetadata().getLabels());
219 | mariadb.setMetadata(emptyObjectMeta);
220 | mariadb.setStatus(null);
221 | Pod newPod = oc.pods().create(mariadb);
222 | log.info("mariadb: {}", oc.pods().withName("mariadb").get());
223 | Awaitility.await().atMost(30,TimeUnit.SECONDS).until(()->oc.pods().withName("mariadb").isReady());
224 | //Recreate table, load data
225 | loadSql();
226 |
227 | //Receive response message
228 | TextMessage message = (TextMessage) jmsTemplate.receive("user.out");
229 | String response = message.getText();
230 |
231 | log.info("Response: {}",response);
232 |
233 | //Asserts
234 | assertEquals("testSucc@test.com", JsonPath.read(response, "$.email"));
235 | assertEquals("5551234567", JsonPath.read(response, "$.phone"));
236 | assertEquals("Test State", JsonPath.read(response, "$.address.state"));
237 | assertEquals("Test City", JsonPath.read(response, "$.address.city"));
238 | assertEquals("1 Test St", JsonPath.read(response, "$.address.address"));
239 | assertEquals("T001", JsonPath.read(response, "$.address.zip"));
240 |
241 | }
242 |
243 | private void loadSql() throws Exception{
244 | // Run command in container using OpenShiftClient java client - run sql in mysql
245 | log.info("Sql load - start");
246 | final CountDownLatch latch = new CountDownLatch(1);
247 | OutputStream execOut = new ByteArrayOutputStream();
248 | OutputStream execErr = new ByteArrayOutputStream();
249 | ExecWatch exec = oc.pods().withName("mariadb")
250 | .readingInput(this.getClass().getClassLoader().getResourceAsStream("sql/sql-load.sql"))
251 | .writingOutput(execOut)
252 | .writingError(execErr)
253 | //.withTTY() //Optional
254 | .usingListener(createCountDownListener(latch))
255 | .exec("/opt/rh/rh-mariadb102/root/usr/bin/mysql","-u", "myuser", "-pmypassword", "-h", "127.0.0.1", "testdb")
256 | ;
257 | if (!latch.await(20, TimeUnit.SECONDS)) {
258 | throw new Exception("Exec timeout");
259 | }
260 | log.info("Exec out: {}", ((ByteArrayOutputStream) execOut).toString());
261 | log.info("Exec err: {}", ((ByteArrayOutputStream) execErr).toString());
262 | log.info("Sql load - end");
263 | }
264 |
265 | //Helper method for OpenShiftClient exec()
266 | public static ExecListener createCountDownListener(CountDownLatch latch){
267 | return new ExecListener() {
268 | @Override
269 | public void onOpen(Response response) {
270 | log.info("onOpen response: {}",response);
271 | }
272 |
273 | @Override
274 | public void onFailure(Throwable t, Response response) {
275 | log.info("onFailure response: {}",response,t);
276 | latch.countDown();
277 |
278 | }
279 |
280 | @Override
281 | public void onClose(int code, String reason) {
282 | log.info("onClose reason: {} {}",code, reason);
283 | latch.countDown();
284 |
285 | }
286 | };
287 | }
288 |
289 | }
290 |
--------------------------------------------------------------------------------
/arquillian-test/src/test/resources/after-namespace.sh:
--------------------------------------------------------------------------------
1 | #This script is run after the namespace is created/chosen (see $KUBERNETES_NAMESPACE), but before applying kubernetes.yaml.
2 | #It's run under the Arquillian test process, so 'oc' should be available on the test host as it's used in this script.
3 |
4 | #The best practice is to have 'oc' on the test host logged in with a user (e.g. system:serviceaccount:myproject:arquillian)
5 | # and don't overwrite in arquillian.xml, so this script and Arquillian uses the same oc user
6 | #Make sure that this user can create new projects:
7 | # oc adm policy add-cluster-role-to-user self-provisioner system:serviceaccount:myproject:arquillian
8 |
9 | #Check where we are
10 | pwd
11 | env
12 |
13 | #oc is independent from arquillian.xml, so the "current" logged in user is used (e.g. service account of the pod)
14 | #the current 'oc project' is also NOT the namespace created by Arquillian
15 | oc whoami
16 | oc project
17 |
18 |
19 | #Make sure the 'default' SA in our $KUBERNETES_NAMESPACE can pull image from the CI/CD project 'myproject'
20 | #Easiest is to allow any serviceaccount to pull images from the ci/cd project in advance
21 | # oc policy add-role-to-group system:image-puller system:serviceaccounts -n myproject
22 | #Or if the current user has admin permissions, you can add image-puller role for the new namespace's default SA
23 | # oc policy add-role-to-user system:image-puller system:serviceaccount:$KUBERNETES_NAMESPACE:default -n myproject
24 |
25 |
26 | #Allow 'default' SA to read configMap, actually this is why we have this script in this example. This is not needed if you don't want to read configMaps in your pods.
27 | #We want to add this permission in advance otherwise the app-users pod fails to start and test execution won't start
28 | #Make sure that the current 'oc whoami' has the right permissions. If Arquillian created the project, the current user can run this
29 | oc policy add-role-to-user view system:serviceaccount:$KUBERNETES_NAMESPACE:default -n $KUBERNETES_NAMESPACE
--------------------------------------------------------------------------------
/arquillian-test/src/test/resources/app-users-test.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | #App under test
5 | - apiVersion: v1
6 | kind: Pod
7 | metadata:
8 | name: app-users
9 | labels:
10 | app: app-users
11 | spec:
12 | containers:
13 | - name: app-users
14 | image: 172.30.1.1:5000/myproject/app-users:latest
15 | resources:
16 | limits:
17 | memory: 512Mi
18 | env:
19 | - name: SPRING_PROFILES_ACTIVE
20 | value: xarquillian
21 | - name: SPRING_CLOUD_KUBERNETES_ENABLED
22 | value: true
23 | readinessProbe:
24 | httpGet:
25 | path: /health
26 | port: 8080
27 | initialDelaySeconds: 5
28 | ports:
29 | - name: jolokia
30 | containerPort: 8778
31 | protocol: TCP
32 | volumeMounts:
33 | - name: config-volume
34 | mountPath: /etc/config
35 | volumes:
36 | - name: config-volume
37 | configMap:
38 | name: app-users
39 | #ConfigMap for App under test
40 | - apiVersion: v1
41 | kind: ConfigMap
42 | metadata:
43 | name: app-users
44 | labels:
45 | app: app-users
46 | data:
47 | logging.level.com.mycompany: DEBUG
48 | management.security.enabled: false
49 | amq.brokerUrl: tcp://amqsvc:61616
50 | amq.username: test
51 | amq.password: secret
52 | spring.datasource.url: jdbc:mariadb://mariadbsvc/testdb
53 | spring.datasource.username: myuser
54 | spring.datasource.password: mypassword
55 | spring.datasource.driver-class-name: org.mariadb.jdbc.Driver
56 | api.url: http://mockserversvc:1080/v1/
57 |
58 | #DB Pod and Service
59 | - apiVersion: v1
60 | kind: Pod
61 | metadata:
62 | name: mariadb
63 | labels:
64 | app: mariadb
65 | spec:
66 | containers:
67 | - name: mariadb
68 | image: registry.access.redhat.com/rhscl/mariadb-102-rhel7:1
69 | resources:
70 | limits:
71 | memory: 256Mi
72 | env:
73 | - name: MYSQL_USER
74 | value: myuser
75 | - name: MYSQL_PASSWORD
76 | value: mypassword
77 | - name: MYSQL_DATABASE
78 | value: testdb
79 | - name: MYSQL_ROOT_PASSWORD
80 | value: secret
81 | readinessProbe:
82 | tcpSocket:
83 | port: 3306
84 | initialDelaySeconds: 5
85 | - apiVersion: v1
86 | kind: Service
87 | metadata:
88 | name: mariadbsvc
89 | spec:
90 | ports:
91 | - port: 3306
92 | targetPort: 3306
93 | selector:
94 | app: mariadb
95 |
96 | #AMQ Pod and Service
97 | - apiVersion: v1
98 | kind: Pod
99 | metadata:
100 | name: amq
101 | labels:
102 | app: amq
103 | spec:
104 | containers:
105 | - name: amq
106 | image: registry.access.redhat.com/jboss-amq-6/amq63-openshift:1.3
107 | resources:
108 | limits:
109 | memory: 256Mi
110 | env:
111 | - name: AMQ_USER
112 | value: test
113 | - name: AMQ_PASSWORD
114 | value: secret
115 | readinessProbe:
116 | tcpSocket:
117 | port: 61616
118 | initialDelaySeconds: 5
119 | ports:
120 | - name: jolokia
121 | containerPort: 8778
122 | protocol: TCP
123 | - apiVersion: v1
124 | kind: Service
125 | metadata:
126 | name: amqsvc
127 | spec:
128 | ports:
129 | - port: 61616
130 | targetPort: 61616
131 | selector:
132 | app: amq
133 |
134 | #External API Third party (provided by mockserver)
135 | - apiVersion: v1
136 | kind: Pod
137 | metadata:
138 | name: mockserver
139 | labels:
140 | app: mockserver
141 | spec:
142 | containers:
143 | - name: mockserver
144 | image: jamesdbloom/mockserver:mockserver-5.3.0
145 | resources:
146 | limits:
147 | memory: 256Mi
148 | env:
149 | - name: LOG_LEVEL
150 | value: INFO
151 | - name: JVM_OPTIONS
152 | value: -Xmx128m
153 | readinessProbe:
154 | tcpSocket:
155 | port: 1080
156 | initialDelaySeconds: 5
157 | - apiVersion: v1
158 | kind: Service
159 | metadata:
160 | name: mockserversvc
161 | spec:
162 | ports:
163 | - port: 1080
164 | targetPort: 1080
165 | selector:
166 | app: mockserver
167 | - apiVersion: v1
168 | kind: Route
169 | metadata:
170 | name: mockserverroute
171 | spec:
172 | to:
173 | kind: Service
174 | name: mockserversvc
--------------------------------------------------------------------------------
/arquillian-test/src/test/resources/arquillian.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | app-users-test.yaml
7 | arquillian
8 | after-namespace.sh
9 | true
10 |
11 |
12 |
--------------------------------------------------------------------------------
/arquillian-test/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %d{HH:mm:ss.SSS} [%16.16thread] %-5level %-30.30logger{30} - %m%n
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/arquillian-test/src/test/resources/sql/sql-load.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE users (
2 | email VARCHAR(256),
3 | phone VARCHAR(64),
4 | ts_created DATETIME DEFAULT CURRENT_TIMESTAMP,
5 | PRIMARY KEY (email)
6 | );
7 | INSERT INTO users (email, phone) VALUES ('testSucc@test.com', '5551234567');
8 | INSERT INTO users (email, phone) VALUES ('testRetry@test.com', '5551230000');
9 | select * from users;
10 | exit
11 |
--------------------------------------------------------------------------------
/configuration/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | redhat-repos
6 |
7 | true
8 |
9 |
10 |
11 | central
12 | http://repo1.maven.org/maven2
13 |
14 | true
15 |
16 |
17 | false
18 |
19 |
20 |
21 | redhatga
22 | Red Hat
23 | http://maven.repository.redhat.com/ga
24 |
25 |
26 | redhatea
27 | Red Hat Early Access
28 | http://maven.repository.redhat.com/earlyaccess/all
29 |
30 |
31 |
32 |
33 |
34 | central
35 | http://repo1.maven.org/maven2
36 |
37 | true
38 |
39 |
40 | false
41 |
42 |
43 |
44 | redhatga
45 | Red Hat
46 | http://maven.repository.redhat.com/ga
47 |
48 |
49 | redhatea
50 | Red Hat Early Access
51 | http://maven.repository.redhat.com/earlyaccess/all
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/integration-test/mockserver/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo Prepare MockServer responses
3 |
4 | json_escape_file () {
5 | [ -f "$1" ] || (echo "File not found! $1"; return 1)
6 | cat "$1" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
7 | }
8 |
9 | #Load all .ok with times=unlimited
10 | for file in $(find ./mockserver/ -name '*.ok'); do
11 | filename=$(basename $file)
12 | id="${filename%.*}"
13 | echo Add $id
14 |
15 | URL="/v1/address/email/$id"
16 | BODY="$(json_escape_file $file)"
17 |
18 | curl -sX PUT "http://localhost:1080/expectation" -d "{
19 | httpRequest : {
20 | path: \"$URL\"
21 | },
22 | httpResponse : {
23 | body: $BODY
24 | },
25 | times: {
26 | unlimited: true
27 | },
28 | timeToLive: {
29 | unlimited: true
30 | }
31 | }"
32 | done
33 |
34 | #Load 2 error then unlimited for testRetry
35 | file="./mockserver/testRetry@test.com.err"
36 | filename=$(basename $file)
37 | id="${filename%.*}"
38 | echo Add $id
39 |
40 | URL="/v1/address/email/$id"
41 | BODY="$(json_escape_file $file)"
42 |
43 | curl -sX PUT "http://localhost:1080/expectation" -d "{
44 | httpRequest : {
45 | path: \"$URL\"
46 | },
47 | httpResponse : {
48 | statusCode: 500
49 | },
50 | times: {
51 | remainingTimes : 2,
52 | unlimited : false
53 | },
54 | timeToLive: {
55 | unlimited: true
56 | }
57 | }"
58 |
59 | curl -sX PUT "http://localhost:1080/expectation" -d "{
60 | httpRequest : {
61 | path: \"$URL\"
62 | },
63 | httpResponse : {
64 | body: $BODY
65 | },
66 | times: {
67 | unlimited: true
68 | },
69 | timeToLive: {
70 | unlimited: true
71 | }
72 | }"
73 |
--------------------------------------------------------------------------------
/integration-test/mockserver/testRetry@test.com.err:
--------------------------------------------------------------------------------
1 | {
2 | "state": "Test State",
3 | "city": "Test City",
4 | "address": "2 Test St",
5 | "zip": "T002"
6 | }
7 |
--------------------------------------------------------------------------------
/integration-test/mockserver/testSucc@test.com.ok:
--------------------------------------------------------------------------------
1 | {
2 | "state": "Test State",
3 | "city": "Test City",
4 | "address": "1 Test St",
5 | "zip": "T001"
6 | }
7 |
--------------------------------------------------------------------------------
/integration-test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.mycompany.k8sit
6 | integration-test
7 | 1.0-SNAPSHOT
8 | Example :: Integration test on Kubernetes with Jenkins pipeline :: Integration Tests
9 |
10 |
11 | UTF-8
12 |
13 | 5.2.0
14 | 5.0.6.RELEASE
15 | 1.2.0
16 | 2.4.0
17 | 5.15.4
18 |
19 | 3.7.0
20 | 2.21.0
21 |
22 |
23 |
24 |
25 |
26 |
27 | org.springframework
28 | spring-framework-bom
29 | ${spring.version}
30 | pom
31 | import
32 |
33 |
34 |
35 | org.junit
36 | junit-bom
37 | ${junit.version}
38 | pom
39 | import
40 |
41 |
42 |
43 | com.jayway.jsonpath
44 | json-path
45 | ${json-path.version}
46 |
47 |
48 |
49 | org.apache.activemq
50 | activemq-client
51 | ${activemq.version}
52 | test
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework
61 | spring-context
62 | test
63 |
64 |
65 |
66 | org.springframework
67 | spring-test
68 | test
69 |
70 |
71 | org.springframework
72 | spring-jms
73 | test
74 |
75 |
76 |
77 | org.apache.activemq
78 | activemq-client
79 | test
80 |
81 |
82 |
83 | com.jayway.jsonpath
84 | json-path
85 | test
86 |
87 |
88 |
89 | org.junit.jupiter
90 | junit-jupiter-api
91 | test
92 |
93 |
94 |
95 | org.slf4j
96 | slf4j-simple
97 | 1.7.22
98 | test
99 |
100 |
101 |
102 |
103 |
104 |
105 | maven-compiler-plugin
106 | ${maven-compiler-plugin.version}
107 |
108 | 1.8
109 | 1.8
110 |
111 |
112 |
113 |
114 | maven-surefire-plugin
115 | ${maven-surefire-plugin.version}
116 |
117 |
118 | org.junit.platform
119 | junit-platform-surefire-provider
120 | ${junit-platform.version}
121 |
122 |
123 |
124 | org.junit.jupiter
125 | junit-jupiter-engine
126 | ${junit.version}
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/integration-test/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo docker rm -f mockserver
3 | sudo docker rm -f mariadb
4 | sudo docker rm -f amq
5 |
6 | sudo docker run --name mockserver -d -p 1080:1080 docker.io/jamesdbloom/mockserver
7 | sudo docker run --name mariadb -e MYSQL_USER=myuser -e MYSQL_PASSWORD=mypassword -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=testdb -d -p 3306:3306 registry.access.redhat.com/rhscl/mariadb-102-rhel7
8 | sudo docker run --name amq -e AMQ_USER=test -e AMQ_PASSWORD=secret -d -p 61616:61616 -p 8181:8181 registry.access.redhat.com/jboss-amq-6/amq63-openshift
9 |
10 | sleep 10
11 |
12 | sh sql/setup.sh
13 | sh mockserver/setup.sh
14 |
15 | cd ../app-users
16 | java -Dspring.profiles.active=k8sit -jar target/app-users-1.0-SNAPSHOT.jar &
17 | pid=$!
18 | cd -
19 |
20 | export AMQ_USER=test
21 | export AMQ_PASSWORD=secret
22 | mvn clean test
23 |
24 | kill $pid
--------------------------------------------------------------------------------
/integration-test/sql/create-tables.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE users (
2 | email VARCHAR(256),
3 | phone VARCHAR(64),
4 | ts_created DATETIME DEFAULT CURRENT_TIMESTAMP,
5 | PRIMARY KEY (email)
6 | );
7 |
--------------------------------------------------------------------------------
/integration-test/sql/load-data.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO users (email, phone) VALUES ('testSucc@test.com', '5551234567');
2 | INSERT INTO users (email, phone) VALUES ('testRetry@test.com', '5551230000');
--------------------------------------------------------------------------------
/integration-test/sql/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | mysql -u myuser -pmypassword -h 127.0.0.1 testdb