Christopher Francisco
Christopher Francisco

Reputation: 16288

ChefSpec runs super slow

I'm following this basic tutorial and it seems these tests are supposed to be run in like 2 seconds max, but I'm getting 41 seconds for 5 tests.

I ran ChefSpec with --profile and this is the result

Top 8 slowest examples (41.17 seconds, 99.8% of total time):
  webserver_test::default When run on CentOS 7.2.1511 installs httpd
5.21 seconds ./spec/unit/recipes/default_spec.rb:20
  webserver_test::default When run on Ubuntu 14.04 converges successfully
5.17 seconds ./spec/unit/recipes/default_spec.rb:39
  webserver_test::default When run on CentOS 7.2.1511 enables the httpd service
5.16 seconds ./spec/unit/recipes/default_spec.rb:24
  webserver_test::default When run on Ubuntu 14.04 starts the apache2 service
5.15 seconds ./spec/unit/recipes/default_spec.rb:51
  webserver_test::default When run on CentOS 7.2.1511 converges successfully
5.15 seconds ./spec/unit/recipes/default_spec.rb:16
  webserver_test::default When run on Ubuntu 14.04 installs apache2
5.13 seconds ./spec/unit/recipes/default_spec.rb:43
  webserver_test::default When run on CentOS 7.2.1511 starts the httpd service
5.11 seconds ./spec/unit/recipes/default_spec.rb:28
  webserver_test::default When run on Ubuntu 14.04 enables apache2 service
5.1 seconds ./spec/unit/recipes/default_spec.rb:47

Finished in 41.26 seconds (files took 6.58 seconds to load)

8 examples, 0 failures

Upvotes: 1

Views: 477

Answers (3)

timurb
timurb

Reputation: 5554

If you have large dirs or files in your repo (like .git or vendor/bundle, see du -chs * for a full list) this may affect the run: chefspec uploads all of them to local temporary Chef server.

Add these to chefignore to avoid uploading them.

This may not be relevant to your case directly but I just met a similar issue (chefspec run of 40 minutes on CI server vs less than 10 seconds on my laptop) so I feel I should leave the solution if anyone runs into this too.

Upvotes: 0

coderanger
coderanger

Reputation: 54249

There are a couple of issues:

  1. The Berkshelf integration adds a pretty high fixed overhead (i.e. it takes some time but only once no matter how many specs you have.
  2. ServerRunner is unilaterally slower than SoloRunner. You should almost always be using SoloRunner. The Chef tutorials are wrong in this respect.
  3. As @smefju mentioned, caching can help though it is often just easier to combine multiple specs:

    it "does httpd stuff" do
       expect(chef_run).to enable_service 'httpd'
       expect(chef_run).to start_service 'httpd'
    end
    

    This will only run the converge once and use it for both checks, rather than having them as two separate examples like in the tutorial. You can put any number of assertions in a single example, just understand that you will improve speed but reduce test isolation. In this case, probably worth it.

Upvotes: 6

Maciej Małecki
Maciej Małecki

Reputation: 2745

You didn't shared the code, but the most likely is that you does not have any cache mechanism for chef run.

Basically this code:

let(:chef_run) do
  runner = ChefSpec::ServerRunner.new
  runner.converge(described_recipe)
end

needs to converge machine in every spec and this is slow. You can consider using built-in mechanism for caching chef_run result or build your own solution if you have more complex spec rules (for example caching for different attributes and services across the whole test suite).

Another part solution is to divide and execute specs in parallel. You can achieve it with parallel_tests gem.

Upvotes: 1

Related Questions