2 Documentation General Utils library. This library has broad scope, it can be used by any robot system tests.
9 Library RequestsLibrary
10 Library OperatingSystem
11 Library ${CURDIR}/UtilLibrary.py
12 Resource ${CURDIR}/SSHKeywords.robot
13 Resource ${CURDIR}/TemplatedRequests.robot
14 Resource ${CURDIR}/../variables/Variables.robot
15 Resource ${CURDIR}/../variables/openflowplugin/Variables.robot
19 # TODO: Introduce ${tree_size} and use instead of 1 in the next line.
20 ${start} sudo mn --controller=remote,ip=${ODL_SYSTEM_IP} --topo tree,1 --switch ovsk,protocols=OpenFlow13
25 [Documentation] Basic setup/cleanup work that can be done safely before any system
27 [Arguments] ${system}=${TOOLS_SYSTEM_IP} ${user}=${TOOLS_SYSTEM_USER} ${password}=${TOOLS_SYSTEM_PASSWORD} ${prompt}=${TOOLS_SYSTEM_PROMPT} ${timeout}=30s
28 Log Start the test on the base edition
30 ${mininet_conn_id}= Open Connection ${system} prompt=${prompt} timeout=${timeout}
31 Set Suite Variable ${mininet_conn_id}
32 SSHKeywords.Flexible Mininet Login user=${user} password=${password}
33 Execute Command sudo ovs-vsctl set-manager ptcp:6644
38 [Documentation] Cleanup/Shutdown work that should be done at the completion of all
40 [Arguments] ${prompt}=${TOOLS_SYSTEM_PROMPT}
41 Log Stop the test on the base edition
42 Switch Connection ${mininet_conn_id}
48 Report Failure Due To Bug
49 [Documentation] Report that a test failed due to a known Bugzilla bug whose
50 ... number is provided as an argument.
51 ... Not FAILED (incl. SKIPPED) test are not reported.
52 ... This keyword must be used in the [Teardown] setting of the affected test
53 ... or as the first line of the test if FastFail module is not being
54 ... used. It reports the URL of the bug on console and also puts it
55 ... into the Robot log file.
56 [Arguments] ${number} ${include_bug_in_tags}=True
57 ${test_skipped}= BuiltIn.Evaluate len(re.findall('SKIPPED', """${TEST_MESSAGE}""")) > 0 modules=re
58 IF ('${TEST_STATUS}' != 'FAIL') or ${test_skipped} RETURN
59 Comment Jira tickets are {PROJECT}-{NUMBER} while Bugzilla tickets are {NUMBER}
60 ${match}= BuiltIn.Run Keyword And Return Status Should Contain ${number} -
61 ${bug_url}= BuiltIn.Set Variable If
63 ... https://jira.opendaylight.org/browse/${number}
64 ... https://bugs.opendaylight.org/show_bug.cgi?id=${number}
65 ${msg}= BuiltIn.Set_Variable This test fails due to ${bug_url}
66 ${newline}= BuiltIn.Evaluate chr(10)
67 BuiltIn.Set Test Message ${msg}${newline}${newline}${TEST_MESSAGE}
69 IF "${include_bug_in_tags}"=="True" Set Tags ${bug_url}
71 Report_Failure_And_Point_To_Linked_Bugs
72 [Documentation] Report that a test failed and point to linked Bugzilla bug(s).
73 ... Linked bugs must contain the ${reference} inside comments (workaround
74 ... becasue of currently missing suitable field for external references and
75 ... not correctly working the CONTENT MATCHES filter).
76 ... Not FAILED (incl. SKIPPED) test are not reported.
77 ... This keyword must be used in the [Teardown] setting of the affected test
78 ... or as the first line of the test if FastFail module is not being
79 ... used. It reports the URL of the bug on console and also puts it
80 ... into the Robot log file.
81 ${test_skipped}= BuiltIn.Evaluate len(re.findall('SKIPPED', """${TEST_MESSAGE}""")) > 0 modules=re
82 IF ('${TEST_STATUS}' != 'FAIL') or ${test_skipped} RETURN
83 ${newline}= BuiltIn.Evaluate chr(10)
84 ${reference}= String.Replace_String_Using_Regexp ${SUITE_NAME}_${TEST_NAME} [ /\.-] _
85 ${reference}= String.Convert_To_Lowercase ${reference}
86 ${msg}= BuiltIn.Set_Variable
87 ... ... click for list of related bugs or create a new one if needed (with the${newline}"${reference}"${newline}reference somewhere inside)
88 ${bugs}= BuiltIn.Set_Variable
89 ... "https://bugs.opendaylight.org/buglist.cgi?f1=cf_external_ref&o1=substring&v1=${reference}&order=bug_status"
90 BuiltIn.Set Test Message ${msg}${newline}${bugs}${newline}${newline}${TEST_MESSAGE}
91 BuiltIn.Log ${msg}${newline}${bugs}
94 [Documentation] A GET on the /node/${node} API is made and specific flow stat
95 ... strings are checked for existence.
96 [Arguments] ${node} ${session}=session
97 ${resp}= RequestsLibrary.Get Request
99 ... ${RFC8040_NODES_API}/node=${node}?${RFC8040_OPERATIONAL_CONTENT}
100 Should Be Equal As Strings ${resp.status_code} 200
101 Should Contain ${resp.text} flow-capable-node-connector-statistics
102 Should Contain ${resp.text} flow-table-statistics
104 Check For Specific Number Of Elements At URI
105 [Documentation] A GET is made to the specified ${URI} and the specific count of a
106 ... given element is done (as supplied by ${element} and ${expected_count})
107 [Arguments] ${uri} ${element} ${expected_count} ${session}=session
108 ${resp}= RequestsLibrary.Get Request ${session} ${uri}
110 Should Be Equal As Strings ${resp.status_code} 200
111 Should Contain X Times ${resp.text} ${element} ${expected_count}
114 [Arguments] ${resp_content}
115 IF '''${resp_content}''' != '${EMPTY}'
116 ${resp_json}= RequestsLibrary.To Json ${resp_content} pretty_print=True
118 ${resp_json}= BuiltIn.Set Variable ${EMPTY}
120 BuiltIn.Log ${resp_json}
123 Check For Elements At URI
124 [Documentation] A GET is made at the supplied ${URI} and every item in the list of
125 ... ${elements} is verified to exist in the response
126 [Arguments] ${uri} ${elements} ${session}=session ${pretty_print_json}=False
127 ${resp}= RequestsLibrary.Get Request ${session} ${uri}
128 IF "${pretty_print_json}" == "True"
129 Log Content ${resp.text}
131 BuiltIn.Log ${resp.text}
133 Should Be Equal As Strings ${resp.status_code} 200
134 FOR ${i} IN @{elements}
135 Should Contain ${resp.text} ${i}
138 Check For Elements Not At URI
139 [Documentation] A GET is made at the supplied ${uri} and every item in the list of
140 ... ${elements} is verified to NOT exist in the response. If ${check_for_null} is True
141 ... return of 404 is treated as empty list. From Neon onwards, an empty list is always
142 ... returned as null, giving 404 on rest call.
143 [Arguments] ${uri} ${elements} ${session}=session ${pretty_print_json}=False ${check_for_null}=False
144 ${resp}= RequestsLibrary.Get Request ${session} ${uri}
145 IF "${pretty_print_json}" == "True"
146 Log Content ${resp.text}
148 BuiltIn.Log ${resp.text}
150 IF "${check_for_null}" == "True"
151 IF ${resp.status_code} == 404 or ${resp.status_code} == 409 RETURN
153 Should Be Equal As Strings ${resp.status_code} 200
154 FOR ${i} IN @{elements}
155 Should Not Contain ${resp.text} ${i}
159 [Arguments] ${system}=${TOOLS_SYSTEM_IP}
160 Run Command On Mininet ${system} sudo mn -c
161 Run Command On Mininet
163 ... sudo ps -elf | egrep 'usr/local/bin/mn' | egrep python | awk '{print "sudo kill -9",$4}' | sh
166 [Documentation] Cleans up the OVS instance and remove any existing common known bridges.
167 [Arguments] ${system}=${TOOLS_SYSTEM_IP}
168 ${output}= Run Command On Mininet ${system} sudo ovs-vsctl list-br
170 FOR ${i} IN ${output}
171 Run Command On Mininet ${system} sudo ovs-vsctl --if-exists del-br ${i}
173 Run Command On Mininet ${system} sudo ovs-vsctl del-manager
175 Extract Value From Content
176 [Documentation] Will take the given response content and return the value at the given index as a string
177 [Arguments] ${content} ${index}
178 ${JSON}= Evaluate json.loads('''${content}''') json
179 ${value}= Set Variable ${JSON${index}}
182 Get Process ID Based On Regex On Remote System
183 [Documentation] Uses ps to find a process that matches the supplied regex. Returns the PID of that process
184 ... The ${regex_string_to_match_on} should produce a unique process otherwise the PID returned may not be
186 [Arguments] ${system} ${regex_string_to_match_on} ${user}=${TOOLS_SYSTEM_USER} ${password}=${EMPTY} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=30s
187 # doing the extra -v grep in this command to exclude the grep process itself from the output
188 ${cmd}= Set Variable ps -elf | grep -v grep | grep ${regex_string_to_match_on} | awk '{print $4}'
189 ${output}= Run Command On Remote System
193 ... password=${password}
195 ... prompt_timeout=${prompt_timeout}
196 # ${output} contains the system prompt and all we want is the value of the number
197 ${pid}= Fetch From Left ${output} \r
200 # ... Should there be * On Mininet and * On Controller specializations?
201 # TODO: Get Process * keywords have perhaps non-standard default credentials.
203 Get Process Thread Count On Remote System
204 [Documentation] Executes the ps command to retrieve the lightweight process (aka thread) count.
205 [Arguments] ${system} ${pid} ${user}=${TOOLS_SYSTEM_USER} ${password}=${EMPTY} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=30s
206 ${cmd}= Set Variable ps --no-headers -o nlwp ${pid}
207 ${output}= Run Command On Remote System
211 ... password=${password}
213 ... prompt_timeout=${prompt_timeout}
214 # ${output} contains the system prompt and all we want is the value of the number
215 ${thread_count}= Fetch From Left ${output} \r
216 RETURN ${thread_count}
219 [Documentation] Will strip ALL quotes from given string and return the new string
220 [Arguments] ${string_to_strip}
221 ${string_to_return}= Replace String ${string_to_strip} " \ count=-1
222 RETURN ${string_to_return}
224 Run Command On Remote System
225 [Documentation] Reduces the common work of running a command on a remote system to a single higher level
226 ... robot keyword, taking care to log in with a public key and. The command given is written and the return value
227 ... depends on the passed argument values of return_stdout (default: True) and return_stderr (default: False).
228 ... At least one should be True, or the keyword will exit and FAIL. If both are True, the resulting return value
229 ... will be a two element list containing both. Otherwise the resulting return value is a string.
230 ... No test conditions are checked.
231 [Arguments] ${system} ${cmd} ${user}=${DEFAULT_USER} ${password}=${EMPTY} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=${DEFAULT_TIMEOUT}
232 ... ${return_stdout}=True ${return_stderr}=False
233 IF "${return_stdout}"!="True" and "${return_stderr}"!="True"
234 Fail At least one of {return_stdout} or {return_stderr} args should be set to True
236 ${current_ssh_connection}= SSHLibrary.Get Connection
238 ... Attempting to execute command "${cmd}" on remote system "${system}" by user "${user}" with keyfile pass "${keyfile_pass}" and prompt "${prompt}" and password "${password}"
239 ${conn_id}= SSHLibrary.Open Connection ${system} prompt=${prompt} timeout=${prompt_timeout}
240 SSHKeywords.Flexible SSH Login ${user} ${password}
241 ${stdout} ${stderr}= SSHLibrary.Execute Command ${cmd} return_stderr=True
242 SSHLibrary.Close Connection
244 IF "${return_stdout}"!="True" RETURN ${stderr}
245 IF "${return_stderr}"!="True" RETURN ${stdout}
246 RETURN ${stdout} ${stderr}
247 [Teardown] SSHKeywords.Restore_Current_SSH_Connection_From_Index ${current_ssh_connection.index}
249 Run Command On Remote System And Log
250 [Documentation] Reduces the common work of running a command on a remote system to a single higher level
251 ... robot keyword, taking care to log in with a public key and. The command given is written
252 ... and the output returned. No test conditions are checked.
253 [Arguments] ${system} ${cmd} ${user}=${DEFAULT_USER} ${password}=${EMPTY} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=${DEFAULT_TIMEOUT}
254 ${output}= Run Command On Remote System ${system} ${cmd} ${user} ${password} ${prompt}
255 ... ${prompt_timeout}
259 Run Command On Mininet
260 [Documentation] Call Run Comand On Remote System, but with default values suitable for Mininet machine.
261 [Arguments] ${system}=${TOOLS_SYSTEM_IP} ${cmd}=echo ${user}=${TOOLS_SYSTEM_USER} ${password}=${TOOLS_SYSTEM_PASSWORD} ${prompt}=${TOOLS_SYSTEM_PROMPT}
262 BuiltIn.Run Keyword And Return
263 ... Run Command On Remote System
270 Run Command On Controller
271 [Documentation] Call Run Comand On Remote System, but with default values suitable for Controller machine.
272 [Arguments] ${system}=${ODL_SYSTEM_IP} ${cmd}=echo ${user}=${ODL_SYSTEM_USER} ${password}=${ODL_SYSTEM_PASSWORD} ${prompt}=${ODL_SYSTEM_PROMPT}
273 BuiltIn.Run Keyword And Return
274 ... Run Command On Remote System
281 Run Command On Existing Connection
282 [Documentation] Switch to and run command on an already existing SSH connection and switch back
283 [Arguments] ${conn_id}=${EMPTY} ${cmd}=echo ${return_stdout}=True ${return_stderr}=False
284 IF "${return_stdout}"!="True" and "${return_stderr}"!="True"
285 Fail At least one of {return_stdout} or {return_stderr} args should be set to True
287 ${current_ssh_connection}= SSHLibrary.Get Connection
288 BuiltIn.Log Attempting to execute command "${cmd}" on existing connection "${conn_id}
289 SSHLibrary.Switch Connection ${conn_id}
290 ${stdout} ${stderr}= SSHLibrary.Execute Command ${cmd} return_stderr=True
292 IF "${return_stdout}"!="True" RETURN ${stderr}
293 IF "${return_stderr}"!="True" RETURN ${stdout}
294 RETURN ${stdout} ${stderr}
295 [Teardown] SSHKeywords.Restore_Current_SSH_Connection_From_Index ${current_ssh_connection.index}
297 Verify File Exists On Remote System
298 [Documentation] Will create connection with public key and will PASS if the given ${file} exists,
299 ... otherwise will FAIL
300 [Arguments] ${system} ${file} ${user}=${TOOLS_SYSTEM_USER} ${password}=${TOOLS_SYSTEM_PASSWORD} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=5s
301 ${conn_id}= Open Connection ${system} prompt=${prompt} timeout=${prompt_timeout}
302 SSHKeywords.Flexible SSH Login ${user} ${password}
303 SSHLibrary.File Should Exist ${file}
306 Check Karaf Log File Does Not Have Messages
307 [Documentation] Fails if the provided ${message} is found in the karaf.log file. Uses grep to search. The
308 ... karaf.log file can be overridden with ${log_file} to be any file on the given system @ ${ip}
309 [Arguments] ${ip} ${message} ${user}=${ODL_SYSTEM_USER} ${password}=${ODL_SYSTEM_PASSWORD} ${prompt}=${ODL_SYSTEM_PROMPT} ${log_file}=${WORKSPACE}/${BUNDLEFOLDER}/data/log/karaf.log
310 ${output}= Run Command On Controller
312 ... grep -c '${message}' ${log_file}
314 ... password=${password}
316 Should Be Equal As Strings ${output} 0
318 Verify Controller Is Not Dead
319 [Documentation] Will execute any tests to verify the controller is not dead. Some checks are
320 ... Out Of Memory Execptions.
321 [Arguments] ${controller_ip}=${ODL_SYSTEM_IP}
322 Check Karaf Log File Does Not Have Messages ${controller_ip} java.lang.OutOfMemoryError
323 # TODO: Should Verify Controller * keywords also accept user, password, prompt and karaf_log arguments?
325 Verify Controller Has No Null Pointer Exceptions
326 [Documentation] Will execute any tests to verify the controller is not having any null pointer eceptions.
327 [Arguments] ${controller_ip}=${ODL_SYSTEM_IP}
328 Check Karaf Log File Does Not Have Messages ${controller_ip} java.lang.NullPointerException
330 Verify Controller Has No Runtime Exceptions
331 [Documentation] Will execute any tests to verify the controller is not having any runtime eceptions.
332 [Arguments] ${controller_ip}=${ODL_SYSTEM_IP}
333 Check Karaf Log File Does Not Have Messages ${controller_ip} java.lang.RuntimeException
336 [Documentation] Get the Epoc time from MM/DD/YYYY HH:MM:SS
338 ${epoch_time}= Convert Date ${time} epoch exclude_milles=True date_format=%m/%d/%Y %H:%M:%S
339 ${epoch_time}= Convert To Integer ${epoch_time}
342 Remove Space on String
343 [Documentation] Remove the empty space from given string.count is optional,if its given
344 ... that many occurence of space will be removed from left
345 [Arguments] ${str} ${count}=-1
346 ${x}= Convert To String ${str}
347 ${x}= Replace String ${str} ${SPACE} ${EMPTY} count=${count}
350 Split Value from String
351 [Documentation] Split the String based on given splitter and return as list
352 [Arguments] ${str} ${splitter}
353 @{x}= Split String ${str} ${splitter}
356 Concatenate the String
357 [Documentation] Catenate the two non-string objects and return as String
358 [Arguments] ${str1} ${str2}
359 ${str1}= Convert to String ${str1}
360 ${str2}= Convert to String ${str2}
361 ${output}= Catenate ${str1} ${str2}
365 [Documentation] Perform a POST rest operation, using the URL and data provided
366 [Arguments] ${rest_uri} ${data} ${headers}=${headers} ${session}=session
367 ${resp}= RequestsLibrary.Post Request ${session} ${rest_uri} data=${data} headers=${headers}
369 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
371 Remove All Elements At URI
372 [Arguments] ${uri} ${session}=session
373 ${resp}= RequestsLibrary.Delete Request ${session} ${uri}
374 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
376 Remove All Elements At URI And Verify
377 [Arguments] ${uri} ${session}=session
378 ${resp}= RequestsLibrary.Delete Request ${session} ${uri}
379 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
380 ${resp}= RequestsLibrary.Get Request ${session} ${uri}
381 Should Contain ${DELETED_STATUS_CODES} ${resp.status_code}
383 Remove All Elements If Exist
384 [Documentation] Delete all elements from an URI if the configuration was not empty
385 [Arguments] ${uri} ${session}=session
386 ${resp}= RequestsLibrary.Get Request ${session} ${uri}
387 IF '${resp.status_code}'!='404' and '${resp.status_code}'!='409'
388 Remove All Elements At URI ${uri} ${session}
391 Add Elements To URI From File
392 [Documentation] Put data from a file to a URI
393 [Arguments] ${dest_uri} ${data_file} ${headers}=${headers} ${session}=session
394 ${body}= OperatingSystem.Get File ${data_file}
395 ${resp}= RequestsLibrary.Put Request ${session} ${dest_uri} data=${body} headers=${headers}
396 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
398 Add Elements To URI From File And Verify
399 [Documentation] Put data from a file to a URI and verify the HTTP response
400 [Arguments] ${dest_uri} ${data_file} ${headers}=${headers} ${session}=session
401 ${body}= OperatingSystem.Get File ${data_file}
402 Add Elements to URI And Verify ${dest_uri} ${body} ${headers} ${session}
404 Add Elements To URI And Verify
405 [Documentation] Put data to a URI and verify the HTTP response
406 [Arguments] ${dest_uri} ${data} ${headers}=${headers} ${session}=session
407 ${resp}= RequestsLibrary.Put Request ${session} ${dest_uri} ${data} headers=${headers}
408 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
409 ${resp}= RequestsLibrary.Get Request ${session} ${dest_uri}
410 Should Not Contain ${DELETED_STATUS_CODES} ${resp.status_code}
412 Add Elements To URI From File And Check Validation Error
413 [Documentation] Shorthand for PUTting data from file and expecting status code 400.
414 [Arguments] ${dest_uri} ${data_file} ${headers}=${headers} ${session}=session
415 BuiltIn.Comment TODO: Does this have any benefits, considering TemplatedRequests can also do this in one line?
416 ${body}= OperatingSystem.Get File ${data_file}
417 ${resp}= RequestsLibrary.Put Request ${session} ${dest_uri} data=${body} headers=${headers}
418 Should Contain ${DATA_VALIDATION_ERROR} ${resp.status_code}
420 Add Elements To URI From File And Check Server Error
421 [Documentation] Shorthand for PUTting data from file and expecting status code 500.
422 ... Consider opening a Bug against ODL, as in most test cases, 400 is the http code to expect.
423 [Arguments] ${dest_uri} ${data_file} ${headers}=${headers} ${session}=session
424 BuiltIn.Comment TODO: Does this have any benefits, considering TemplatedRequests can also do this in one line?
425 ${body}= OperatingSystem.Get File ${data_file}
426 ${resp}= RequestsLibrary.Put Request ${session} ${dest_uri} data=${body} headers=${headers}
427 Should Contain ${INTERNAL_SERVER_ERROR} ${resp.status_code}
429 Post Elements To URI From File
430 [Arguments] ${dest_uri} ${data_file} ${headers}=${headers} ${session}=session
431 ${body}= OperatingSystem.Get File ${data_file}
432 ${resp}= RequestsLibrary.Post Request ${session} ${dest_uri} data=${body} headers=${headers}
433 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
435 Run Process With Logging And Status Check
436 [Documentation] Execute an OS command, log STDOUT and STDERR output and check exit code to be 0
437 [Arguments] @{proc_args}
438 ${result}= Run Process @{proc_args}
441 Should Be Equal As Integers ${result.rc} 0
445 [Documentation] Issue a GET request and return the data obtained or on error log the error and fail.
446 ... Issues a GET request for ${uri} in ${session} using headers from
447 ... ${headers}. If the request returns a HTTP error, fails. Otherwise
448 ... returns the data obtained by the request.
449 [Arguments] ${session} ${uri} ${headers}=${NONE}
450 ${resp}= RequestsLibrary.Get Request ${session} ${uri} ${headers}
451 IF ${resp.status_code} == 200 RETURN ${resp.text}
452 Builtin.Log ${resp.text}
453 Builtin.Fail The request failed with code ${resp.status_code}
456 [Documentation] Issue a GET request and verify a successfull HTTP return.
457 ... Issues a GET request for ${uri} in ${session} using headers from ${headers}.
458 [Arguments] ${uri} ${session}=session ${headers}=${NONE}
459 ${resp}= RequestsLibrary.Get Request ${session} ${uri} ${headers}
460 Builtin.Log ${resp.status_code}
461 Should Contain ${ALLOWED_STATUS_CODES} ${resp.status_code}
464 [Documentation] Issue a GET request and return on error 404 (No content) or will fail and log the content.
465 ... Issues a GET request for ${uri} in ${session} using headers from
466 ... ${headers}. If the request returns a HTTP error, fails. Otherwise
467 ... returns the data obtained by the request.
468 [Arguments] ${session} ${uri} ${headers}=${NONE}
469 ${resp}= RequestsLibrary.Get Request ${session} ${uri} ${headers}
470 IF ${resp.status_code} == 404 or ${resp.status_code} == 409 RETURN
471 Builtin.Log ${resp.text}
472 Builtin.Fail The request failed with code ${resp.status_code}
474 Get Index From List Of Dictionaries
475 [Documentation] Extract index for the dictionary in a list that contains a key-value pair. Returns -1 if key-value is not found.
476 [Arguments] ${dictionary_list} ${key} ${value}
477 ${length}= Get Length ${dictionary_list}
478 ${index}= Set Variable -1
479 FOR ${i} IN RANGE ${length}
480 ${dictionary}= Get From List ${dictionary_list} ${i}
481 IF """${dictionary}[${key}]""" == """${value}"""
482 Set Test Variable ${index} ${i}
487 Check Item Occurrence
488 [Documentation] Check string for occurrences of items expressed in a list of dictionaries {item=occurrences}. 0 occurences means item is not present.
489 [Arguments] ${string} ${dictionary_item_occurrence}
490 FOR ${item} IN @{dictionary_item_occurrence}
491 Should Contain X Times ${string} ${item} ${dictionary_item_occurrence}[${item}]
495 [Documentation] Post body to ${uri}, log response content, and check status
496 [Arguments] ${uri} ${body} ${session}=session ${status_codes}=200
497 ${resp}= RequestsLibrary.Post Request ${session} ${uri} ${body}
499 TemplatedRequests.Check Status Code ${resp} ${status_codes}
503 [Documentation] Get the name of the suite sanitized to be usable as a part of filename.
504 ... These names are used to constructs names of the log files produced
505 ... by the testing tools so two suites using a tool wont overwrite the
506 ... log files if they happen to run in one job.
507 [Arguments] ${testtool} ${testcase}=${EMPTY}
508 ${name}= BuiltIn.Evaluate """${SUITE_NAME}""".replace(" ","-").replace("/","-").replace(".","-")
509 ${suffix}= BuiltIn.Set_Variable_If '${testcase}' != '' --${testcase} ${EMPTY}
510 ${date}= DateTime.Get Current Date
511 ${timestamp}= DateTime.Convert Date ${date} epoch
512 RETURN ${testtool}--${name}${suffix}.${timestamp}.log
514 Set_User_Configurable_Variable_Default
515 [Documentation] Set a default value for an user configurable variable.
516 ... This keyword is needed if your default value is calculated using
517 ... a complex expression which needs BuiltIn.Evaluate or even more
518 ... complex keywords. It sets the variable ${name} (the name of the
519 ... variable MUST be specified WITHOUT the ${} syntactic sugar due
520 ... to limitations of Robot Framework) to ${value} but only if the
521 ... variable ${name} was not set previously. This keyword is intended
522 ... for user configurable variables which are supposed to be set only
523 ... with pybot -v; calling this keyword on a variable that was already
524 ... set by another keyword will silently turn the call into a NOP and
525 ... thus is a bug in the suite or resource trying to call this
527 [Arguments] ${name} ${value}
528 # TODO: Figure out how to make the ${value} evaluation "lazy" (meaning
529 # evaluating it only when the user did not set anything and thus the
530 # default is needed). This might be needed to avoid potentially costly
531 # keyword invocations when they are not needed. Currently no need for
532 # this was identified, thus leaving it here as a TODO. Based on
533 # comments the best approach would be to create another keyword that
534 # expects a ScalarClosure in the place of ${value} and calls the
535 # closure to get the value but only if the value is needed).
536 # The best idea how to implement this "laziness" would be to have the
537 # used to define another keyword that will be responsible for getting
538 # the default value and then passing the name of this getter keyword
539 # to this keyword. Then this keyword would call the getter (to obtain
540 # the expensive default value) only if it discovers that this value
541 # is really needed (because the variable is not set yet).
542 # TODO: Is the above TODO really necessary? Right now we don't have any
543 # examples of "expensive default values" where to obtain the default
544 # value is so expensive on resources (e.g. need to SSH somewhere to
545 # check something) that we would want to skip the calculation if the
546 # variable for which it is needed has a value already provided by the
547 # user using "pybot -v" or something. One example would be
548 # JAVA_HOME if it would be designed as user-configurable variable
549 # (currently it is not; users can specify "use jdk7" or "use jdk8"
550 # but not "use the jdk over there"; and there actually is no JAVA_HOME
551 # present in the resource, rather the Java invocation command uses the
552 # Java invocation with a full path). The default value of JAVA_HOME
553 # has to be obtained by issuing commands on the SSH connection where
554 # the resulting Java invocation command will be used (to check
555 # multiple candidate paths until one that fits is found) and we could
556 # skip all this checking if a JAVA_HOME was supplied by the user using
558 ${value}= BuiltIn.Get_Variable_Value \${${name}} ${value}
559 BuiltIn.Set_Suite_Variable \${${name}} ${value}
562 [Documentation] Convert a Robot time string to an integer expressing the time in minutes, rounded up
563 ... This is a wrapper around DateTime.Convert_Time which does not
564 ... provide this functionality directly nor is even able to produce
565 ... an integer directly. It is needed for RestPerfClient which
566 ... cannot accept floats for its --timeout parameter and interprets
567 ... the value supplied in this parameter in minutes.
569 ${seconds}= DateTime.Convert_Time ${time} result_format=number
570 ${minutes}= BuiltIn.Evaluate int(math.ceil(${seconds}/60.0)) modules=math
573 Write Commands Until Expected Prompt
574 [Documentation] quick wrapper for Write and Read Until Prompt Keywords to make test cases more readable
575 [Arguments] ${cmd} ${prompt} ${timeout}=${DEFAULT_TIMEOUT}
576 BuiltIn.Log cmd: ${cmd}
577 SSHLibrary.Set Client Configuration timeout=${timeout}
579 SSHLibrary.Write ${cmd}
580 ${output}= SSHLibrary.Read Until ${prompt}
583 Write Commands Until Expected Regexp
584 [Documentation] quick wrapper for Write and Read Until Prompt Keywords to make test cases more readable
585 [Arguments] ${cmd} ${regexp} ${timeout}=${DEFAULT_TIMEOUT}
586 BuiltIn.Log cmd: ${cmd}
587 SSHLibrary.Set Client Configuration timeout=${timeout}
589 SSHLibrary.Write ${cmd}
590 ${output}= SSHLibrary.Read Until Regexp ${regexp}
593 Install Package On Ubuntu System
594 [Documentation] Keyword to install packages for testing to Ubuntu Mininet VM
595 [Arguments] ${package_name} ${system}=${TOOLS_SYSTEM_IP} ${user}=${TOOLS_SYSTEM_USER} ${password}=${TOOLS_SYSTEM_PASSWORD} ${prompt}=${DEFAULT_LINUX_PROMPT} ${prompt_timeout}=30s
596 Log Keyword to install package to Mininet Ubuntu VM
597 Open Connection ${system} prompt=${prompt} timeout=${prompt_timeout}
598 SSHKeywords.Flexible Mininet Login user=${user} password=${password}
599 Write sudo apt-get install -y ${package_name}
602 Json Parse From String
603 [Documentation] Parse given plain string into json (dictionary)
604 [Arguments] ${plain_string_with_json}
605 ${json_data}= Evaluate json.loads('''${plain_string_with_json}''') json
609 [Documentation] Parse given file content into json (dictionary)
610 [Arguments] ${json_file}
611 ${json_plain_string}= OperatingSystem.Get file ${json_file}
612 ${json_data}= Json Parse From String ${json_plain_string}
615 Modify Iptables On Remote System
616 [Documentation] Wrapper keyword to run iptables with any given ${iptables_rule} string on the remote system given
617 ... by ${remote_system_ip}. The iptables listing will be output before and after the command is run
618 [Arguments] ${remote_system_ip} ${iptables_rule} ${user}=${ODL_SYSTEM_USER} ${password}=${ODL_SYSTEM_PASSWORD} ${prompt}=${ODL_SYSTEM_PROMPT}
619 ${list_iptables_command}= BuiltIn.Set Variable sudo /sbin/iptables -L -n
620 ${output}= Utils.Run Command On Remote System
621 ... ${remote_system_ip}
622 ... ${list_iptables_command}
626 BuiltIn.Log ${output}
627 Utils.Run Command On Remote System
628 ... ${remote_system_ip}
629 ... sudo /sbin/iptables ${iptables_rule}
633 ${output}= Utils.Run Command On Remote System
634 ... ${remote_system_ip}
635 ... ${list_iptables_command}
639 BuiltIn.Log ${output}
641 Get_Sysstat_Statistics
642 [Documentation] Store current connection index, open new connection to ip_address. Run command to get sysstat results from script,
643 ... which is running on all children nodes. Returns cpu, network, memory usage statistics from the node for each 10 minutes
644 ... that node was running. Used for debug purposes. Returns whole output of sysstat.
645 [Arguments] ${ip_address}=${ODL_SYSTEM_IP}
646 ${current_connection}= SSHLibrary.Get_Connection
647 SSHKeywords.Open_Connection_To_ODL_System ${ip_address}
648 SSHLibrary.Write sar -A -f /var/log/sa/sa*
649 ${output}= SSHLibrary.Read_Until_Prompt
650 BuiltIn.Log ${output}
651 SSHLibrary.Close_Connection
653 [Teardown] SSHKeywords.Restore_Current_SSH_Connection_From_Index ${current_connection.index}
656 [Documentation] GET http://${ip_address}:${RESTCONFPORT}/diagstatus and return the response. ${check_status}
657 ... and ${expected_status_code} can be used to ignore the status code, or validate any status code value.
658 ... By default, this keyword will pass if the status code returned is 200, and fail otherwise.
659 [Arguments] ${ip_address}=${ODL_SYSTEM_IP} ${check_status}=True ${expected_status}=${200}
660 RequestsLibrary.Create Session diagstatus_session http://${ip_address}:${RESTCONFPORT}
661 ${resp}= RequestsLibrary.Get Request diagstatus_session /diagstatus
662 IF "${check_status}" == "True"
663 BuiltIn.Should Be Equal As Strings ${resp.status_code} ${expected_status}
667 Download File On Openstack Node
668 [Documentation] Download a file from web to the node. the input will be a session ID with established SSH connection.
669 [Arguments] ${conn_id} ${save_file_name} ${url}
670 SSHLibrary.Switch Connection ${conn_id}
671 Utils.Write Commands Until Expected Prompt
672 ... wget -O /tmp/${save_file_name} ${url}
673 ... ${DEFAULT_LINUX_PROMPT_STRICT}