XOS Scale test
- creating OLTs, ONUs and required ports
- creating whitelist
- sending ONU activation events
Change-Id: If2b2d02ae4a966756edbedd659108481558636ee
diff --git a/.gitignore b/.gitignore
index 6f5a2ab..b209a27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# IDEs artifacts
+.idea
+
+# Virtual envs
+src/test/cord-api/venv-cord-tester/
+
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
diff --git a/src/test/cord-api/Tests/XosScaleValidations/README.md b/src/test/cord-api/Tests/XosScaleValidations/README.md
new file mode 100644
index 0000000..a37c11a
--- /dev/null
+++ b/src/test/cord-api/Tests/XosScaleValidations/README.md
@@ -0,0 +1,30 @@
+# XOS Scale test
+
+This test suite is still under active developemnt so some
+manual steps are needed in order to execute it.
+
+## Setup the test
+
+There a `setup-venv.sh` script in `../..`, use that.
+
+In order to connect to kafka, find the correct IP with:
+
+```bash
+kubectl get svc | grep cord-platform-kafka
+```
+
+It will be needed while running the command
+
+## Run the test
+
+Tests can executed via the cli with this command:
+
+```bash
+robot --variable xos_chameleon_url:127.0.0.1 \
+--variable xos_chameleon_port:30006 \
+--variable cord_kafka:10.152.183.118 \
+--variable num_olts:10 \
+--variable num_onus:1 \
+--variable num_pon_ports:10 \
+xos-scale-att-workflow.robot
+```
\ No newline at end of file
diff --git a/src/test/cord-api/Tests/XosScaleValidations/utils/devices.py b/src/test/cord-api/Tests/XosScaleValidations/utils/devices.py
new file mode 100644
index 0000000..fe93488
--- /dev/null
+++ b/src/test/cord-api/Tests/XosScaleValidations/utils/devices.py
@@ -0,0 +1,235 @@
+# 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.
+
+from tinydb import TinyDB, Query
+from robot.api import logger
+
+class devices(object):
+
+ def __init__(self):
+ self.olts = TinyDB('olts.json')
+ self.pon_ports = TinyDB('pon_ports.json')
+ self.onus = TinyDB('onus.json')
+ self.uni_ports = TinyDB('uni_ports.json')
+
+ def get_mock_data(self):
+ """
+ Get all the mock data,
+ this method is mostly intended for debugging
+ :return: a dictionary containing all the mocked data
+ """
+ olts = self.olts.all()
+ pon_ports = self.pon_ports.all()
+ onus = self.onus.all()
+ uni_ports = self.uni_ports.all()
+ return {
+ 'olts': olts,
+ 'pon_ports': pon_ports,
+ 'onus': onus,
+ 'uni_ports': uni_ports,
+ }
+
+ def clean_storage(self):
+ self.olts.purge()
+ self.pon_ports.purge()
+ self.onus.purge()
+ self.uni_ports.purge()
+
+###############################################################
+# OLT #
+###############################################################
+
+ def create_mock_olts(self, num_olts, voltservice_id):
+ """
+ :param num_olts: Number of OLTs to be created
+ :param voltservice_id: ID if the vOLT service
+ :return:
+ """
+ olts = []
+ for index in range(1, int(num_olts) + 1):
+ olt = {
+ 'name': 'Test OLT%s' % index,
+ 'volt_service_id': voltservice_id,
+ 'device_type': 'fake_olt',
+ 'host': '127.0.0.1',
+ 'port': index,
+ 'uplink': '65536',
+ 'switch_datapath_id': 'of:0000000000000001',
+ 'switch_port': str(index),
+ 'of_id': 'of:000000%s' % index,
+ }
+ # logger.info('Created OLT %s' % olt, also_console=True)
+ olts.append(olt)
+ self.olts.insert(olt)
+
+ return olts
+
+ def get_rest_olts(self):
+ """
+ Get all the OLTs that have been created for the test
+ formatted for the XOS Rest API
+ :return: a list of OLTs
+ """
+ return self.olts.all()
+
+ def update_olt_id(self, olt, id):
+ """
+ Update in the memory storage the XOS ID
+ of a particular OLT as it's needed to create PON Ports
+ :param olt: The OLT object to update
+ :param id: The ID returned from XOS
+ :return: None
+ """
+ Olt = Query()
+ self.olts.update({'id': id}, Olt.name == olt['name'])
+
+###############################################################
+# PON PORT #
+###############################################################
+
+ def create_mock_pon_ports(self, num_pon):
+
+ ports = []
+ for olt in self.olts.all():
+ for index in range(1, int(num_pon) +1):
+ port = {
+ 'name': 'Test PonPort %s' % index,
+ 'port_no': index,
+ 'olt_device_id': olt['id']
+ }
+ ports.append(port)
+ self.pon_ports.insert(port)
+ return ports
+
+ def get_rest_pon_ports(self):
+ """
+ Get all the PON Ports that have been created for the test
+ formatted for the XOS Rest API
+ :return: a list of PON Ports
+ """
+ return self.pon_ports.all();
+
+ def update_pon_port_id(self, pon_port, id):
+ """
+ Update in the memory storage the XOS ID
+ of a particular PON Port as it's needed to create ONUs
+ :param pon_port: The PON Port object to update
+ :param id: The ID returned from XOS
+ :return: None
+ """
+ PonPort = Query()
+ self.pon_ports.update({'id': id}, PonPort.name == pon_port['name'])
+
+###############################################################
+# ONU #
+###############################################################
+
+ def create_mock_onus(self, num_onus):
+ onus = []
+ j = 0
+ for port in self.pon_ports.all():
+ j = j + 1
+ for index in range(1, int(num_onus) + 1):
+ onu = {
+ 'serial_number': "ROBOT%s%s" % (j, index),
+ 'vendor': 'Robot',
+ 'pon_port_id': port['id']
+ }
+ onus.append(onu)
+ self.onus.insert(onu)
+ return onus
+
+ def get_rest_onus(self):
+ return self.onus.all();
+
+ def update_onu_id(self, onu, id):
+ Onu = Query()
+ self.onus.update({'id': id}, Onu.serial_number == onu['serial_number'])
+
+###############################################################
+# UNI #
+###############################################################
+
+ def create_mock_unis(self):
+ # NOTE I believe UNI port number must be unique across OLT
+ unis = []
+ i = 0
+ for onu in self.onus.all():
+ uni = {
+ 'name': 'Test UniPort %s' % i,
+ 'port_no': i,
+ 'onu_device_id': onu['id']
+ }
+ unis.append(uni)
+ self.uni_ports.insert(uni)
+ i = i+1
+ return unis
+
+ def get_rest_unis(self):
+ return self.uni_ports.all();
+
+ def update_uni_id(self, uni, id):
+ UniPort = Query()
+ self.uni_ports.update({'id': id}, UniPort.name == uni['name'])
+
+###############################################################
+# WHITELIST #
+###############################################################
+
+ def create_mock_whitelist(self, attworkflowservice_id):
+ entries = []
+ for onu in self.onus.all():
+ e = {
+ 'owner_id': attworkflowservice_id,
+ 'serial_number': onu['serial_number'],
+ 'pon_port_id': self._find_pon_port_by_onu(onu)['port_no'],
+ 'device_id': self._find_olt_by_onu(onu)['of_id']
+ }
+ entries.append(e)
+
+ return entries
+
+###############################################################
+# EVENTS #
+###############################################################
+
+ def generate_onu_events(self):
+ events = []
+ for onu in self.onus.all():
+ ev = {
+ 'status': 'activated',
+ 'serial_number': onu['serial_number'],
+ 'uni_port_id': self._find_uni_by_onu(onu)['port_no'],
+ 'of_dpid': self._find_olt_by_onu(onu)['of_id'],
+ }
+ events.append(ev)
+ return events
+
+###############################################################
+# HELPERS #
+###############################################################
+
+ def _find_uni_by_onu(self, onu):
+ Uni = Query()
+ # NOTE there's an assumption that 1 ONU has 1 UNI Port
+ return self.uni_ports.search(Uni.onu_device_id == onu['id'])[0]
+
+ def _find_pon_port_by_onu(self, onu):
+ PonPort = Query()
+ return self.pon_ports.search(PonPort.id == onu['pon_port_id'])[0]
+
+ def _find_olt_by_onu(self, onu):
+ pon_port = self._find_pon_port_by_onu(onu)
+ Olt = Query()
+ return self.olts.search(Olt.id == pon_port['olt_device_id'])[0]
\ No newline at end of file
diff --git a/src/test/cord-api/Tests/XosScaleValidations/xos-scale-att-workflow.robot b/src/test/cord-api/Tests/XosScaleValidations/xos-scale-att-workflow.robot
new file mode 100644
index 0000000..d084334
--- /dev/null
+++ b/src/test/cord-api/Tests/XosScaleValidations/xos-scale-att-workflow.robot
@@ -0,0 +1,232 @@
+*** Settings ***
+Documentation Scale up models in a SEBA deployment with no backends
+Library KafkaLibrary
+Library RequestsLibrary
+Library HttpLibrary.HTTP
+Library Collections
+Library String
+Library OperatingSystem
+Library ./utils/devices.py
+Suite Setup Setup
+Suite Teardown Teardown
+
+*** Variables ***
+${xos_chameleon_url} xos-chameleon
+${xos_chameleon_port} 9101
+${cord_kafka} cord-kafka
+
+${num_olts} 1
+${num_pon_ports} 1
+${num_onus} 1
+
+${timeout} 300s
+
+*** Test Cases ***
+
+Check OLTs Created
+ ${res} = CORD Get /xosapi/v1/volt/oltdevices
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Convert To Integer ${num_olts}
+ Should Be Equal ${length} ${total}
+
+Check PON Ports Created
+ ${res} = CORD Get /xosapi/v1/volt/ponports
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Evaluate ${num_olts} * ${num_pon_ports}
+ Should Be Equal ${length} ${total}
+
+Check ONUs Created
+ ${res} = CORD Get /xosapi/v1/volt/onudevices
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Evaluate ${num_olts} * ${num_pon_ports} * ${num_onus}
+ Should Be Equal ${length} ${total}
+
+Check UNI Ports Created
+ ${res} = CORD Get /xosapi/v1/volt/uniports
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Evaluate ${num_olts} * ${num_pon_ports} * ${num_onus}
+ Should Be Equal ${length} ${total}
+
+Check Whitelist Created
+ ${res} = CORD Get /xosapi/v1/att-workflow-driver/attworkflowdriverwhitelistentries
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Evaluate ${num_olts} * ${num_pon_ports} * ${num_onus}
+ Should Be Equal ${length} ${total}
+
+Activate ONUs
+ [Documentation] Send activation events for all the ONUs and waits for the model_policies of ATT Workflow Driver Service Instances to have completed
+ ${events} = Generate Onu Events
+ : FOR ${e} IN @{events}
+ \ Send Kafka Event onu.events ${e}
+ Wait Until Keyword Succeeds ${timeout} 5s Validate ATT_SI Number ${events}
+
+*** Keywords ***
+
+Validate ATT_SI Number
+ [Arguments] ${events}
+ ${res} = CORD Get /xosapi/v1/att-workflow-driver/attworkflowdriverserviceinstances
+ ${jsondata} = To Json ${res.content}
+ ${length} = Get Length ${jsondata['items']}
+ ${total} = Get Length ${events}
+ Should Be Equal ${length} ${total}
+ ModelPolicy completed ${jsondata['items']}
+
+ModelPolicy completed
+ [Documentation] Check that model_policies had run for all the items in the list
+ [Arguments] ${list}
+ # NOTE we assume that here we get res.content["items"]
+ : FOR ${i} IN @{list}
+ \ Should Be Equal As Integers ${i["policy_code"]} 1
+
+Setup
+ ${target} = Evaluate ${num_olts} * ${num_pon_ports} * ${num_onus}
+ Log Testing with ${target} ONUs
+ Connect Producer ${cord_kafka}:9092 onu.events
+ Connect Producer ${cord_kafka}:9092 authentication.events
+ Connect Producer ${cord_kafka}:9092 dhcp.events
+ ${auth} = Create List admin@opencord.org letmein
+ ${HEADERS} Create Dictionary Content-Type=application/json allow_modify_feedback=True
+ Create Session XOS http://${xos_chameleon_url}:${xos_chameleon_port} auth=${AUTH} headers=${HEADERS}
+ Store Data
+ Mock Data
+ ${mock} = Get Mock Data
+ Log ${mock}
+
+Teardown
+ [Documentation] Delete all models created
+ Log Teardown
+ Delete OLTs
+ Delete Whitelist
+ Delete ServiceInstances
+ Delete All Sessions
+ Clean Storage
+
+Mock Data
+ [Documentation] Mock all the data needed from the test
+ Create Mock Olts ${num_olts} ${voltservice_id}
+ Create Olts
+ Create Mock Pon Ports ${num_pon_ports}
+ Create Pon Ports
+ Create Mock Onus ${num_onus}
+ Create Onus
+ Create Mock Unis
+ Create Unis
+ Create Whitelist
+
+Create Olts
+ [Documentation] Stub OLT for the test
+ ${olts} = Get Rest Olts
+ : FOR ${OLT} IN @{olts}
+ \ Log ${OLT}
+ \ ${res} = CORD Post /xosapi/v1/volt/oltdevices ${OLT}
+ \ ${jsondata} = To Json ${res.content}
+ \ Update Olt Id ${OLT} ${jsondata['id']}
+
+Create Pon Ports
+ ${pon_ports} = Get Rest Pon Ports
+ : FOR ${port} IN @{pon_ports}
+ \ Log ${port}
+ \ ${res} = CORD Post /xosapi/v1/volt/ponports ${port}
+ \ ${jsondata} = To Json ${res.content}
+ \ Update Pon Port Id ${port} ${jsondata['id']}
+
+Create Onus
+ ${onus} = Get Rest Onus
+ : FOR ${onu} IN @{onus}
+ \ Log ${onu}
+ \ ${res} = CORD Post /xosapi/v1/volt/onudevices ${onu}
+ \ ${jsondata} = To Json ${res.content}
+ \ Update Onu Id ${onu} ${jsondata['id']}
+
+Create Unis
+ ${unis} = Get Rest Unis
+ : FOR ${uni} IN @{unis}
+ \ Log ${uni}
+ \ ${res} = CORD Post /xosapi/v1/volt/uniports ${uni}
+ \ ${jsondata} = To Json ${res.content}
+ \ Update Uni Id ${uni} ${jsondata['id']}
+
+Create Whitelist
+ [Documentation] Create a whitelist for the tests
+ ${whitelist} = Create Mock Whitelist ${attworkflowservice_id}
+ : FOR ${e} IN @{whitelist}
+ \ Log ${e}
+ \ ${res} = CORD Post /xosapi/v1/att-workflow-driver/attworkflowdriverwhitelistentries ${e}
+
+Delete Olts
+ [Documentation] Remove all the OLTs created for the test
+ ${res} = CORD Get /xosapi/v1/volt/oltdevices
+ ${jsondata} = To Json ${res.content}
+ :FOR ${ELEMENT} IN @{jsondata['items']}
+ \ ${id}= Get From Dictionary ${ELEMENT} id
+ \ CORD Delete /xosapi/v1/volt/oltdevices ${id}
+
+Delete Whitelist
+ [Documentation] Clean the whitelist
+ ${res} = CORD Get /xosapi/v1/att-workflow-driver/attworkflowdriverwhitelistentries
+ ${jsondata} = To Json ${res.content}
+ :FOR ${ELEMENT} IN @{jsondata['items']}
+ \ ${id}= Get From Dictionary ${ELEMENT} id
+ \ CORD Delete /xosapi/v1/att-workflow-driver/attworkflowdriverwhitelistentries ${id}
+
+Delete ServiceInstances
+ [Documentation] Clean the whitelist
+ ${res} = CORD Get /xosapi/v1/att-workflow-driver/attworkflowdriverserviceinstances
+ ${jsondata} = To Json ${res.content}
+ :FOR ${ELEMENT} IN @{jsondata['items']}
+ \ ${id}= Get From Dictionary ${ELEMENT} id
+ \ CORD Delete /xosapi/v1/att-workflow-driver/attworkflowdriverserviceinstances ${id}
+
+Store Data
+ [Documentation] Store all the ids needed for the test to work
+ # Get AttWorkflowDriverService id
+ ${resp}= CORD Get /xosapi/v1/att-workflow-driver/attworkflowdriverservices
+ ${jsondata}= To Json ${resp.content}
+ ${attworkflowservice}= Get From List ${jsondata['items']} 0
+ ${attworkflowservice_id}= Get From Dictionary ${attworkflowservice} id
+ Set Suite Variable ${attworkflowservice_id}
+
+ # Get VoltService id
+ ${resp}= CORD Get /xosapi/v1/volt/voltservices
+ ${jsondata}= To Json ${resp.content}
+ ${voltservice}= Get From List ${jsondata['items']} 0
+ ${voltservice_id}= Get From Dictionary ${voltservice} id
+ Set Suite Variable ${voltservice_id}
+
+Send Kafka Event
+ [Documentation] Send event
+ [Arguments] ${topic} ${message}
+ Log Sending event
+ ${event}= evaluate json.dumps(${message}) json
+ Send ${topic} ${event}
+ Flush
+
+CORD Get
+ [Documentation] Make a GET call to XOS
+ [Arguments] ${service}
+ ${resp}= Get Request XOS ${service}
+ Log ${resp.content}
+ Should Be Equal As Strings ${resp.status_code} 200
+ [Return] ${resp}
+
+CORD Post
+ [Documentation] Make a POST call to XOS
+ [Arguments] ${service} ${data}
+ ${data}= Evaluate json.dumps(${data}) json
+ ${resp}= Post Request XOS uri=${service} data=${data}
+ Log ${resp.content}
+ Should Be Equal As Strings ${resp.status_code} 200
+ [Return] ${resp}
+
+CORD Delete
+ [Documentation] Make a DELETE call to the CORD controller
+ [Arguments] ${service} ${data_id}
+ ${resp}= Delete Request XOS uri=${service}/${data_id}
+ Log ${resp.content}
+ Should Be Equal As Strings ${resp.status_code} 200
+ [Return] ${resp}
\ No newline at end of file
diff --git a/src/test/cord-api/setup_venv.sh b/src/test/cord-api/setup_venv.sh
index 6975307..cf08442 100755
--- a/src/test/cord-api/setup_venv.sh
+++ b/src/test/cord-api/setup_venv.sh
@@ -32,6 +32,6 @@
pip install --upgrade pip
pip install robotframework robotframework-requests robotframework-sshlibrary pexpect \
robotframework-httplibrary robotframework-kafkalibrary pygments pyyaml
-pip install requests
+pip install requests tinydb
echo "CORD-TESTER virtualenv created. Run 'source ${VENVDIR}/bin/activate'."
\ No newline at end of file