Dduvall has submitted this change and it was merged. Change subject: Unit tests for Environment class ......................................................................
Unit tests for Environment class Created an rspec suite which can be run with `bundle exec rspec`, and implemented examples for all public methods of `Environment`. All filesystem IO is currently being mocked using the fakefs gem. Bug: T76627 Change-Id: Ic766a621faad15525de1407bcf7b7a7c39a4b803 --- A .rspec M Gemfile M mediawiki-vagrant.gemspec A spec/mediawiki_vagrant/environment_spec.rb A spec/spec_helper.rb A spec/support/mock_environment.rb A spec/support/string.rb 7 files changed, 424 insertions(+), 4 deletions(-) Approvals: Dduvall: Looks good to me, approved diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color diff --git a/Gemfile b/Gemfile index 0f0665e..01566f1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,14 @@ source 'https://rubygems.org' group :development do - gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git' - gem 'pry-byebug' - gem 'rubocop', require: false + gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git' + gem 'rubocop', require: false +end + +group :development, :test do + gem 'pry-byebug' end group :plugins do - gem 'mediawiki-vagrant', path: '.' + gemspec end diff --git a/mediawiki-vagrant.gemspec b/mediawiki-vagrant.gemspec index c4f36a4..865e6a6 100644 --- a/mediawiki-vagrant.gemspec +++ b/mediawiki-vagrant.gemspec @@ -21,4 +21,7 @@ s.version = MediaWikiVagrant::VERSION s.require_paths = ['lib'] + + s.add_development_dependency 'rspec', '~> 3.1', '>= 3.1.0' + s.add_development_dependency 'fakefs', '~> 0.6', '>= 0.6.5' end diff --git a/spec/mediawiki_vagrant/environment_spec.rb b/spec/mediawiki_vagrant/environment_spec.rb new file mode 100644 index 0000000..625bff0 --- /dev/null +++ b/spec/mediawiki_vagrant/environment_spec.rb @@ -0,0 +1,340 @@ +require 'spec_helper' +require 'mediawiki-vagrant/environment' + +module MediaWikiVagrant + describe Environment do + include SpecHelpers::MockEnvironment + + let(:environment) { Environment.new(directory) } + let(:directory) { '/example' } + + let(:hiera_path) { environment.path('puppet/hieradata/vagrant-managed.yaml') } + + describe '#commit', :fakefs do + subject { environment.commit } + + context 'where .git/refs/heads/master does not exist' do + it { is_expected.to be(nil) } + end + + context 'where .git/refs/heads/master exists' do + before { mock_files_in(directory, '.git/refs/heads/master' => '123456789abc') } + + it('should be the first 9 characters of the master ref') do + expect(subject).to eq('123456789') + end + end + end + + describe '#hiera_delete', :fakefs do + subject { environment.hiera_delete(key) } + + let(:key) { 'foo' } + + before do + mock_file(hiera_path, content: align(<<-end)) + --- + foo: bar + baz: qux + end + end + + it 'deletes the given hiera entry' do + subject + expect(hiera_path.read).to eq(align(<<-end)) + --- + baz: qux + end + end + end + + describe '#hiera_get', :fakefs do + subject { environment.hiera_get(key) } + + let(:key) { 'foo' } + + before do + mock_file(hiera_path, content: align(<<-end)) + --- + foo: bar + baz: qux + end + end + + it 'should be the value of the given hiera entry' do + expect(subject).to eq('bar') + end + end + + describe '#hiera_set', :fakefs do + subject { environment.hiera_set(key, value) } + + let(:key) { 'foo' } + let(:value) { 'quux' } + + before do + mock_file(hiera_path, content: align(<<-end)) + --- + foo: bar + baz: qux + end + end + + it 'should set the given hiera entry' do + subject + expect(hiera_path.read).to eq(align(<<-end)) + --- + foo: quux + baz: qux + end + end + end + + describe '#path' do + subject { environment.path('sub/path') } + + it { is_expected.to be_a(Pathname) } + it { is_expected.to eq(Pathname.new('/example/sub/path')) } + end + + describe '#prune_roles' do + subject { environment.prune_roles } + + it 'removes any configuration for enabled roles that are no longer available' do + expect(environment).to receive(:roles_available).and_return(['foo', 'bar']) + expect(environment).to receive(:roles_enabled).and_return(['foo', 'baz']) + expect(environment).to receive(:update_roles).with(['foo']) + subject + end + end + + describe '#purge_puppet_created_files', :fakefs do + subject { environment.purge_puppet_created_files } + + before do + mock_empty_files_in( + directory, + 'settings.d/puppet-managed/foo.php', + 'settings.d/puppet-managed/bar.php', + 'settings.d/multiwiki/foo.php', + 'settings.d/wikis/foo/bar.php', + 'vagrant.d/foo.yaml', + 'mediawiki/LocalSettings.php' + ) + end + + it 'deletes the global puppet managed PHP files' do + subject + expect(environment.path('settings.d/puppet-managed')).to exist + expect(environment.path('settings.d/puppet-managed/foo.php')).to_not exist + expect(environment.path('settings.d/puppet-managed/bar.php')).to_not exist + end + + it 'deletes the entire directory of multiwiki settings' do + subject + expect(environment.path('settings.d/multiwiki')).to_not exist + end + + it 'deletes the entire directory of wiki settings' do + subject + expect(environment.path('vagrant.d')).to_not exist + end + + it 'deletes the entire directory of vagrant settings' do + subject + expect(environment.path('vagrant.d')).to_not exist + end + + it 'deletes the MediaWiki LocalSettings.php' do + subject + expect(environment.path('mediawiki/LocalSettings.php')).to_not exist + end + end + + describe '#roles_available', :fakefs do + subject { environment.roles_available } + + before do + mock_files_in( + environment.path('puppet/modules/role/manifests'), + 'generic.pp' => 'class role::generic {}', + 'mediawiki.pp' => 'class role::mediawiki {}', + 'labs_initial_content.pp' => 'class role::labs_initial_content {}', + 'foo.pp' => 'class role::foo {}', + 'bar.pp' => 'class role::bar {}', + 'baz.pp' => 'class role::bar {}', + 'blek.pp' => 'class blek {}' + ) + end + + it 'should be a sorted array of unique and properly defined roles' do + expect(subject).to eq(['bar', 'foo']) + end + end + + describe '#roles_enabled', :fakefs do + subject { environment.roles_enabled } + + before do + mock_file(hiera_path, content: align(<<-end)) + --- + classes: + - role::foo + - role::bar + end + end + + it 'should be a sorted array of available roles' do + expect(subject).to eq(['bar', 'foo']) + end + + context 'when a legacy roles file exists' do + let(:legacy_path) { environment.path('puppet/manifests/manifests.d/vagrant-managed.pp') } + + before do + mock_file(legacy_path, content: align(<<-end)) + include role::baz + include role::qux + end + end + + it 'migrates the legacy settings' do + expect(subject).to eq(['baz', 'qux']) + end + + it 'removes the legacy file' do + subject + expect(legacy_path).to_not exist + end + end + end + + describe '#role_docstring', :fakefs do + subject { environment.role_docstring(role) } + + let(:role) { 'foo' } + let(:role_path) { environment.path('puppet/modules/role/manifests/foo.pp') } + + context 'when the role file does not exist' do + it { is_expected.to be(nil) } + end + + context 'when the role file exists' do + before do + mock_file(role_path, content: align(<<-end)) + # == Class: role::foo + # Provides some foo + # + # A Note. + # + class role::foo($bar) {} + end + end + + it { is_expected.to be_a(String) } + + it 'should be the comment header without the leading #s' do + expect(subject).to eq(align(<<-end)) + == Class: role::foo + Provides some foo + + A Note. + + end + end + end + end + + describe '#update_roles', :fakefs do + subject { environment.update_roles(roles) } + + let(:roles) { ['foo', 'bar'] } + + before do + mock_file(hiera_path, content: align(<<-end)) + --- + classes: + - role::baz + - role::qux + end + end + + it 'overwrites the hiera classes with the sorted roles' do + subject + expect(hiera_path.read).to eq(align(<<-end)) + --- + classes: + - role::bar + - role::foo + end + end + end + + describe '#update', :fakefs do + subject { environment.update } + + let(:head_path) { environment.path('.git/FETCH_HEAD') } + let(:stale) { Time.now - (60 * 60 * 24 * 7) - 1 } + + context 'when HEAD is stale' do + before do + mock_file(head_path, mtime: stale) + end + + it 'performs a `git fetch origin` in the environment directory' do + expect(environment).to receive(:system).with('git fetch origin', chdir: directory) + subject + end + + context 'but the MWV_NO_UPDATE flag is set' do + before do + stub_const('ENV', 'MWV_NO_UPDATE' => '1') + end + + it 'does nothing' do + expect(environment).to_not receive(:system) + subject + end + end + + context 'but a no-update file exists in the environment directory' do + before do + mock_file(environment.path('no-update')) + end + + it 'does nothing' do + expect(environment).to_not receive(:system) + subject + end + end + end + + context 'when HEAD is not stale' do + before do + mock_file(head_path, mtime: Time.now) + end + + it 'does nothing' do + expect(environment).to_not receive(:system) + subject + end + end + end + + describe '#valid?' do + subject { environment.valid? } + + context 'when the environment directory is the project directory' do + let(:environment) { Environment.new(File.expand_path('../../../', __FILE__)) } + + it { is_expected.to be(true) } + end + + context 'when the environment directory is elsewhere' do + let(:environment) { Environment.new('/') } + + it { is_expected.to be(false) } + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..cdf972a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,10 @@ +require 'rspec' +require 'fakefs/spec_helpers' + +require_relative 'support/mock_environment' +require_relative 'support/string' + +RSpec.configure do |config| + config.include FakeFS::SpecHelpers, fakefs: true + config.include MediaWikiVagrant::SpecHelpers::String +end diff --git a/spec/support/mock_environment.rb b/spec/support/mock_environment.rb new file mode 100644 index 0000000..48a0ecb --- /dev/null +++ b/spec/support/mock_environment.rb @@ -0,0 +1,33 @@ +module MediaWikiVagrant + module SpecHelpers + module MockEnvironment + def mock_directory(path) + raise 'you must explicitly enable fakefs before mocking files' unless FakeFS.activated? + + FakeFS::FileUtils.mkdir_p(path) + end + + def mock_empty_files_in(dir, *paths) + mock_files_in(dir, paths.each.with_object({}) { |path, hash| hash[path] = '' }) + end + + def mock_file(path, content: "\n", mtime: nil) + raise 'you must explicitly enable fakefs before mocking files' unless FakeFS.activated? + + mock_directory(File.dirname(path)) + FakeFS::File.write(path, content) + FakeFS::File.utime(mtime, mtime, path) unless mtime.nil? + end + + def mock_files(paths_and_content = {}) + paths_and_content.each { |path, content| mock_file(path, content: content) } + end + + def mock_files_in(dir, paths_and_content = {}) + dir = Pathname.new(dir) + + paths_and_content.each { |path, content| mock_file(dir.join(path), content: content) } + end + end + end +end diff --git a/spec/support/string.rb b/spec/support/string.rb new file mode 100644 index 0000000..a095cd3 --- /dev/null +++ b/spec/support/string.rb @@ -0,0 +1,30 @@ +module MediaWikiVagrant + module SpecHelpers + module String + # Removes the least amount of leading spaces from the beginning of each + # line in order to left align the given string. This method helps to + # keep things tidy when using heredocs in examples. + # + # @example + # align(<<-end) + # foo + # bar + # end + # # => "foo\n bar" + # + def align(str) + padding = str.each_line.reduce(nil) do |min, line| + line_padding = line.match(/^( +)[^ ]/) { |m| m[1].length } + + if min && line_padding + [min, line_padding].min + else + min || line_padding + end + end + + padding.nil? ? str : str.gsub(/^ {#{padding}}/, '') + end + end + end +end -- To view, visit https://gerrit.wikimedia.org/r/185350 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ic766a621faad15525de1407bcf7b7a7c39a4b803 Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/vagrant Gerrit-Branch: master Gerrit-Owner: Dduvall <[email protected]> Gerrit-Reviewer: BryanDavis <[email protected]> Gerrit-Reviewer: Dduvall <[email protected]> Gerrit-Reviewer: Hashar <[email protected]> Gerrit-Reviewer: Ori.livneh <[email protected]> Gerrit-Reviewer: Zfilipin <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
