Skip to content

Commit

Permalink
Merge pull request #9 from lawnmowerlatte/master
Browse files Browse the repository at this point in the history
Deduplicate extra results caused by @autoretry in Behave 1.2.6
  • Loading branch information
andreybehalf committed Jun 11, 2017
2 parents 2345f72 + 5e68013 commit 51f7dfb
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 7 deletions.
48 changes: 45 additions & 3 deletions behave2cucumber/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
'''


def convert(json_file, remove_background=False, duration_format=False):
def convert(json_file, remove_background=False, duration_format=False, deduplicate=False):
# json_nodes are the scopes available in behave/cucumber json: Feature -> elements(Scnerios) -> Steps
json_nodes = ['feature', 'elements', 'steps']
# These fields doesn't exist in cucumber report, there-fore when converting from behave, we need to delete these
Expand Down Expand Up @@ -63,7 +63,49 @@ def format_level(tree, index=0, id_counter=0):

# Option to remove background element because behave pushes it steps to all scenarios already
if remove_background:
if json_file[0]['elements'][0]['keyword'] == 'Background':
json_file[0]['elements'].pop(0)
for feature in json_file:
if feature['elements'][0]['keyword'] == 'Background':
feature['elements'].pop(0)

if deduplicate:
def check_dupe(current_feature, current_scenario, previous_scenario):
if "autoretry" not in current_feature['tags'] and "autoretry" not in current_scenario['tags']:
return False
if previous_scenario['keyword'] != current_scenario['keyword']:
return False
elif previous_scenario['location'] != current_scenario['location']:
return False
elif previous_scenario['name'] != current_scenario['name']:
return False
elif previous_scenario['tags'] != current_scenario['tags']:
return False
elif previous_scenario['type'] != current_scenario['type']:
return False
else:
return True

for feature in json_file:
# Create a working list
scenarios = []

# For each scenario in the feature
for scenario in feature['elements']:
# Append the scenario to the working list
scenarios.append(scenario)

# Check the previous scenario
try:
# See if the previous scenario exists and matches
previous_scenario = scenarios[-2]
if check_dupe(feature, scenario, previous_scenario):
# Remove the earlier scenario from the working list
scenarios.pop(-2)
except IndexError:
# If we're at the beginning of the list, don't do anything
pass

# Replace the existing list with the working list
feature['elements'] = scenarios

# Begin the recursion
return format_level(json_file)
15 changes: 11 additions & 4 deletions behave2cucumber/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@


options = {
"short": "hd:i:o:rf",
"short": "hd:i:o:rfD",
"long": [
"help", "debug=", "infile=", "outfile=", "remove-background", "format-duration"
"help", "debug=", "infile=", "outfile=", "remove-background",
"format-duration","deduplicate"
],
"descriptions": [
"Print help message",
"Set debug level",
"Specify the input JSON",
"Specify the output JSON, otherwise use stdout",
"Remove background steps from output",
"Format the duration"
"Format the duration",
"Remove duplicate scenarios caused by @autoretry"
]
}

Expand Down Expand Up @@ -84,6 +86,7 @@ def main(argv):
outfile = None
remove_background = False
duration_format = False
deduplicate = False

for opt, arg in opts:
if opt in ("-i", "--infile"):
Expand All @@ -98,6 +101,9 @@ def main(argv):
if opt in ("-f", "--format-duration"):
log.info("Format Duration: Enabled")
duration_format = True
if opt in ("-D", "--deduplicate"):
log.info("Deduplicate: Enabled")
deduplicate = True

if infile is None:
log.critical("No input JSON provided.")
Expand All @@ -107,7 +113,8 @@ def main(argv):
with open(infile) as f:
cucumber_output = convert(json.load(f),
remove_background=remove_background,
duration_format=duration_format)
duration_format=duration_format,
deduplicate=deduplicate)

if outfile is not None:
with open(outfile, 'w') as f:
Expand Down
108 changes: 108 additions & 0 deletions tests/fixtures/autoretry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
[{"elements": [{"keyword": "Scenario",
"location": "features/test.feature:15",
"name": "A failing test with autoretry",
"steps": [{"keyword": "Given",
"location": "features/test.feature:16",
"match": {"arguments": [],
"location": "features/steps/test.py:3"},
"name": "we have behave installed",
"result": {"duration": 0.00012183189392089844,
"status": "passed"},
"step_type": "given"},
{"keyword": "When",
"location": "features/test.feature:17",
"match": {"arguments": [],
"location": "features/steps/test.py:7"},
"name": "we implement a test",
"result": {"duration": 0.00010704994201660156,
"status": "passed"},
"step_type": "when"},
{"keyword": "Then",
"location": "features/test.feature:18",
"match": {"arguments": [],
"location": "features/steps/test.py:15"},
"name": "behave will fail it for us...sometimes",
"result": {"duration": 0.0002589225769042969,
"error_message": ["Traceback (most recent call last):",
" File \"/data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py\", line 1456, in run",
" match.run(runner.context)",
" File \"/data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py\", line 1903, in run",
" self.func(context, *args, **kwargs)",
" File \"features/steps/test.py\", line 17, in step_impl",
" assert (1 == 2)",
"AssertionError"],
"status": "failed"},
"step_type": "then"}],
"tags": ["autoretry"],
"type": "scenario"},
{"keyword": "Scenario",
"location": "features/test.feature:15",
"name": "A failing test with autoretry",
"steps": [{"keyword": "Given",
"location": "features/test.feature:16",
"match": {"arguments": [],
"location": "features/steps/test.py:3"},
"name": "we have behave installed",
"result": {"duration": 0.00012183189392089844,
"status": "passed"},
"step_type": "given"},
{"keyword": "When",
"location": "features/test.feature:17",
"match": {"arguments": [],
"location": "features/steps/test.py:7"},
"name": "we implement a test",
"result": {"duration": 0.00010704994201660156,
"status": "passed"},
"step_type": "when"},
{"keyword": "Then",
"location": "features/test.feature:18",
"match": {"arguments": [],
"location": "features/steps/test.py:15"},
"name": "behave will fail it for us...sometimes",
"result": {"duration": 0.0002589225769042969,
"error_message": ["Traceback (most recent call last):",
" File \"/data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py\", line 1456, in run",
" match.run(runner.context)",
" File \"/data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py\", line 1903, in run",
" self.func(context, *args, **kwargs)",
" File \"features/steps/test.py\", line 17, in step_impl",
" assert (1 == 2)",
"AssertionError"],
"status": "failed"},
"step_type": "then"}],
"tags": ["autoretry"],
"type": "scenario"},
{"keyword": "Scenario",
"location": "features/test.feature:15",
"name": "A failing test with autoretry",
"steps": [{"keyword": "Given",
"location": "features/test.feature:16",
"match": {"arguments": [],
"location": "features/steps/test.py:3"},
"name": "we have behave installed",
"result": {"duration": 0.00012183189392089844,
"status": "passed"},
"step_type": "given"},
{"keyword": "When",
"location": "features/test.feature:17",
"match": {"arguments": [],
"location": "features/steps/test.py:7"},
"name": "we implement a test",
"result": {"duration": 0.00010704994201660156,
"status": "passed"},
"step_type": "when"},
{"keyword": "Then",
"location": "features/test.feature:18",
"match": {"arguments": [],
"location": "features/steps/test.py:15"},
"name": "behave will fail it for us...sometimes",
"result": {"duration": 0.0002589225769042969,
"status": "passed"},
"step_type": "then"}],
"tags": ["autoretry"],
"type": "scenario"}],
"keyword": "Feature",
"location": "features/test.feature:1",
"name": "showing off behave",
"status": "failed",
"tags": []}]
36 changes: 36 additions & 0 deletions tests/fixtures/autoretry_dedupe.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[{"description": "",
"elements": [{"description": "",
"id": 1,
"keyword": "Scenario",
"line": 15,
"name": "A failing test with autoretry",
"steps": [{"keyword": "Given",
"line": 16,
"match": {"arguments": [],
"location": "features/steps/test.py:3"},
"name": "we have behave installed",
"result": {"duration": 0.00012183189392089844,
"status": "passed"}},
{"keyword": "When",
"line": 17,
"match": {"arguments": [],
"location": "features/steps/test.py:7"},
"name": "we implement a test",
"result": {"duration": 0.00010704994201660156,
"status": "passed"}},
{"keyword": "Then",
"line": 18,
"match": {"arguments": [],
"location": "features/steps/test.py:15"},
"name": "behave will fail it for us...sometimes",
"result": {"duration": 0.0002589225769042969,
"status": "passed"}}],
"tags": [{"line": 14, "name": "@autoretry"}],
"type": "scenario",
"uri": "features/test.feature"}],
"id": 0,
"keyword": "Feature",
"line": 1,
"name": "showing off behave",
"tags": [],
"uri": "features/test.feature"}]
1 change: 1 addition & 0 deletions tests/fixtures/autoretry_expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"elements": [{"keyword": "Scenario", "name": "A failing test with autoretry", "steps": [{"keyword": "Given", "match": {"arguments": [], "location": "features/steps/test.py:3"}, "name": "we have behave installed", "result": {"duration": 0.00012183189392089844, "status": "passed"}, "line": 16}, {"keyword": "When", "match": {"arguments": [], "location": "features/steps/test.py:7"}, "name": "we implement a test", "result": {"duration": 0.00010704994201660156, "status": "passed"}, "line": 17}, {"keyword": "Then", "match": {"arguments": [], "location": "features/steps/test.py:15"}, "name": "behave will fail it for us...sometimes", "result": {"duration": 0.0002589225769042969, "status": "failed", "error_message": "['Traceback (most recent call last):', ' File /data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py, line 1456, in run', ' match.run(runner.context)', ' File /data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py, line 1903, in run', ' self.func(context, *args, **kwargs)', ' File features/steps/test.py, line 17, in step_impl', ' assert (1 == 2)', 'AssertionError']"}, "line": 18}], "tags": [{"name": "@autoretry", "line": 14}], "type": "scenario", "line": 15, "uri": "features/test.feature", "description": "", "id": 1}, {"keyword": "Scenario", "name": "A failing test with autoretry", "steps": [{"keyword": "Given", "match": {"arguments": [], "location": "features/steps/test.py:3"}, "name": "we have behave installed", "result": {"duration": 0.00012183189392089844, "status": "passed"}, "line": 16}, {"keyword": "When", "match": {"arguments": [], "location": "features/steps/test.py:7"}, "name": "we implement a test", "result": {"duration": 0.00010704994201660156, "status": "passed"}, "line": 17}, {"keyword": "Then", "match": {"arguments": [], "location": "features/steps/test.py:15"}, "name": "behave will fail it for us...sometimes", "result": {"duration": 0.0002589225769042969, "status": "failed", "error_message": "['Traceback (most recent call last):', ' File /data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py, line 1456, in run', ' match.run(runner.context)', ' File /data/home/london/fprincipato/b2c_fix/lib/python2.6/site-packages/behave/model.py, line 1903, in run', ' self.func(context, *args, **kwargs)', ' File features/steps/test.py, line 17, in step_impl', ' assert (1 == 2)', 'AssertionError']"}, "line": 18}], "tags": [{"name": "@autoretry", "line": 14}], "type": "scenario", "line": 15, "uri": "features/test.feature", "description": "", "id": 2}, {"keyword": "Scenario", "name": "A failing test with autoretry", "steps": [{"keyword": "Given", "match": {"arguments": [], "location": "features/steps/test.py:3"}, "name": "we have behave installed", "result": {"duration": 0.00012183189392089844, "status": "passed"}, "line": 16}, {"keyword": "When", "match": {"arguments": [], "location": "features/steps/test.py:7"}, "name": "we implement a test", "result": {"duration": 0.00010704994201660156, "status": "passed"}, "line": 17}, {"keyword": "Then", "match": {"arguments": [], "location": "features/steps/test.py:15"}, "name": "behave will fail it for us...sometimes", "result": {"duration": 0.0002589225769042969, "status": "passed"}, "line": 18}], "tags": [{"name": "@autoretry", "line": 14}], "type": "scenario", "line": 15, "uri": "features/test.feature", "description": "", "id": 3}], "keyword": "Feature", "name": "showing off behave", "tags": [], "line": 1, "uri": "features/test.feature", "description": "", "id": 0}]
21 changes: 21 additions & 0 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

BEHAVE_JSON = os.path.dirname(os.path.realpath(__file__)) + "/fixtures/behave.json"
EXPECTED_JSON = os.path.dirname(os.path.realpath(__file__)) + "/fixtures/expected.json"
AUTORETRY_BEHAVE_JSON = os.path.dirname(os.path.realpath(__file__)) + "/fixtures/autoretry.json"
AUTORETRY_EXPECTED_JSON = os.path.dirname(os.path.realpath(__file__)) + "/fixtures/autoretry_expected.json"
AUTORETRY_DEDUPE_JSON = os.path.dirname(os.path.realpath(__file__)) + "/fixtures/autoretry_dedupe.json"
class TestB2C(unittest.TestCase):
def test_convert(self):
with open(BEHAVE_JSON) as f:
Expand All @@ -15,6 +18,24 @@ def test_convert(self):

assert (sorted(converted) == sorted(expected_result))

def test_autoretry_convert(self):
with open(AUTORETRY_BEHAVE_JSON) as f:
converted = behave2cucumber.convert(json.load(f))

with open(AUTORETRY_EXPECTED_JSON) as f:
expected_result = json.load(f)

assert (sorted(converted) == sorted(expected_result))

def test_dedupe_convert(self):
with open(AUTORETRY_BEHAVE_JSON) as f:
converted = behave2cucumber.convert(json.load(f), deduplicate=True)

with open(AUTORETRY_DEDUPE_JSON) as f:
expected_result = json.load(f)

assert (sorted(converted) == sorted(expected_result))

def test_ids_are_unique(self):
with open(BEHAVE_JSON) as f:
converted = behave2cucumber.convert(json.load(f))
Expand Down

0 comments on commit 51f7dfb

Please sign in to comment.