Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

s3_source: Lazy load fog library #293

Merged
merged 1 commit into from
May 19, 2015
Merged

s3_source: Lazy load fog library #293

merged 1 commit into from
May 19, 2015

Conversation

Igorshp
Copy link
Contributor

@Igorshp Igorshp commented May 13, 2015

This speeds up all knife commands on systems where knife-ec2 plugin is
installed.

Benchmarks ( done with 'time' command):

Command Before After % Improvement
knife help 8.523s 2.616s 69%
knife search "chef_environment:prod" 20.429s 15.094 26%
knife search "chef_environment:prod AND role:admin" 10.625 5.125s 51%

@Igorshp
Copy link
Contributor Author

Igorshp commented May 13, 2015

As far as I can see, this does not break s3 functionality, but i'm struggling to identify a correct way to test it. Any suggestions?

@btm
Copy link
Contributor

btm commented May 13, 2015

Looking at other code, I'd try something like this. I'm not sure it works, so I'd test it against master too and make sure it fails.

it "loads deps all lazily" do
  expect(Chef::Knife::S3Source).not_to receive(:require)
  Chef::Knife::S3Source.new
end

@Igorshp
Copy link
Contributor Author

Igorshp commented May 13, 2015

Thanks @btm, i like the idea, but unforunately it doesn't work.
I believe it's because that checks for a method called 'require' on S3Source class and real 'require' is part of ruby kernel? https:/ruby/ruby/blob/ca6b174078fa15f33655be704d9409fdbc4f9929/lib/rubygems/core_ext/kernel_require.rb#L38

However:

expect(Kernel).not_to receive(:require)

also doesn't seem to work

@Igorshp
Copy link
Contributor Author

Igorshp commented May 13, 2015

Correct me if I'm wrong, but I'm starting to think that this is impossible to test as s3_source.rb is loaded and parsed when rspec loads.
So by the time it gets to tests, top level 'require' blocks have already been processed and do not get evaluated again.

It is also not possible to check if Fog::* is defined as it is required at the top of the rspec test and is used later for mocking.

@btm
Copy link
Contributor

btm commented May 13, 2015

Yeah, might be impossible. Maybe for the second idea you move the require into the describe block somewhere and create a second describe block? I poked around the tests in core for the knife lazy loader stuff and I didn't see anything magical.

@Igorshp
Copy link
Contributor Author

Igorshp commented May 13, 2015

I'll try that.

I've also revised the PR. after researching how S3Source is used and how load_deps work, the original pr wouldn't have worked as run method is never called for S3Source.

Moving require to 'fog' method seems like a much simpler solution.

@willejs
Copy link

willejs commented May 14, 2015

👍

@Igorshp
Copy link
Contributor Author

Igorshp commented May 19, 2015

@thom @btm
I've added 2 tests, but there is an interesting caveat.

  • first test tries to run fog and expects name error to show that library doesn't get loaded by default
  • second test, runs S3Source.fog and expects argument error to show that :fog method loads fog

If you run s3_source_deps_spec.rb on its own, it works great.

But! if it gets run as part of global tests with 'rspec', the first test fails, as fog is loaded in another spec and gets carried over.

this dependency leak essentially invalidates both of the tests.

@btm
Copy link
Contributor

btm commented May 19, 2015

@Igorshp Oh yeah. I think we're totally in territory where what you're doing is a great exercise, but not required.

I could see a couple options if you want to pursue tests, but I'd be fine adding a comment about the require saying that we don't want to load fog right off.

You could run the test in shell like chef/spec/integration/client/client_spec.rb does, where you call out to ruby and make sure it doesn't raise / exit with an error.

You could add an rspec filter so the test doesn't run if Fog is already loaded (which probably means the test almost never runs, but has some documentation value).

@Igorshp
Copy link
Contributor Author

Igorshp commented May 19, 2015

@btm makes sense, I think that's a good solution.
I've added a spec filter and a couple of comments, it works well.

Will squash the commits once everyone is happy with the PR.

@btm
Copy link
Contributor

btm commented May 19, 2015

@adamedx looks like just you and me over here. Review?

@adamedx
Copy link

adamedx commented May 19, 2015

👍 as long as tests all pass and we have coverage that the lazy load actually works. In general, anything we can do to speed up knife subcommands is welcome, particularly on Windows.

@btm
Copy link
Contributor

btm commented May 19, 2015

@Igorshp 👍 rebase and I'll merge.

This speeds up all knife commands on systems where knife-ec2 plugin is
installed.

Benchmarks ( done with 'time' command):

|               Command                 | Before | After | % Improvement |
|---------------------------------------|--------|---------|-------------|
knife help                              | 8.523s | 2.616s  | 69%         |
knife search "chef_environment:prod"    | 20.429s | 15.094 | 26%         |
knife search "chef_environment:prod AND role:admin"| 10.625| 5.125s| 51% |

Added test for lazy loading, however,  because rspec loads dependencies first
and runs tests second, this specific test needs to be run in isolation from others.
For that reason, it is excluded from global rspec run.

It can be run manually wiht:
rspec spec/unit/s3_source_deps_spec.rb
@Igorshp
Copy link
Contributor Author

Igorshp commented May 19, 2015

@btm all done. squashed commits, updated the commit message

btm added a commit that referenced this pull request May 19, 2015
s3_source: Lazy load fog library
@btm btm merged commit 46b4d87 into chef:master May 19, 2015
@Igorshp
Copy link
Contributor Author

Igorshp commented May 19, 2015

Sweet, thanks @btm @adamedx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants