# -*- coding: robot -*-
# :setf robot
# :set noexpandtab
*** Settings ***
Documentation	This is a sample Robot Framework suite which takes advantage of the AristaLibrary
...	for communicating with and controlling Arista switches.
...	Run with:
...	pybot --pythonpath=AristaLibrary --noncritical new demo/unittest.txt

Library	AristaLibrary
Library	Collections
Library	Easter
Suite Setup	Connect To Switch
Suite Teardown	Clear All Connections

*** Variables ***
${TRANSPORT}	http
${SW1_HOST}	localhost
${SW1_PORT}	2080
${SW2_HOST}	localhost
${SW2_PORT}	2081
${USERNAME}	vagrant
${PASSWORD}	vagrant

*** Test Cases ***
Robot Easter Egg
	Run Keyword and Expect Error	*	None Shall Pass	Fred

Run Commands and Log show version
	[Documentation]	Test Run Commands which executes EOS commands and returns a raw JSON dictionary.
	...	Additionally, demonstrate several options for retrieving data out of the raw JSON.
	[tags]	runCommands
	${output}=	Run Commands	show version
	Log	"show version returned: ${output}"
	Should Not Be Equal	${output}	${None}	msg="Output of 'show version' was empty"
	Dictionary Should Contain Key	${output}	memTotal	msg="JSON from 'show version' did not contain expected results"
	Log	"Connected to ${output['modelName']}, SN ${output['serialNumber']}, SysMAC ${output['systemMacAddress']} running ${output['version']}"
	${match}	${group1}=	Should Match Regexp	${output['version']}	(\\d+\\.\\d+\\.\\w*)[\\W]*
	Set Global Variable	\${VERSION}	${group1}
	Set Suite Metadata	EOS Version	${group1}
	Set Suite Metadata	EOS Version	${group1}	top=True

Run Commands With a list of commands
	[Documentation]	Test Run Commands which executes EOS commands and returns a raw JSON dictionary, this time passing a list of several commands.
	[tags]	runCommands
	@{commands}=	Create List
	...	show version
	...	show interfaces status connected
	${output}=	Run Commands	${commands}
	Log	"List of commands returned: ${output}"
	Should Not Be Equal	${output}	${None}	msg="Output of 'show version' was empty"

Run Commands With Invalid Command
	[Documentation]	Verify that we get an appropriate error raised when sending invalid commands.
	[tags]	runCommands	negative
	${err}=	Run Keyword And Expect Error	*invalid command*	Run Commands	show ver
	Log	"'Expected ERROR was returned: ${err}"

Run Cmds and Log Version
	[Documentation]	Test Run Cmds which executes EOS commands and returns a raw JSON dictionary.
	...	Additionally, demonstrate several options for retrieving data out of the raw JSON.
	[tags]	runCmds
	${output}=	Run Cmds	show version
	Log	"show version returned: ${output}"
	Should Not Be Equal	${output}	${None}	msg="Output of 'show version' was empty"
	Dictionary Should Contain Key	${output}	result	msg="JSON from 'show version' did not contain results"
	${result}=	Get From List	${output['result']}	0
	Log	"Connected to ${result['modelName']}, SN ${result['serialNumber']}, SysMAC ${result['systemMacAddress']} running ${result['version']}"

Run Cmds With a list of commands
	[Documentation]	Test Run Cmds which executes EOS commands and returns a raw JSON dictionary, this time passing a list of several commands.
	[tags]	runCmds
	@{commands}=	Create List
	...	show version
	...	show interfaces status connected
	${output}=	Run Cmds	${commands}
	Log	"List of commands returned: ${output}"
	Should Not Be Equal	${output}	${None}	msg="Output of 'show version' was empty"

Run Cmds With Invalid Command
	[Documentation]	Verify that we get an appropriate error raised when sending invalid commands.
	...	TODO: Fix possible False Positive by not checking the actual error returned
	[tags]	runCmds	negative
	${err}=	Run Keyword And Expect Error	*CommandError*	Run Cmds	show ver
	Log	"'Expected ERROR was returned: ${err}"

