Skip to content

Commit

Permalink
Merge pull request #15 from jyejare/inverse_compare
Browse files Browse the repository at this point in the history
Inverse Reporting - Shows whats not changed
  • Loading branch information
jyejare authored Apr 23, 2024
2 parents ed4b1d9 + 885109f commit ad7b965
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 99 deletions.
17 changes: 0 additions & 17 deletions 6_14.yaml

This file was deleted.

10 changes: 10 additions & 0 deletions 6_14_constants.yaml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
expected_constants:
# These are just examples, please replace these with some real expected constants
hosts:
content_facet_something: content_source_something_id

skipped_constants:
# These are just examples, please replace these with some real skip-able constants
content_view_versions:
environments:
permissions_something: something here
10 changes: 10 additions & 0 deletions 6_14_variations.yaml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
expected_variations:
# These are just examples, please replace these with some real expected variations
hosts:
content_facet_somevar: content_source_ssomevar_id

skipped_variations:
# These are just examples, please replace these with some real skip-able variations
content_view_versions:
environments:
permissions_somevar: somevar_here
5 changes: 3 additions & 2 deletions candore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ def compare_entities(
self,
pre_file=None,
post_file=None,
inverse=None,
output=None,
report_type=None,
record_evs=None,
):
comp = Comparator(settings=self.settings)
if record_evs:
comp.record_evs = True
results = comp.compare_json(pre_file=pre_file, post_file=post_file)
results = comp.compare_json(pre_file=pre_file, post_file=post_file, inverse=inverse)
reporter = Reporting(results=results)
reporter.generate_report(output_file=output, output_type=report_type)
reporter.generate_report(output_file=output, output_type=report_type, inverse=inverse)

def find_path(self, path, json_file, delimiter):
finder = Finder()
Expand Down
4 changes: 3 additions & 1 deletion candore/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def extract(ctx, mode, output, full):
@candore.command(help="Compare pre and post upgrade data")
@click.option("--pre", type=str, help="The pre upgrade json file")
@click.option("--post", type=str, help="The post upgrade json file")
@click.option("-i", "--inverse", is_flag=True, help="Inverse comparison, shows whats not changed")
@click.option("-o", "--output", type=str, help="The output file name")
@click.option(
"-t",
Expand All @@ -64,11 +65,12 @@ def extract(ctx, mode, output, full):
)
@click.option("--record-evs", is_flag=True, help="Record Expected Variations in reporting")
@click.pass_context
def compare(ctx, pre, post, output, report_type, record_evs):
def compare(ctx, pre, post, inverse, output, report_type, record_evs):
candore_obj = ctx.parent.candore
candore_obj.compare_entities(
pre_file=pre,
post_file=post,
inverse=inverse,
output=output,
report_type=report_type,
record_evs=record_evs,
Expand Down
97 changes: 68 additions & 29 deletions candore/modules/comparator.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import json

from candore.modules.variatons import Variations
from candore.utils import last_index_of_element
from candore.modules.variations import Variations, Constants
from candore.utils import last_index_of_element, is_list_contains_dict


class Comparator:
def __init__(self, settings):
self.big_key = []
self.big_compare = {}
self.big_diff = {}
self.big_constant = {}
self.record_evs = False
self.variations = Variations(settings)
self.constants = Constants(settings)
self.expected_variations = self.variations.expected_variations
self.skipped_variations = self.variations.skipped_variations
self.expected_constants = self.constants.expected_constants
self.skipped_constants = self.constants.skipped_constants

def remove_non_variant_key(self, key):


def remove_verifed_key(self, key):
reversed_bk = self.big_key[::-1]
if key in reversed_bk:
reversed_bk.remove(key)
Expand All @@ -36,13 +42,32 @@ def record_variation(self, pre, post, var_details=None):
"post": post,
"variation": var_details or "Expected(A)",
}
self.big_compare.update({full_path: variation})
self.big_diff.update({full_path: variation})
elif (
var_full_path not in self.expected_variations
and var_full_path not in self.skipped_variations
):
variation = {"pre": pre, "post": post, "variation": var_details or ""}
self.big_compare.update({full_path: variation})
self.big_diff.update({full_path: variation})

def record_constants(self, pre, post, var_details=None):
big_key = [str(itm) for itm in self.big_key]
full_path = "/".join(big_key)
var_full_path = "/".join([itm for itm in self.big_key if not isinstance(itm, int)])
if var_full_path in self.expected_constants or var_full_path in self.skipped_constants:
if self.record_evs:
variation = {
"pre": pre,
"post": post,
"constant": var_details or "Expected(A)",
}
self.big_constant.update({full_path: variation})
elif (
var_full_path not in self.expected_constants
and var_full_path not in self.skipped_constants
):
variation = {"pre": pre, "post": post, "constant": var_details or ""}
self.big_constant.update({full_path: variation})

def _is_data_type_dict(self, pre, post, unique_key=""):
if (pre and 'id' in pre) and (post and 'id' in post):
Expand All @@ -62,32 +87,41 @@ def _is_data_type_dict(self, pre, post, unique_key=""):
)
self.remove_path(unique_key)

def _is_data_type_list(self, pre, post, unique_key=""):
def _is_data_type_list_contains_dict(self, pre, post):
for pre_entity in pre:
if not pre_entity:
continue
if type(pre_entity) is dict:
for post_entity in post:
if not post_entity:
continue
if "id" in pre_entity:
if pre_entity["id"] == post_entity["id"]:
self.compare_all_pres_with_posts(
pre_entity, post_entity, unique_key=pre_entity["id"]
)
else:
key = list(pre_entity.keys())[0]
if pre_entity[key] == post_entity[key]:
self.compare_all_pres_with_posts(
pre_entity[key], post_entity[key], unique_key=key
)
for post_entity in post:
if not post_entity:
continue
if "id" in pre_entity:
self.remove_path(pre_entity["id"])
if pre_entity["id"] == post_entity["id"]:
self.compare_all_pres_with_posts(
pre_entity, post_entity, unique_key=pre_entity["id"]
)
else:
self.remove_path(pre_entity[list(pre_entity.keys())[0]])
key = list(pre_entity.keys())[0]
if pre_entity[key] == post_entity[key]:
self.compare_all_pres_with_posts(
pre_entity[key], post_entity[key], unique_key=key
)
if "id" in pre_entity:
self.remove_path(pre_entity["id"])
else:
if pre_entity not in post:
self.record_variation(pre, post)
self.remove_path(pre_entity[list(pre_entity.keys())[0]])

def _is_data_type_list(self, pre, post, unique_key=""):

def custom_key(elem):
return 'None' if elem is None else str(elem)

if not is_list_contains_dict(pre):
if sorted(pre, key=custom_key) != sorted(post, key=custom_key):
self.record_variation(pre, post)
else:
self.record_constants(pre, post)
else:
self._is_data_type_list_contains_dict(pre, post)
self.remove_path(unique_key)

def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_details=None):
Expand All @@ -100,9 +134,11 @@ def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_de
else:
if pre_data != post_data:
self.record_variation(pre_data, post_data, var_details)
self.remove_non_variant_key(unique_key)
else:
self.record_constants(pre_data, post_data, var_details)
self.remove_verifed_key(unique_key)

def compare_json(self, pre_file, post_file):
def compare_json(self, pre_file, post_file, inverse):
pre_data = post_data = None

with open(pre_file, "r") as fpre:
Expand All @@ -112,4 +148,7 @@ def compare_json(self, pre_file, post_file):
post_data = json.load(fpost)

self.compare_all_pres_with_posts(pre_data, post_data)
return self.big_compare
if not inverse:
return self.big_diff
else:
return self.big_constant
18 changes: 12 additions & 6 deletions candore/modules/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ def __init__(self, results):
"""
self.results = results

def generate_report(self, output_file, output_type):
def generate_report(self, output_file, output_type, inverse):
"""Generate a report of the compared results
Args:
output_file (str): The file to write the report to
output_type (str): The type of report to generate json / CSV
inverse (bool): Shows what not changed in comparison results
Returns:
None
Raises:
Expand All @@ -31,9 +32,9 @@ def generate_report(self, output_file, output_type):
if output_type == "json":
self._generate_json_report(output_file)
elif output_type == "html":
self._generate_html_report()
print('The HTML reporting is not implemented yet! Try next time!')
elif output_type == "csv":
self._generate_csv_report(output_file)
self._generate_csv_report(output_file, inverse=inverse)
else:
raise ValueError("Output type {} not supported".format(output_type))

Expand Down Expand Up @@ -65,7 +66,7 @@ def _generate_html_report(self):
# render_webpage()
print("HTML report is ready to view at: http://localhost:5000")

def _generate_csv_report(self, output_file):
def _generate_csv_report(self, output_file, inverse):
"""Generate a CSV report of the compared results
Args:
Expand All @@ -78,8 +79,13 @@ def _generate_csv_report(self, output_file):
output_file = Path(output_file)
# Convert json to csv and write to output file
csv_writer = csv.writer(output_file.open("w"))
csv_writer.writerow(["Variation Path", "Pre-Upgrade", "Post-Upgrade", "Variation"])
# Table Column Names
columns = ["Path", "Pre-Upgrade", "Post-Upgrade", "Variation?" if not inverse else 'Constant?']
csv_writer.writerow(columns)
# Writing Rows
for var_path, vals in self.results.items():
csv_writer.writerow([var_path, vals["pre"], vals["post"], vals["variation"]])
csv_writer.writerow([
var_path, vals["pre"], vals["post"],
vals["variation" if not inverse else "constant"]])
print("Wrote CSV report to {}".format(output_file))
print("CSV report contains {} results".format(len(self.results)))
44 changes: 44 additions & 0 deletions candore/modules/variations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
A module responsible for calculating expected and skipped variations from
`conf/variations` yaml file and convert them into processable list
"""
from functools import cached_property
from candore.utils import yaml_reader, get_yaml_paths

import yaml


class Variations:
def __init__(self, settings):
self.settings = settings

@cached_property
def variations(self):
yaml_data = yaml_reader(file_path=self.settings.candore.var_file)
return yaml_data

@cached_property
def expected_variations(self):
return get_yaml_paths(yaml_data=self.variations.get("expected_variations"))

@cached_property
def skipped_variations(self):
return get_yaml_paths(yaml_data=self.variations.get("skipped_variations"))


class Constants:
def __init__(self, settings):
self.settings = settings

@cached_property
def constants(self):
yaml_data = yaml_reader(file_path=self.settings.candore.constant_file)
return yaml_data

@cached_property
def expected_constants(self):
return get_yaml_paths(yaml_data=self.constants.get("expected_constants"))

@cached_property
def skipped_constants(self):
return get_yaml_paths(yaml_data=self.constants.get("skipped_constants"))
43 changes: 0 additions & 43 deletions candore/modules/variatons.py

This file was deleted.

Loading

0 comments on commit ad7b965

Please sign in to comment.