puppet 3.2.2 → 3.2.3.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (50) hide show
  1. data/Gemfile +1 -1
  2. data/Rakefile +7 -2
  3. data/ext/build_defaults.yaml +1 -1
  4. data/ext/debian/changelog.erb +6 -0
  5. data/ext/debian/control +1 -1
  6. data/ext/project_data.yaml +1 -1
  7. data/ext/redhat/puppet.spec.erb +4 -1
  8. data/ext/windows/service/daemon.bat +1 -1
  9. data/lib/puppet/application/agent.rb +1 -1
  10. data/lib/puppet/application.rb +2 -2
  11. data/lib/puppet/defaults.rb +39 -26
  12. data/lib/puppet/parser/ast/block_expression.rb +4 -0
  13. data/lib/puppet/parser/ast/branch.rb +0 -15
  14. data/lib/puppet/parser/functions/collect.rb +8 -7
  15. data/lib/puppet/parser/functions/each.rb +6 -5
  16. data/lib/puppet/parser/functions/foreach.rb +6 -5
  17. data/lib/puppet/parser/functions/reduce.rb +20 -18
  18. data/lib/puppet/parser/functions/reject.rb +6 -5
  19. data/lib/puppet/parser/functions/select.rb +6 -5
  20. data/lib/puppet/parser/functions/slice.rb +4 -3
  21. data/lib/puppet/resource/catalog.rb +6 -4
  22. data/lib/puppet/resource/type.rb +1 -9
  23. data/lib/puppet/scheduler/timer.rb +1 -1
  24. data/lib/puppet/type/file/ensure.rb +10 -11
  25. data/lib/puppet/util/adsi.rb +15 -15
  26. data/lib/puppet/util/monkey_patches.rb +0 -9
  27. data/lib/puppet/util/windows/user.rb +7 -5
  28. data/lib/puppet/version.rb +1 -1
  29. data/spec/integration/application/apply_spec.rb +4 -0
  30. data/spec/unit/application/apply_spec.rb +1 -0
  31. data/spec/unit/application/facts_spec.rb +3 -1
  32. data/spec/unit/configurer_spec.rb +1 -0
  33. data/spec/unit/parser/ast/block_expression_spec.rb +67 -0
  34. data/spec/unit/parser/functions/fqdn_rand_spec.rb +22 -42
  35. data/spec/unit/parser/functions/sprintf_spec.rb +6 -1
  36. data/spec/unit/pops/parser/rgen_sanitycheck_spec.rb +9 -1
  37. data/spec/unit/provider/exec/posix_spec.rb +1 -0
  38. data/spec/unit/provider/group/windows_adsi_spec.rb +1 -1
  39. data/spec/unit/provider/package/pip_spec.rb +4 -0
  40. data/spec/unit/provider/service/redhat_spec.rb +2 -1
  41. data/spec/unit/provider/user/windows_adsi_spec.rb +1 -2
  42. data/spec/unit/resource/catalog_spec.rb +23 -3
  43. data/spec/unit/resource/type_spec.rb +3 -12
  44. data/spec/unit/type/exec_spec.rb +3 -2
  45. data/spec/unit/util/adsi_spec.rb +46 -11
  46. data/spec/unit/util/rdoc/parser_spec.rb +1 -1
  47. data/spec/unit/util/run_mode_spec.rb +38 -10
  48. data/spec/unit/util/zaml_spec.rb +1 -1
  49. data/spec/unit/util_spec.rb +4 -1
  50. metadata +16 -14
@@ -7,30 +7,29 @@ module Puppet
7
7
 
8
8
  desc <<-'EOT'
9
9
  Whether to create files that don't currently exist.
10
- Possible values are *absent*, *present*, *file*, and *directory*.
10
+ Possible values are `absent`, `present`, `file`, `directory`, and `link`.
11
11
  Specifying `present` will match any form of file existence, and
12
12
  if the file is missing will create an empty file. Specifying
13
- `absent` will delete the file (or directory, if `recurse => true`).
13
+ `absent` will delete the file (or directory, if `recurse => true` and
14
+ `force => true`). Specifying `link` requires that you also set the `target`
15
+ attribute; note that symlinks cannot be managed on Windows.
14
16
 
