--- /dev/null
+*** Settings ***
+Documentation PCEP performance suite, uses restconf with configurable authentication.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+...
+...
+... General Overview:
+...
+... This is a suite which has both scale and performance aspects.
+... Given scale target, suite reports failures if functional error
+... is detected, or if various time limits expire.
+... For passing test cases, their duration is the performance metric.
+...
+... ODL acts as a translation layer between PCEP capable devices
+... and users employing RESTCONF.
+... Performance measurement focuses on two different workflows.
+...
+... The first workflow is initial synchronization, when ODL learns
+... the state of PCEP topology as devices connect to it,
+... while restconf user reads the state repeatedly.
+... The second workflow is mass update, when restconf users issue RPCs
+... to updale Layer Switched Paths on Path Computation Clients.
+...
+... This suite uses pcc-mock (downloaded from Nexus) to simulate PCCs.
+... It needs segment of bindable IP addresses,
+... one for each simulated PCC; so running pcc-mock from remote machine
+... is only viable when just single PCC is simulated.
+... Testing with multiple PCCs works best when pcc-mock
+... runs on the same VM as ODL, so 127.0.0.0/8 subnet can be used.
+...
+... Library AuthStandalone is used directly for restconf reads
+... in the first workflow. That library transparently handles several
+... http authentication methods, based on credentials and pybot arguments.
+...
+... In the second workflow, updater.py utility is used for issuing
+... rapid restconf requests. It can use multiple worker threads,
+... as http requests are blocking.
+... Due to CPython interpreter itself being single threaded,
+... amounts of threads above 8-16 are actually slightly slower
+... (which may roughly correspond to network traffic
+... being more limiting factor than CPU).
+... This suite starts updater utility bound to single CPU,
+... as this setup was the most performant in other tests.
+...
+... In case of failed test case, other tests are skipped (unless
+... this is overriden by [Setup]) to finish test run sooner.
+...
+... Variables and test case names refer to Controller and Mininet,
+... those are assumed to be separate remote VMs, one to host ODL,
+... other to host tools.
+... In case updater and pcc-mock are desired to run
+... from separate machines, their parameters use Mininet
+... values as default.
+... If both updater VM and pcc-mock VM parameters are specified,
+... Mininet parameters may be skipped.
+...
+... Some launch scripts put restrictions on how pybot options
+... can be specified, so there are utility variables to help with
+... copying Controller related value to apply fo updater of pccmock.
+... Having a tool co-located with ODL reduces network latency,
+... but puts more pressure on CPU and memory on Controller VM.
+...
+... In some environments, issues with TIME-WAIT prevent high restconf rates,
+... so TCP reuse is temporarily allowed during the suite run, if possible
+... (and if not disabled by UPDATERVM_ENABLE_TCP_RW_REUSE option value).
+... See http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html
+... This suite ignores possible failures when changing reuse.
+...
+... Similarly, in some environments, handling of requests.Session object matters
+... try changing RESTCONF_REUSE value to see if it helps.
+...
+... Variables to override (only if needed) in pybot command:
+... (Look into Variables table to see the default values.)
+...
+... CONTROLLER: Numeric IP address of VM where ODL runs.
+... CONTROLLER_USER: Username for ssh login to ODL VM.
+... CONTROLLER_PASSWORD: Ssh password, empty means public keys are used instead.
+... CONTROLLER_PROMPT: Substring to identify Linux prompt on ODL VM.
+... CONTROLLER_WORKSPACE: Path to where files can be written on ODL VM.
+... FIRST_PCC_IP: Set in case bind address is different from public pcc-mock VM address.
+... LOG_NAME: Filename (without path) to save pcc-mock output into.
+... LOG_PATH: Override if not the same as pccmock VM workspace.
+... LSPS: Number of LSPs per PCC to simulate and test.
+... MININET: Numeric IP address of VM to run pcc-mock and updater from by default.
+... MININET_PASSWORD: Linux password to go with the username (empty means keys).
+... MININET_PROMPT: Substring to identify Linux prompt on Mininet VM.
+... MININET_USER: Linux username to SSH to on Mininet VM.
+... MININET_WORKSPACE: Path to where files may be created on Mininet VM.
+... MOCK_FILE: Filename to use for mock-pcc executable instead of the timestamped one.
+... PCCDOWNLOAD_HOSTHEADER: Download server may check checks this header before showing content.
+... PCCDOWNLOAD_URLBASE: URL to pcep-pcc-mock folder in Nexus (use numberic IP if DNS has problems).
+... PCCMOCK_COLOCATED: If True, set PCCMOCKVM* to mirror CONTROLLER*
+... PCCMOCKVM_IP: Override MININET for pcc-mock usage.
+... PCCMOCKVM_*: Override corresponding MININET_* for pcc-mock usage.
+... PCCS: Number of PCCs to simulate and test.
+... PCEP_READY_VERIFY_TIMEOUT: Grace period for pcep-topology to appear. Lower if ODL is ready.
+... RESTCONF_*: USER, PASSWORD and SCOPE to authenticate with, REUSE session.
+... (Note: If SCOPE is not empty, token-based authentication is used.)
+... UPDATER_COLOCATED: If True, overrides UPDATERVM_* parameters to point at Controller
+... (The purpose is to provide an option without ability to unpack CONTROLLER value.)
+... UPDATER_ODLADDRESS: Override if public CONTROLLER address is not best fit.
+... UPDATER_REFRESH: Main updater thread may sleep this long. Balance precision with overhead.
+... UPDATER_TIMEOUT: If updater stops itself if running more than this time.
+... (Set this limit according to your performance target.)
+... UPDATERVM_ENABLE_TCP_RW_REUSE: Set to false if changing Linux configuration is not desired.
+... UPDATERVM_IP: Override MININET for updater.py usage.
+... UPDATERVM_*: Override corresponding MININET_* for updater.py usage.
+Suite Setup FailFast.Do_Not_Fail_Fast_From_Now_On
+Suite Teardown Disconnect
+Test Setup FailFast.Fail_This_Fast_On_Previous_Error
+Test Teardown FailFast.Start_Failing_Fast_If_This_Failed
+Variables ${CURDIR}/../../../variables/Variables.py
+Library SSHLibrary timeout=10s
+Library RequestsLibrary
+Library ${CURDIR}/../../../libraries/AuthStandalone.py
+Resource ${CURDIR}/../../../libraries/Utils.robot
+Resource ${CURDIR}/../../../libraries/FailFast.robot
+
+*** Variables ***
+# This table acts as an exhaustive list of variables users can modify on pybot invocation.
+# It also contains commented-out lines for variables defined elswhere.
+# Keep this list in alphabetical order.
+# ${CONTROLLER} is inherited from Variables.py
+# ${CONTROLLER_USER} is inherited from Variables.py
+# ${CONTROLLER_PASSWORD} is inherited from Variables.py
+${CONTROLLER_PROMPT} ${DEFAULT_LINUX_PROMPT} # from Variables.py
+${CONTROLLER_WORKSPACE} /tmp
+${FIRST_PCC_IP} ${PCCMOCKVM_IP}
+# ${LOG_FILE} is reserved for location of pybot-created log.html
+${LOG_NAME} throughpcep.log
+${LOG_PATH} ${PCCMOCKVM_WORKSPACE}
+${LSPS} 65535
+${MININET} 127.0.0.1
+# ${MININET_PASSWORD} is inherited from Variables.py
+${MININET_PROMPT} ${DEFAULT_LINUX_PROMPT} # from Variables.py
+${MININET_USER} mininet
+${MININET_WORKSPACE} /tmp
+${MOCK_FILE} pcc-mock-ecexutable.jar
+${PCCDOWNLOAD_HOSTHEADER} nexus.opendaylight.org
+${PCCDOWNLOAD_URLBASE} http://${PCCDOWNLOAD_HOSTHEADER}/content/repositories/opendaylight.snapshot/org/opendaylight/bgpcep/pcep-pcc-mock/
+${PCCMOCK_COLOCATED} False
+${PCCMOCKVM_IP} ${MININET}
+${PCCMOCKVM_PASSWORD} ${MININET_PASSWORD}
+${PCCMOCKVM_PROMPT} ${MININET_PROMPT}
+${PCCMOCKVM_USER} ${MININET_USER}
+${PCCMOCKVM_WORKSPACE} ${MININET_WORKSPACE}
+${PCCS} 1
+${PCEP_READY_VERIFY_TIMEOUT} 300s
+# Yes, the default timeout is 5 minutes, as this suite might be started eagerly just after ODL starts booting up.
+${RESTCONF_PASSWORD} ${PWD} # from Variables.py
+${RESTCONF_REUSE} True
+${RESTCONF_SCOPE} ${EMPTY}
+${RESTCONF_USER} ${USER} # from Variables.py
+${UPDATER_COLOCATED} False
+${UPDATER_ODLADDRESS} ${CONTROLLER}
+${UPDATER_REFRESH} 0.1
+${UPDATER_TIMEOUT} 300
+${UPDATERVM_ENABLE_TCP_RW_REUSE} True
+${UPDATERVM_IP} ${MININET}
+${UPDATERVM_PASSWORD} ${MININET_PASSWORD}
+${UPDATERVM_PROMPT} ${MININET_PROMPT}
+${UPDATERVM_USER} ${MININET_USER}
+${UPDATERVM_WORKSPACE} ${MININET_WORKSPACE}
+
+*** TestCases ***
+Download_Pcc_Mock
+ [Documentation] SSH login to pcc-mock VM, download latest pcc-mock executable from Nexus.
+ BuiltIn.Run_Keyword_If ${PCCMOCK_COLOCATED} Pccmock_From_Controller
+ SSHLibrary.Open_Connection ${PCCMOCKVM_IP} alias=pccmock
+ SSHLibrary.Set_Client_Configuration timeout=10s
+ SSHLibrary.Set_Client_Configuration prompt=${PCCMOCKVM_PROMPT}
+ Utils.Flexible_SSH_Login ${PCCMOCKVM_USER} ${PCCMOCKVM_PASSWORD} delay=4s
+ ${curl_common} = BuiltIn.Set_Variable curl -s -H "Host:${PCCDOWNLOAD_HOSTHEADER}" ${PCCDOWNLOAD_URLBASE}
+ ${version} = SSHLibrary.Execute_Command ${curl_common}/maven-metadata.xml \| grep latest \| cut -d '>' -f 2 \| cut -d '<' -f 1
+ BuiltIn.Log ${version}
+ ${namepart} = SSHLibrary.Execute_Command ${curl_common}/${version}/maven-metadata.xml \| grep value \| head -n 1 \| cut -d '>' -f 2 \| cut -d '<' -f 1
+ BuiltIn.Log ${namepart}
+ BuiltIn.Set_Suite_Variable ${filename} pcep-pcc-mock-${namepart}-executable.jar
+ BuiltIn.Log ${filename}
+ BuiltIn.Set_Suite_Variable ${mocklocation} ${PCCMOCKVM_WORKSPACE}/${MOCK_FILE}
+ # TODO: Debug to make wget -N work
+ ${response} ${err} ${return_code} = SSHLibrary.Execute_Command ${curl_common}/${version}/${filename} > ${mocklocation} return_rc=True return_stderr=True
+ BuiltIn.Log ${err}
+ BuiltIn.Should_Be_Equal ${return_code} ${0}
+
+Put_Updater
+ [Documentation] Open SSH session to updater VM, copy the utility there, including dependencies, also prepare direct http session.
+ BuiltIn.Run_Keyword_If ${UPDATER_COLOCATED} Updater_From_Controller
+ SSHLibrary.Open_Connection ${UPDATERVM_IP} alias=updater
+ SSHLibrary.Set_Client_Configuration timeout=20s
+ SSHLibrary.Set_Client_Configuration prompt=${UPDATERVM_PROMPT}
+ Utils.Flexible_SSH_Login ${UPDATERVM_USER} ${UPDATERVM_PASSWORD} delay=4s
+ Require_Python
+ SSHLibrary.Put_File ${CURDIR}/../../../../tools/pcep_updater/updater.py ${UPDATERVM_WORKSPACE}/
+ SSHLibrary.Put_File ${CURDIR}/../../../libraries/AuthStandalone.py ${UPDATERVM_WORKSPACE}/
+ Assure_Library_Counter workspace=${UPDATERVM_WORKSPACE}
+ Assure_Library_Ipaddr workspace=${UPDATERVM_WORKSPACE}
+ # Done preparation of Updater VM, now use AuthStandalone to create session from robot VM too.
+ BuiltIn.Log_Many ${RESTCONF_USER} ${RESTCONF_PASSWORD} ${RESTCONF_SCOPE} ${CONTROLLER}
+ ${session} = AuthStandalone.Init_Session ${CONTROLLER} ${RESTCONF_USER} ${RESTCONF_PASSWORD} ${RESTCONF_SCOPE}
+ BuiltIn.Set_Suite_Variable ${rest_session} ${session}
+ # TODO: Define http timeouts.
+
+Save_And_Enable_Tcp_Rw_Reuse
+ [Documentation] If requested, temporarily enable TCP port reuse on Updater VM to allow for high rate of TCP connections. Do not start failing fast.
+ BuiltIn.Pass_Execution_If not ${UPDATERVM_ENABLE_TCP_RW_REUSE} Manipulation of tcp_rw_reuse is not requested.
+ ${old_value} = SSHLibrary.Execute_Command cat /proc/sys/net/ipv4/tcp_tw_reuse
+ # The next line may be skipped if the previous line failed.
+ BuiltIn.Set_Suite_Variable ${tcp_rw_reuse} ${old_value}
+ ${out} ${rc} = SSHLibrary.Execute_Command sudo bash -c "echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse" return_rc=True
+ BuiltIn.Should_Be_Equal ${rc} ${0}
+ # Lack of sudo access should not prevent the rest of suite from trying without TCP reuse.
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Topology_Precondition
+ [Documentation] Verify that within timeout, PCEP topology is present, with no PCC connected.
+ [Tags] critical
+ Set_Hop 0
+ Builtin.Wait_Until_Keyword_Succeeds ${PCEP_READY_VERIFY_TIMEOUT} 1s Pcep_Off
+ # Yes, timeout is 5 minutes, as this suite might be started eagerly just after ODL starts booting up.
+
+Start_Pcc_Mock
+ [Documentation] Launch pcc-mock on background so simulated PCCs start connecting to controller.
+ SSHLibrary.Switch_Connection pccmock
+ ${command} = BuiltIn.Set_Variable java -jar ${mocklocation} --local-address ${FIRST_PCC_IP} --remote-address ${CONTROLLER} --pcc ${PCCS} --lsp ${LSPS} &> ${LOG_PATH}/${LOG_NAME}
+ BuiltIn.Log ${command}
+ SSHLibrary.Write ${command}
+ # The pccmock SSH session is left alive, but no data will be exchanged for a while.
+ # We need this connection to stay alive to send ctrl+c later.
+ # SSHLibrary.Start_Command would not do that for us.
+
+Topology_Intercondition
+ [Documentation] Verify that within timeout, PCEP topology contains correct numbers of LSPs.
+ [Tags] critical
+ ${localsize} = Evaluate int(${PCCS})*int(${LSPS})
+ Builtin.Set_Suite_Variable ${size} ${localsize}
+ BuiltIn.Log ${size}
+ Builtin.Wait_Until_Keyword_Succeeds 120s 1s Pcep_On
+ # TODO: Make timeout value scale with ${size}?
+
+Updater_1
+ [Documentation] Run updater tool to change hops, using 1 blocking http thread.
+ [Tags] critical
+ Updater 1
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_1
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 1
+
+Updater_2
+ [Documentation] Run updater tool to change hops again, using 2 blocking http threads.
+ [Tags] critical
+ Updater 2
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_2
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 2
+
+Updater_3
+ [Documentation] Run updater tool to change hops again, using 4 blocking http threads.
+ [Tags] critical
+ Updater 3
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_3
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 3
+
+Updater_4
+ [Documentation] Run updater tool to change hops again, using 8 blocking http threads.
+ [Tags] critical
+ Updater 4
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_4
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 4
+
+Updater_5
+ [Documentation] Run updater tool to change hops again, using 16 blocking http threads.
+ [Tags] critical
+ Updater 5
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_5
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 5
+
+Updater_6
+ [Documentation] Run updater tool to change hops again, using 32 blocking http threads.
+ [Tags] critical
+ Updater 6
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_6
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 6
+
+Updater_7
+ [Documentation] Run updater tool to change hops again, using 64 blocking http threads.
+ [Tags] critical
+ Updater 7
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_7
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 7
+
+Updater_8
+ [Documentation] Run updater tool to change hops again, using 128 blocking http threads.
+ [Tags] critical
+ Updater 8
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_8
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 8
+
+Updater_9
+ [Documentation] Run updater tool to change hops again, using 256 blocking http threads.
+ [Tags] critical
+ Updater 9
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_9
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 9
+
+Updater_10
+ [Documentation] Run updater tool to change hops again, using 512 blocking http threads.
+ [Tags] critical
+ Updater 10
+ [Teardown] Do_Not_Start_Failing_If_This_Failed
+
+Verify_10
+ [Documentation] Verify that within timeout, the correct number of new hops is in PCEP topology.
+ [Tags] critical
+ Verify 10
+
+Stop_Pcc_Mock
+ [Documentation] Send ctrl+c to pcc-mock, see prompt again within timeout.
+ [Setup] Run_Even_When_Failing_Fast
+ # TODO: This should be in a library similar to BGPSpeaker.robot
+ SSHLibrary.Switch_Connection pccmock
+ # FIXME: send_ctrl should be in some library.
+ ${command} = BuiltIn.Evaluate chr(int(3))
+ BuiltIn.Log ${command}
+ SSHLibrary.Write ${command}
+ ${response} = SSHLibrary.Read_Until_Prompt
+ BuiltIn.Log ${response}
+
+Download_Pccmock_Log
+ [Documentation] Transfer pcc-mock output from pcc-mock VM to robot VM.
+ [Setup] Run_Even_When_Failing_Fast
+ SSHLibrary.Get_File ${LOG_PATH}/${LOG_NAME} ${CURDIR}/${LOG_NAME}
+
+Topology_Postcondition
+ [Documentation] Verify that within timeout, PCEP topology contains no PCCs again.
+ [Tags] critical
+ [Setup] Run_Even_When_Failing_Fast
+ Builtin.Wait_Until_Keyword_Succeeds 30s 1s Pcep_Off_Again
+
+Restore_Tcp_Rw_Reuse
+ [Documentation] If requested, restore the old value if enabling TCP reuse was successful on Updater VM.
+ [Setup] Run_Even_When_Failing_Fast
+ BuiltIn.Pass_Execution_If not ${UPDATERVM_ENABLE_TCP_RW_REUSE} Manipulation of tcp_rw_reuse is not requested.
+ SSHLibrary.Switch_Connection updater
+ BuiltIn.Variable_Should_Exist ${tcp_rw_reuse}
+ ${out} ${rc} = SSHLibrary.Execute_Command sudo bash -c "echo ${tcp_rw_reuse} > /proc/sys/net/ipv4/tcp_tw_reuse" return_rc=True
+ BuiltIn.Should_Be_Equal ${rc} ${0}
+
+*** Keywords ***
+Pccmock_From_Controller
+ [Documentation] Copy Controller values to Pccmock VM variables.
+ BuiltIn.Set_Suite_Variable ${PCCMOCKVM_IP} ${CONTROLLER}
+ BuiltIn.Set_Suite_Variable ${PCCMOCKVM_PASSWORD} ${CONTROLLER_PASSWORD}
+ BuiltIn.Set_Suite_Variable ${PCCMOCKVM_PROMPT} ${CONTROLLER_PROMPT}
+ BuiltIn.Set_Suite_Variable ${PCCMOCKVM_WORKSPACE} ${CONTROLLER_WORKSPACE}
+ BuiltIn.Set_Suite_Variable ${LOG_PATH} ${CONTROLLER_WORKSPACE}
+
+Updater_From_Controller
+ [Documentation] Copy Controller values to Uprater VM variables.
+ BuiltIn.Set_Suite_Variable ${UPDATERVM_IP} ${CONTROLLER}
+ BuiltIn.Set_Suite_Variable ${UPDATERVM_PASSWORD} ${CONTROLLER_PASSWORD}
+ BuiltIn.Set_Suite_Variable ${UPDATERVM_PROMPT} ${CONTROLLER_PROMPT}
+ BuiltIn.Set_Suite_Variable ${UPDATERVM_WORKSPACE} ${CONTROLLER_WORKSPACE}
+
+Require_Python
+ [Documentation] Verify current SSH connection leads to machine with python working. Fatal fail otherwise.
+ ${passed} = Execute_Command_Passes python --help
+ BuiltIn.Return_From_Keyword_If ${passed}
+ BuiltIn.Fatal_Error Python is not installed!
+
+Assure_Library_Counter
+ [Arguments] ${workspace}=/tmp
+ [Documentation] Tests whether Counter is present in collections on ssh-connected machine, Puts Counter.py to workspace if not.
+ ${passed} = Execute_Command_Passes bash -c 'cd "${workspace}" && python -c "from collections import Counter"'
+ # TODO: Move the bash-cd wrapper to separate keyword?
+ BuiltIn.Return_From_Keyword_If ${passed}
+ SSHLibrary.Put_File ${CURDIR}/../../../libraries/Counter.py ${workspace}/
+
+Assure_Library_Ipaddr
+ [Arguments] ${workspace}=/tmp
+ [Documentation] Tests whether ipaddr module is present on ssh-connected machine, Puts ipaddr.py to workspace if not.
+ ${passed} = Execute_Command_Passes bash -c 'cd "${workspace}" && python -c "import ipaddr"'
+ BuiltIn.Return_From_Keyword_If ${passed}
+ SSHLibrary.Put_File ${CURDIR}/../../../libraries/ipaddr.py ${workspace}/
+
+Execute_Command_Passes
+ [Arguments] ${command}
+ [Documentation] Execute command via SSH. If RC is nonzero, log everything. Retrun bool of command success.
+ ${stdout} ${stderr} ${rc} = SSHLibrary.Execute_Command ${command} return_stderr=True return_rc=True
+ BuiltIn.Return_From_Keyword_If ${rc} == 0 True
+ BuiltIn.Log ${stdout}
+ BuiltIn.Log ${stderr}
+ BuiltIn.Log ${rc}
+ [Return] False
+
+Disconnect
+ [Documentation] Explicitly close all SSH connections.
+ SSHLibrary.Close_All_Connections
+ # TODO: Make AuthStandalone session object closable?
+
+Get_Pcep_Topology_Data
+ [Documentation] Use session object to download PCEP topology JSON. Check status and return Response object.
+ ${resp} = AuthStandalone.Get_Using_Session ${rest_session} operational/network-topology:network-topology/topology/pcep-topology
+ # Not Logging content, as it may be huge.
+ BuiltIn.Should_Be_Equal ${resp.status_code} ${200}
+ [Return] ${resp}
+
+Get_Pcep_Topology_Count
+ [Arguments] ${pattern}
+ [Documentation] Get topology data, return number of pattern matches.
+ ${resp} = Get_Pcep_Topology_Data
+ # BuiltIn.Log ${resp.text}
+ ${count} = BuiltIn.Evaluate len(re.findall('${pattern}', '''${resp.text}''')) modules=re
+ BuiltIn.Log ${count}
+ [Return] ${count}
+
+Pcep_Off
+ [Documentation] Get topology data, Log content and assert the exact JSON of empty topology.
+ ${resp} = Get_Pcep_Topology_Data
+ # Used before topology had chance to grow huge. Be aware when creating a longevity suite from this.
+ BuiltIn.Log ${resp.text}
+ BuiltIn.Should_Be_Equal ${resp.text} {"topology":[{"topology-id":"pcep-topology","topology-types":{"network-topology-pcep:topology-pcep":{}}}]}
+
+Pcep_On
+ [Documentation] Get topology count of current hop, assert the number of matches.
+ # Suite variables ${size} and ${hop} are set elsewhere.
+ ${resp} = Get_Pcep_Topology_Count ${hop}
+ BuiltIn.Should_Be_Equal ${resp} ${size}
+
+Pcep_Off_Again
+ [Documentation] Get topology count of final hop, assert there is none.
+ ... This is more log friendly than Pcep_Off keyword, as it does not Log possibly large content.
+ Set_Hop 0
+ ${resp} = Get_Pcep_Topology_Count ${hop}
+ BuiltIn.Should_Be_Equal ${resp} ${0}
+
+Set_Hop
+ [Arguments] ${iteration}
+ [Documentation] Set pattern to match the currently expected hop.
+ ${i} = BuiltIn.Evaluate str(1 + int(${iteration}))
+ # Regular Expressions need a dot to be escaped to represent a dot.
+ BuiltIn.Set_Suite_Variable ${hop} ${i}\.${i}\.${i}\.${i}/32
+ BuiltIn.Log ${hop}
+
+Updater
+ [Arguments] ${iteration}
+ [Documentation] Compute number of workers, call updater.py, assert its response.
+ SSHLibrary.Switch_Connection pccmock
+ # In some systems, inactive SSH sessions get severed.
+ ${command} = BuiltIn.Set_Variable echo "still alive"
+ ${output} = SSHLibrary.Execute_Command bash -c '${command}'
+ # The previous line relies on a fact that Execute_Command spawns separate shels, so running pcc-mock is not affected.
+ ${workers} = Evaluate 2**int(${iteration} - 1)
+ # TODO: Provide ${workers} explicitly as an argument to avoid math?
+ BuiltIn.Log ${workers}
+ Set_Hop ${iteration}
+ SSHLibrary.Switch_Connection updater
+ ${response} = SSHLibrary.Execute_Command bash -c "cd ${UPDATERVM_WORKSPACE}; taskset 0x00000001 python updater.py --workers '${workers}' --odladdress '${UPDATER_ODLADDRESS}' --user '${RESTCONF_USER}' --password '${RESTCONF_PASSWORD}' --scope '${RESTCONF_SCOPE}' --pccaddress '${FIRST_PCC_IP}' --pccs '${PCCS}' --lsps '${LSPS}' --hop '${hop}' --timeout '${UPDATER_TIMEOUT}' --refresh '${UPDATER_REFRESH}' --reuse '${RESTCONF_REUSE}' 2>&1"
+ BuiltIn.Log ${response}
+ ${expected} = BuiltIn.Set_Variable Counter({'pass': ${size}})
+ BuiltIn.Log ${expected}
+ BuiltIn.Should_Contain ${response} ${expected}
+
+Verify
+ [Arguments] ${iteration}
+ [Documentation] Set hop and verify that within timeout, all LSPs in topology are updated.
+ Set_Hop ${iteration}
+ Builtin.Wait_Until_Keyword_Succeeds 30s 1s Pcep_On