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': 'host_uuid', 'Value': '4feff42d-bc8d-4006-9922-a7fa10a6ee19'}
|
||||||
# {'Property': 'label_key', 'Value': 'kube-cpu-mgr-policy'}
|
# {'Property': 'label_key', 'Value': 'kube-cpu-mgr-policy'}
|
||||||
# {'Property': 'label_value', 'Value': 'static'}
|
# {'Property': 'label_value', 'Value': 'static'}
|
||||||
# {'Property': 'Property', 'Value': 'Value'} ###### SEPERATOR ROW ######
|
|
||||||
# {'Property': 'uuid', 'Value': '0260240f-bcca-41f5-9f32-b3acc030dfb0'}
|
# {'Property': 'uuid', 'Value': '0260240f-bcca-41f5-9f32-b3acc030dfb0'}
|
||||||
# {'Property': 'host_uuid', 'Value': '4feff42d-bc8d-4006-9922-a7fa10a6ee19'}
|
# {'Property': 'host_uuid', 'Value': '4feff42d-bc8d-4006-9922-a7fa10a6ee19'}
|
||||||
# {'Property': 'label_key', 'Value': 'kube-topology-mgr-policy'}
|
# {'Property': 'label_key', 'Value': 'kube-topology-mgr-policy'}
|
||||||
@@ -51,13 +50,10 @@ class SystemHostLabelAssignOutput:
|
|||||||
system_host_label_object = SystemHostLabelObject()
|
system_host_label_object = SystemHostLabelObject()
|
||||||
for value in output_values:
|
for value in output_values:
|
||||||
|
|
||||||
# A middle row with 'Property' means that we are changing entry.
|
if value['Property'] == 'uuid': # Every time we hit a uuid, we are encountering a new object.
|
||||||
if value['Property'] == 'Property':
|
|
||||||
self.system_host_labels.append(system_host_label_object)
|
|
||||||
system_host_label_object = SystemHostLabelObject()
|
system_host_label_object = SystemHostLabelObject()
|
||||||
|
|
||||||
if value['Property'] == 'uuid':
|
|
||||||
system_host_label_object.set_uuid(value['Value'])
|
system_host_label_object.set_uuid(value['Value'])
|
||||||
|
self.system_host_labels.append(system_host_label_object)
|
||||||
|
|
||||||
if value['Property'] == 'host_uuid':
|
if value['Property'] == 'host_uuid':
|
||||||
system_host_label_object.set_host_uuid(value['Value'])
|
system_host_label_object.set_host_uuid(value['Value'])
|
||||||
@@ -68,8 +64,6 @@ class SystemHostLabelAssignOutput:
|
|||||||
if value['Property'] == 'label_value':
|
if value['Property'] == 'label_value':
|
||||||
system_host_label_object.set_label_value(value['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]:
|
def get_all_host_labels(self) -> [SystemHostLabelObject]:
|
||||||
"""
|
"""
|
||||||
Gets all the host label objects that were assigned
|
Gets all the host label objects that were assigned
|
||||||
|
@@ -5,6 +5,21 @@ from framework.logging.automation_logger import get_logger
|
|||||||
class SystemTableParser:
|
class SystemTableParser:
|
||||||
"""
|
"""
|
||||||
Class for System table parsing
|
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):
|
def __init__(self, system_output):
|
||||||
@@ -19,28 +34,60 @@ class SystemTableParser:
|
|||||||
|
|
||||||
headers = []
|
headers = []
|
||||||
output_values_list = []
|
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:
|
for line in self.system_output:
|
||||||
# output that we care about like headers and actual output have | separators
|
|
||||||
if line.__contains__('|'):
|
# We have hit a separator which enters Headers, Content, or Ends the table
|
||||||
# find the headers first
|
if line.__contains__('+'):
|
||||||
if not found_headers:
|
|
||||||
headers = line.split('|')[1:-1]
|
# Find out in which part of the table we are, based on the "+----" separator.
|
||||||
found_headers = True
|
if not is_in_headers_block and not is_in_content_block: # First separator -> Enter Headers
|
||||||
else:
|
is_in_headers_block = True
|
||||||
output_values = {}
|
is_in_content_block = False
|
||||||
values = line.split('|')[1:-1]
|
number_of_columns = line.count('+') - 1
|
||||||
if len(headers) != len(values):
|
headers = [""] * number_of_columns
|
||||||
get_logger().log_error(
|
continue # This is a separator line, don't try to parse anything.
|
||||||
f"Number of headers was {len(headers)} "
|
elif is_in_headers_block and not is_in_content_block: # Second separator -> Go to Content
|
||||||
f"but the number of values was {len(values)}. "
|
is_in_headers_block = False
|
||||||
f"Full output was {self.system_output}"
|
is_in_content_block = True
|
||||||
)
|
continue # This is a separator line, don't try to parse anything.
|
||||||
raise KeywordException("Number of headers and values do not match")
|
else: # Last separator -> The table is complete
|
||||||
index = 0
|
is_in_headers_block = False
|
||||||
for header in headers:
|
is_in_content_block = False
|
||||||
# create dictionary with header and value
|
|
||||||
output_values[header.strip()] = values[index].strip()
|
# Build the list of headers, which could be multi-lined.
|
||||||
index = index + 1
|
if is_in_headers_block:
|
||||||
output_values_list.append(output_values)
|
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
|
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",
|
"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():
|
def test_system_parser():
|
||||||
"""
|
"""
|
||||||
@@ -218,7 +233,7 @@ def test_system_parser_error():
|
|||||||
SystemTableParser(system_output_error).get_output_values_list()
|
SystemTableParser(system_output_error).get_output_values_list()
|
||||||
assert False, "There should be an exception when parsing the output."
|
assert False, "There should be an exception when parsing the output."
|
||||||
except KeywordException as e:
|
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():
|
def test_system_host_output():
|
||||||
@@ -253,7 +268,7 @@ def test_system_host_output_error():
|
|||||||
SystemHostOutput(system_output_error).get_hosts()
|
SystemHostOutput(system_output_error).get_hosts()
|
||||||
assert False, "There should be an exception when we parse the output."
|
assert False, "There should be an exception when we parse the output."
|
||||||
except KeywordException as e:
|
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():
|
def test_system_application_output():
|
||||||
@@ -276,6 +291,30 @@ def test_system_application_output():
|
|||||||
assert application.get_status() == 'applied'
|
assert application.get_status() == 'applied'
|
||||||
assert application.get_progress() == 'completed'
|
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():
|
def test_system_host_label_assign_output():
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user