15
- Anything other than the above values will create a symlink; note that
16
- symlinks cannot be managed on Windows. In the interest of readability
17
- and clarity, symlinks should be created by setting `ensure => link` and
18
- explicitly specifying a target; however, if a `target` attribute isn't
19
- provided, the value of the `ensure` attribute will be used as the
20
- symlink target. The following two declarations are equivalent:
17
+ If you specify the path to another file as the ensure value, it is
18
+ equivalent to specifying `link` and using that path as the `target`:
21
19
 
22
- # (Useful on Solaris)
20
+ # Equivalent resources:
23
21
 
24
- # Less maintainable:
25
22
  file { "/etc/inetd.conf":
26
23
  ensure => "/etc/inet/inetd.conf",
27
24
  }
28
25
 
29
- # More maintainable:
30
26
  file { "/etc/inetd.conf":
31
27
  ensure => link,
32
28
  target => "/etc/inet/inetd.conf",
33
29
  }
30
+
31
+ However, we recommend using `link` and `target` explicitly, since this
32
+ behavior can be harder to read.
34
33
  EOT
35
34
 
36
35
  # Most 'ensure' properties have a default, but with files we, um, don't.
@@ -33,16 +33,16 @@ module Puppet::Util::ADSI
33
33
  @computer_name
34
34
  end
35
35
 
36
- def computer_uri
37
- "WinNT://#{computer_name}"
36
+ def computer_uri(host = '.')
37
+ "WinNT://#{host}"
38
38
  end
39
39
 
40
40
  def wmi_resource_uri( host = '.' )
41
41
  "winmgmts:{impersonationLevel=impersonate}!//#{host}/root/cimv2"
42
42
  end
43
43
 
44
- def uri(resource_name, resource_type)
45
- "#{computer_uri}/#{resource_name},#{resource_type}"
44
+ def uri(resource_name, resource_type, host = '.')
45
+ "#{computer_uri(host)}/#{resource_name},#{resource_type}"
46
46
  end
47
47
 
48
48
  def wmi_connection
@@ -54,7 +54,7 @@ module Puppet::Util::ADSI
54
54
  end
55
55
 
56
56
  def sid_for_account(name)
57
- Puppet.deprecation_warning "Puppet::Util::ADSI.sid_for_account is deprecated and will be removed in 3.0, use Puppet::Util::Windows::SID.name_to_account instead."
57
+ Puppet.deprecation_warning "Puppet::Util::ADSI.sid_for_account is deprecated and will be removed in 3.0, use Puppet::Util::Windows::SID.name_to_sid instead."
58
58
 
59
59
  Puppet::Util::Windows::Security.name_to_sid(name)
60
60
  end
@@ -74,8 +74,8 @@ module Puppet::Util::ADSI
74
74
  @native_user ||= Puppet::Util::ADSI.connect(uri)
75
75
  end
76
76
 
77
- def self.uri(name)
78
- Puppet::Util::ADSI.uri(name, 'user')
77
+ def self.uri(name, host = '.')
78
+ Puppet::Util::ADSI.uri(name, 'user', host)
79
79
  end
80
80
 
81
81
  def uri
@@ -175,11 +175,11 @@ module Puppet::Util::ADSI
175
175
  end
176
176
 
177
177
  def self.each(&block)
178
- wql = Puppet::Util::ADSI.execquery("select * from win32_useraccount")
178
+ wql = Puppet::Util::ADSI.execquery("select name from win32_useraccount")
179
179
 
180
180
  users = []
181
181
  wql.each do |u|
182
- users << new(u.name, u)
182
+ users << new(u.name)
183
183
  end
184
184
 
185
185
  users.each(&block)
@@ -216,8 +216,8 @@ module Puppet::Util::ADSI
216
216
  self.class.uri(name)
217
217
  end
218
218
 
219
- def self.uri(name)
220
- Puppet::Util::ADSI.uri(name, 'group')
219
+ def self.uri(name, host = '.')
220
+ Puppet::Util::ADSI.uri(name, 'group', host)
221
221
  end
222
222
 
223
223
  def native_group
@@ -235,14 +235,14 @@ module Puppet::Util::ADSI
235
235
 
236
236
  def add_members(*names)
237
237
  names.each do |name|