Version Should Contain - Good
	[Documentation]	Positive test for version matching.
	[tags]	versionCheck
	#Version Should Contain	4.14.3F
	Version Should Contain	${VERSION}

Version Should Contain - Negative
	[Documentation]	Ensure a good error message is returned for a failed version check.
	[tags]	versionCheck	negative
	#Run Keyword And Expect Error	Searched for 4.14.2F, Found *	Version Should Contain	4.14.2F
	Run Keyword And Expect Error	Searched for 1.2.3Fred, Found *	Version Should Contain	1.2.3Fred

Connect To Switch With Incorrect Password
	[Documentation]	Ensure useful error is raised during a failed connection setup
	[tags]	connect	negative
	${err}=	Run Keyword And Expect Error	ConnectionError*	Connect To	host=${SW1_HOST}	transport=${TRANSPORT}	username=${USERNAME}	password='fred'	port=${SW1_PORT}
	#Log To Console	"Connection to switch1: ${switch1}"
	Log	"'Expected ERROR was returned: ${err}"

Connect To Switch With Invalid Transport
	[Documentation]	Ensure useful error is raised during a failed connection setup
	[tags]	connect	negative
	${err}=	Run Keyword And Expect Error	TypeError*	Connect To	host=${SW1_HOST}	transport=file	username=${USERNAME}	password=${PASSWORD}	port=${SW1_PORT}
	#Log To Console	"Connection to switch1: ${switch1}"
	Log	"'Expected ERROR was returned: ${err}"

Connect To Switch With Incorrect Transport
	[Documentation]	Ensure useful error is raised during a failed connection setup
	[tags]	connect	negative
	${err}=	Run Keyword And Expect Error	ConnectionError*	Connect To	host=${SW1_HOST}	transport=https	username=${USERNAME}	password=${PASSWORD}	port=${SW1_PORT}
	#Log To Console	"Connection to switch1: ${switch1}"
	Log	"'Expected ERROR was returned: ${err}"

Connect To Switch With Incorrect port
	[Documentation]	Ensure useful error is raised during a failed connection setup
	[tags]	connect	negative
	${err}=	Run Keyword And Expect Error	ConnectionError*	Connect To	host=${SW1_HOST}	transport=${TRANSPORT}	username=${USERNAME}	password=${PASSWORD}	port=9999
	#Log To Console	"Connection to switch1: ${switch1}"
	Log	"Expected ERROR was returned: ${err}"

Get Switch Info
	[tags]	connect	switch
	${previous}=	Change To Switch	1
	${result}=	Get Switch
	Log Dictionary	${result}
	Should Not Be Equal	${result['index']}	${None}	msg="Bad index or alias"
	Log	The switch connection uses port ${result['port']}

Add A New Switch Connection
	[tags]	connect	switch
	${switch2}=	Connect To	host=${SW2_HOST}	transport=${TRANSPORT}	username=${USERNAME}	password=${PASSWORD}	port=${SW2_PORT}
	#Log To Console	${switch2}

Add A Switch Connection with alias
	[tags]	connect	switch
	${switch2}=	Connect To	alias=my_alias	host=${SW2_HOST}	transport=${TRANSPORT}	username=${USERNAME}	password=${PASSWORD}	port=${SW2_PORT}

Get All Switches Info
	[tags]	connect	switch
	@{result}=	Get Switches
	Log List	${result}
	Get Length	${result}
	#Length Should Be	${result}	6	msg="Did not find 6 connections in list."
	Length Should Be	${result}	3	msg="Did not find 3 connections in list."
	${first}=	Get From List	${result}	0
	Log Dictionary	${first}
	Log	The first switch connection uses port ${first['port']}

Get Switch Info From Numeric Alias
	[tags]	connect	switch
	${result}=	Get Switch	index_or_alias=1
	Log Dictionary	${result}
	Log	The switch connection uses port ${result['port']}

Get Switch Info From Text Alias
	[tags]	connect	switch
	${result}=	Get Switch	index_or_alias=my_alias
	Log Dictionary	${result}
	Log	The switch connection uses port ${result['port']}

Get Switch Info From Non-existent Alias
	[tags]	connect	switch	negative
	#Run Keyword And Expect Error	ValueError*	Get Switch	index_or_alias=not_an_alias
	${result}	Get Switch	index_or_alias=not_an_alias
	Log Dictionary	${result}
	Should Be Equal	${result['index']}	${None}

Change Between Switches
	[tags]	connect	switch
	@{result}=	Get Switches
	Log List	${result}
	${pre_info}=	Get Switch
	Log Dictionary	${pre_info}
	${previous}=	Change To Switch	1
	${previous_info}=	Get Switch	index_or_alias=${previous}
	Log Dictionary	${previous_info}
	Dictionaries Should Be Equal	${pre_info}	${previous_info}
	${new_info}=	Get Switch
	Log Dictionary	${new_info}
	${output}=	Run Commands	show version
	${alias}=	Change To Switch	my_alias
	${alias_info}=	Get Switch	index_or_alias=${alias}
	Log Dictionary	${alias_info}
	${output}=	Run Commands	show version

Enable With One Command
	[tags]	enable
	${output}=	Enable	show version
	Log List	${output}
	Log Dictionary	${output[0]['result']}
	Should Not Be Equal	${output}	${None}	msg="Output of 'show version' was empty"
	Dictionary Should Contain Key	${output[0]['result']}	memTotal	msg="JSON from 'show version' did not contain expected results"
	@{items}=	Get Dictionary Items	${output[0]['result']}
	${result}=	Create Dictionary	@{items}
	Comment	Alternative method: ${result}=	Get From Dictionary	${output[0]}	result
	Log	"Connected to ${result['modelName']}, SN ${result['serialNumber']}, SysMAC ${result['systemMacAddress']} running ${result['version']}"

Enable With a list of commands
	[tags]	enable
	@{commands}=	Create List
	...	show version
	...	show interfaces status connected
	Log List	${commands}
	${output}=	Enable	${commands}
	Log List	${output}
	Log Dictionary	${output[0]}
	Log Dictionary	${output[1]}
	Log Dictionary	${output[0]['result']}
	Log Dictionary	${output[1]['result']}
	Dictionary Should Contain Key	${output[0]['result']}	systemMacAddress	msg="JSON from 'show version' did not contain expected results"
	Dictionary Should Contain Key	${output[1]['result']}	interfaceStatuses	msg="JSON from 'show interfaces status connected' did not contain expected results"
	${result}=	Get From Dictionary	${output[0]}	result
	Log	"Connected to ${result['modelName']}, SN ${result['serialNumber']}, SysMAC ${result['systemMacAddress']} running ${result['version']}"

Enable With Invalid Command
	[tags]	enable	negative
	${err}=	Run Keyword And Expect Error	*invalid command*	Enable	show ver
	Log	"'Expected ERROR was returned: ${err}"

Get Startup Config
	[tags]	config
	${config}=	Get Startup Config
	Log	"startup-config:\n\n${config}"
	Should Contain	${config}	Startup-config last modified
	Should Contain	${config}	management api http-commands

Get Startup Config Section
	[tags]	config
	${config}=	Get Startup Config	^management api http-commands$
	Log	"startup-config:\n\n${config}"
	# Result should contain section header and lines indented by 3 spaces
	Should Match Regexp	${config}	(?m)^management api http-commands
	Should Match Regexp	${config}	(?m)^\\s{3}(no )?protocol http?$
	Should Match Regexp	${config}	(?m)^\\s{3}(no )?protocol https?$
	Should Match Regexp	${config}	(?m)^\\s{3}(no )?shutdown$
	# Result should not contain hostname or interface sections
	Should Not Match Regexp	${config}	(?m)^hostname
	Should Not Match Regexp	${config}	(?m)^interface

Get Startup Config Section No Match
	[tags]	config	negative
	${err}=	Run Keyword And Expect Error	*config section not found	Get Startup Config	^logging level
	Log	"'Expected ERROR was returned: ${err}"

Get Running Config
	[tags]	config
	${config}=	Get Running Config
	Log	"running-config:\n\n${config}"
	Should Contain	${config}	Command: show running-config
	Should Contain	${config}	management api http-commands

