r10k 1.1.4 → 1.2.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +1 -0
  3. data/.nodeset.yml +7 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +2 -1
  6. data/CHANGELOG +17 -12
  7. data/Gemfile +8 -0
  8. data/README.markdown +4 -2
  9. data/Rakefile +1 -0
  10. data/doc/dynamic-environments.markdown +206 -0
  11. data/doc/puppetfile.markdown +87 -0
  12. data/lib/r10k/cli.rb +1 -1
  13. data/lib/r10k/errors.rb +30 -3
  14. data/lib/r10k/execution.rb +5 -2
  15. data/lib/r10k/git/cache.rb +26 -42
  16. data/lib/r10k/git/commit.rb +22 -0
  17. data/lib/r10k/git/errors.rb +31 -22
  18. data/lib/r10k/git/head.rb +33 -0
  19. data/lib/r10k/git/ref.rb +63 -0
  20. data/lib/r10k/git/repository.rb +65 -36
  21. data/lib/r10k/git/tag.rb +26 -0
  22. data/lib/r10k/git/working_dir.rb +93 -83
  23. data/lib/r10k/git.rb +14 -0
  24. data/lib/r10k/module/forge.rb +129 -62
  25. data/lib/r10k/module/git.rb +72 -6
  26. data/lib/r10k/module/metadata.rb +47 -0
  27. data/lib/r10k/module/svn.rb +99 -0
  28. data/lib/r10k/module.rb +1 -0
  29. data/lib/r10k/module_repository/forge.rb +64 -0
  30. data/lib/r10k/module_repository.rb +8 -0
  31. data/lib/r10k/semver.rb +1 -1
  32. data/lib/r10k/svn/working_dir.rb +76 -0
  33. data/lib/r10k/task/deployment.rb +21 -28
  34. data/lib/r10k/util/subprocess/io.rb +12 -0
  35. data/lib/r10k/util/subprocess/result.rb +36 -0
  36. data/lib/r10k/util/subprocess/runner.rb +88 -0
  37. data/lib/r10k/util/subprocess.rb +107 -0
  38. data/lib/r10k/version.rb +1 -1
  39. data/r10k.gemspec +11 -1
  40. data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/and_the_expected_version_is_latest/can_fetch_all_versions_of_a_given_module.yml +42 -0
  41. data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/and_the_expected_version_is_latest/can_fetch_the_latest_version_of_a_given_module.yml +42 -0
  42. data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions/can_fetch_all_versions_of_a_given_module.yml +42 -0
  43. data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions/can_fetch_the_latest_version_of_a_given_module.yml +42 -0
  44. data/spec/fixtures/vcr/cassettes/R10K_ModuleRepository_Forge/looking_up_versions.yml +42 -0
  45. data/spec/fixtures/vcr/cassettes/R10K_Module_Forge/and_the_expected_version_is_latest/sets_the_expected_version_based_on_the_latest_forge_version.yml +42 -0
  46. data/spec/rspec-system-r10k/puppetfile.rb +24 -0
  47. data/spec/rspec-system-r10k/tmpdir.rb +32 -0
  48. data/spec/shared-examples/git-ref.rb +49 -0
  49. data/spec/spec_helper.rb +23 -0
  50. data/spec/system/module/forge/install_spec.rb +51 -0
  51. data/spec/system/module/git/install_spec.rb +117 -0
  52. data/spec/system/module/svn/install_spec.rb +51 -0
  53. data/spec/system/module/svn/update_spec.rb +38 -0
  54. data/spec/system/spec_helper.rb +60 -0
  55. data/spec/system/system-helpers.rb +4 -0
  56. data/spec/system/version_spec.rb +7 -0
  57. data/spec/system-provisioning/el.rb +38 -0
  58. data/spec/unit/deployment/source_spec.rb +1 -1
  59. data/spec/unit/git/cache_spec.rb +38 -0
  60. data/spec/unit/git/commit_spec.rb +33 -0
  61. data/spec/unit/git/head_spec.rb +27 -0
  62. data/spec/unit/git/ref_spec.rb +68 -0
  63. data/spec/unit/git/tag_spec.rb +31 -0
  64. data/spec/unit/module/forge_spec.rb +157 -37
  65. data/spec/unit/module/git_spec.rb +49 -0
  66. data/spec/unit/module/metadata_spec.rb +68 -0
  67. data/spec/unit/module/svn_spec.rb +146 -0
  68. data/spec/unit/module_repository/forge_spec.rb +32 -0
  69. metadata +151 -8