238
- native_group.Add(Puppet::Util::ADSI::User.uri(name))
238
+ native_group.Add(Puppet::Util::ADSI::User.uri(name, Puppet::Util::ADSI.computer_name))
239
239
  end
240
240
  end
241
241
  alias add_member add_members
242
242
 
243
243
  def remove_members(*names)
244
244
  names.each do |name|
245
- native_group.Remove(Puppet::Util::ADSI::User.uri(name))
245
+ native_group.Remove(Puppet::Util::ADSI::User.uri(name, Puppet::Util::ADSI.computer_name))
246
246
  end
247
247
  end
248
248
  alias remove_member remove_members
@@ -283,11 +283,11 @@ module Puppet::Util::ADSI
283
283
  end
284
284
 
285
285
  def self.each(&block)
286
- wql = Puppet::Util::ADSI.execquery( "select * from win32_group" )
286
+ wql = Puppet::Util::ADSI.execquery( "select name from win32_group" )
287
287
 
288
288
  groups = []
289
289
  wql.each do |g|
290
- groups << new(g.name, g)
290
+ groups << new(g.name)
291
291
  end
292
292
 
293
293
  groups.each(&block)
@@ -399,12 +399,3 @@ if Puppet::Util::Platform.windows?
399
399
  end
400
400
  end
401
401
 
402
- # Old puppet clients may make large GET requests, lets be reasonably tolerant
403
- # in our default WEBrick server.
404
- require 'webrick'
405
- if defined?(WEBrick::HTTPRequest::MAX_URI_LENGTH) and WEBrick::HTTPRequest::MAX_URI_LENGTH < 8192
406
- # Silence ruby warning: already initialized constant MAX_URI_LENGTH
407
- v, $VERBOSE = $VERBOSE, nil
408
- WEBrick::HTTPRequest.const_set("MAX_URI_LENGTH", 8192)
409
- $VERBOSE = v
410
- end
@@ -54,17 +54,18 @@ module Puppet::Util::Windows::User
54
54
  fLOGON32_PROVIDER_DEFAULT = 0
55
55
 
56
56
  logon_user = Win32API.new("advapi32", "LogonUser", ['P', 'P', 'P', 'L', 'L', 'P'], 'L')
57
- close_handle = Win32API.new("kernel32", "CloseHandle", ['P'], 'V')
57
+ close_handle = Win32API.new("kernel32", "CloseHandle", ['L'], 'B')
58
58
 
59
59
  token = 0.chr * 4
60
60
  if logon_user.call(name, ".", password, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token) == 0
61
61
  raise Puppet::Util::Windows::Error.new("Failed to logon user #{name.inspect}")
62
62
  end
63
63
 
64
+ token = token.unpack('L')[0]
64
65
  begin
65
- yield token.unpack('L')[0] if block_given?
66
+ yield token if block_given?
66
67
  ensure
67
- close_handle.call(token.unpack('L')[0])
68
+ close_handle.call(token)
68
69
  end
69
70
  end
70
71
  module_function :logon_user
@@ -88,7 +89,7 @@ module Puppet::Util::Windows::User
88
89
  pi = [4 * 8, fPI_NOUI, user, nil, nil, nil, nil, profile].pack('LLPPPPPP')
89
90
 
90
91
  load_user_profile = Win32API.new('userenv', 'LoadUserProfile', ['L', 'P'], 'L')
91
- unload_user_profile = Win32API.new('userenv', 'UnloadUserProfile', ['L', 'P'], 'L')
92
+ unload_user_profile = Win32API.new('userenv', 'UnloadUserProfile', ['L', 'L'], 'L')
92
93
 
93
94
  # Load the profile. Since it doesn't exist, it will be created
94
95
  if load_user_profile.call(token, pi) == 0
@@ -97,7 +98,8 @@ module Puppet::Util::Windows::User
97
98
 
98
99
  Puppet.debug("Loaded profile for #{user}")
99
100
 
100
- if unload_user_profile.call(token, pi.unpack('LLLLLLLL').last) == 0
101
+ profile = pi.unpack('LLLLLLLL').last
102
+ if unload_user_profile.call(token, profile) == 0
101
103
  raise Puppet::Util::Windows::Error.new("Failed to unload user profile #{user.inspect}")
102
104
  end