Get Running Config Section
	[tags]	config
	${config}=	Get Running Config	^management api http-commands$
	Log	"running-config:\n\n${config}"
	# Result should contain section header and lines indented by 3 spaces
	Should Match Regexp	${config}	(?m)^management api http-commands
	Should Match Regexp	${config}	(?m)^\\s{3}(no )?protocol http(s)?$
	Should Match Regexp	${config}	(?m)^\\s{3}(no )?protocol unix-socket$
	# Result should not contain hostname or interface sections
	Should Not Match Regexp	${config}	(?m)^hostname
	Should Not Match Regexp	${config}	(?m)^interface

Get Running Config Section No Match
	[tags]	config	negative
	${err}=	Run Keyword And Expect Error	*config section not found	Get Running Config	^Invalid config section$
	Log	"'Expected ERROR was returned: ${err}"

Configure - Single Command
	[tags]	config
	Change To Switch	1
	Configure	hostname veos0
	${config}=	Get Running Config
	Should Match Regexp	${config}	hostname veos0	msg="Failed to locate hostname configuration"
	Log	"running-config:\n\n${config}"

Config (short version) - Single Command
	[tags]	config
	Change To Switch	1
	Config	hostname veos0-test2
	${config}=	Get Running Config
	Should Match Regexp	${config}	hostname veos0-test2	msg="Failed to locate hostname configuration"
	Log	"running-config:\n\n${config}"

Configure - List of Commands
	[tags]	config
	Change To Switch	1
	@{cmds}=	Create List
	...	interface ethernet1
	...	ip address 10.1.1.0/31
	...	description This is a test interface
	...	shutdown
	...	interface management1
	...	description Management interface
	#@{cmds}=	Create List	interface ethernet1	ip address 10.1.1.0/31	description This is a test interface	shutdown	interface management1	description Management interface
	Configure	default interface ethernet1
	Configure	${cmds}
	${config}=	Get Running Config
	Should Match Regexp	${config}	ip address 10\\.1\\.1\\.0	msg="Failed to locate hostname configuration"
	Log	"running-config:\n\n${config}"

Configure - Invalid Config Command
	[tags]	config
	Change To Switch	1
	${err}=	Run Keyword And Expect Error	*invalid command*	Configure	int ma1

Refresh Running
	[tags]	refresh
	Configure	hostname veos
	${config}=	Get Running Config
	${match}	${oldname}=	Should Match Regexp	${config}	hostname (.*)	msg="Failed to locate pre-hostname"
	Should Not Be Equal	${oldname}	veos-refresh
	Configure	hostname veos-refresh
	${config}=	Get Running Config
	Should Match Regexp	${config}	hostname ${oldname}	msg="Failed to locate old hostname configuration before refresh"
	Refresh
	${config}=	Get Running Config
	Should Match Regexp	${config}	hostname veos-refresh	msg="Failed to locate hostname configuration after refresh"
	Configure	hostname ${oldname}

Refresh Startup
	[tags]	refresh
	Configure	hostname veos
	Enable	copy running-config startup-config
	${config}=	Get Startup Config
	${match}	${oldname}=	Should Match Regexp	${config}	hostname (.*)	msg="Failed to locate pre-hostname"
	Should Not Be Equal	${oldname}	veos-refresh
	Configure	hostname veos-refresh
	${config}=	Get Startup Config
	Should Match Regexp	${config}	hostname ${oldname}	msg="Failed to locate old hostname configuration before refresh"
	Enable	copy running-config startup-config
	Refresh
	${config}=	Get Startup Config
	Should Match Regexp	${config}	hostname veos-refresh	msg="Failed to locate hostname configuration after refresh"
	Configure	hostname ${oldname}



*** Keywords ***
Connect To Switch
	[Documentation]	Establish connection to a switch which gets used by test cases.
	${switch1}=	Connect To	host=${SW1_HOST}	transport=${TRANSPORT}	username=${USERNAME}	password=${PASSWORD}	port=${SW1_PORT}
	#Log To Console	"Connection to switch1: ${switch1}"

