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

Reply via email to