103
105
  end
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '3.2.2'
10
+ PUPPETVERSION = '3.2.3-rc1'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -6,6 +6,10 @@ require 'puppet/application/apply'
6
6
  describe "apply" do
7
7
  include PuppetSpec::Files
8
8
 
9
+ before :each do
10
+ Puppet[:reports] = "none"
11
+ end
12
+
9
13
  describe "when applying provided catalogs" do
10
14
  it "should be able to apply catalogs provided in a file in pson" do
11
15
  file_to_create = tmpfile("pson_catalog")
@@ -10,6 +10,7 @@ describe Puppet::Application::Apply do
10
10
  before :each do
11
11
  @apply = Puppet::Application[:apply]
12
12
  Puppet::Util::Log.stubs(:newdestination)
13
+ Puppet[:reports] = "none"
13
14
  end
14
15
 
15
16
  after :each do
@@ -21,7 +21,9 @@ describe Puppet::Application::Facts do
21
21
  subject.command_line.stubs(:args).returns %w{find whatever --render-as yaml}
22
22
 
23
23
  expect {
24
- expect { subject.run }.to exit_with 0
24
+ expect {
25
+ subject.run
26
+ }.to exit_with 0
25
27
  }.to have_printed(/object:Puppet::Node::Facts/)
26
28
 
27
29
  @logs.should be_empty
@@ -386,6 +386,7 @@ describe Puppet::Configurer do
386
386
  Puppet[:lastrunfile] = tmpfile('last_run_file')
387
387
 
388
388
  @report = Puppet::Transaction::Report.new("apply")
389
+ Puppet[:reports] = "none"
389
390
  end
390
391
 
391
392
  it "should print a report summary if configured to do so" do
@@ -0,0 +1,67 @@
1
+ #! /usr/bin/env ruby
2
+ require 'spec_helper'
3
+
4
+ describe Puppet::Parser::AST::BlockExpression do
5
+ class StackDepthAST < Puppet::Parser::AST
6
+ attr_reader :call_depth
7
+ def evaluate(*options)
8
+ @call_depth = caller.length
9
+ end
10
+ end
11
+
12
+ NO_SCOPE = nil
13
+
14
+ def depth_probe
15
+ StackDepthAST.new({})
16
+ end
17
+
18
+ def sequence_probe(name, sequence)
19
+ probe = mock("Sequence Probe #{name}")
20
+ probe.expects(:safeevaluate).in_sequence(sequence)
21
+ probe
22
+ end
23
+
24
+ def block_of(children)
25
+ Puppet::Parser::AST::BlockExpression.new(:children => children)
26
+ end
27
+
28
+ def assert_all_at_same_depth(*probes)
29
+ depth0 = probes[0].call_depth
30
+ probes.drop(1).each do |p|
31
+ p.call_depth.should == depth0
32
+ end
33
+ end
34
+
35
+ it "evaluates all its children at the same stack depth" do
36
+ depth_probes = [depth_probe, depth_probe]
37
+ expr = block_of(depth_probes)
38
+
39
+ expr.evaluate(NO_SCOPE)
40
+
41
+ assert_all_at_same_depth(*depth_probes)
42
+ end
43
+
44
+ it "evaluates sequenced children at the same stack depth" do
45
+ depth1 = depth_probe
46
+ depth2 = depth_probe
47
+ depth3 = depth_probe
48
+
49
+ expr1 = block_of([depth1])
50
+ expr2 = block_of([depth2])
51
+ expr3 = block_of([depth3])
52
+
53
+ expr1.sequence_with(expr2).sequence_with(expr3).evaluate(NO_SCOPE)
54
+
55
+ assert_all_at_same_depth(depth1, depth2, depth3)
56
+ end
57
+
58
+ it "evaluates sequenced children in order" do
59
+ evaluation_order = sequence("Child evaluation order")
60
+ expr1 = block_of([sequence_probe("Step 1", evaluation_order)])
61
+ expr2 = block_of([sequence_probe("Step 2", evaluation_order)])
62
+ expr3 = block_of([sequence_probe("Step 3", evaluation_order)])
63
+
64
+ expr1.sequence_with(expr2).sequence_with(expr3).evaluate(NO_SCOPE)
65
+ end
66
+ end
67
+
@@ -2,62 +2,42 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe "the fqdn_rand function" do
5
- before :all do
6
- Puppet::Parser::Functions.autoloader.loadall
5
+ it "provides a random number strictly less than the given max" do
6
+ fqdn_rand(3).should satisfy {|n| n.to_i < 3 }
7
7
  end
8
8
 
9
- before :each do
10
- node = Puppet::Node.new('localhost')
11
- compiler = Puppet::Parser::Compiler.new(node)
12
- @scope = Puppet::Parser::Scope.new(compiler)
13
- @scope["fqdn"] = "127.0.0.1"
9
+ it "provides the same 'random' value on subsequent calls for the same host" do
10
+ fqdn_rand(3).should eql(fqdn_rand(3))
14
11
  end
15
12
 
16
- it "should exist" do
17
- Puppet::Parser::Functions.function("fqdn_rand").should == "function_fqdn_rand"
18
- end
19
-
20
- it "should handle 0 arguments" do
21
- lambda { @scope.function_fqdn_rand([]) }.should_not raise_error(Puppet::ParseError)
22
- end
13
+ it "considers the same host and same extra arguments to have the same random sequence" do
14
+ first_random = fqdn_rand(3, :extra_identifier => [1, "same", "host"])
15
+ second_random = fqdn_rand(3, :extra_identifier => [1, "same", "host"])
23
16
 
24
- it "should handle 1 argument'}" do
25
- lambda { @scope.function_fqdn_rand([3]) }.should_not raise_error(Puppet::ParseError)
17
+ first_random.should eql(second_random)
26
18
  end
27
19
 
20
+ it "allows extra arguments to control the random value on a single host" do
21
+ first_random = fqdn_rand(10000, :extra_identifier => [1, "different", "host"])
22
+ second_different_random = fqdn_rand(10000, :extra_identifier => [2, "different", "host"])
28
23
 
29
- (1..10).each { |n|
30
- it "should handle #{n} additional arguments" do
31
- lambda { @scope.function_fqdn_rand([3,1,2,3,4,5,6,7,8,9,10][0..n]) }.should_not raise_error(Puppet::ParseError)
32
- end
33
- it "should handle #{n} additional string arguments" do
34
- lambda { @scope.function_fqdn_rand([3,%w{ 1 2 3 4 5 6 7 8 9 10}].flatten[0..n]) }.should_not raise_error(Puppet::ParseError)
35
- end
36
- }
37
-
38
- it "should return a value less than max" do
39
- @scope.function_fqdn_rand([3]).should satisfy {|n| n.to_i < 3 }
40
- end
41
-
42
- it "should return the same values on subsequent invocations for the same host" do
43
- @scope.function_fqdn_rand([3,4]).should eql(@scope.function_fqdn_rand([3, 4]))
24
+ first_random.should_not eql(second_different_random)
44
25
  end
45
26
 
46
27
  it "should return different sequences of value for different hosts" do
47
- val1 = @scope.function_fqdn_rand([10000000,4])
48
- @scope.expects(:[]).with("::fqdn").returns("127.0.0.2")
49
- val2 = @scope.function_fqdn_rand([10000000,4])
50
- val1.should_not eql(val2)
51
- end
28
+ val1 = fqdn_rand(1000000000, :host => "first.host.com")
29
+ val2 = fqdn_rand(1000000000, :host => "second.host.com")
52
30
 
53
- it "should return different values for the same hosts with different seeds" do
54
- val1 = @scope.function_fqdn_rand([10000000,4])
55
- val2 = @scope.function_fqdn_rand([10000000,42])
56
31
  val1.should_not eql(val2)
57
32
  end
58
33
 
59
- it "should use the Puppet::Util function" do
60
- Puppet::Util.expects(:deterministic_rand).with(177093203648075535190027737376590689559,4)
61
- @scope.function_fqdn_rand([4])
34
+ def fqdn_rand(max, args = {})
35
+ host = args[:host] || '127.0.0.1'
36
+ extra = args[:extra_identifier] || []
37
+
38
+ scope = Puppet::Parser::Scope.new_for_test_harness('localhost')
39
+ scope.stubs(:[]).with("::fqdn").returns(host)
40
+
41
+ scope.function_fqdn_rand([max] + extra)
62
42
  end
