167 lines
6.4 KiB
Python
167 lines
6.4 KiB
Python
|
|
#!/usr/bin/env python
|
||
|
|
#
|
||
|
|
# Copyright (c) 2020, The OpenThread Authors.
|
||
|
|
# All rights reserved.
|
||
|
|
#
|
||
|
|
# Redistribution and use in source and binary forms, with or without
|
||
|
|
# modification, are permitted provided that the following conditions are met:
|
||
|
|
# 1. Redistributions of source code must retain the above copyright
|
||
|
|
# notice, this list of conditions and the following disclaimer.
|
||
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||
|
|
# notice, this list of conditions and the following disclaimer in the
|
||
|
|
# documentation and/or other materials provided with the distribution.
|
||
|
|
# 3. Neither the name of the copyright holder nor the
|
||
|
|
# names of its contributors may be used to endorse or promote products
|
||
|
|
# derived from this software without specific prior written permission.
|
||
|
|
#
|
||
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
#
|
||
|
|
"""
|
||
|
|
parse_topofile.py
|
||
|
|
-----------------
|
||
|
|
This script is used to parse TopologyConfig.txt file to list vendor device info
|
||
|
|
when preparing for the Thread Certification testbed
|
||
|
|
|
||
|
|
usage: parse_topofile.py [-h] [-f TOPO_FILE] [-c CASE_LIST [CASE_LIST ...]]
|
||
|
|
|
||
|
|
parse TopologyConfig file and list all devices by case
|
||
|
|
|
||
|
|
optional arguments:
|
||
|
|
-h, --help show this help message and exit
|
||
|
|
-f TOPO_FILE Topology config file (default: C:/GRL/Thread1.1/Thread
|
||
|
|
_Harness/TestScripts/TopologyConfig.txt)
|
||
|
|
-c CASE_LIST [CASE_LIST ...]
|
||
|
|
Test case list (e.g. 5.1.1 9.2.1, default: all)
|
||
|
|
|
||
|
|
Examples:
|
||
|
|
1. Get case 5.1.1 vendor info
|
||
|
|
cmd: python parse_topofile.py -f TopologyConfig.txt -c 5.1.1
|
||
|
|
output:
|
||
|
|
case 5.1.1:
|
||
|
|
role-vendor pair: [('Leader', 'ARM'), ('Router_1', 'ARM')]
|
||
|
|
vendor devices : {'ARM': 2}
|
||
|
|
|
||
|
|
Testbed needed vendor devices:{'ARM': 2}
|
||
|
|
|
||
|
|
2. Get case 5.1.1 and 5.2.1 vendor info
|
||
|
|
cmd: python parse_topofile.py -f TopologyConfig.txt -c 5.1.1 5.2.1
|
||
|
|
output:
|
||
|
|
case 5.1.1:
|
||
|
|
role-vendor pair: [('Leader', 'ARM'), ('Router_1', 'ARM')]
|
||
|
|
vendor devices : {'ARM': 2}
|
||
|
|
case 5.2.1:
|
||
|
|
role-vendor pair: [('Leader', 'OpenThread'), ('REED_1', 'Kirale'), ('MED_1', 'SiLabs')]
|
||
|
|
vendor devices : {'OpenThread': 1, 'Kirale': 1, 'SiLabs': 1}
|
||
|
|
|
||
|
|
Testbed needed vendor devices:{'ARM': 2, 'OpenThread': 1, 'Kirale': 1, 'SiLabs': 1}
|
||
|
|
|
||
|
|
3. Get all cases vendor info
|
||
|
|
cmd: python parse_topofile.py -f TopologyConfig.txt
|
||
|
|
output:
|
||
|
|
... ... ...
|
||
|
|
|
||
|
|
Testbed needed vendor devices:{'ARM': 4, 'NXP': 5, 'OpenThread': 5, 'Kirale': 6, 'SiLabs': 5, 'Any': 7}
|
||
|
|
|
||
|
|
Notes:
|
||
|
|
The result is just for reference, the exact requirement per vendor may be equal or less than what is generated by the script.
|
||
|
|
|
||
|
|
"""
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import logging
|
||
|
|
import re
|
||
|
|
from collections import Counter
|
||
|
|
|
||
|
|
logging.basicConfig(format='%(message)s', level=logging.DEBUG)
|
||
|
|
MAX_VENDOR_DEVICE = 32
|
||
|
|
|
||
|
|
|
||
|
|
def device_calculate(topo_file, case_list):
|
||
|
|
testbed_vendor_dict = Counter()
|
||
|
|
with open(topo_file, 'r') as f:
|
||
|
|
for line in f:
|
||
|
|
|
||
|
|
case_vendor_dict = Counter()
|
||
|
|
|
||
|
|
if not line:
|
||
|
|
break
|
||
|
|
line = line.strip()
|
||
|
|
|
||
|
|
# line example :
|
||
|
|
# 5.5.1-Leader:Kirale,Router_1:OpenThread
|
||
|
|
try:
|
||
|
|
if re.match(r'\s*#.*', line):
|
||
|
|
continue
|
||
|
|
|
||
|
|
matched_case = re.match(r'(.*)-(.*)', line, re.M | re.I)
|
||
|
|
|
||
|
|
if 'all' not in case_list and matched_case.group(1) not in case_list:
|
||
|
|
continue
|
||
|
|
|
||
|
|
logging.info('case %s:' % matched_case.group(1))
|
||
|
|
if 'all' not in case_list:
|
||
|
|
case_list.remove(matched_case.group(1))
|
||
|
|
role_vendor_str = matched_case.group(2)
|
||
|
|
role_vendor_raw_list = re.split(',', role_vendor_str)
|
||
|
|
role_vendor_list = []
|
||
|
|
|
||
|
|
for device_pair in role_vendor_raw_list:
|
||
|
|
device_pair = re.split(':', device_pair)
|
||
|
|
role_vendor_list.append(tuple(device_pair))
|
||
|
|
logging.info('\trole-vendor pair: %s' % role_vendor_list)
|
||
|
|
except Exception as e:
|
||
|
|
logging.info('Unrecognized format: %s\n%s' % (line, format(e)))
|
||
|
|
raise
|
||
|
|
|
||
|
|
for _, vendor in role_vendor_list:
|
||
|
|
case_vendor_dict[vendor] += 1
|
||
|
|
testbed_vendor_dict[vendor] = max(testbed_vendor_dict[vendor], case_vendor_dict[vendor])
|
||
|
|
|
||
|
|
logging.info('\tvendor devices : %s' % dict(case_vendor_dict))
|
||
|
|
|
||
|
|
if case_list and 'all' not in case_list:
|
||
|
|
logging.info('Case %s not found' % str(case_list)[1:-1])
|
||
|
|
|
||
|
|
# vendor 'Any' stands for any other vendors
|
||
|
|
# override 'Any' counter when overlapping with other vendors
|
||
|
|
count_any = MAX_VENDOR_DEVICE
|
||
|
|
for key in testbed_vendor_dict:
|
||
|
|
if key != 'Any':
|
||
|
|
count_any -= testbed_vendor_dict[key]
|
||
|
|
if 'Any' in testbed_vendor_dict:
|
||
|
|
testbed_vendor_dict['Any'] = count_any
|
||
|
|
|
||
|
|
logging.info('\nTestbed needed vendor devices:%s' % dict(testbed_vendor_dict))
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(description='parse TopologyConfig file and list all devices by case')
|
||
|
|
parser.add_argument(
|
||
|
|
'-f',
|
||
|
|
dest='topo_file',
|
||
|
|
default='C:/GRL/Thread1.1/Thread_Harness/TestScripts/TopologyConfig.txt',
|
||
|
|
help='Topology config file (default: C:/GRL/Thread1.1/Thread_Harness/TestScripts/TopologyConfig.txt)',
|
||
|
|
)
|
||
|
|
|
||
|
|
parser.add_argument('-c',
|
||
|
|
dest='case_list',
|
||
|
|
nargs='+',
|
||
|
|
default=['all'],
|
||
|
|
help='Test case list (e.g. 5.1.1 9.2.1, default: all) ')
|
||
|
|
args = parser.parse_args()
|
||
|
|
device_calculate(args.topo_file, args.case_list)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|