@@ -0,0 +1,38 @@
1
+ require 'system/spec_helper'
2
+
3
+ describe 'updating modules from SVN' do
4
+
5
+ extend SystemProvisioning::EL
6
+
7
+ before(:all) { yum_install 'subversion' }
8
+ after(:all) { shell %[yum -y remove subversion] }
9
+
10
+
11
+ it "reinstalls the module when the installed module isn't an svn repo"
12
+ it "reinstalls the module when the svn url doesn't match the installed module"
13
+
14
+ describe 'updating to a specific revision' do
15
+
16
+ include_context 'system module installation'
17
+
18
+ before(:all) do
19
+ shell %[echo "mod 'gitolite', :svn => 'https://github.com/nvalentine-puppetlabs/puppet-gitolite/trunk', :rev => '10'" > ./Puppetfile]
20
+ shell %[r10k puppetfile install]
21
+ shell %[echo "mod 'gitolite', :svn => 'https://github.com/nvalentine-puppetlabs/puppet-gitolite/trunk', :rev => '20'" > ./Puppetfile]
22
+ end
23
+
24
+ it "installs the module successfully" do
25
+ shell %[r10k puppetfile install] do |sh|
26
+ expect(sh.exit_code).to eq 0
27
+ end
28
+ end
29
+
30
+ it "checks out the specific revision" do
31
+ expect(command('cd modules/gitolite; svn info')).to return_stdout /Revision: 20/
32
+ end
33
+ end
34
+
35
+ describe 'when the installed revision is newer than the requested version' do
36
+ it 'downgrades the module'
37
+ end
38
+ end
@@ -0,0 +1,60 @@
1
+ require 'rspec-system/spec_helper'
2
+ require 'rspec-system-serverspec/helpers'
3
+
4
+ require 'system/system-helpers'
5
+
6
+ require 'system-provisioning/el'
7
+
8
+ require 'rspec-system-r10k/tmpdir'
9
+ require 'rspec-system-r10k/puppetfile'
10
+
11
+ RSpec.configure do |c|
12
+
13
+ include SystemProvisioning::EL
14
+
15
+ def install_deps
16
+ install_epel_release
17
+ install_puppetlabs_release
18
+
19
+ yum_install %w[ruby rubygems]
20
+ yum_install %w[puppet]
21
+ end
22
+
23
+ def build_artifact
24
+ require 'r10k/version'
25
+
26
+ desc = %x{git describe}.chomp
27
+ artifact_name = "r10k-#{desc}.gem"
28
+
29
+ system('gem build r10k.gemspec')
30
+ FileUtils.mv "r10k-#{R10K::VERSION}.gem", artifact_name
31
+
32
+ artifact_name
33
+ end
34
+
35
+ def upload_artifact(name)
36
+ rcp :sp => "./#{name}", :dp => '/root'
37
+ FileUtils.rm name
38
+ end
39
+
40
+ def install_artifact(name)
41
+ shell "gem install --no-rdoc --no-ri /root/#{name}"
42
+ shell "rm /root/#{name}"
43
+ end
44
+
45
+ def purge_gems
46
+ shell 'gem list | cut -d" " -f1 | xargs gem uninstall -aIx'
47
+ end
48
+
49
+ def purge_r10k
50
+ shell 'gem uninstall -aIx r10k'
51
+ end
52
+
53
+ c.before(:suite) do
54
+ purge_r10k
55
+ install_deps
56
+ name = build_artifact
57
+ upload_artifact(name)
58
+ install_artifact(name)
59
+ end
60
+ end
@@ -0,0 +1,4 @@
1
+ shared_context 'system module installation' do
2
+ before(:all) { shell 'rm -rf modules' }
3
+ after(:all) { shell 'rm -rf modules' }
4
+ end
@@ -0,0 +1,7 @@
1
+ require 'system/spec_helper'
2
+
3
+ describe 'printing the version' do
4
+ describe command('r10k version') do
5
+ it { should return_stdout /1.1/ }
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ module SystemProvisioning
2
+ module EL
3
+ def install_epel_release
4
+ rpm_install(
5
+ 'epel-release',
6
+ 'http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm'
7
+ )
8
+ end
9
+
10
+ def install_puppetlabs_release
11
+ rpm_install(
12
+ 'puppetlabs-release',
13
+ 'http://yum.puppetlabs.com/puppetlabs-release-el-5.noarch.rpm'
14
+ )
15
+ end
16
+
17
+ def yum_install(*pkgs)
18
+ pkgs = Array(*pkgs)
19
+
20
+ pkgs.each do |pkg|
21
+
22
+ check_cmd = shell "rpm -q --filesbypkg #{pkg}"
23
+ if check_cmd.exit_code != 0
24
+ shell "yum -y install #{pkg}"
25
+ end
26
+ end
27
+ end
28
+
29
+ def rpm_install(name, install_name = nil)
30
+ install_name ||= name
31
+
32
+ check_cmd = shell "rpm -q --filesbypkg #{name}"
33
+ if check_cmd.exit_code != 0
34
+ shell "rpm -Uvh #{install_name}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -6,7 +6,7 @@ describe R10K::Deployment::Source do
6
6
  let(:remote) { 'git://github.com/adrienthebo/r10k-fixture-repo' }