63
43
  end
@@ -32,7 +32,12 @@ describe "the sprintf function" do
32
32
 
33
33
  it "should format large floats" do
34
34
  result = @scope.function_sprintf(["%+.2e", "27182818284590451"])
35
- str = Puppet.features.microsoft_windows? ? "+2.72e+016" : "+2.72e+16"
35
+ str =
36
+ if Puppet.features.microsoft_windows? && RUBY_VERSION[0,3] == '1.8'
37
+ "+2.72e+016"
38
+ else
39
+ "+2.72e+16"
40
+ end
36
41
  result.should(eql(str))
37
42
  end
38
43
 
@@ -4,7 +4,7 @@ require 'puppet/pops'
4
4
 
5
5
  require 'rgen/array_extensions'
6
6
 
7
- describe "RGen working with hashes" do
7
+ describe "RGen extensions to core classes" do
8
8
  it "should be possible to create an empty hash after having required the files above" do
9
9
  # If this fails, it means the rgen addition to Array is not monkey patched as it
10
10
  # should (it will return an array instead of fail in a method_missing), and thus
@@ -12,4 +12,12 @@ describe "RGen working with hashes" do
12
12
  #
13
13
  Hash[[]]
14
14
  end
15
+
16
+ it "should be possible to automatically stringify a nested, empty array during join" do
17
+ # When this fails it means that rgen has incorrectly implemented
18
+ # method_missing on array and is returning an array for to_str instead of
19
+ # failing as is expected allowing stringification to occur
20
+ [[]].join(":").should == ""
21
+ ["1", []].join(":").should == "1:"
22
+ end
15
23
  end
@@ -7,6 +7,7 @@ describe Puppet::Type.type(:exec).provider(:posix) do
7
7
  def make_exe
8
8
  cmdpath = tmpdir('cmdpath')
9
9
  exepath = tmpfile('my_command', cmdpath)
10
+ exepath = exepath + ".exe" if Puppet.features.microsoft_windows?
10
11
  FileUtils.touch(exepath)
11
12
  File.chmod(0755, exepath)
12
13
  exepath
@@ -24,7 +24,7 @@ describe Puppet::Type.type(:group).provider(:windows_adsi) do
24
24
  names = ['group1', 'group2', 'group3']
25
25
  stub_groups = names.map{|n| stub(:name => n)}
26
26
 
27
- connection.stubs(:execquery).with("select * from win32_group").returns stub_groups
27
+ connection.stubs(:execquery).with("select name from win32_group").returns stub_groups
28
28
 
29
29
  described_class.instances.map(&:name).should =~ names
30
30
  end
@@ -192,6 +192,10 @@ describe provider_class do
192
192
 
193
193
  describe "lazy_pip" do
194
194
 
195
+ after(:each) do
196
+ Puppet::Type::Package::ProviderPip.instance_variable_set(:@confine_collection, nil)
197
+ end
198
+
195
199
  it "should succeed if pip is present" do
196
200
  @provider.stubs(:pip).returns(nil)
197
201
  @provider.method(:lazy_pip).call "freeze"
@@ -19,9 +19,10 @@ describe provider_class, :as_platform => :posix do
19
19
  @provider.stubs(:get).with(:hasstatus).returns false
20
20
  FileTest.stubs(:file?).with('/sbin/service').returns true
21
21
  FileTest.stubs(:executable?).with('/sbin/service').returns true
22
+ Facter.stubs(:value).with(:operatingsystem).returns('CentOS')
22
23
  end
23
24
 
24
- osfamily = [ 'redhat', 'suse' ]
25
+ osfamily = [ 'RedHat', 'Suse' ]
25
26
 
26
27
  osfamily.each do |osfamily|
27
28
  it "should be the default provider on #{osfamily}" do
@@ -24,8 +24,7 @@ describe Puppet::Type.type(:user).provider(:windows_adsi) do
24
24
  it "should enumerate all users" do
25
25
  names = ['user1', 'user2', 'user3']
26
26
  stub_users = names.map{|n| stub(:name => n)}
27
-
28
- connection.stubs(:execquery).with("select * from win32_useraccount").returns(stub_users)
27
+ connection.stubs(:execquery).with("select name from win32_useraccount").returns(stub_users)
29
28
 
