VOL-2499 Robot testing framework for alarms
Change-Id: If8e66344f5bb84c242a3e16fe6b162c44f7d02f2
diff --git a/Makefile b/Makefile
index 3b6f8c0..0719cdb 100644
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,11 @@
failure-test: ROBOT_CONFIG_FILE := $(ROBOT_FAIL_SINGLE_PON_FILE)
failure-test: voltha-test
+bbsim-alarms-kind: ROBOT_MISC_ARGS += -X -i active
+bbsim-alarms-kind: ROBOT_FILE := Voltha_AlarmTests.robot
+bbsim-alarms-kind: ROBOT_CONFIG_FILE := $(ROBOT_SCALE_SINGLE_PON_FILE)
+bbsim-alarms-kind: voltctl-docker-image-build voltctl-docker-image-install-kind voltha-test
+
voltha-test: ROBOT_MISC_ARGS += -e notready
voltha-test: vst_venv
@@ -174,3 +179,10 @@
clean-all: clean
rm -rf vst_venv gendocs
+
+voltctl-docker-image-build:
+ cd docker && docker build -t opencord/voltctl:local -f Dockerfile.voltctl .
+
+voltctl-docker-image-install-kind:
+ @if [ "`kind get clusters | grep voltha`" = '' ]; then echo "no voltha cluster found" && exit 1; fi
+ kind load docker-image --name `kind get clusters | grep voltha` opencord/voltctl:local
diff --git a/docker/Dockerfile.voltctl b/docker/Dockerfile.voltctl
new file mode 100644
index 0000000..d17711f
--- /dev/null
+++ b/docker/Dockerfile.voltctl
@@ -0,0 +1,21 @@
+# Copyright 2018-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM busybox:1.31.1-glibc
+
+RUN mkdir -p /usr/bin
+RUN wget -O - https://github.com/opencord/voltctl/releases/download/v1.0.6/voltctl-1.0.6-linux-amd64 > /usr/bin/voltctl
+COPY volt.config /root/.volt/config
+RUN chmod a+x /usr/bin/voltctl && sync && voltctl completion bash >> /root/.bashrc
+CMD ["sh", "-c", "sleep infinity"]
\ No newline at end of file
diff --git a/docker/volt.config b/docker/volt.config
new file mode 100644
index 0000000..991e01e
--- /dev/null
+++ b/docker/volt.config
@@ -0,0 +1,28 @@
+
+# Copyright 2019-present Ciena Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+apiVersion: v2
+server: voltha-api.voltha:55555
+kafka: voltha-kafka-0.voltha-kafka-headless.voltha:9092
+tls:
+ useTls: false
+ caCert: ""
+ cert: ""
+ key: ""
+ verify: ""
+grpc:
+ timeout: 10s
+
diff --git a/libraries/k8s.robot b/libraries/k8s.robot
index c3b67fe..24a1ca6 100644
--- a/libraries/k8s.robot
+++ b/libraries/k8s.robot
@@ -51,6 +51,41 @@
... kubectl delete pod ${restart_pod_name} -n ${namespace} --grace-period=0 --force
Log ${output}
+Exec Pod
+ [Arguments] ${namespace} ${name} ${command}
+ [Documentation] Uses kubectl to execute a command in the pod and return the output
+ ${rc} ${exec_pod_name}= Run and Return Rc and Output
+ ... kubectl get pods -n ${namespace} | grep ${name} | awk 'NR==1{print $1}'
+ Log ${exec_pod_name}
+ Should Not Be Empty ${exec_pod_name} Unable to parse pod name
+ ${rc} ${output}= Run and Return Rc and Output
+ ... kubectl exec -i ${exec_pod_name} -n ${namespace} -- ${command}
+ Log ${output}
+ [return] ${output}
+
+Exec Pod Separate Stderr
+ [Arguments] ${namespace} ${name} ${command}
+ [Documentation] Uses kubectl to execute a command in the pod and return the stderr and stdout
+ ${rc} ${exec_pod_name}= Run and Return Rc and Output
+ ... kubectl get pods -n ${namespace} | grep ${name} | awk 'NR==1{print $1}'
+ Log ${exec_pod_name}
+ Should Not Be Empty ${exec_pod_name} Unable to parse pod name
+ @{args}= Split String ${command}
+ ${result}= Run Process
+ ... kubectl exec -i ${exec_pod_name} -n ${namespace} -- @{args}
+ ${stdout}= Set Variable ${result.stdout}
+ ${stderr}= Set Variable ${result.stderr}
+ Log ${stdout}
+ Log ${stderr}
+ [return] ${stdout} ${stderr}
+
+Apply Kubernetes Resources
+ [Arguments] ${resource_yaml} ${namespace}
+ [Documentation] Use kubectl to create resources given a yaml file
+ ${rc} Run and Return Rc
+ ... kubectl apply -n ${namespace} -f ${resource_yaml}
+ Should Be Equal as Integers ${rc} 0
+
Validate Pod Status
[Arguments] ${pod_name} ${namespace} ${expectedStatus}
[Documentation] To run the kubectl command and check the status of the given pod matches the expected status
diff --git a/libraries/utils.robot b/libraries/utils.robot
index fed2694..779d987 100644
--- a/libraries/utils.robot
+++ b/libraries/utils.robot
@@ -320,3 +320,20 @@
... ${dst['dp_iface_name']}.${src['s_tag']} ${dst['ip']} ${dst['user']} ${dst['pass']}
... ${dst['container_type']} ${dst['container_name']}
END
+
+Should Be Larger Than
+ [Documentation] Verify that value_1 is > value_2
+ [Arguments] ${value_1} ${value_2}
+ Run Keyword If ${value_1} <= ${value_2}
+ ... Fail The value ${value_1} is not larger than ${value_2}
+
+Should Be Float
+ [Documentation] Verify that value is a floating point number type
+ [Arguments] ${value}
+ ${type} Evaluate type(${value}).__name__
+ Should Be Equal ${type} float
+
+Get Current Time
+ [Documentation] Return the current time in RFC3339 format
+ ${output}= Run date -u +"%FT%T%:z"
+ [return] ${output}
diff --git a/libraries/voltctl.robot b/libraries/voltctl.robot
index 87ec701..6c942db 100644
--- a/libraries/voltctl.robot
+++ b/libraries/voltctl.robot
@@ -384,6 +384,15 @@
Log ${sn}
[Return] ${sn}
+Get Parent ID From Device ID
+ [Arguments] ${device_id}
+ [Documentation] Gets the device id by matching for ${device_id}
+ ${rc} ${pid}= Run and Return Rc and Output
+ ... ${VOLTCTL_CONFIG}; voltctl device list --filter=Id=${device_id} --format='{{.ParentId}}'
+ Should Be Equal As Integers ${rc} 0
+ Log ${pid}
+ [Return] ${pid}
+
Validate Device Removed
[Arguments] ${id}
[Documentation] Verifys that device, ${serial_number}, has been removed
diff --git a/tests/functional/Voltha_AlarmTests.robot b/tests/functional/Voltha_AlarmTests.robot
new file mode 100755
index 0000000..06a71b6
--- /dev/null
+++ b/tests/functional/Voltha_AlarmTests.robot
@@ -0,0 +1,162 @@
+#Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+*** Settings ***
+Documentation This test raises alarms using bbsimctl and verifies them using voltctl
+Suite Setup Setup Suite
+Suite Teardown Teardown Suite
+Library Collections
+Library String
+Library OperatingSystem
+Library XML
+Library RequestsLibrary
+Library ../../libraries/DependencyLibrary.py
+Resource ../../libraries/onos.robot
+Resource ../../libraries/voltctl.robot
+Resource ../../libraries/utils.robot
+Resource ../../libraries/k8s.robot
+Resource ../../variables/variables.robot
+
+*** Variables ***
+${timeout} 60s
+${long_timeout} 420s
+${of_id} 0
+${logical_id} 0
+${has_dataplane} True
+${external_libs} True
+${setup_device} True
+${teardown_device} True
+${VOLTCTL_NAMESPACE} default
+${BBSIMCTL_NAMESPACE} voltha
+${VOLTCTL_POD_NAME} voltctl
+${BBSIMCTL_POD_NAME} bbsim
+
+*** Test Cases ***
+Ensure required pods Running
+ [Documentation] Ensure the bbsim and voltctl pods are in Running state
+ [Tags] active
+ Validate Pod Status ${BBSIMCTL_POD_NAME} ${BBSIMCTL_NAMESPACE} Running
+ Validate Pod Status ${VOLTCTL_POD_NAME} ${VOLTCTL_NAMESPACE} Running
+
+ONU Discovery
+ [Documentation] Discover lists of ONUS, their Serial Numbers and device id, and pick one for subsequent tests
+ [Tags] active
+ #build onu sn list
+ ${List_ONU_Serial} Create List
+ Set Suite Variable ${List_ONU_Serial}
+ Build ONU SN List ${List_ONU_Serial}
+ Log ${List_ONU_Serial}
+ #validate onu states
+ Wait Until Keyword Succeeds ${long_timeout} 20s
+ ... Validate ONU Devices ENABLED ACTIVE REACHABLE ${List_ONU_Serial}
+ # Pick an ONU to use for subsequent test cases
+ ${onu_sn} Set Variable ${List_ONU_Serial}[0]
+ Set Suite Variable ${onu_sn}
+ ${onu_id} Get Device ID From SN ${onu_sn}
+ Set Suite Variable ${onu_id}
+
+Test StartupFailureAlarm
+ [Documentation] Raise StartupFailure Alarm and verify event received
+ [Tags] not_active
+ Raise Alarm StartupFailure ${onu_sn}
+ # This one is actually broken...
+ # TODO: complete test once alarm is working...
+
+Test RaiseLossOfBurstAlarm
+ [Documentation] Raise Loss Of Burst Alarm and verify event received
+ [Tags] active
+ ${since} Get Current Time
+ Raise Alarm LossOfBurst ${onu_sn}
+ ${header} ${deviceEvent} Get Device Event ONU_LOSS_OF_BURST_RAISE_EVENT ${since}
+ Verify Header ${header} Voltha.openolt.ONU_LOSS_OF_BURST\.(\\d+)
+ Should Be Equal ${deviceEvent}[deviceEventName] ONU_LOSS_OF_BURST_RAISE_EVENT
+ # TODO: Why does the event have the OLT ID instead of the ONU ID ? Verify correctness.
+ ${parent_id} Get Parent ID From Device ID ${onu_id}
+ Should Be Equal ${deviceEvent}[resourceId] ${parent_id}
+
+Test ClearLossOfBurstAlarm
+ [Documentation] Clear Loss Of Burst Alarm and verify event received
+ [Tags] active
+ ${since} Get Current Time
+ Clear Alarm LossOfBurst ${onu_sn}
+ ${header} ${deviceEvent} Get Device Event ONU_LOSS_OF_BURST_CLEAR_EVENT ${since}
+ Verify Header ${header} Voltha.openolt.ONU_LOSS_OF_BURST\.(\\d+)
+ Should Be Equal ${deviceEvent}[deviceEventName] ONU_LOSS_OF_BURST_CLEAR_EVENT
+ # TODO: Why does the event have the OLT ID instead of the ONU ID ? Verify correctness.
+ ${parent_id} Get Parent ID From Device ID ${onu_id}
+ Should Be Equal ${deviceEvent}[resourceId] ${parent_id}
+
+*** Keywords ***
+Setup Suite
+ [Documentation] Set up the test suite
+ Common Test Suite Setup
+ # Ensure the voltctl pod is deployed and running
+ Apply Kubernetes Resources ./voltctl.yaml ${VOLTCTL_NAMESPACE}
+ Wait Until Keyword Succeeds ${timeout} 5s
+ ... Validate Pod Status ${VOLTCTL_POD_NAME} ${VOLTCTL_NAMESPACE} Running
+ # Call Setup keyword in utils library to create and enable device
+ Run Keyword If ${setup_device} Setup
+
+Teardown Suite
+ [Documentation] Clean up devices if desired
+ ... kills processes and cleans up interfaces on src+dst servers
+ Run Keyword If ${external_libs} Get ONOS Status ${k8s_node_ip}
+ Run Keyword If ${has_dataplane} Clean Up Linux
+ Run Keyword If ${external_libs}
+ ... Log Kubernetes Containers Logs Since Time ${datetime} ${container_list}
+ Run Keyword If ${teardown_device} Delete Device and Verify
+ Run Keyword If ${teardown_device} Test Empty Device List
+ Run Keyword If ${teardown_device} Execute ONOS CLI Command ${k8s_node_ip} ${ONOS_SSH_PORT}
+ ... device-remove ${of_id}
+
+Raise Alarm
+ [Documentation] Raise an Alarm
+ [Arguments] ${name} ${sn}
+ ${raiseOutput} Exec Pod ${BBSIMCTL_NAMESPACE} ${BBSIMCTL_POD_NAME} bbsimctl alarm raise ${name} ${sn}
+ Should Contain ${raiseOutput} Alarm Indication Sent
+
+Clear Alarm
+ [Documentation] Raise an Alarm
+ [Arguments] ${name} ${sn}
+ ${raiseOutput} Exec Pod ${BBSIMCTL_NAMESPACE} ${BBSIMCTL_POD_NAME} bbsimctl alarm clear ${name} ${sn}
+ Should Contain ${raiseOutput} Alarm Indication Sent
+
+Get Device Event
+ [Documentation] Get the most recent alarm event from voltha.events
+ [Arguments] ${deviceEventName} ${since}
+ ${output} ${raiseErr} Exec Pod Separate Stderr ${VOLTCTL_NAMESPACE} ${VOLTCTL_POD_NAME}
+ ... voltctl event listen --show-body -t 1 -o json -f Titles=${deviceEventName} -s ${since}
+ ${json} To Json ${output}
+ ${count} Get Length ${json}
+ # If there is more than one event (which could happen if we quickly do a raise and a clear),
+ # then return the most recent one.
+ Should Be Larger Than ${count} 0
+ ${lastIndex} Evaluate ${count}-1
+ ${lastItem} Set Variable ${json}[${lastIndex}]
+ ${header} Set Variable ${lastItem}[header]
+ ${deviceEvent} Set Variable ${lastItem}[deviceEvent]
+ Log ${header}
+ Log ${deviceEvent}
+ [return] ${header} ${deviceEvent}
+
+Verify Header
+ [Documentation] Verify that a DeviceEvent's header is sane and the id matches regex
+ [Arguments] ${header} ${id}
+ Should Be Equal ${header}[subCategory] ONU
+ Should Be Equal ${header}[type] DEVICE_EVENT
+ Should Match Regexp ${header}[id] ${id}
+ # TODO Revisit when timestamp format is changed from Float to Timestamp
+ Should Be Float ${header}[raisedTs]
+ Should Be Float ${header}[reportedTs]
+
diff --git a/tests/functional/voltctl.yaml b/tests/functional/voltctl.yaml
new file mode 100644
index 0000000..0f0554d
--- /dev/null
+++ b/tests/functional/voltctl.yaml
@@ -0,0 +1,37 @@
+# Copyright 2018-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+
+apiVersion: apps/v1beta2
+kind: Deployment
+metadata:
+ name: voltctl
+ labels:
+ app: voltctl
+ chart: voltctl
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: voltctl
+ template:
+ metadata:
+ labels:
+ app: voltctl
+ spec:
+ containers:
+ - name: voltctl
+ image: opencord/voltctl:local
+ imagePullPolicy: IfNotPresent