Re: migration to NODES

2010-09-28 Thread Daniel Shahaf
I'd rather have O(1) hand-crafted wc's than all 950 wc's the test suite
generates, of which likely 99% are 'normal'... (especially as it's the
end-of-run state, after any conflicts have been resolved etc)

Greg Stein wrote on Tue, Sep 28, 2010 at 05:47:36 -0400:
 I took the 1.6.x branch and ran the test suite. It produced about 950
 working copies, and the (compressed) tarball sits at about 850k. I'm
 thinking about recording 'svn status' for each working copy, and
 checking the tarball in as test data. We can then run an 'svn upgrade'
 on each working copy, then 'svn status', and verify that the two
 status results match. (caveat minor improvements in state tracking and
 status reporting)
 
 But... running upgrade on about 950 working copies and checking their
 status isn't cheap. The tarball sizes don't bother me too much... I'm
 more concerned about test suite runtime.
 
 Anybody else? Should this be normal test run? Or should we set up an
 extended set of tests and drop this into that batch?
 
 Or not even go with this approach?


Re: migration to NODES

2010-09-28 Thread Hyrum K. Wright
On Tue, Sep 28, 2010 at 4:47 AM, Greg Stein gst...@gmail.com wrote:
 On Mon, Sep 27, 2010 at 13:25, Julian Foad julian.f...@wandisco.com wrote:
 On Fri, 2010-09-24, Greg Stein wrote:
 On Fri, Sep 24, 2010 at 11:16, Julian Foad julian.f...@wandisco.com wrote:
 ...
  I think we should produce a test framework that can give us a WC
  containing all the different possible WC states.  Then we can write
  tests against this framework, some tests that test specific state, and
  other tests that apply the same operations to all the states and check
  that it works in all the states that it should.

 This requires a manual process of thinking of all states and all
 permutations. I don't trust it.

 This kind of testing is more about checking that the design is
 implemented and that the code paths are exercised ...

 If we could somehow capture working copies from during normal test
 runs, *then* I think we'd have everything. We can easily get the
 terminal state for each test, which is a great first step. It would be
 great if we could also get the intermediate steps.

 ... while this kind is more about checking for regression or unwanted
 changes of behaviour.  The two approaches are complementary.

 Fair enough.

 I took the 1.6.x branch and ran the test suite. It produced about 950
 working copies, and the (compressed) tarball sits at about 850k. I'm
 thinking about recording 'svn status' for each working copy, and
 checking the tarball in as test data. We can then run an 'svn upgrade'
 on each working copy, then 'svn status', and verify that the two
 status results match. (caveat minor improvements in state tracking and
 status reporting)

 But... running upgrade on about 950 working copies and checking their
 status isn't cheap. The tarball sizes don't bother me too much... I'm
 more concerned about test suite runtime.

 Anybody else? Should this be normal test run? Or should we set up an
 extended set of tests and drop this into that batch?

I've been advocating for a long time the need for an extended test
suite.  (I mean, really, merge_tests.py exercises all of the basic
functions in so many more ways than basic_tests.py, that the latter is
pretty much redundant when doing pre-commit checks.)  This might be an
opportunity to start that ball rolling, but it's probably also a lot
of work. :)

-Hyrum


Re: migration to NODES

2010-09-27 Thread Julian Foad
On Fri, 2010-09-24, Greg Stein wrote:
 On Fri, Sep 24, 2010 at 11:16, Julian Foad julian.f...@wandisco.com wrote:
 ...
  I think we should produce a test framework that can give us a WC
  containing all the different possible WC states.  Then we can write
  tests against this framework, some tests that test specific state, and
  other tests that apply the same operations to all the states and check
  that it works in all the states that it should.
 
 This requires a manual process of thinking of all states and all
 permutations. I don't trust it.

This kind of testing is more about checking that the design is
implemented and that the code paths are exercised ...

 If we could somehow capture working copies from during normal test
 runs, *then* I think we'd have everything. We can easily get the
 terminal state for each test, which is a great first step. It would be
 great if we could also get the intermediate steps.

... while this kind is more about checking for regression or unwanted
changes of behaviour.  The two approaches are complementary.

 Haven't thought much about it, but my thoughts were somewhere along that line.

  I have been thinking this for a while.  As yet I've just got a
  rudimentary constructor for a WC containing (nearly) all *base* states.
  Not changes, yet.  Here it is:
 
 Not sure if it solves everything, but it is a good start. Review below:

Thanks for the review comments.  All useful.

- Julian




Re: migration to NODES