30
29
  described_class.instances.map(&:name).should =~ names
31
30
  end
@@ -285,10 +285,30 @@ describe Puppet::Resource::Catalog, "when compiling" do
285
285
  @catalog.resource("notify[one]", nil).must equal(@one)
286
286
  end
287
287
 
288
- it "should not allow two resources with the same resource reference" do
289
- @catalog.add_resource(@one)
288
+ describe 'with a duplicate resource' do
289
+ def resource_at(type, name, file, line)
290
+ resource = Puppet::Resource.new(type, name)
291
+ resource.file = file
292
+ resource.line = line
293
+
294
+ Puppet::Type.type(type).new(resource)
295
+ end
296
+
297
+ let(:orig) { resource_at(:notify, 'duplicate-title', '/path/to/orig/file', 42) }
298
+ let(:dupe) { resource_at(:notify, 'duplicate-title', '/path/to/dupe/file', 314) }
290
299
 
291
- proc { @catalog.add_resource(@dupe) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError)
300
+ it "should print the locations of the original duplicated resource" do
301
+ @catalog.add_resource(orig)
302
+
303
+ expect { @catalog.add_resource(dupe) }.to raise_error { |error|
304
+ error.should be_a Puppet::Resource::Catalog::DuplicateResourceError
305
+
306
+ error.message.should match %r[Duplicate declaration: Notify\[duplicate-title\] is already declared]
307
+ error.message.should match %r[in file /path/to/orig/file:42]
308
+ error.message.should match %r[cannot redeclare]
309
+ error.message.should match %r[at /path/to/dupe/file:314]
310
+ }
311
+ end
292
312
  end
293
313
 
294
314
  it "should not store objects that do not respond to :ref" do
@@ -715,15 +715,6 @@ describe Puppet::Resource::Type do
715
715
  dest.doc.should == "foonessyayness"
716
716
  end
717
717
 
718
- it "should turn its code into a BlockExpression if necessary" do
719
- dest = Puppet::Resource::Type.new(:hostclass, "bar", :code => code("foo"))
720
- source = Puppet::Resource::Type.new(:hostclass, "foo", :code => code("bar"))
721
-
722
- dest.merge(source)
723
-
724
- dest.code.should be_instance_of(Puppet::Parser::AST::BlockExpression)
725
- end
726
-
727
718
  it "should set the other class's code as its code if it has none" do
728
719
  dest = Puppet::Resource::Type.new(:hostclass, "bar")
729
720
  source = Puppet::Resource::Type.new(:hostclass, "foo", :code => code("bar"))
@@ -734,15 +725,15 @@ describe Puppet::Resource::Type do
734
725
  end
735
726
 
736
727
  it "should append the other class's code to its code if it has any" do
737
- dcode = Puppet::Parser::AST::ASTArray.new :children => [code("dest")]
728
+ dcode = Puppet::Parser::AST::BlockExpression.new(:children => [code("dest")])
738
729
  dest = Puppet::Resource::Type.new(:hostclass, "bar", :code => dcode)
739
730
 
740
- scode = Puppet::Parser::AST::ASTArray.new :children => [code("source")]
731
+ scode = Puppet::Parser::AST::BlockExpression.new(:children => [code("source")])
741
732
  source = Puppet::Resource::Type.new(:hostclass, "foo", :code => scode)
742
733
 
743
734
  dest.merge(source)
744
735
 
745
- dest.code.children.collect { |l| l[0].value }.should == %w{dest source}
736
+ dest.code.children.collect { |l| l.value }.should == %w{dest source}
746
737
  end
747
738
  end
748
739
  end
@@ -42,8 +42,9 @@ describe Puppet::Type.type(:exec) do
42
42
  describe "when not stubbing the provider" do
43
43
  before do
44
44
  path = tmpdir('path')
45
- true_cmd = File.join(path, 'true')
46
- false_cmd = File.join(path, 'false')
45
+ ext = Puppet.features.microsoft_windows? ? '.exe' : ''
46
+ true_cmd = File.join(path, "true#{ext}")
47
+ false_cmd = File.join(path, "false#{ext}")
47
48
 
48
49
  FileUtils.touch(true_cmd)
49
50
  FileUtils.touch(false_cmd)