blob: 038331867de8d27e52922440873b3406412900bf [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
Jeremy Ronquilloe4e83912019-07-29 12:58:48 -0700264def isPostingResult( manual, postresult ){
265 // check if it is posting the result.
266 // posting when it is automatically running or has postResult condition from the manual run
267
268 return manual == "false" || postresult == "true"
269}
270
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700271def publishToConfluence( isManualRun, isPostResult, wikiLink, file ){
272 // publish HTML script to wiki confluence
273 // isManualRun : string "true" "false"
274 // isPostResult : string "true" "false"
275 // wikiLink : link of the wiki page to publish
276 // file : name of the file to be published
277
278 if ( isPostingResult( isManualRun, isPostResult ) ){
279 publishConfluence siteName: 'wiki.onosproject.org', pageName: wikiLink, spaceName: 'ONOS',
280 attachArchivedArtifacts: true, buildIfUnstable: true,
281 editorList: [ confluenceWritePage( confluenceFile( file ) ) ]
282 }
283}
284
285def postLogs( testName, prefix ){
286 // posting logs of the onos jobs specifically SR tests
287 // testName : name of the test
288 // prefix : branch prefix ( master, 2.1, 1.15 ... )
289
290 resultURL = ""
291 if ( category == "SR" ){
292 def post = build job: "SR-log-" + prefix, propagate: false
293 resultURL = post.getAbsoluteUrl()
294 }
295 return resultURL
296}
297
298def analyzeResult( prop, workSpace, pureTestName, testName, resultURL, wikiLink, isSCPF ){
299 // analyzing the result of the test and send to slack if any abnormal result is logged.
300 // prop : property dictionary
301 // workSpace : workSpace where the result file is saved
302 // pureTestName : TestON name of the test
303 // testName : Jenkins name of the test. Example: SCPFflowTPFobj
304 // resultURL : url for the logs for SR tests. Will not be posted if it is empty
305 // wikiLink : link of the wiki page where the result was posted
306 // isSCPF : Check if it is SCPF. If so, it won't post the wiki link.
307
308 node( testStation ) {
309 def alarmFile = workSpace + "/" + pureTestName + "Alarm.txt"
310 if ( fileExists( alarmFile ) ) {
311 def alarmContents = readFile( alarmFile )
312 slackSend( channel: "#jenkins-related",
313 color: "FF0000",
314 message: "[" + prop[ "ONOSBranch" ] + "]" + testName + " : triggered alarms:\n" +
315 alarmContents + "\n" +
316 "[TestON log] : \n" +
317 "https://jenkins.onosproject.org/blue/organizations/jenkins/${ env.JOB_NAME }/detail/${ env.JOB_NAME }/${ env.BUILD_NUMBER }/pipeline" +
318 ( isSCPF ? "" : ( "\n[Result on Wiki] : \n" +
319 "https://wiki.onosproject.org/display/ONOS/" +
320 wikiLink.replaceAll( "\\s", "+" ) ) ) +
321 ( resultURL != "" ? ( "\n[Karaf log] : \n" +
322 resultURL + "artifact/" ) : "" ),
323 teamDomain: 'onosproject' )
Jeremy Ronquilloe4e83912019-07-29 12:58:48 -0700324 print "Abnormal test result."
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700325 throw new Exception( "Abnormal test result." )
326 }
327 else {
328 print "Test results are OK."
329 }
330 }
331}
332
333def runTest( testName, toBeRun, prop, pureTestName, graphOnly, testCategory, graph_generator_file,
334 graph_saved_directory ){
335 // run the test on the machine that contains all the steps : init and run test, copy files, publish result ...
336 // testName : name of the test in Jenkins
337 // toBeRun : boolean value whether the test will be run or not. If not, it won't be run but shows up with empty
338 // result on pipeline view
339 // prop : dictionary property on the machine
340 // pureTestName : Pure name of the test. ( ex. pureTestName of SCPFflowTpFobj will be SCPFflowTp )
341 // graphOnly : check if it is generating graph job. If so, it will only generate the generating graph part
342 // testCategory : Map for the test suit ( SCPF, SR, FUNC, ... ) which contains information about the tests
343 // graph_generator_file : Rscript file with the full path.
344 // graph_saved_directory : where the generated graph will be saved to.
345
346 return {
347 catchError {
348 stage( testName ) {
349 if ( toBeRun ){
350 def workSpace = "/var/jenkins/workspace/" + testName
351 def fileContents = ""
352 node( testStation ) {
353 withEnv( [ 'ONOSBranch=' + prop[ "ONOSBranch" ],
354 'ONOSJAVAOPTS=' + prop[ "ONOSJAVAOPTS" ],
355 'TestONBranch=' + prop[ "TestONBranch" ],
356 'ONOSTag=' + prop[ "ONOSTag" ],
357 'WikiPrefix=' + prop[ "WikiPrefix" ],
358 'WORKSPACE=' + workSpace ] ) {
359 if ( !graphOnly ){
360 if ( isSCPF ){
361 // Remove the old database file
362 sh SCPFfuncs.cleanupDatabaseFile( testName )
363 }
364 sh script: initTest(), label: "Test Initialization: stc shutdown; stc teardown; ./cleanup.sh"
365 catchError{
366 sh script: runTestCli_py( testName, testCategory ), label: ( "Run Test: ./cli.py run " + testName )
367 }
368 catchError{
369 sh script: concludeRunTest(), label: "Conclude Running Test: ./cleanup.sh; git clean -df"
370 }
371 catchError{
372 // For the Wiki page
373 sh script: cleanAndCopyFiles( pureTestName ), label: "Clean and Copy Files"
374 }
375 }
376 graphs.databaseAndGraph( prop, testName, pureTestName, graphOnly,
377 graph_generator_file, graph_saved_directory )
378 if ( !graphOnly ){
379 sh script: fetchLogs( pureTestName ), label: "Fetch Logs"
380 if ( !isSCPF ){
381 publishToConfluence( prop[ "manualRun" ], prop[ "postResult" ],
382 prop[ "WikiPrefix" ] + "-" + testCategory[ testName ][ 'wikiName' ],
383 workSpace + "/" + testCategory[ testName ][ 'wikiFile' ] )
384 }
385 }
386 }
387 }
388 graphs.postResult( prop, graphOnly, nodeLabel )
389 if ( !graphOnly ){
390 def resultURL = postLogs( testName, prop[ "WikiPrefix" ] )
391 analyzeResult( prop, workSpace, pureTestName, testName, resultURL,
392 isSCPF ? "" : testCategory[ testName ][ 'wikiName' ],
393 isSCPF )
394 }
395 }
396 }
397 }
398 }
399}
400
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700401def generateGraphs(){
Jeremy Ronquillo06950992019-07-09 11:16:49 -0700402 if ( category != "SCPF" ){
403 // generate the overall graph of the non SCPF tests.
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700404 graphs.generateOverallGraph( prop, testsToRun, graphPaths[ "saveDirectory" ], nodeLabel, category )
Jeremy Ronquillobb3001f2019-07-01 12:57:07 -0700405 }
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700406}
407
408def sendToSlack(){
Jeremy Ronquillo336110a2019-07-11 14:20:40 -0700409 // send the result of the test to the slack when it is not manually running.
410 // start : start time of the test
411 // isManualRun : string that is whether "false" or "true"
412 // branch : branch of the onos.
413
414 try {
415 if ( prop[ "manualRun" ] == "false" ){
416 end = getCurrentTime()
417 TimeDuration duration = TimeCategory.minus( end, start )
418 // FIXME: for now we disable notifications of normal test results
419 /*
420 slackSend( color: "#5816EE",
421 message: category + "-" + prop[ "WikiPrefix" ] + " tests ended at: " + end.toString() +
422 "\nTime took : " + duration )
423 */
424 }
425 }
426 catch ( all ){
427 }
Jeremy Ronquillo21c29fc2019-06-05 11:15:24 -0700428}