2010-09-24 Thread Julian Foad
On Fri, 2010-09-24 at 01:40 -0400, Greg Stein wrote:
 Hey all,
 
 So I've been thinking of how we upgrade working copies to the new
 NODES table. As before, we have two scenarios to be concerned with:
 
 1. formats 4..10: releases 1.0 thru 1.6
 2. formats 11..19: 1.7-dev
 
 For (1), we revamp the old-entries-writing in entries.c, which is
 invoked as part of upgrade_to_wcng(). Rather than writing to the
 *_NODE tables, we will write to NODES and ACTUAL_NODE. This doesn't
 feel too hard, except for the testing part. Our current
 entries-writing code was tested via entry_modify() and friends when
 those functions were still in use. The only way to test this code path
 now is to create a large set of working copies with all state
 variations. Not fun. Maybe there is a way to automate this, or use our
 test suite to generate working copy datasets?
 
 For (2), I would prefer to do this in code, but being such a difficult
 series of transforms (prior auto-upgrades were quite simple), and that
 we've already had precedent for an external script... I'm thinking of
 just doing that.
 
 Thoughts?

Sounds good.

I think we should produce a test framework that can give us a WC
containing all the different possible WC states.  Then we can write
tests against this framework, some tests that test specific state, and
other tests that apply the same operations to all the states and check
that it works in all the states that it should.

I have been thinking this for a while.  As yet I've just got a
rudimentary constructor for a WC containing (nearly) all *base* states.
Not changes, yet.  Here it is:

