Well, I originally only set out to build a quick script to help me, then I decided to release it. Now, a few versions later, I find myself without the safety of a suite of behavioural specifications.
I have received three separate reports of piston import being broken. One was even reported in the comments here.
To that end, I have started adding behavioural specifications to Piston. The specs run very slowly, due to the nature of the specifications I wrote:
- svnadmin create remote-repository
- svn checkout
- make some changes
- svn commit
- svnadmin create local-repository
- svn checkout
- use the piston commands
working_copy.should match_expectations
Here is one specification:
specs/convert_spec.rb
1 context "convert with no svn:externals" do 2 context_setup do 3 @remote_repos = Repository.new 4 @rwc = WorkingCopy.new(@remote_repos) 5 @rwc.checkout 6 @rwc.mkdir("/trunk") 7 8 @rwc.add("/trunk/README", "this is line 1") 9 @rwc.commit 10 11 @rwc.add("/trunk/main.c", "int main() { return 0; }") 12 @rwc.commit 13 14 @local_repos = Repository.new 15 @lwc = WorkingCopy.new(@local_repos) 16 @lwc.checkout 17 18 @lwc.mkdir("/vendor") 19 @lwc.commit 20 @lwc.update 21 22 convert(@lwc.path + "/vendor") 23 end 24 25 setup do 26 convert(@lwc.path + "/vendor") 27 end 28 29 teardown do 30 @lwc.revert("--recursive") 31 @lwc.status.split.each do |path| 32 FileUtils.rm_rf(path) if path =~ /^\?/ 33 end 34 end 35 36 context_teardown do 37 @lwc.destroy 38 @local_repos.destroy 39 @rwc.destroy 40 @remote_repos.destroy 41 end 42 43 specify "does not touch the working copy" do 44 @lwc.status.should == "" 45 end 46 47 def convert(non_options=[], options=[]) 48 @command = Piston::Commands::Convert.new([non_options].flatten, options) 49 @command.logging_stream = @stream = StringIO.new 50 @command.run 51 end 52 end
In RSpec documentation, the developers of RSpec say about #context_setup and #context_teardown:
The use of these is generally discouraged, because it introduces dependencies between the specs. Still, it might prove useful for very expensive operations if you know what you are doing.
Well, I did find a use for it. And thank god for that. The specs run in 20 seconds, and I only have three specifications at this time:
1 $ spec --format=specdoc 2 3 import with a valid repository URL 4 - copies the files into a named directory 5 6 convert with no svn:externals 7 - does not touch the working copy 8 9 convert with one svn:externals 10 - removes existing folder to replace with piston export 11 12 Finished in 18.186754 seconds 13 14 3 specifications, 0 failures
This journey has been interesting. And interestingly enough, the code I am developing to help me in my specs will help me in the original implementation. I now have real WorkingCopy and Repository objects.
One interesting thing: svnadmin create requires a good entropy source, or else it will block, waiting for more entropy to be generated. I had to recompile Subversion and set --with-devrandom=/dev/urandom. In fact, this is a flag that is passed to APR.
I will release a new Piston version today or tomorrow with at least the golden paths tested.