7
7
  let(:basedir) { '/tmp' }
8
8
 
9
- describe 'environments' do
9
+ describe 'environments', :integration => true do
10
10
  it 'uses the name as a prefix when told' do
11
11
  subject = described_class.new(name, remote, basedir, true)
12
12
  subject.fetch_remote()
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'r10k/git/cache'
3
+
4
+ describe R10K::Git::Cache do
5
+
6
+ subject(:cache) { described_class.new('git://some/git/remote') }
7
+
8
+ before do
9
+ expect(cache).to receive(:execute).never
10
+ end
11
+
12
+ describe "updating the cache" do
13
+ it "only updates the cache once" do
14
+ expect(cache).to receive(:sync!).exactly(1).times
15
+ cache.sync
16
+ cache.sync
17
+ end
18
+ end
19
+
20
+
21
+ describe "enumerating branches" do
22
+ let(:refs) do
23
+ %w[
24
+ refs/heads/master
25
+ refs/heads/next
26
+ refs/heads/next-fetch-errors
27
+ refs/heads/next-update-forge-modules
28
+ ].map { |line| line + "\n" }.join
29
+ end
30
+
31
+ it "lists local branches using git for-each-ref" do
32
+ expect(cache).to receive(:git).with(%w[for-each-ref refs/heads --format %(refname)], anything).and_return refs
33
+
34
+ expect(cache.branches).to eq %w[master next next-fetch-errors next-update-forge-modules]
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'r10k/git'
3
+
4
+ describe R10K::Git::Commit do
5
+
6
+ let(:ref) { '96eeaba8c5069e31400a3dfcbeb37d016c1b1980' }
7
+ let(:repo) { double('git repository') }
8
+ subject { described_class.new(ref) }
9
+
10
+
11
+ describe "determining if the commit can be resolved" do
12
+ before do
13
+ subject.repository = repo
14
+ end
15
+
16
+ it "is true if the commit can be rev-parsed" do
17
+ expect(repo).to receive(:rev_parse).with(ref).and_return ref
18
+ expect(subject).to be_resolvable
19
+ end
20
+
21
+ it "is true if the commit cannot be rev-parsed" do
22
+ expect(repo).to receive(:rev_parse).with(ref).and_raise(R10K::Git::UnresolvableRefError, :ref => ref)
23
+ expect(subject).to_not be_resolvable
24
+ end
25
+ end
26
+
27
+ it "can be converted to a string" do
28
+ expect(subject.to_s).to eq ref
29
+ end
30
+
31
+ it_behaves_like "a git ref"
32
+ it_behaves_like "an immutable git ref"
33
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'r10k/git'
3
+
4
+ describe R10K::Git::Head do
5
+
6
+ let(:ref) { 'git/branch' }
7
+ let(:repo) { double('git repository') }
8
+ subject { described_class.new(ref) }
9
+
10
+
11
+ describe "determining if the head can be resolved" do
12
+ it "is always false"
13
+ end
14
+
15
+ describe "determining if the head needs to be fetched" do
16
+ it "is always true" do
17
+ expect(subject.fetch?).to be_true
18
+ end
19
+ end
20
+
21
+ it "can be converted to a string" do
22
+ expect(subject.to_s).to eq ref
23
+ end
24
+
25
+ it_behaves_like "a git ref"
26
+ end
27
+
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'r10k/git'
3
+
4
+ describe R10K::Git::Ref do
5
+
6
+ let(:ref) { 'master' }
7
+ let(:repo) { double('git repository') }
8
+ subject { described_class.new(ref) }
9
+
10
+ describe "fetching the SHA1" do
11
+ it "raises an error if there is not a linked repository" do
12
+ expect {
13
+ subject.sha1
14
+ }.to raise_error(ArgumentError, /Cannot resolve .*#{ref}.*: no associated git repository/)
15
+ end
16
+
17
+ it "raises an error if the SHA1 could not be resolved" do
18
+ subject.repository = repo
19
+ expect(repo).to receive(:rev_parse).with(ref).and_raise(R10K::Git::UnresolvableRefError)
20
+
21
+ expect {
22
+ subject.sha1
23
+ }.to raise_error(R10K::Git::UnresolvableRefError)
24
+ end
25
+
26
+ it "looks up the ref against the linked repository" do
27
+ subject.repository = repo
28
+ expect(repo).to receive(:rev_parse).with(ref).and_return 'hash'
29
+ expect(subject.sha1).to eq 'hash'
30
+ end
31
+
32
+ it "invokes the #ref method" do
33
+ subject.repository = repo
34
+ expect(repo).to receive(:rev_parse).with(ref).and_return 'hash'
35
+ expect(subject).to receive(:ref).and_return ref
36
+ expect(subject.sha1).to eq 'hash'
37
+ end
38
+ end
39
+
40
+ describe "determining if the ref can be resolved" do
41
+ describe "and the ref is a head" do
42
+ it "is always false"
43
+ end
44
+
45
+ describe "and the ref is a tag" do
46
+ it "is true if the tag has been fetched"
47
+ it "is false if the tag cannot be resolved"
48
+ end
49
+
50
+ describe "and the ref is a commit" do
51
+ it "is true if the commit has been fetched"
52
+ it "is false if the commit cannot be resolved"
53
+ end
54
+ end
55
+
56
+ describe "determining if the ref needs to be fetched" do
57
+ it "uses the result of #resolvable? if the ref is a tag"
58
+ it "uses the result of #resolvable? if the ref is a commit"
59
+
60
+ it "is true if the ref is a head"
61
+ end
62
+
63
+ it "can be converted to a string" do
64
+ expect(subject.to_s).to eq ref
65
+ end
66
+
67
+ it_behaves_like "a git ref"
68
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'r10k/git'
3
+
4
+ describe R10K::Git::Tag do
5
+
6
+ let(:ref) { '0.1.0' }
7
+ let(:repo) { double('git repository') }
8
+ subject { described_class.new(ref) }
9
+
10
+
11
+ describe "determining if the tag can be resolved" do
12
+ it "is true if the tag has been fetched" do
13
+ expect(repo).to receive(:rev_parse).with(ref).and_return('32f8ec692906783ee60e02e4a4154bc3a87dfeb6')
14
+ subject.repository = repo
15
+ expect(subject).to be_resolvable
16
+ end
17
+
18
+ it "is false if the tag cannot be resolved" do
19
+ expect(repo).to receive(:rev_parse).with(ref).and_raise(R10K::Git::UnresolvableRefError, :ref => ref)
20
+ subject.repository = repo
21
+ expect(subject).to_not be_resolvable
22
+ end
23
+ end
24
+
25
+ it "can be converted to a string" do
26
+ expect(subject.to_s).to eq ref
27
+ end
28
+
29
+ it_behaves_like "a git ref"
30
+ it_behaves_like "an immutable git ref"
31
+ end
@@ -3,26 +3,24 @@ require 'r10k/semver'
3
3
  require 'spec_helper'
4
4
 
5
5
  describe R10K::Module::Forge do
6
- before :each do
7
- allow_any_instance_of(Object).to receive(:systemu).and_raise "Tests should never invoke system calls"
8
- end
9
6
 
10
- before :each do
11
- log = double('stub logger').as_null_object
12
- described_class.any_instance.stub(:logger).and_return log
13
- end
7
+ include_context 'stub logging'
8
+ include_context 'fail on execution'
9
+
10
+ let(:fixture_modulepath) { File.expand_path('spec/fixtures/module/forge', PROJECT_ROOT) }
11
+ let(:empty_modulepath) { File.expand_path('spec/fixtures/empty', PROJECT_ROOT) }
14
12
 
15
13
  describe "implementing the Puppetfile spec" do
16
14
  it "should implement 'branan/eight_hundred', '8.0.0'" do
17
- described_class.should be_implement('branan/eight_hundred', '8.0.0')
15
+ expect(described_class).to be_implement('branan/eight_hundred', '8.0.0')
18
16
  end
19
17
 
20
18
  it "should fail with an invalid full name" do
21
- described_class.should_not be_implement('branan-eight_hundred', '8.0.0')
19
+ expect(described_class).to_not be_implement('branan-eight_hundred', '8.0.0')
22
20
  end
23
21
 
24
22
  it "should fail with an invalid version" do
25
- described_class.should_not be_implement('branan-eight_hundred', 'not a semantic version')
23
+ expect(described_class).to_not be_implement('branan-eight_hundred', 'not a semantic version')
26
24
  end
27
25
  end
28
26
 
@@ -30,61 +28,183 @@ describe R10K::Module::Forge do
30
28
  subject { described_class.new('branan/eight_hundred', '/moduledir', '8.0.0') }
31
29
 
32
30
  its(:name) { should eq 'eight_hundred' }
33
- its(:owner) { should eq 'branan' }
31
+ its(:author) { should eq 'branan' }
34
32
  its(:full_name) { should eq 'branan/eight_hundred' }
35
33
  its(:basedir) { should eq '/moduledir' }
36
34
  its(:full_path) { should eq '/moduledir/eight_hundred' }
37
35
  end
38
36
 
39
37
  describe "when syncing" do
40
- let(:fixture_modulepath) { File.expand_path('spec/fixtures/module/forge', PROJECT_ROOT) }
41
- let(:empty_modulepath) { File.expand_path('spec/fixtures/empty', PROJECT_ROOT) }
38
+ let(:metadata) do
39
+ double('metadata',
40
+ :exist? => true,
41
+ :author => 'branan',
42
+ :version => R10K::SemVer.new('8.0.0'))
43
+ end
44
+
45
+ subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
46
+
47
+ before { allow(R10K::Module::Metadata).to receive(:new).and_return metadata }
42
48
 
43
49
  describe "and the module is in sync" do
44
- subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
50
+ before do
51
+ allow(subject).to receive(:status).and_return :insync
52
+ end
45
53
 
46
- it { should be_insync }
47
- its(:version) { should eq '8.0.0' }
54
+ it "is in sync" do
55
+ expect(subject).to be_insync
56
+ end
57
+
58
+ it "doesn't act when syncing anything" do
59
+ expect(subject).to receive(:install).never
60
+ expect(subject).to receive(:upgrade).never
61
+ expect(subject).to receive(:reinstall).never
62
+ subject.sync
63
+ end
48
64
  end
49
65
 
50
- describe "and the desired version is newer than the installed version" do
51
- subject { described_class.new('branan/eight_hundred', fixture_modulepath, '80.0.0') }
66
+ describe "and the module is mismatched" do
67
+ before do
68
+ allow(subject).to receive(:status).and_return :mismatched
69
+ end
70
+
71
+ it "is not in sync" do
72
+ expect(subject).to_not be_insync
73
+ end
74
+
75
+ it "reinstalls the module" do
76
+ expect(subject).to receive(:reinstall)
77
+ subject.sync
78
+ end
52
79
 
53
- it { should_not be_insync }
54
- its(:version) { should eq 'v8.0.0' }
80
+ it "reinstalls by removing the existing directory and calling the module tool" do
81
+ expect(FileUtils).to receive(:rm_rf)
82
+ expect(subject).to receive(:pmt) do |args|
83
+ expect(args).to include 'install'
84
+ expect(args).to include '--version=8.0.0'
85
+ expect(args).to include 'branan/eight_hundred'
86
+ end
55
87
 
56
- it "should try to upgrade the module" do
57
- expected = %w{upgrade --version=80.0.0 --ignore-dependencies branan/eight_hundred}
58
- expect(subject).to receive(:pmt).with(expected)
59
88
  subject.sync
60
89
  end
61
90
  end
62
91
 
63
- describe "and the desired version is older than the installed version" do
64
- subject { described_class.new('branan/eight_hundred', fixture_modulepath, '7.0.0') }
92
+ describe "and the module is outdated" do
93
+ before do
94
+ allow(subject).to receive(:status).and_return :outdated
95
+ end
96
+
97
+ it "is not in sync" do
98
+ expect(subject).to_not be_insync
99
+ end
100
+
101
+ it "upgrades the module" do
102
+ expect(subject).to receive(:upgrade)
103
+ subject.sync
104
+ end
65
105
 
66
- it { should_not be_insync }
67
- its(:version) { should eq '8.0.0' }
106
+ it "upgrades by calling the module tool" do
107
+ expect(subject).to receive(:pmt) do |args|
108
+ expect(args).to include 'upgrade'
109
+ expect(args).to include '--version=8.0.0'
110
+ expect(args).to include 'branan/eight_hundred'
111
+ end
68
112
 
69
- it "should try to downgrade the module" do
70
- # Again with the magical "v" prefix to the version.
71
- expected = %w{upgrade --version=7.0.0 --ignore-dependencies branan/eight_hundred}
72
- expect(subject).to receive(:pmt).with(expected)
73
113
  subject.sync
74
114
  end
75
115
  end
76
116
 
77
117
  describe "and the module is not installed" do
78
- subject { described_class.new('branan/eight_hundred', empty_modulepath, '8.0.0') }
118
+ before do
119
+ allow(subject).to receive(:status).and_return :absent
120
+ end
79
121
 
80
- it { should_not be_insync }
81
- its(:version) { should eq R10K::SemVer::MIN }
122
+ it "is not in sync" do
123
+ expect(subject).to_not be_insync
124
+ end
82
125
 
83
- it "should try to install the module" do
84
- expected = %w{install --version=8.0.0 --ignore-dependencies branan/eight_hundred}
85
- expect(subject).to receive(:pmt).with(expected)
126
+ it "installs the module" do
127
+ expect(subject).to receive(:uninstall).never
128
+ expect(subject).to receive(:install)
86
129
  subject.sync
87
130
  end
131
+
132
+ it "installs by calling the module tool" do
133
+ expect(subject).to receive(:pmt) do |args|
134
+ expect(args).to include 'install'
135
+ expect(args).to include '--version=8.0.0'
136
+ expect(args).to include 'branan/eight_hundred'
137
+ end
138
+
139
+ subject.sync
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "determining the status" do
145
+
146
+ let(:metadata) { double 'metadata', :version => R10K::SemVer.new('8.0.0'), :author => 'branan', :exist? => true, :read => nil }
147
+
148
+ subject { described_class.new('branan/eight_hundred', '/moduledir', '8.0.0') }
149
+
150
+ before do
151
+ allow(R10K::Module::Metadata).to receive(:new).and_return metadata
152
+ end
153
+
154
+ it "is :absent if the module directory is absent" do
155
+ allow(subject).to receive(:exist?).and_return false
156
+ expect(subject.status).to eq :absent
157
+ end
158
+
159
+ it "is :mismatched if there is no module metadata" do
160
+ allow(subject).to receive(:exist?).and_return true
161
+ allow(metadata).to receive(:exist?).and_return false
162
+
163
+ expect(subject.status).to eq :mismatched
164
+ end
165
+
166
+ it "is :mismatched if the metadata author doesn't match the expected author" do
167
+ allow(subject).to receive(:exist?).and_return true
168
+
169
+ allow(metadata).to receive(:author).and_return 'blargh'
170
+
171
+ expect(subject.status).to eq :mismatched
172
+ end
173
+
174
+ it "is :outdated if the metadata version doesn't match the expected version" do
175
+ allow(subject).to receive(:exist?).and_return true
176
+
177
+ allow(metadata).to receive(:version).and_return R10K::SemVer.new('7.0.0')
178
+
179
+ expect(subject.status).to eq :outdated
180
+ end
181
+
182
+ it "is :insync if the version and the author are in sync" do
183
+ allow(subject).to receive(:exist?).and_return true
184
+
185
+ expect(subject.status).to eq :insync
186
+ end
187
+ end
188
+
189
+ describe "and the expected version is :latest", :vcr => true, :unless => (RUBY_VERSION == '1.8.7') do
190
+ subject { described_class.new('branan/eight_hundred', '/moduledir', :latest) }
191
+
192
+ let(:_metadata) do
193
+ double('metadata',
194
+ :version => R10K::SemVer.new('7.0.0'),
195
+ :author => 'branan',
196
+ :exist? => true,
197
+ :read => nil)
198
+ end
199
+
200
+ before do
201
+ allow(R10K::Module::Metadata).to receive(:new).and_return _metadata
202
+ end
203
+
204
+ it "sets the expected version based on the latest forge version" do
205
+ allow(subject).to receive(:exist?).and_return true
206
+ expect(subject.status).to eq :outdated
207
+ expect(subject.expected_version).to eq R10K::SemVer.new('8.0.0')
88
208
  end
89
209
  end
90
210
  end