SystemTableParser to support multi-line
Enhancing the algorithm used by the SystemTableParser to support broken lines and multi-line parsing. Change-Id: Iacce397078f88ff4c6360ff907f1dff4f034abf2
This commit is contained in:
@@ -42,7 +42,6 @@ class SystemHostLabelAssignOutput:
|
||||
# {'Property': 'host_uuid', 'Value': '4feff42d-bc8d-4006-9922-a7fa10a6ee19'}
|
||||
# {'Property': 'label_key', 'Value': 'kube-cpu-mgr-policy'}
|
||||
# {'Property': 'label_value', 'Value': 'static'}
|
||||
# {'Property': 'Property', 'Value': 'Value'} ###### SEPERATOR ROW ######
|
||||
# {'Property': 'uuid', 'Value': '0260240f-bcca-41f5-9f32-b3acc030dfb0'}
|
||||
# {'Property': 'host_uuid', 'Value': '4feff42d-bc8d-4006-9922-a7fa10a6ee19'}
|
||||
# {'Property': 'label_key', 'Value': 'kube-topology-mgr-policy'}
|
||||
@@ -51,13 +50,10 @@ class SystemHostLabelAssignOutput:
|
||||
system_host_label_object = SystemHostLabelObject()
|
||||
for value in output_values:
|
||||
|
||||
# A middle row with 'Property' means that we are changing entry.
|
||||
if value['Property'] == 'Property':
|
||||
self.system_host_labels.append(system_host_label_object)
|
||||
if value['Property'] == 'uuid': # Every time we hit a uuid, we are encountering a new object.
|
||||
system_host_label_object = SystemHostLabelObject()
|
||||
|
||||
if value['Property'] == 'uuid':
|
||||
system_host_label_object.set_uuid(value['Value'])
|
||||
self.system_host_labels.append(system_host_label_object)
|
||||
|
||||
if value['Property'] == 'host_uuid':
|
||||
system_host_label_object.set_host_uuid(value['Value'])
|
||||
@@ -68,8 +64,6 @@ class SystemHostLabelAssignOutput:
|
||||
if value['Property'] == 'label_value':
|
||||
system_host_label_object.set_label_value(value['Value'])
|
||||
|
||||
self.system_host_labels.append(system_host_label_object)
|
||||
|
||||
def get_all_host_labels(self) -> [SystemHostLabelObject]:
|
||||
"""
|
||||
Gets all the host label objects that were assigned
|
||||
|
@@ -5,6 +5,21 @@ from framework.logging.automation_logger import get_logger
|
||||
class SystemTableParser:
|
||||
"""
|
||||
Class for System table parsing
|
||||
|
||||
Sample Table:
|
||||
'+--------------------------------------+---------+-----------+---------------+\n'
|
||||
'| uuid | name | ptp_insta | parameters |\n'
|
||||
'| | | nce_name | |\n'
|
||||
'+--------------------------------------+---------+-----------+---------------+\n'
|
||||
"| 0000c96e-6dab-48c2-875a-48af194c893c | n4_p2 | ptp4 | ['masterOnly= |\n"
|
||||
"| | | | 1'] |\n"
|
||||
'| | | | |\n'
|
||||
'| 24003e49-f9c4-4794-970e-506fa5c215c0 | n1_if | clock1 | [] |\n'
|
||||
'| 51e06821-b045-4a6e-854b-6bd829b5c9e2 | ptp1if1 | ptp1 | [] |\n'
|
||||
"| a689d398-329f-46b4-a99f-23b9a2417c27 | n5_p2 | ptp5 | ['masterOnly= |\n"
|
||||
"| | | | 1'] |\n"
|
||||
'| | | | |\n'
|
||||
'+--------------------------------------+---------+-----------+---------------+\n'
|
||||
"""
|
||||
|
||||
def __init__(self, system_output):
|
||||
@@ -19,28 +34,60 @@ class SystemTableParser:
|
||||
|
||||
headers = []
|
||||
output_values_list = []
|
||||
found_headers = False
|
||||
last_output_value = None
|
||||
|
||||
is_in_headers_block = False
|
||||
is_in_content_block = False
|
||||
number_of_columns = -1
|
||||
|
||||
for line in self.system_output:
|
||||
# output that we care about like headers and actual output have | separators
|
||||
if line.__contains__('|'):
|
||||
# find the headers first
|
||||
if not found_headers:
|
||||
headers = line.split('|')[1:-1]
|
||||
found_headers = True
|
||||
else:
|
||||
output_values = {}
|
||||
values = line.split('|')[1:-1]
|
||||
if len(headers) != len(values):
|
||||
get_logger().log_error(
|
||||
f"Number of headers was {len(headers)} "
|
||||
f"but the number of values was {len(values)}. "
|
||||
f"Full output was {self.system_output}"
|
||||
)
|
||||
raise KeywordException("Number of headers and values do not match")
|
||||
index = 0
|
||||
for header in headers:
|
||||
# create dictionary with header and value
|
||||
output_values[header.strip()] = values[index].strip()
|
||||
index = index + 1
|
||||
output_values_list.append(output_values)
|
||||
|
||||
# We have hit a separator which enters Headers, Content, or Ends the table
|
||||
if line.__contains__('+'):
|
||||
|
||||
# Find out in which part of the table we are, based on the "+----" separator.
|
||||
if not is_in_headers_block and not is_in_content_block: # First separator -> Enter Headers
|
||||
is_in_headers_block = True
|
||||
is_in_content_block = False
|
||||
number_of_columns = line.count('+') - 1
|
||||
headers = [""] * number_of_columns
|
||||
continue # This is a separator line, don't try to parse anything.
|
||||
elif is_in_headers_block and not is_in_content_block: # Second separator -> Go to Content
|
||||
is_in_headers_block = False
|
||||
is_in_content_block = True
|
||||
continue # This is a separator line, don't try to parse anything.
|
||||
else: # Last separator -> The table is complete
|
||||
is_in_headers_block = False
|
||||
is_in_content_block = False
|
||||
|
||||
# Build the list of headers, which could be multi-lined.
|
||||
if is_in_headers_block:
|
||||
headers_line = line.split('|')[1:-1]
|
||||
if len(headers_line) != number_of_columns:
|
||||
get_logger().log_error(f"Number of headers should be {number_of_columns} based on the number of '+' but the number of values was {len(headers_line)}.")
|
||||
raise KeywordException("Number of headers and + separator do not match expected value")
|
||||
|
||||
for i in range(number_of_columns):
|
||||
headers[i] += headers_line[i].strip()
|
||||
|
||||
# Build the list of values, which could be multi-lined.
|
||||
if is_in_content_block:
|
||||
values_line = line.split('|')[1:-1]
|
||||
if len(values_line) != number_of_columns:
|
||||
get_logger().log_error(f"Number of values should be {number_of_columns} based on the number of '+' but the number of values was {len(values_line)}.")
|
||||
raise KeywordException("Number of headers and values do not match expected value")
|
||||
|
||||
# If there is a value in the first column, then this is a new entry.
|
||||
if values_line[0].strip():
|
||||
|
||||
# Build a dictionary of the Header:Value
|
||||
last_output_value = {}
|
||||
for i in range(number_of_columns):
|
||||
last_output_value[headers[i]] = values_line[i].strip()
|
||||
output_values_list.append(last_output_value)
|
||||
|
||||
else: # Otherwise, this is the continuation of the previous line.
|
||||
for i in range(number_of_columns):
|
||||
last_output_value[headers[i]] += values_line[i].strip()
|
||||
|
||||
return output_values_list
|
||||
|
@@ -164,6 +164,21 @@ system_application_upload = [
|
||||
"Please use 'system application-list' or 'system application-show hello-kitty' to view the current progress.\n",
|
||||
]
|
||||
|
||||
system_host_if_ptp_remove_wrapped_output = [
|
||||
'+--------------------------------------+---------+-----------+---------------+\n',
|
||||
'| uuid | name | ptp_insta | parameters |\n',
|
||||
'| | | nce_name | |\n',
|
||||
'+--------------------------------------+---------+-----------+---------------+\n',
|
||||
"| 0000c96e-6dab-48c2-875a-48af194c893c | n4_p2 | ptp4 | ['masterOnly= |\n",
|
||||
"| | | | 1'] |\n",
|
||||
'| | | | |\n',
|
||||
'| 24003e49-f9c4-4794-970e-506fa5c215c0 | n1_if | clock1 | [] |\n',
|
||||
'| 51e06821-b045-4a6e-854b-6bd829b5c9e2 | ptp1if1 | ptp1 | [] |\n',
|
||||
"| a689d398-329f-46b4-a99f-23b9a2417c27 | n5_p2 | ptp5 | ['masterOnly= |\n",
|
||||
"| | | | 1'] |\n",
|
||||
'| | | | |\n',
|
||||
'+--------------------------------------+---------+-----------+---------------+\n',
|
||||
]
|
||||
|
||||
def test_system_parser():
|
||||
"""
|
||||
@@ -218,7 +233,7 @@ def test_system_parser_error():
|
||||
SystemTableParser(system_output_error).get_output_values_list()
|
||||
assert False, "There should be an exception when parsing the output."
|
||||
except KeywordException as e:
|
||||
assert e.args[0] == 'Number of headers and values do not match'
|
||||
assert e.args[0] == 'Number of headers and + separator do not match expected value'
|
||||
|
||||
|
||||
def test_system_host_output():
|
||||
@@ -253,7 +268,7 @@ def test_system_host_output_error():
|
||||
SystemHostOutput(system_output_error).get_hosts()
|
||||
assert False, "There should be an exception when we parse the output."
|
||||
except KeywordException as e:
|
||||
assert e.args[0] == 'Number of headers and values do not match'
|
||||
assert e.args[0] == 'Number of headers and + separator do not match expected value'
|
||||
|
||||
|
||||
def test_system_application_output():
|
||||
@@ -276,6 +291,30 @@ def test_system_application_output():
|
||||
assert application.get_status() == 'applied'
|
||||
assert application.get_progress() == 'completed'
|
||||
|
||||
def test_system_table_parser_with_wrapped_table_entry():
|
||||
"""
|
||||
Test the system vertical parser with a table that has a column wrapped.
|
||||
Returns:
|
||||
|
||||
"""
|
||||
|
||||
system_vertical_table_parser = SystemTableParser(system_host_if_ptp_remove_wrapped_output)
|
||||
list_of_values = system_vertical_table_parser.get_output_values_list()
|
||||
assert len(list_of_values) == 4
|
||||
|
||||
first_entry = list_of_values[0]
|
||||
assert len(first_entry.keys()) == 4
|
||||
assert first_entry['uuid'] == '0000c96e-6dab-48c2-875a-48af194c893c'
|
||||
assert first_entry['name'] == 'n4_p2'
|
||||
assert first_entry['ptp_instance_name'] == 'ptp4'
|
||||
assert first_entry['parameters'] == "['masterOnly=1']"
|
||||
|
||||
second_entry = list_of_values[1]
|
||||
assert len(second_entry.keys()) == 4
|
||||
assert second_entry['uuid'] == '24003e49-f9c4-4794-970e-506fa5c215c0'
|
||||
assert second_entry['name'] == 'n1_if'
|
||||
assert second_entry['ptp_instance_name'] == 'clock1'
|
||||
assert second_entry['parameters'] == "[]"
|
||||
|
||||
def test_system_host_label_assign_output():
|
||||
"""
|
||||
|
Reference in New Issue
Block a user