One of the most common developer operations when developing a new feature is running a single test related to that feature. As ubicloud uses rspec, generally that takes the form of `rspec file:line`. When you run `rspec file:line`, it needs to load all ruby libraries necessary to run that particular spec, which can take much more time than running the spec itself. For example: ``` $ time rspec spec/model/nic_spec.rb:7 Run options: include {:locations=>{"./spec/model/nic_spec.rb"=>[7]}} Randomized with seed 54633 Nic ubid_to_name returns name from ubid Top 1 slowest examples (0.00289 seconds, 3.5% of total time): Nic ubid_to_name returns name from ubid 0.00289 seconds ./spec/model/nic_spec.rb:7 Finished in 0.08183 seconds (files took 0.90238 seconds to load) 1 example, 0 failures Randomized with seed 54633 real 0m1.361s user 0m1.074s sys 0m0.191s ``` We see here that it takes 1.36 seconds to run this rspec command, of which 0.90 seconds were spent loading files, and only 0.08 seconds were spent running the spec. Most of the time spent loading files is actually spent loading libraries required by files. Since those libraries should be unchanged until you have updated your Gemfile, one strategy for speeding up running a single spec is preloading all libraries into a Ruby process, and then using that Ruby process (or a fork of it) to execute the spec. That approach is implemented by "by". To speed up the above running of a single spec, you first run `rake by`, which will open up a new shell. Inside that shell, you then append `by` before rspec: ``` $ time by rspec spec/model/nic_spec.rb:7 Run options: include {:locations=>{"./spec/model/nic_spec.rb"=>[7]}} Randomized with seed 64910 Nic ubid_to_name returns name from ubid Top 1 slowest examples (0.00293 seconds, 4.8% of total time): Nic ubid_to_name returns name from ubid 0.00293 seconds ./spec/model/nic_spec.rb:7 Finished in 0.06144 seconds (files took 0.12752 seconds to load) 1 example, 0 failures Randomized with seed 64910 real 0m0.579s user 0m0.275s sys 0m0.056s ``` You can see that this drops total execution time from 1.36 seconds to 0.58 seconds, because the time to load files drops from 0.90 seconds to 0.13 seconds. How this works is that `rake by` calls `by-session`. `by-session` creates a `by-server` process that loads `.by-session-setup.rb`, That file loads all libraries in the Gemfile, as well as as any extensions/plugins/other files used by libraries, which are not loaded by requiring the library itself. After the `by-server` process is created, `by-session` spawns a shell that supports `by`. Running `by` inside the subshell connects to the server process, providing the arguments, environment, stdin/stdout/stderr, and the current directory. The server process forks, sets up ENV, reopens stdin/stdout/stderr, changes to the directory in which you called `by`, and operates on the arguments given. If the first argument to `by` is `rspec`, then `by` will operate similarly to `rspec`. This currently uses the master branch of `by`, because rspec support was just added to `by` (to support this feature in ubicloud), and is not yet in a released version. This will require some minor additional maintenance going forward. As there are new files loaded by the specs, beyond what would be loaded by the Gemfile, those will need to be added to `.by-session-setup.rb.
6.1 KiB
6.1 KiB