Re: migration to NODES
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
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
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
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
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, +