Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unify: unified_patches order fix #71

Merged
merged 1 commit into from May 19, 2016

Conversation

mihaibivol
Copy link
Collaborator

  • Fixes the way patches are chosen to be part of the final result.
  • Adds regression tests for the added fix.

Signed-off-by: Mihai Bivol miha.bivol@cern.ch

@mihaibivol
Copy link
Collaborator Author

cc @mvesper

@coveralls
Copy link

coveralls commented May 17, 2016

Coverage Status

Coverage decreased (-0.3%) to 99.735% when pulling 2fdb4a0 on mihaibivol:fix_unify into 5258111 on inveniosoftware:master.

@coveralls
Copy link

coveralls commented May 17, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 74f7bee on mihaibivol:fix_unify into 5258111 on inveniosoftware:master.

if conflict:
if not conflict.handled:
conflict.handled = True
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this check since the same conflict can be checked twice:

  • on its first_patch
  • on its second_patch

Since we check below that the patch we are trying to apply is either first_patch or second_patch, given the conflict resolution, the second time the conflict is brought up from self._index it would always be different than the patch we are checking against.

patches = [fp1, sp1, sp2]
conflicts = [(fp1,sp1), (fp1,sp2)]
_index = {
  fp1: (fp1, sp2)
  sp1: (fp1, sp1),
  sp2: (fp1, sp2),
}

# Try to take first:
# fp1 will point to (fp1, sp2) and its resolution is fp1 so we append.
# sp1 will point to (fp1, sp1) but the conflict resolves to fp1.
# sp2 will point to (fp1, sp2) but the conflict resolves to fp1.
# -- We will never find fp1 in the patch list.
# -- Every conflict that resolves to fp1 will never be matched with anything else in the list.
unified = [fp1]

# Try to take second:
# fp1 will point to (fp1, sp2) but the conflict resolves to sp2, so we skip it.
# sp1 will point to (fp1, sp1) and its resolution is sp1 so we append.
# sp2 will point to (fp1, sp2) and its resolution is sp2 so we append.
unified = [sp1, sp2]

Rough demonstration of algo:

  • We always append in the correct order
  • For any patch p in sorted patches
    • It never appeared before in sorted_patches
    • It will never appear afterwards in sorted_patches
    • If it points to a conflict:
      • Conflicts resolves to p and from 1st and 2nd bullet no other p1exists in sorted_patches so that p == p1. For appending a patch patch.take_patch() should be equal to p. Therefore we won't find another patch that satisfies this condition so there's no need to check about handling a conflict twice.
      • Conflict does not resolve to p but to p1 -> we will append p1 when it occurs in the list (if we didn't already)

@jirikuncar jirikuncar added this to the v0.5.1 milestone May 17, 2016
@jirikuncar jirikuncar assigned jirikuncar and mvesper and unassigned jirikuncar May 17, 2016
@@ -43,6 +44,41 @@ def take_first(conflict, _, __, ___):
self.assertEqual(m.unified_patches,
[('change', 'changeme', ('Jo', 'Joe'))])

def test_continue_run_multiple_conflicts_per_patch(self):
lca = {'foo': [{'x': [1, 2, 3]}, {'y': [2, 3, 4]}]}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try to make simpler test data and remove duplicated code from two tests?

def test_continue_run_multiple_conflicts_per_path(self):
    lca = {'first': [1, 2]}
    first = {'first': [1, 2, 3]}
    second = {'second': 2}
    expected = [
        ('f', {'first': [1, 2, 3], 'second': 2}),
        ('s', {'second': 2}),
    ]

    for resolution, result in expected:
        m = Merger(lca, first, second, {})
       try:
           m.run()
        except UnresolvedConflictsException as e:
           m.continue_run([resolution for _ in e.content])

        self.assertEqual(patch(m.unified_patches, lca), result)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simpler test case does not trigger the problem that I was fixing. We need nested objects for this test to fail before the fix, so I'll keep the large test fixtures.

Also, when regression testing the bug it made sense to have two separate tests for each case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, when regression testing the bug it made sense to have two separate tests for each case.

@mihaibivol since we are using pytest, you can use @pytest.mark.parameterize to keep the results of each run visible.

@coveralls
Copy link

coveralls commented May 17, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 757d86a on mihaibivol:fix_unify into 5258111 on inveniosoftware:master.

@coveralls
Copy link

coveralls commented May 18, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 4defa07 on mihaibivol:fix_unify into 5258111 on inveniosoftware:master.

first = {'foo': [{'x': 1}, {'y': 2}, {'z': 4}]}
second = {'bar': 'baz'}

expected = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use list of tuples then you don't need following dict access expected[resolution] (moreover it's easier to use pytest.mark.parameterize).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests inherits from unittest.TestCase so that's why parametrize does not work (SO).
I'll just change to items() iteration and I'll leave it as is for the time being.