[[[
Add test suite functions to create a WC containing all valid base
states.  I would define a base state as a state in which there is
nothing to commit and no unresolved conflicts.

* subversion/tests/cmdline/basic_tests.py
  (add_to_version_control, get_complex_wc_repository_state,
   make_complex_wc_base_state, make_complex_wc_checkout):
New functions.
  (check_out_all_wc_base_states): New dummy test, to exercise these.

 Index: subversion/tests/cmdline/basic_tests.py
 ===
 --- subversion/tests/cmdline/basic_tests.py   (revision 1000757)
 +++ subversion/tests/cmdline/basic_tests.py   (working copy)
 @@ -2551,6 +2551,191 @@ def delete_and_add_same_file(sbox):
  None,
  wc_dir)
  
 +
 +#--
 +
 +# Functions for testing a WC that contains all possible WC states.
 +
 +def add_to_version_control(state_desc, wc_dir):
 +  Create each item in STATE_DESC as a new versioned node in the existing
 + working copy WC_DIR.
 + STATE_DESC is a dictionary of { path string : StateItem object }.
 +
 +  # First, the directories.  Be sure to create parents before their children.
 +  dir_fullpaths = []
 +  for path, state in sorted(state_desc.items()):
 +if state.contents is None:  # a directory
 +  fullpath = os.path.join(wc_dir, path)
 +  dir_fullpaths += [fullpath]
 +  svntest.actions.run_and_verify_svn(None, None, [],
 + 'mkdir', '--parents', 
 *tuple(dir_fullpaths))
 +  # Now all the files.
 +  file_fullpaths = []
 +  for path, state in state_desc.items():
 +if state.contents is not None:  # a file
 +  fullpath = os.path.join(wc_dir, path)
 +  file_fullpaths += [fullpath]
 +  open(fullpath, 'wb').write(state.contents)
 +  svntest.actions.run_and_verify_svn(None, None, [],
 + 'add', *tuple(file_fullpaths))
 +
 +  # Now set each node's properties.  Create a dict {(pname,pval)=[paths]},
 +  # and run one propset per key, for speed.
 +  props_map = {}
 +  for path, state in state_desc.items():
 +fullpath = os.path.join(wc_dir, path)
 +for pname, pval in state.props.items():
 +  props_map[(pname, pval)] = props_map.get((pname, pval), []) + 
 [fullpath]
 +  for (pname, pval), paths in props_map.items():
 +svntest.actions.run_and_verify_svn(None, None, [],
 +   'propset', pname, pval, *tuple(paths))
 +
 +def get_complex_wc_repository_state():
 +  Return a repository state suitable for use as a base for a complex WC.
 + Return ({ dict of StateItem objects }, { dict of authz rules }).
 +
 + - exclude/D/...'D' will be excluded from the WC
 + - exclude/f'f' will be excluded from the WC
 + - unauthz/D/...'D' will be unauthorized for reading
 + - unauthz/f'f' will be unauthorized for reading
 + - notpres/D/...'D' will be updated to a 'not present' state in WC
 + - notpres/f'f' will be updated to a 'not present' state in WC
 + - normal/D-empty   dir, empty, no props
 + - normal/D/... dir with children and props
 + - normal/f-empty   file, empty, no props
 + - normal/f file, with text, with props 

Re: migration to NODES

2010-09-24 Thread Greg Stein
On Fri, Sep 24, 2010 at 11:16, Julian Foad julian.f...@wandisco.com wrote:
...
 I think we should produce a test framework that can give us a WC
 containing all the different possible WC states.  Then we can write
 tests against this framework, some tests that test specific state, and
 other tests that apply the same operations to all the states and check
 that it works in all the states that it should.

This requires a manual process of thinking of all states and all
permutations. I don't trust it.

If we could somehow capture working copies from during normal test
runs, *then* I think we'd have everything. We can easily get the
terminal state for each test, which is a great first step. It would be
great if we could also get the intermediate steps.

Haven't thought much about it, but my thoughts were somewhere along that line.

 I have been thinking this for a while.  As yet I've just got a
 rudimentary constructor for a WC containing (nearly) all *base* states.
 Not changes, yet.  Here it is:

Not sure if it solves everything, but it is a good start. Review below:

...
 +++ subversion/tests/cmdline/basic_tests.py   (working copy)
 @@ -2551,6 +2551,191 @@ def delete_and_add_same_file(sbox):
                                          None,
                                          wc_dir)

 +
 +#--
 +
 +# Functions for testing a WC that contains all possible WC states.
 +
 +def add_to_version_control(state_desc, wc_dir):

pass sbox rather than wc_dir

 +  Create each item in STATE_DESC as a new versioned node in the existing
 +     working copy WC_DIR.
 +     STATE_DESC is a dictionary of { path string : StateItem object }.
 +
 +  # First, the directories.  Be sure to create parents before their 
 children.
 +  dir_fullpaths = []
 +  for path, state in sorted(state_desc.items()):
 +    if state.contents is None:  # a directory
 +      fullpath = os.path.join(wc_dir, path)
 +      dir_fullpaths += [fullpath]
 +  svntest.actions.run_and_verify_svn(None, None, [],
 +                                     'mkdir', '--parents', 
 *tuple(dir_fullpaths))

sbox.simple_mkdir(*dir_fullpaths)

I know that 2.5 does not require conversion to a tuple. 2.4 may, but I
don't have that handy.

You shouldn't need --parents if you create parents before children
(per the comment).

 +  # Now all the files.
 +  file_fullpaths = []
 +  for path, state in state_desc.items():
 +    if state.contents is not None:  # a file
 +      fullpath = os.path.join(wc_dir, path)
 +      file_fullpaths += [fullpath]
 +      open(fullpath, 'wb').write(state.contents)
 +  svntest.actions.run_and_verify_svn(None, None, [],
 +                                     'add', *tuple(file_fullpaths))

sbox.simple_add(*file_fullpaths)

 +
 +  # Now set each node's properties.  Create a dict {(pname,pval)=[paths]},
 +  # and run one propset per key, for speed.
 +  props_map = {}
 +  for path, state in state_desc.items():
 +    fullpath = os.path.join(wc_dir, path)
 +    for pname, pval in state.props.items():
 +      props_map[(pname, pval)] = props_map.get((pname, pval), []) + 
 [fullpath]
 +  for (pname, pval), paths in props_map.items():
 +    svntest.actions.run_and_verify_svn(None, None, [],
 +                                       'propset', pname, pval, 
 *tuple(paths))

sbox.simple_propset(pname, pval, *paths)

 +
 +def get_complex_wc_repository_state():
 +  Return a repository state suitable for use as a base for a complex WC.

Not sure why you have a separate function to build these lists. Just
inline this into the single caller.

...
 +
 +def make_complex_wc_base_state(sbox):
 +  Create a repository revision to use as a base for a complex WC.
 +     SBOX.repo_url must point to an existing repository.
 +     ### Currently, SBOX.wc_dir must point to a WC at rev 1.
 +     Return the dictionary of StateItems objects.
 +  
 +
 +  wc_dir = sbox.wc_dir
 +
 +  items, authz_rules = get_complex_wc_repository_state()
 +
 +  # Make the WC empty, just for ease of checking the expected result.
 +  svntest.actions.run_and_verify_update(wc_dir, None, None, None,
 +                                        None, None, None, None, None, False,
 +                                        '-r0', os.path.join(wc_dir, 'A'),
 +                                        os.path.join(wc_dir, 'iota'))
 +
 +  # Create the desired state in the WC ...
 +  add_to_version_control(items, wc_dir)
 +
 +  # ... and commit it to the repository.
 +  expected_output = svntest.wc.State(wc_dir, {})
 +  for path in items.keys():
 +    expected_output.add({ path: Item(verb='Adding') })
 +  expected_status = svntest.wc.State(wc_dir, {
 +    '': Item(status='  ', wc_rev='1') })
 +  for path in items.keys():
 +    expected_status.add({ path: Item(status='  ', wc_rev='2') })
 +  svntest.actions.run_and_verify_commit(wc_dir,
 +                                        expected_output, expected_status,
 +