You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ne...@apache.org on 2010/06/29 22:22:19 UTC
svn commit: r959090 - in /subversion/trunk/subversion/tests/manual: ./
README permutations.py tree-conflicts-add-vs-add.py
Author: neels
Date: Tue Jun 29 20:22:19 2010
New Revision: 959090
URL: http://svn.apache.org/viewvc?rev=959090&view=rev
Log:
Add a manual test script for add-vs-add tree conflicts.
* subversion/tests/manual: New directory.
* subversion/tests/manual/README,
subversion/tests/manual/tree-conflicts-add-vs-add.py,
subversion/tests/manual/permutations.py: New files.
Added:
subversion/trunk/subversion/tests/manual/
subversion/trunk/subversion/tests/manual/README
subversion/trunk/subversion/tests/manual/permutations.py
subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py (with props)
Added: subversion/trunk/subversion/tests/manual/README
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/manual/README?rev=959090&view=auto
==============================================================================
--- subversion/trunk/subversion/tests/manual/README (added)
+++ subversion/trunk/subversion/tests/manual/README Tue Jun 29 20:22:19 2010
@@ -0,0 +1,3 @@
+These tests have not made it into the automatic test suite, probably because
+they have no automatic validation, or because they take an insane amount of
+time to finish.
Added: subversion/trunk/subversion/tests/manual/permutations.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/manual/permutations.py?rev=959090&view=auto
==============================================================================
--- subversion/trunk/subversion/tests/manual/permutations.py (added)
+++ subversion/trunk/subversion/tests/manual/permutations.py Tue Jun 29 20:22:19 2010
@@ -0,0 +1,72 @@
+# A class that maps out all combinations of a given set
+# This is not a test, this is included by tests,
+# e.g. tree-conflicts-add-vs-add.py
+#
+# See an example below.
+# To run the example, type
+# python permutations.py
+
+import types
+
+class Permutations:
+ def __init__(self, *tokens):
+ self.tokens = tokens
+ self.skip = None
+ self.reset()
+
+ def next(self):
+ if self.eol:
+ return False
+
+ self.row = [ self.tokens[n][self.counter[n]]
+ for n in range(len(self.tokens)) ]
+
+ self.inc()
+
+ if isinstance(self.skip, types.FunctionType) and self.skip(self.row):
+ return self.next()
+ return True
+
+ # Add-with-carry
+ def inc(self, digit=0):
+ n = len(self.tokens) - digit - 1
+ self.counter[n] += 1
+ if self.counter[n] >= len(self.tokens[n]):
+ self.counter[n] -= len(self.tokens[n])
+ if digit + 1 < len(self.tokens):
+ self.inc(digit + 1)
+ else:
+ self.eol = True
+
+ def get(self):
+ return self.row
+
+ def reset(self):
+ self.counter = [0] * len(self.tokens)
+ self.row = None
+ self.eol = False
+
+
+if __name__ == '__main__':
+ print "Example for using the Permutations class."
+ class Foo:
+ str = 'foo'
+
+ class Bar:
+ str = 'bar'
+
+ x = Foo()
+ y = Bar()
+
+ p = Permutations(('A', 'B'), (1, 2, 3), ('-',), (x, y))
+ print "All items:"
+ while p.next():
+ print p.row
+
+ print "\nDefining some items to be skipped:"
+ p.reset()
+ p.skip = lambda row: row[0] == 'B' and row[3] == y
+ while p.next():
+ print p.row
+
+
Added: subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py?rev=959090&view=auto
==============================================================================
--- subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py (added)
+++ subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py Tue Jun 29 20:22:19 2010
@@ -0,0 +1,335 @@
+#!/usr/bin/env python
+
+# Setup your environment so that `which svn` shows the svn you want to test.
+# Just run this file, no parameters. Test files are created in /tmp/...
+# To adjust which tests are run, look at 'p = Permutations(' way below...
+#
+# This runs an insane amount of tests of add-vs.-add situations during update
+# and switch. The output scrolls by, and a summary for all tests with simple
+# greps and wc.db SELECT results is printed in the very end.
+#
+# There is no automatic validation. You have to read the results.
+#
+# To run a gdb in any given place, replace a 'svn()' with 'gdbsvn()',
+# presumably in either up() or sw().
+
+from subprocess import Popen, PIPE, call
+from types import FunctionType, ListType
+import tempfile, os
+from permutations import Permutations
+
+
+def run_cmd(cmd, verbose=True, shell=False):
+ if verbose:
+ if shell:
+ print '\n---', cmd
+ else:
+ print '\n---', ' '.join(cmd)
+ p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=shell)
+ stdout,stderr = p.communicate()[0:2]
+ if verbose and stdout:
+ print stdout,
+ if verbose and stderr:
+ print stderr,
+ return stdout,stderr
+
+def qsvn(*args):
+ return run_cmd(['svn'] + list(args), False)
+
+def svn(*args):
+ return run_cmd(['svn'] + list(args))
+
+def gdbsvn(*args):
+ call(['gdb', '--args', 'svn'] + list(args))
+ return 'gdb', 'gdb'
+
+def shell(script):
+ return run_cmd(script, shell=True)
+
+def rewrite_file(path, contents, auto_newline='\n\n'):
+ dirname = os.path.dirname(path)
+ if dirname and not os.path.lexists(dirname):
+ os.makedirs(dirname)
+ f = open(path, "w")
+ f.write(contents + (auto_newline or ''))
+ f.close()
+
+def read_file(path):
+ try:
+ f = open(path, "r")
+ contents = f.read()
+ f.close()
+ return contents
+ except IOError:
+ return None
+
+def append_file(path, contents):
+ dirname = os.path.dirname(path)
+ if not os.path.lexists(dirname):
+ os.makedirs(dirname)
+ f = open(path, "a")
+ f.write(contents)
+ f.close()
+
+def remove_file(path):
+ if os.path.isfile(path):
+ os.remove(path)
+
+def tempdir():
+ return tempfile.mkdtemp(prefix='tc_add-')
+
+j = os.path.join
+
+f = 'f' # file
+d = 'd' # dir
+l = 'l' # symbolic link
+
+class TestContext:
+ def __init__(self):
+ self.base = tempdir()
+ self.repos = j(self.base, 'repos')
+ self.WC = j(self.base, 'wc')
+ #self.WC2 = j(self.base, 'wc2')
+ self.URL = 'file://' + self.repos
+ shell('svnadmin create "' + self.repos + '"')
+ svn('checkout', self.URL, self.WC)
+ #svn('checkout', self.URL, self.WC2)
+ #svn('up', self.WC2)
+
+ def wc(self, *relpath):
+ if not relpath:
+ return self.WC
+ return j(self.WC, *relpath)
+
+# def wc2(self, *relpath):
+# if not relpath:
+# return self.WC2
+# return j(self.WC2, *relpath)
+
+ def url(self, relpath):
+ if not relpath:
+ return self.URL
+ return self.URL + '/' + relpath
+
+ def head(self):
+ out, err = qsvn('info', self.URL)
+ revstr = 'Revision: '
+ for line in out.split('\n'):
+ if line.startswith(revstr):
+ return int(line.strip()[len(revstr):])
+
+
+
+def unver(ctx, target, kind, content=None):
+ if not content:
+ content = 'content of ' + os.path.basename(target)
+
+ if kind == f:
+ rewrite_file(target, content)
+ shell('cat ' + target)
+ elif kind == l:
+ os.symlink('symlink', target)
+ else:
+ os.mkdir(target)
+
+
+
+def add(ctx, target, kind, content):
+ unver(ctx, target, kind, content)
+ svn('add', target)
+ svn('ps', 'PROP_add_' + content + '_' + kind,
+ 'content_add_' + content + '_' + kind,
+ target)
+
+
+
+def cp(ctx, suffix, target, kind, content=None):
+ if not content:
+ content = 'modified ' + os.path.basename(target)
+
+ if kind == f:
+ src = ctx.url('file' + suffix)
+ elif kind == l:
+ src = ctx.url('symlink' + suffix)
+ else:
+ src = ctx.url('dir' + suffix)
+
+ src = src + '@1'
+ svn('copy', src, target)
+ svn('ps', 'PROP_copied_' + content + '_' + kind + suffix,
+ 'content_' + content + '_' + kind + suffix,
+ target)
+ svn('status', target)
+
+
+def cp1(ctx, target, kind, content=None):
+ return cp(ctx, '1', target, kind, content)
+
+def cp2(ctx, target, kind, content=None):
+ return cp(ctx, '2', target, kind, content)
+
+def prepare_cp(ctx, kind, suffix):
+ if kind == f:
+ target = ctx.wc('file' + suffix)
+ if not os.path.lexists(target):
+ rewrite_file(target, 'copy source ' + suffix)
+ svn('add', target)
+ svn('ps', 'PROP_copy_source_' + kind + suffix,
+ 'content_copy_source_' + kind + suffix,
+ target)
+ elif kind == l:
+ target = ctx.wc('symlink' + suffix)
+ if not os.path.lexists(target):
+ os.symlink('copy_source' + suffix, target)
+ svn('add', target)
+ svn('ps', 'PROP_copy_source_' + kind + suffix,
+ 'content_copy_source_' + kind + suffix,
+ target)
+ else:
+ target = ctx.wc('dir' + suffix)
+ svn('mkdir', target)
+ svn('ps', 'PROP_copy_source_' + kind + suffix,
+ 'content_copy_source_' + kind + suffix,
+ target)
+
+
+def prepare(ctx, action, kind):
+ if action == cp1:
+ prepare_cp(ctx, kind, '1')
+ elif action == cp2:
+ prepare_cp(ctx, kind, '2')
+
+
+
+def up(name, local_action, local_kind, incoming_action, incoming_kind):
+ ctx = TestContext()
+
+ prepare(ctx, local_action, local_kind)
+ prepare(ctx, incoming_action, incoming_kind)
+
+ svn('commit', '-mm', ctx.WC)
+ svn('up', ctx.WC)
+
+ head = ctx.head()
+ print head
+
+ target = ctx.wc(name)
+ incoming_action(ctx, target, incoming_kind, 'incoming')
+ svn('commit', '-mm', ctx.WC)
+
+ # time warp
+ svn('update', '-r', str(head), ctx.WC)
+
+ local_action(ctx, target, local_kind, 'local')
+
+ # get conflicts
+ o1,e1 = svn('update', '--accept=postpone', ctx.WC)
+ o2,e2 = svn('status', ctx.WC)
+ o3,e3 = run_cmd(['sqlite3', ctx.wc('.svn', 'wc.db'),
+ 'select local_relpath,properties from base_node; '
+ +'select local_relpath,properties from working_node; '
+ +'select local_relpath,properties from actual_node; '
+ ])
+ return o1, e1, o2, e2, o3, e3
+
+
+def sw(name, local_action, local_kind, incoming_action, incoming_kind):
+ ctx = TestContext()
+ prepare(ctx, local_action, local_kind)
+ prepare(ctx, incoming_action, incoming_kind)
+ svn('commit', '-mm', ctx.WC)
+
+ svn('mkdir', '-mm', ctx.url('trunk'))
+ svn('copy', '-mm', ctx.url('trunk'), ctx.url('branch'))
+
+ svn('up', ctx.WC)
+
+ target = ctx.wc('branch', name)
+ incoming_action(ctx, target, incoming_kind, 'incoming')
+ svn('commit', '-mm', ctx.WC)
+ svn('up', ctx.WC)
+
+ target = ctx.wc('trunk', name)
+ local_action(ctx, target, local_kind, 'local')
+
+ # get conflicts
+ o1,e1 = svn('switch', '--accept=postpone', ctx.url('branch'), ctx.wc('trunk'))
+ o2,e2 = svn('status', ctx.WC)
+ o3,e3 = run_cmd(['sqlite3', ctx.wc('trunk', '.svn', 'wc.db'),
+ 'select local_relpath,properties from base_node; select'
+ + ' local_relpath,properties from working_node;'])
+ # This is a bit stupid. Someone rewire this.
+ return o1, e1, o2, e2, o3, e3
+
+
+# This controls which tests are run. All possible combinations are tested.
+# The elements are functions for up,sw and add,cp1,cp2,unver, and they are
+# simple strings for f (file), l (symlink), d (directory).
+#
+# cmd local action and kind incoming action and kind
+p = Permutations((up,sw), (add,cp1,unver), (f,l,d), (add,cp2,cp1), (f,l,d))
+
+# Incoming cp1 is meant to match up only with local cp1. Also, cp1-cp1 is
+# supposed to perform identical copies in both incoming and local, so they
+# only make sense with matching kinds. Skip all rows that don't match this:
+p.skip = lambda row: (row[3] == cp1 and (row[4] != row[2] or row[1] != cp1)
+ #Select subsets if desired
+ #or (row[2] != l and row[4] != l)
+ #
+ #or row not in (
+ ##[up, cp1, l, add, l],
+ ##[up, cp1, f, cp2, l],
+ #[up, cp1, f, cp2, f],
+ ##[up, cp1, f, add, f],
+ ##[up, cp1, f, add, l],
+ ##[up, add, l, add, l],
+ #)
+ )
+
+
+
+
+def nameof(thing):
+ if isinstance(thing, FunctionType):
+ return thing.__name__
+ if isinstance(thing, ListType):
+ return '_'.join([ nameof(thang) for thang in thing])
+ return str(thing)
+
+
+def analyze(name, outs):
+ stats = []
+ for o in outs:
+ for line in o.split('\n'):
+ if (line.startswith('svn: ') or line.startswith(' > ')
+ or line.find(name) > -1):
+ stats.append(line)
+ return stats
+
+#os.environ['SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS'] = 'yes'
+
+results = []
+name = None
+try:
+ while p.next():
+ name = nameof(p.row)
+ print name
+ test_func = p.row[0]
+ results.append( (name, analyze( name, test_func( name, *p.row[1:] ) )) )
+except:
+ if name:
+ print 'Error during', name
+ raise
+finally:
+ lines = []
+ for result in results:
+ name = result[0]
+ if result[1]:
+ lines.append('----- ' + name)
+ for stat in result[1]:
+ lines.append(stat)
+ else:
+ lines.append('----- ' + name + ': nothing.')
+ dump = '\n'.join(lines)
+ print dump
+ rewrite_file('tree-conflicts-add-vs-add.py.results', dump)
Propchange: subversion/trunk/subversion/tests/manual/tree-conflicts-add-vs-add.py
------------------------------------------------------------------------------
svn:executable = *
Re: svn commit: r959090 - in /subversion/trunk/subversion/tests/manual:
./ README permutations.py tree-conflicts-add-vs-add.py
Posted by Neels J Hofmeyr <ne...@elego.de>.
On 2010-06-30 08:53, Daniel Shahaf wrote:
> neels@apache.org wrote on Tue, 29 Jun 2010 at 23:22 -0000:
>> + p = Permutations(('A', 'B'), (1, 2, 3), ('-',), (x, y))
>> + print "All items:"
>> + while p.next():
>> + print p.row
>
> Does this duplicate the functionality of itertools.product()?
>
> http://docs.python.org/library/itertools.html?highlight=cartesian
indeed. I asked #python cause it's a bit hard to understand the itertools
help page. And it seems product() does exactly what I want.
list( itertools.product( (1,2), (a,b,c), (x,y) ) )
thanks!
~Neels
Re: svn commit: r959090 - in /subversion/trunk/subversion/tests/manual:
./ README permutations.py tree-conflicts-add-vs-add.py
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
neels@apache.org wrote on Tue, 29 Jun 2010 at 23:22 -0000:
> + p = Permutations(('A', 'B'), (1, 2, 3), ('-',), (x, y))
> + print "All items:"
> + while p.next():
> + print p.row
Does this duplicate the functionality of itertools.product()?
http://docs.python.org/library/itertools.html?highlight=cartesian
Re: svn commit: r959090 - in /subversion/trunk/subversion/tests/manual:
./ README permutations.py tree-conflicts-add-vs-add.py
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
neels@apache.org wrote on Tue, 29 Jun 2010 at 23:22 -0000:
> + p = Permutations(('A', 'B'), (1, 2, 3), ('-',), (x, y))
> + print "All items:"
> + while p.next():
> + print p.row
Does this duplicate the functionality of itertools.product()?
http://docs.python.org/library/itertools.html?highlight=cartesian