The follow-up solutions for this would either be:

  • Require nose-parametrize for parametrizing unitest.TestCase test methods
  • Port everything to pytest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have say "easier to port to use pytest.mark.parameterize.

@coveralls
Copy link

coveralls commented May 18, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 0d7e6c1 on mihaibivol:fix_unify into 5258111 on inveniosoftware:master.

@jirikuncar
Copy link
Member

@mvesper can you please have a look at these changes?

@mihaibivol please keep the PR up-to-date with the master branch until it gets integrated. Thanks

@coveralls
Copy link

coveralls commented May 18, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling b148b48 on mihaibivol:fix_unify into 7f5d303 on inveniosoftware:master.

@mvesper
Copy link
Collaborator

mvesper commented May 18, 2016

@jirikuncar Mihai and I discussed the issue when he found the bug. The changes and regression test seem reasonable.

@jirikuncar
Copy link
Member

@mihaibivol @mvesper Thank you both!

Last thing I will ask @mihaibivol to amend commit message by adding FIX label to the first bullet point. Shall we mark removal of property Conflict.handled as backward INCOMPATIBLE change?

After you amend the commit message you can run kwalitee prepare release v0.5.0.. to see the new RELEASE-NOTES.rst (pip install -e git+https://github.com/inveniosoftware/kwalitee.git#egg=kwalitee).

@mihaibivol
Copy link
Collaborator Author

I don't seem to make kwalitee work due to some poor version of libgit2-dev in my package manager, so I just amended my commit.

@coveralls
Copy link

coveralls commented May 18, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 0655e4f on mihaibivol:fix_unify into 7f5d303 on inveniosoftware:master.

@jirikuncar
Copy link
Member

jirikuncar commented May 18, 2016

* FIX Fixes the way patches are chosen to be part of the final result.

Can you be more descriptive so people can understand this change in RELEASE-NOTES?

  • during conflict resolution
  • final result -> unified patch?
  • keep max. line length of bullet points < 72 chars.

pip install -e git+https://github.com/inveniosoftware/kwalitee.git#egg=kwalitee[gitpython]

* FIX Fixes order in which handled conflicts are unified so that the
  Merger's unified_patches can be always appplied.

* Adds regression tests for the added fix.

* Removes conflict.handled field.

Signed-off-by: Mihai Bivol <miha.bivol@cern.ch>
@coveralls
Copy link

coveralls commented May 18, 2016

Coverage Status

Coverage remained the same at 100.0% when pulling 707b459 on mihaibivol:fix_unify into 7f5d303 on inveniosoftware:master.

@mihaibivol
Copy link
Collaborator Author

mihaibivol commented May 18, 2016

New features

Improved features

  • Updates package structure, sorts imports and runs doctests.

Bug fixes

  • Fixes order in which handled conflicts are unified so that the
    Merger's unified_patches can be always appplied.

@jirikuncar jirikuncar merged commit e637f35 into inveniosoftware:master May 19, 2016
@jirikuncar jirikuncar assigned jirikuncar and unassigned mihaibivol May 19, 2016
@mihaibivol mihaibivol deleted the fix_unify branch May 19, 2016 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants