blob: 2edc09d993a9d63ecba77fd6ef9d8e4df21b968c [file] [log] [blame]
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -07001#!groovy
2// Copyright 2017 Open Networking Foundation (ONF)
3//
4// Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5// the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6// or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7//
8// TestON is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation, either version 2 of the License, or
11// (at your option) any later version.
12//
13// TestON is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with TestON. If not, see <http://www.gnu.org/licenses/>.
20
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070021import groovy.time.TimeCategory
22import groovy.time.TimeDuration
23
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070024// read the dependency files
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070025graphs = evaluate readTrusted( 'TestON/JenkinsFile/dependencies/JenkinsGraphs.groovy' )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070026test_list = evaluate readTrusted( 'TestON/JenkinsFile/dependencies/JenkinsTestONTests.groovy' )
27fileRelated = evaluate readTrusted( 'TestON/JenkinsFile/dependencies/JenkinsPathAndFiles.groovy' )
28SCPFfuncs = evaluate readTrusted( 'TestON/JenkinsFile/dependencies/PerformanceFuncs.groovy' )
29
30category = null
31prop = null
32testsToRun = null
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -070033testsToRunStrList = null
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070034branch = null
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070035branchWithPrefix = null
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -070036start = null
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070037nodeLabel = null
Jeremy Ronquillo6fbfdd52019-07-09 13:49:34 -070038testStation = null
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070039testsOverride = null
40isGraphOnly = false
41isSCPF = false
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070042testsFromList = [:]
43graphPaths = [:]
44pipeline = [:]
45
46main()
47
48def main(){
49 init()
50 runTests()
Jeremy Ronquillobb3001f2019-07-01 12:57:07 -070051 generateGraphs()
52 sendToSlack()
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070053}
54
55def init(){
56 fileRelated.init()
57 test_list.init()
58 readParams()
59
60 if ( category == "SCPF" ){
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070061 isSCPF = true
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070062 SCPFfuncs.init()
Jeremy Ronquillo442ce4d2019-07-26 16:35:11 -070063 graphs.initialize( SCPFfuncs );
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070064 prop = getProperties()
65 isOldFlow = ( prop[ "isOldFlow" ] == "true" )
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -070066 SCPFfuncs.oldFlowRuleCheck( isOldFlow, prop[ "ONOSBranch" ] )
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -070067 } else {
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070068 isSCPF = false
69 graphs.initialize()
70 prop = getProperties()
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070071 }
72
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070073 // get the list of the test and init branch to it.
74 testsFromList = test_list.getTestsFromCategory( category )
75
76 initGraphPaths()
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070077 tokenizeTokens = "\n;, "
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070078
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070079 if ( testsOverride == "" || testsOverride == null ){
80 testsToRunStrList = prop[ "Tests" ].tokenize( tokenizeTokens )
81 } else {
82 testsToRunStrList = testsOverride.tokenize( tokenizeTokens )
83 }
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -070084 testsToRun = test_list.getTestsFromStringList( testsToRunStrList )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -070085}
86
87def readParams(){
Jeremy Ronquillo6fbfdd52019-07-09 13:49:34 -070088 category = params.Category // "FUNC", "HA", "USECASE", etc.
89 branch = params.Branch // "1.15", "2.1", "master", etc.
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070090 branchWithPrefix = test_list.addPrefixToBranch( branch )
Jeremy Ronquillo6fbfdd52019-07-09 13:49:34 -070091 testStation = params.TestStation // "TestStation-BMs", etc.
92 nodeLabel = params.NodeLabel // "BM", "VM", "Fabric-1.x", etc.
Jeremy Ronquillo336110a2019-07-11 14:20:40 -070093 testsOverride = params.TestsOverride // "FUNCflow, FUNCintent, [...]", overrides property file
94 isGraphOnly = params.OnlyRefreshGraphs // true or false
95}
96
97def getProperties(){
98 // get the properties of the test by reading the TestONOS.property
99
100 filePath = '''/var/jenkins/TestONOS-''' + category + '''-''' + branchWithPrefix + '''.property'''
101
102 node( testStation ) {
103 return readProperties( file: filePath )
104 }
105}
106
107def getCurrentTime(){
108 // get time of the PST zone.
109
110 TimeZone.setDefault( TimeZone.getTimeZone( 'PST' ) )
111 return new Date()
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700112}
113
114def initGraphPaths(){
Jeremy Ronquillo1e5d7f22019-07-17 14:18:42 -0700115 graphPaths.put( "trendIndividual", fileRelated.rScriptPaths[ "scripts" ][ "trendIndividual" ] )
Jeremy Ronquilloa8490fb2019-06-26 11:59:50 -0700116 if ( category == "SR" ){
Jeremy Ronquillo1e5d7f22019-07-17 14:18:42 -0700117 graphPaths.put( "saveDirectory", fileRelated.workspaces[ "base" ] + "postjob-" + ( testStation - "TestStation-" - "s" ) + "/" )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700118 } else if ( category == "SRHA" ) {
Jeremy Ronquillo1e5d7f22019-07-17 14:18:42 -0700119 graphPaths.put( "saveDirectory", fileRelated.workspaces[ "Fabric" ] )
Jeremy Ronquillobb3001f2019-07-01 12:57:07 -0700120 } else if ( category == "SCPF" || category == "USECASE" ){
Jeremy Ronquillo1e5d7f22019-07-17 14:18:42 -0700121 graphPaths.put( "saveDirectory", fileRelated.workspaces[ "BM" ] )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700122 } else {
Jeremy Ronquillo1e5d7f22019-07-17 14:18:42 -0700123 graphPaths.put( "saveDirectory", fileRelated.workspaces[ "VM" ] )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700124 }
125}
126
127def runTests(){
128 // run the test sequentially and save the function into the dictionary.
129 for ( String test : testsToRun.keySet() ){
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700130 toBeRun = test
131 stepName = ( toBeRun ? "" : "Not " ) + "Running $test"
132 pureTestName = ( testsToRun[ test ].containsKey( "test" ) ? testsToRun[ test ][ "test" ].split().head() : test )
133 pipeline[ stepName ] = runTest( test,
134 toBeRun,
135 prop,
136 pureTestName,
137 isGraphOnly,
138 testsToRun,
139 graphPaths[ "trendIndividual" ],
140 graphPaths[ "saveDirectory" ] )
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700141 }
142
143 // get the start time of the test.
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700144 start = getCurrentTime()
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700145
146 // run the tests sequentially.
147 for ( test in pipeline.keySet() ){
148 pipeline[ test ].call()
149 }
150}
151
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700152def initTest(){
153 return '''#!/bin/bash -l
154 set -i # interactive
155 set +e
156 shopt -s expand_aliases # expand alias in non-interactive mode
157 export PYTHONUNBUFFERED=1
158 ifconfig
159 echo "ONOS Branch is: $ONOSBranch"
160 echo "TestON Branch is: $TestONBranch"
161 echo "Test date: "
162 date
163 cd ~
164 export PATH=$PATH:onos/tools/test/bin
165 timeout 240 stc shutdown | head -100
166 timeout 240 stc teardown | head -100
167 timeout 240 stc shutdown | head -100
168 cd ~/OnosSystemTest/TestON/bin
169 git log | head
170 ./cleanup.sh -f || true
171 '''
172}
173
174def runTestCli_py( testName, testCategory ){
175 // Bash script that will run the test.
176 // testName : name of the test
177 // testCategory : (SR,FUNC ... )
178
179 return '''cd ~/OnosSystemTest/TestON/bin
180 ./cli.py run ''' +
181 testName +
182 ''' --params GRAPH/nodeCluster=''' + nodeLabel
183}
184
185def concludeRunTest(){
186 return '''cd ~/OnosSystemTest/TestON/bin
187 ./cleanup.sh -f || true
188 # cleanup config changes
189 cd ~/onos/tools/package/config
190 git clean -df'''
191}
192
193def copyLogs(){
194 // bash script to copy the logs and other necessary element for SR tests.
195
196 result = ""
197 if ( category == "SR" ){
198 result = '''
199 sudo rm /var/jenkins/workspace/SR-log-${WikiPrefix}/*
200 sudo cp *karaf.log.* /var/jenkins/workspace/SR-log-${WikiPrefix}/
201 sudo cp *Flows* /var/jenkins/workspace/SR-log-${WikiPrefix}/
202 sudo cp *Groups* /var/jenkins/workspace/SR-log-${WikiPrefix}/
203 sudo cp *.tar.gz /var/jenkins/workspace/SR-log-${WikiPrefix}/
204 sudo cp t3-* /var/jenkins/workspace/SR-log-${WikiPrefix}/
205 '''
206 }
207 return result
208}
209
210def cleanAndCopyFiles( testName ){
211 // clean up some files that were in the folder and copy the new files from the log
212 // testName : name of the test
213
214 return '''#!/bin/bash -i
215 set +e
216 echo "ONOS Branch is: ${ONOSBranch}"
217 echo "TestON Branch is: ${TestONBranch}"
218 echo "Job name is: "''' + testName + '''
219 echo "Workspace is: ${WORKSPACE}/"
220 echo "Wiki page to post is: ${WikiPrefix}-"
221 # remove any leftover files from previous tests
222 sudo rm ${WORKSPACE}/*Wiki.txt
223 sudo rm ${WORKSPACE}/*Summary.txt
224 sudo rm ${WORKSPACE}/*Result.txt
225 sudo rm ${WORKSPACE}/*Alarm.txt || true
226 sudo rm ${WORKSPACE}/*.csv
227 #copy files to workspace
228 cd `ls -t ~/OnosSystemTest/TestON/logs/*/ | head -1 | sed 's/://'`
229 ''' + copyLogs() + '''
230 sudo cp *.txt ${WORKSPACE}/
231 sudo cp *.csv ${WORKSPACE}/
232 cd ${WORKSPACE}/
233 for i in *.csv
234 do mv "$i" "$WikiPrefix"-"$i"
235 done
236 ls -al
237 cd '''
238}
239
240def fetchLogs( testName ){
241 // fetch the logs of onos from onos nodes to onos System Test logs
242 // testName: name of the test
243
244 return '''#!/bin/bash
245 set +e
246 cd ~/OnosSystemTest/TestON/logs
247 echo "TestON test name is: "''' + testName + '''
248 TestONlogDir=$(ls -t | grep ${TEST_NAME}_ |head -1)
249 echo "########################################################################################"
250 echo "##### copying ONOS logs from all nodes to TestON/logs directory: ${TestONlogDir}"
251 echo "########################################################################################"
252 cd $TestONlogDir
253 if [ $? -eq 1 ]
254 then
255 echo "Job name does not match any test suite name to move log!"
256 else
257 pwd
258 for i in $OC{1..7}; do onos-fetch-logs $i || echo log does not exist for onos $i; done
259 for i in $OC{1..7}; do atomix-fetch-logs $i || echo log does not exist for atomix $i; done
260 fi
261 cd'''
262}
263
264def publishToConfluence( isManualRun, isPostResult, wikiLink, file ){
265 // publish HTML script to wiki confluence
266 // isManualRun : string "true" "false"
267 // isPostResult : string "true" "false"
268 // wikiLink : link of the wiki page to publish
269 // file : name of the file to be published
270
271 if ( isPostingResult( isManualRun, isPostResult ) ){
272 publishConfluence siteName: 'wiki.onosproject.org', pageName: wikiLink, spaceName: 'ONOS',
273 attachArchivedArtifacts: true, buildIfUnstable: true,
274 editorList: [ confluenceWritePage( confluenceFile( file ) ) ]
275 }
276}
277
278def postLogs( testName, prefix ){
279 // posting logs of the onos jobs specifically SR tests
280 // testName : name of the test
281 // prefix : branch prefix ( master, 2.1, 1.15 ... )
282
283 resultURL = ""
284 if ( category == "SR" ){
285 def post = build job: "SR-log-" + prefix, propagate: false
286 resultURL = post.getAbsoluteUrl()
287 }
288 return resultURL
289}
290
291def analyzeResult( prop, workSpace, pureTestName, testName, resultURL, wikiLink, isSCPF ){
292 // analyzing the result of the test and send to slack if any abnormal result is logged.
293 // prop : property dictionary
294 // workSpace : workSpace where the result file is saved
295 // pureTestName : TestON name of the test
296 // testName : Jenkins name of the test. Example: SCPFflowTPFobj
297 // resultURL : url for the logs for SR tests. Will not be posted if it is empty
298 // wikiLink : link of the wiki page where the result was posted
299 // isSCPF : Check if it is SCPF. If so, it won't post the wiki link.
300
301 node( testStation ) {
302 def alarmFile = workSpace + "/" + pureTestName + "Alarm.txt"
303 if ( fileExists( alarmFile ) ) {
304 def alarmContents = readFile( alarmFile )
305 slackSend( channel: "#jenkins-related",
306 color: "FF0000",
307 message: "[" + prop[ "ONOSBranch" ] + "]" + testName + " : triggered alarms:\n" +
308 alarmContents + "\n" +
309 "[TestON log] : \n" +
310 "https://jenkins.onosproject.org/blue/organizations/jenkins/${ env.JOB_NAME }/detail/${ env.JOB_NAME }/${ env.BUILD_NUMBER }/pipeline" +
311 ( isSCPF ? "" : ( "\n[Result on Wiki] : \n" +
312 "https://wiki.onosproject.org/display/ONOS/" +
313 wikiLink.replaceAll( "\\s", "+" ) ) ) +
314 ( resultURL != "" ? ( "\n[Karaf log] : \n" +
315 resultURL + "artifact/" ) : "" ),
316 teamDomain: 'onosproject' )
317 throw new Exception( "Abnormal test result." )
318 }
319 else {
320 print "Test results are OK."
321 }
322 }
323}
324
325def runTest( testName, toBeRun, prop, pureTestName, graphOnly, testCategory, graph_generator_file,
326 graph_saved_directory ){
327 // run the test on the machine that contains all the steps : init and run test, copy files, publish result ...
328 // testName : name of the test in Jenkins
329 // toBeRun : boolean value whether the test will be run or not. If not, it won't be run but shows up with empty
330 // result on pipeline view
331 // prop : dictionary property on the machine
332 // pureTestName : Pure name of the test. ( ex. pureTestName of SCPFflowTpFobj will be SCPFflowTp )
333 // graphOnly : check if it is generating graph job. If so, it will only generate the generating graph part
334 // testCategory : Map for the test suit ( SCPF, SR, FUNC, ... ) which contains information about the tests
335 // graph_generator_file : Rscript file with the full path.
336 // graph_saved_directory : where the generated graph will be saved to.
337
338 return {
339 catchError {
340 stage( testName ) {
341 if ( toBeRun ){
342 def workSpace = "/var/jenkins/workspace/" + testName
343 def fileContents = ""
344 node( testStation ) {
345 withEnv( [ 'ONOSBranch=' + prop[ "ONOSBranch" ],
346 'ONOSJAVAOPTS=' + prop[ "ONOSJAVAOPTS" ],
347 'TestONBranch=' + prop[ "TestONBranch" ],
348 'ONOSTag=' + prop[ "ONOSTag" ],
349 'WikiPrefix=' + prop[ "WikiPrefix" ],
350 'WORKSPACE=' + workSpace ] ) {
351 if ( !graphOnly ){
352 if ( isSCPF ){
353 // Remove the old database file
354 sh SCPFfuncs.cleanupDatabaseFile( testName )
355 }
356 sh script: initTest(), label: "Test Initialization: stc shutdown; stc teardown; ./cleanup.sh"
357 catchError{
358 sh script: runTestCli_py( testName, testCategory ), label: ( "Run Test: ./cli.py run " + testName )
359 }
360 catchError{
361 sh script: concludeRunTest(), label: "Conclude Running Test: ./cleanup.sh; git clean -df"
362 }
363 catchError{
364 // For the Wiki page
365 sh script: cleanAndCopyFiles( pureTestName ), label: "Clean and Copy Files"
366 }
367 }
368 graphs.databaseAndGraph( prop, testName, pureTestName, graphOnly,
369 graph_generator_file, graph_saved_directory )
370 if ( !graphOnly ){
371 sh script: fetchLogs( pureTestName ), label: "Fetch Logs"
372 if ( !isSCPF ){
373 publishToConfluence( prop[ "manualRun" ], prop[ "postResult" ],
374 prop[ "WikiPrefix" ] + "-" + testCategory[ testName ][ 'wikiName' ],
375 workSpace + "/" + testCategory[ testName ][ 'wikiFile' ] )
376 }
377 }
378 }
379 }
380 graphs.postResult( prop, graphOnly, nodeLabel )
381 if ( !graphOnly ){
382 def resultURL = postLogs( testName, prop[ "WikiPrefix" ] )
383 analyzeResult( prop, workSpace, pureTestName, testName, resultURL,
384 isSCPF ? "" : testCategory[ testName ][ 'wikiName' ],
385 isSCPF )
386 }
387 }
388 }
389 }
390 }
391}
392
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700393def generateGraphs(){
Jeremy Ronquillo06950992019-07-09 11:16:49 -0700394 if ( category != "SCPF" ){
395 // generate the overall graph of the non SCPF tests.
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700396 graphs.generateOverallGraph( prop, testsToRun, graphPaths[ "saveDirectory" ], nodeLabel, category )
Jeremy Ronquillobb3001f2019-07-01 12:57:07 -0700397 }
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700398}
399
400def sendToSlack(){
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700401 // send the result of the test to the slack when it is not manually running.
402 // start : start time of the test
403 // isManualRun : string that is whether "false" or "true"
404 // branch : branch of the onos.
405
406 try {
407 if ( prop[ "manualRun" ] == "false" ){
408 end = getCurrentTime()
409 TimeDuration duration = TimeCategory.minus( end, start )
410 // FIXME: for now we disable notifications of normal test results
411 /*
412 slackSend( color: "#5816EE",
413 message: category + "-" + prop[ "WikiPrefix" ] + " tests ended at: " + end.toString() +
414 "\nTime took : " + duration )
415 */
416 }
417 }
418 catch ( all ){
419 }
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700420}