3 require File.dirname(__FILE__) + '/../lib/puppettest'
8 require 'puppettest/support/resources'
10 class TestTransactions < Test::Unit::TestCase
11 include PuppetTest::FileTesting
12 include PuppetTest::Support::Resources
13 class Fakeprop <Puppet::Property
14 attr_accessor :path, :is, :should, :name
15 def should_to_s(value)
27 def mkgenerator(&block)
29 cleanup { $finished = nil }
31 # Create a bogus type that generates new instances with shorter
32 type = Puppet::Type.newtype(:generator) do
33 newparam(:name, :namevar => true)
35 $finished << self.name
39 type.class_eval(&block)
42 Puppet::Type.rmtype(:generator)
48 # Create a new type that generates instances with shorter names.
50 type = mkgenerator() do
54 ret << self.class.create(:title => title[0..-2])
63 type.class_eval(&block)
73 objects << Puppet::Type.newfile(
77 objects << Puppet::Type.newfile(
82 trans = assert_events([:file_created, :file_created], *objects)
86 assert_nothing_raised {
87 report = trans.generate_report
90 # First test the report logs
91 assert(report.logs.length > 0, "Did not get any report logs")
93 report.logs.each do |obj|
94 assert_instance_of(Puppet::Util::Log, obj)
97 # Then test the metrics
98 metrics = report.metrics
100 assert(metrics, "Did not get any metrics")
101 assert(metrics.length > 0, "Did not get any metrics")
103 assert(metrics.has_key?("resources"), "Did not get object metrics")
104 assert(metrics.has_key?("changes"), "Did not get change metrics")
106 metrics.each do |name, metric|
107 assert_instance_of(Puppet::Util::Metric, metric)
112 # Create a type just for testing prefetch
113 name = :prefetchtesting
115 type = Puppet::Type.newtype(name) do
120 Puppet::Type.rmtype(name)
123 # Now create a provider
124 type.provide(:prefetch) do
125 def self.prefetch(resources)
126 $prefetched = resources
130 # Now create an instance
131 inst = type.create :name => "yay"
133 # Create a transaction
134 trans = Puppet::Transaction.new(mk_catalog(inst))
136 # Make sure prefetch works
137 assert_nothing_raised do
141 assert_equal({inst.title => inst}, $prefetched, "type prefetch was not called")
143 # Now make sure it gets called from within evaluate()
145 assert_nothing_raised do
149 assert_equal({inst.title => inst}, $prefetched, "evaluate did not call prefetch")
152 def test_refreshes_generate_events
154 firstpath = tempfile()
155 secondpath = tempfile()
156 file = Puppet::Type.newfile(:title => "file", :path => path, :content => "yayness")
157 first = Puppet::Type.newexec(:title => "first",
158 :command => "/bin/echo first > #{firstpath}",
159 :subscribe => [:file, path],
162 second = Puppet::Type.newexec(:title => "second",
163 :command => "/bin/echo second > #{secondpath}",
164 :subscribe => [:exec, "first"],
168 assert_apply(file, first, second)
170 assert(FileTest.exists?(secondpath), "Refresh did not generate an event")
173 unless %x{groups}.chomp.split(/ /).length > 1
174 $stderr.puts "You must be a member of more than one group to test transactions"
179 group = Etc.getgrgid(gid)
181 puts "Could not retrieve info for group %s: %s" % [gid, detail]
185 return @groups.include?(group.name)
190 @groups = %x{groups}.chomp.split(/ /)
191 unless @groups.length > 1
193 raise "You must be a member of more than one group to test this"
197 def newfile(hash = {})
199 File.open(tmpfile, "w") { |f| f.puts rand(100) }
201 # XXX now, because os x apparently somehow allows me to make a file
202 # owned by a group i'm not a member of, i have to verify that
203 # the file i just created is owned by one of my groups
205 unless ingroup(File.stat(tmpfile).gid)
206 Puppet.info "Somehow created file in non-member group %s; fixing" %
207 File.stat(tmpfile).gid
211 unless firstgr.is_a?(Integer)
212 str = Etc.getgrnam(firstgr)
215 File.chown(nil, firstgr, tmpfile)
218 hash[:name] = tmpfile
219 assert_nothing_raised() {
220 return Puppet.type(:file).create(hash)
225 assert_nothing_raised() {
226 return Puppet.type(:exec).create(
227 :name => "touch %s" % file,
228 :path => "/bin:/usr/bin:/sbin:/usr/sbin",
234 # modify a file and then roll the modifications back
235 def test_filerollback
240 check = [:group,:mode]
243 assert_nothing_raised() {
247 assert_nothing_raised() {
248 check.each { |property|
249 value = file.value(property)
251 properties[property] = value
256 component = mk_catalog("file",file)
258 groupname = Etc.getgrgid(File.stat(file.name).gid).name
259 assert_nothing_raised() {
260 # Find a group that it's not set to
261 group = @groups.find { |group| group != groupname }
263 raise "Could not find suitable group"
269 trans = assert_events([:file_changed, :file_changed], component)
272 assert_rollback_events(trans, [:file_changed, :file_changed], "file")
274 assert_nothing_raised() {
277 properties.each { |property,value|
279 value, file.value(property), "File %s remained %s" % [property, file.value(property)]
284 # test that services are correctly restarted and that work is done
289 execfile = File.join(tmpdir(), "exectestingness")
290 exec = newexec(execfile)
292 check = [:group,:mode]
294 file[:group] = @groups[0]
296 config = mk_catalog(file)
299 @@tmpfiles << execfile
301 # 'subscribe' expects an array of arrays
302 exec[:subscribe] = [[file.class.name,file.name]]
303 exec[:refreshonly] = true
305 assert_nothing_raised() {
310 check.each { |property|
311 properties[property] = file.value(property)
313 assert_nothing_raised() {
317 # Make a new catalog so the resource relationships get
319 config = mk_catalog(file, exec)
321 trans = assert_events([:file_changed, :triggered], config)
323 assert(FileTest.exists?(execfile), "Execfile does not exist")
324 File.unlink(execfile)
325 assert_nothing_raised() {
326 file[:group] = @groups[1]
329 trans = assert_events([:file_changed, :triggered], config)
330 assert(FileTest.exists?(execfile), "Execfile does not exist")
333 # Verify that one component requiring another causes the contained
334 # resources in the requiring component to get refreshed.
335 def test_refresh_across_two_components
338 execfile = File.join(tmpdir(), "exectestingness2")
339 @@tmpfiles << execfile
340 exec = newexec(execfile)
342 check = [:group,:mode]
344 file[:group] = @groups[0]
347 config = Puppet::Node::Catalog.new
348 fcomp = Puppet::Type.type(:component).create(:name => "file")
349 config.add_resource fcomp
350 config.add_resource file
351 config.add_edge!(fcomp, file)
353 ecomp = Puppet::Type.type(:component).create(:name => "exec")
354 config.add_resource ecomp
355 config.add_resource exec
356 config.add_edge!(ecomp, exec)
358 # 'subscribe' expects an array of arrays
359 #component[:require] = [[file.class.name,file.name]]
360 ecomp[:subscribe] = fcomp
361 exec[:refreshonly] = true
363 trans = assert_events([], config)
365 assert_nothing_raised() {
366 file[:group] = @groups[1]
370 trans = assert_events([:file_changed, :file_changed, :triggered], config)
373 # Make sure that multiple subscriptions get triggered.
378 file = Puppet.type(:file).create(
382 exec1 = Puppet.type(:exec).create(
383 :path => ENV["PATH"],
384 :command => "touch %s" % file1,
385 :refreshonly => true,
386 :subscribe => [:file, path]
388 exec2 = Puppet.type(:exec).create(
389 :path => ENV["PATH"],
390 :command => "touch %s" % file2,
391 :refreshonly => true,
392 :subscribe => [:file, path]
395 assert_apply(file, exec1, exec2)
396 assert(FileTest.exists?(file1), "File 1 did not get created")
397 assert(FileTest.exists?(file2), "File 2 did not get created")
400 # Make sure that a failed trigger doesn't result in other events not
402 def test_failedrefreshes
405 file = Puppet.type(:file).create(
409 exec1 = Puppet.type(:exec).create(
410 :path => ENV["PATH"],
411 :command => "touch /this/cannot/possibly/exist",
413 :refreshonly => true,
417 exec2 = Puppet.type(:exec).create(
418 :path => ENV["PATH"],
419 :command => "touch %s" % newfile,
421 :refreshonly => true,
422 :subscribe => [file, exec1],
426 assert_apply(file, exec1, exec2)
427 assert(FileTest.exists?(newfile), "Refresh file did not get created")
430 # Make sure that unscheduled and untagged objects still respond to events
431 def test_unscheduled_and_untagged_response
432 Puppet::Type.type(:schedule).mkdefaultschedules
433 Puppet[:ignoreschedules] = false
434 file = Puppet.type(:file).create(
441 exec = Puppet.type(:exec).create(
442 :name => "touch %s" % fname,
443 :path => "/usr/bin:/bin",
444 :schedule => "monthly",
445 :subscribe => ["file", file.name]
448 config = mk_catalog(file, exec)
452 assert(FileTest.exists?(fname), "File did not get created")
454 assert(!exec.scheduled?, "Exec is somehow scheduled")
456 # Now remove it, so it can get created again
459 file[:content] = "some content"
461 assert_events([:file_changed, :triggered], config)
463 assert(FileTest.exists?(fname), "File did not get recreated")
465 # Now remove it, so it can get created again
471 # And our file, so it runs
474 Puppet[:tags] = "norun"
476 file[:content] = "totally different content"
478 assert(! file.insync?(file.retrieve), "Uh, file is in sync?")
480 assert_events([:file_changed, :triggered], config)
481 assert(FileTest.exists?(fname), "File did not get recreated")
484 def test_failed_reqs_mean_no_run
485 exec = Puppet::Type.type(:exec).create(
486 :command => "/bin/mkdir /this/path/cannot/possibly/exit",
490 file1 = Puppet::Type.type(:file).create(
497 file2 = Puppet::Type.type(:file).create(
504 config = mk_catalog(exec, file1, file2)
508 assert(! FileTest.exists?(file1[:path]),
509 "File got created even tho its dependency failed")
510 assert(! FileTest.exists?(file2[:path]),
511 "File got created even tho its deep dependency failed")
515 def test_relationship_graph
518 config.meta_def(:f) do |name|
519 self.resource("File[%s]" % name)
522 {"one" => "two", "File[f]" => "File[c]", "File[h]" => "middle"}.each do |source_ref, target_ref|
523 source = config.resource(source_ref) or raise "Missing %s" % source_ref
524 target = config.resource(target_ref) or raise "Missing %s" % target_ref
525 target[:require] = source
528 trans = Puppet::Transaction.new(config)
531 assert_nothing_raised do
532 graph = trans.relationship_graph
535 assert_instance_of(Puppet::Node::Catalog, graph,
536 "Did not get relationship graph")
538 # Make sure all of the components are gone
539 comps = graph.vertices.find_all { |v| v.is_a?(Puppet::Type::Component)}
540 assert(comps.empty?, "Deps graph still contains components %s" %
541 comps.collect { |c| c.ref }.join(","))
543 assert_equal([], comps, "Deps graph still contains components")
545 # It must be reversed because of how topsort works
546 sorted = graph.topsort.reverse
548 # Now make sure the appropriate edges are there and are in the right order
549 assert(graph.dependents(config.f(:f)).include?(config.f(:c)),
550 "c not marked a dep of f")
551 assert(sorted.index(config.f(:c)) < sorted.index(config.f(:f)),
554 config.resource("one").each do |o|
555 config.resource("two").each do |t|
556 assert(graph.dependents(o).include?(t),
557 "%s not marked a dep of %s" % [t.ref, o.ref])
558 assert(sorted.index(t) < sorted.index(o),
559 "%s is not before %s" % [t.ref, o.ref])
563 trans.catalog.leaves(config.resource("middle")).each do |child|
564 assert(graph.dependents(config.f(:h)).include?(child),
565 "%s not marked a dep of h" % [child.ref])
566 assert(sorted.index(child) < sorted.index(config.f(:h)),
567 "%s is not before h" % child.ref)
570 # Lastly, make sure our 'g' vertex made it into the relationship
571 # graph, since it's not involved in any relationships.
572 assert(graph.vertex?(config.f(:g)),
573 "Lost vertexes with no relations")
575 # Now make the reversal graph and make sure all of the vertices made it into that
576 reverse = graph.reversal
577 %w{a b c d e f g h}.each do |letter|
578 file = config.f(letter)
579 assert(reverse.vertex?(file), "%s did not make it into reversal" % letter)
583 # Test pre-evaluation generation
589 ret << self.class.create(:title => title[0..-2])
597 yay = Puppet::Type.newgenerator :title => "yay"
598 rah = Puppet::Type.newgenerator :title => "rah"
599 config = mk_catalog(yay, rah)
600 trans = Puppet::Transaction.new(config)
602 assert_nothing_raised do
606 %w{ya ra y r}.each do |name|
607 assert(trans.catalog.vertex?(Puppet::Type.type(:generator)[name]),
608 "Generated %s was not a vertex" % name)
609 assert($finished.include?(name), "%s was not finished" % name)
612 # Now make sure that cleanup gets rid of those generated types.
613 assert_nothing_raised do
617 %w{ya ra y r}.each do |name|
618 assert(!trans.catalog.vertex?(Puppet::Type.type(:generator)[name]),
619 "Generated vertex %s was not removed from graph" % name)
620 assert_nil(Puppet::Type.type(:generator)[name],
621 "Generated vertex %s was not removed from class" % name)
625 # Test mid-evaluation generation.
626 def test_eval_generate
628 cleanup { $evaluated = nil }
629 type = mkreducer() do
631 $evaluated << self.title
636 yay = Puppet::Type.newgenerator :title => "yay"
637 rah = Puppet::Type.newgenerator :title => "rah", :subscribe => yay
638 config = mk_catalog(yay, rah)
639 trans = Puppet::Transaction.new(config)
643 # Now apply the resources, and make sure they appropriately generate
645 assert_nothing_raised("failed to apply yay") do
646 trans.eval_resource(yay)
649 assert(ya, "Did not generate ya")
650 assert(trans.relationship_graph.vertex?(ya),
651 "Did not add ya to rel_graph")
653 # Now make sure the appropriate relationships were added
654 assert(trans.relationship_graph.edge?(yay, ya),
655 "parent was not required by child")
656 assert(! trans.relationship_graph.edge?(ya, rah),
657 "generated child ya inherited depencency on rah")
659 # Now make sure it in turn eval_generates appropriately
660 assert_nothing_raised("failed to apply yay") do
661 trans.eval_resource(type["ya"])
666 assert(res, "Did not generate %s" % name)
667 assert(trans.relationship_graph.vertex?(res),
668 "Did not add %s to rel_graph" % name)
669 assert($finished.include?("y"), "y was not finished")
672 assert_nothing_raised("failed to eval_generate with nil response") do
673 trans.eval_resource(type["y"])
675 assert(trans.relationship_graph.edge?(yay, ya), "no edge was created for ya => yay")
677 assert_nothing_raised("failed to apply rah") do
678 trans.eval_resource(rah)
682 assert(ra, "Did not generate ra")
683 assert(trans.relationship_graph.vertex?(ra),
684 "Did not add ra to rel_graph" % name)
685 assert($finished.include?("ra"), "y was not finished")
687 # Now make sure this generated resource has the same relationships as
688 # the generating resource
689 assert(! trans.relationship_graph.edge?(yay, ra),
690 "rah passed its dependencies on to its children")
691 assert(! trans.relationship_graph.edge?(ya, ra),
692 "children have a direct relationship")
694 # Now make sure that cleanup gets rid of those generated types.
695 assert_nothing_raised do
699 %w{ya ra y r}.each do |name|
700 assert(!trans.relationship_graph.vertex?(type[name]),
701 "Generated vertex %s was not removed from graph" % name)
702 assert_nil(type[name],
703 "Generated vertex %s was not removed from class" % name)
706 # Now, start over and make sure that everything gets evaluated.
707 trans = Puppet::Transaction.new(config)
709 assert_nothing_raised do
713 assert_equal(%w{yay ya y rah ra r}, $evaluated,
714 "Not all resources were evaluated or not in the right order")
717 def test_ignore_tags?
718 config = Puppet::Node::Catalog.new
719 config.host_config = true
720 transaction = Puppet::Transaction.new(config)
721 assert(! transaction.ignore_tags?, "Ignoring tags when applying a host catalog")
723 config.host_config = false
724 transaction = Puppet::Transaction.new(config)
725 assert(transaction.ignore_tags?, "Not ignoring tags when applying a non-host catalog")
728 def test_missing_tags?
729 resource = stub 'resource', :tagged? => true
730 config = Puppet::Node::Catalog.new
732 # Mark it as a host config so we don't care which test is first
733 config.host_config = true
734 transaction = Puppet::Transaction.new(config)
735 assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when none are set")
737 # host catalogs pay attention to tags, no one else does.
738 Puppet[:tags] = "three,four"
739 config.host_config = false
740 transaction = Puppet::Transaction.new(config)
741 assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when not running a host catalog")
744 config.host_config = true
745 transaction = Puppet::Transaction.new(config)
746 assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when running a host catalog and all tags are present")
748 transaction = Puppet::Transaction.new(config)
749 resource.stubs :tagged? => false
750 assert(transaction.missing_tags?(resource), "Considered a resource not to be missing tags when running a host catalog and tags are missing")
753 # Make sure changes generated by eval_generated resources have proxies
754 # set to the top-level resource.
755 def test_proxy_resources
758 return Puppet::PropertyChange.new(Fakeprop.new(
759 :path => :path, :is => :is, :should => :should, :name => self.name, :resource => "a parent"), :is)
763 resource = type.create :name => "test"
764 config = mk_catalog(resource)
765 trans = Puppet::Transaction.new(config)
768 assert_nothing_raised do
769 trans.eval_resource(resource)
772 changes = trans.instance_variable_get("@changes")
774 assert(changes.length > 0, "did not get any changes")
776 changes.each do |change|
777 assert_equal(resource, change.source, "change did not get proxy set correctly")
781 # Make sure changes in contained files still generate callback events.
782 def test_generated_callbacks
786 file = File.join(dir, "file")
787 File.open(file, "w") { |f| f.puts "" }
788 File.chmod(0644, file)
789 File.chmod(0755, dir) # So only the child file causes a change
791 dirobj = Puppet::Type.type(:file).create :mode => "755", :recurse => true, :path => dir
792 exec = Puppet::Type.type(:exec).create :title => "make",
793 :command => "touch #{maker}", :path => ENV['PATH'], :refreshonly => true,
796 assert_apply(dirobj, exec)
797 assert(FileTest.exists?(maker), "Did not make callback file")
800 # Yay, this out to be fun.
803 cleanup { $triggered = nil }
804 trigger = Class.new do
806 include Puppet::Util::Logging
814 $triggered << self.name
822 # Make a graph with some stuff in it.
823 graph = Puppet::Node::Catalog.new
825 # Add a non-triggering edge.
829 nope = Puppet::Relationship.new(a, b)
830 yep = Puppet::Relationship.new(a, c, {:callback => :refresh})
831 graph.add_edge!(nope)
833 # And a triggering one.
836 # Create our transaction
837 trans = Puppet::Transaction.new(graph)
839 # Set the non-triggering on
840 assert_nothing_raised do
841 trans.set_trigger(nope)
844 assert(! trans.targeted?(b), "b is incorrectly targeted")
847 assert_nothing_raised do
848 trans.set_trigger(yep)
850 assert(trans.targeted?(c), "c is not targeted")
852 # Now trigger our three resources
853 assert_nothing_raised do
854 assert_nil(trans.trigger(a), "a somehow triggered something")
856 assert_nothing_raised do
857 assert_nil(trans.trigger(b), "b somehow triggered something")
859 assert_equal([], $triggered,"got something in triggered")
861 assert_nothing_raised do
862 result = trans.trigger(c)
864 assert(result, "c did not trigger anything")
865 assert_instance_of(Array, result)
867 assert_instance_of(Puppet::Event, event)
868 assert_equal(:triggered, event.event, "event was not set correctly")
869 assert_equal(c, event.source, "source was not set correctly")
870 assert_equal(trans, event.transaction, "transaction was not set correctly")
872 assert(trans.triggered?(c, :refresh),
873 "Transaction did not store the trigger")
877 file = Puppet::Type.newfile(:path => tempfile(), :content => "yay")
878 exec1 = Puppet::Type.type(:exec).create :command => "/bin/echo exec1"
879 exec2 = Puppet::Type.type(:exec).create :command => "/bin/echo exec2"
880 trans = Puppet::Transaction.new(mk_catalog(file, exec1, exec2))
882 # First try it with an edge that has no callback
883 edge = Puppet::Relationship.new(file, exec1)
884 assert_nothing_raised { trans.set_trigger(edge) }
885 assert(! trans.targeted?(exec1), "edge with no callback resulted in a target")
887 # Now with an edge that has an unsupported callback
888 edge = Puppet::Relationship.new(file, exec1, :callback => :nosuchmethod, :event => :ALL_EVENTS)
889 assert_nothing_raised { trans.set_trigger(edge) }
890 assert(! trans.targeted?(exec1), "edge with invalid callback resulted in a target")
892 # Lastly, with an edge with a supported callback
893 edge = Puppet::Relationship.new(file, exec1, :callback => :refresh, :event => :ALL_EVENTS)
894 assert_nothing_raised { trans.set_trigger(edge) }
895 assert(trans.targeted?(exec1), "edge with valid callback did not result in a target")
898 # Testing #401 -- transactions are calling refresh() on classes that don't support it.
899 def test_callback_availability
901 klass = Puppet::Type.newtype(:norefresh) do
902 newparam(:name, :namevar => true) {}
903 def method_missing(method, *args)
909 Puppet::Type.rmtype(:norefresh)
912 file = Puppet::Type.newfile :path => tempfile(), :content => "yay"
913 one = klass.create :name => "one", :subscribe => file
915 assert_apply(file, one)
917 assert(! $called.include?(:refresh), "Called refresh when it wasn't set as a method")
920 # Testing #437 - cyclic graphs should throw failures.
921 def test_fail_on_cycle
922 one = Puppet::Type.type(:exec).create(:name => "/bin/echo one")
923 two = Puppet::Type.type(:exec).create(:name => "/bin/echo two")
927 config = mk_catalog(one, two)
928 trans = Puppet::Transaction.new(config)
929 assert_raise(Puppet::Error) do
934 def test_errors_during_generation
935 type = Puppet::Type.newtype(:failer) do
938 raise ArgumentError, "Invalid value"
941 raise ArgumentError, "Invalid value"
944 cleanup { Puppet::Type.rmtype(:failer) }
946 obj = type.create(:name => "testing")
951 def test_self_refresh_causes_triggering
952 type = Puppet::Type.newtype(:refresher, :self_refresh => true) do
953 attr_accessor :refreshed, :testing
955 newproperty(:testing) do
957 self.is = self.should
965 cleanup { Puppet::Type.rmtype(:refresher)}
967 obj = type.create(:name => "yay", :testing => "cool")
969 assert(! obj.insync?(obj.retrieve), "fake object is already in sync")
971 # Now make sure it gets refreshed when the change happens
973 assert(obj.refreshed, "object was not refreshed during transaction")
977 def test_explicit_dependencies_beat_automatic
978 # Create a couple of different resource sets that have automatic relationships and make sure the manual relationships win
980 # First users and groups
981 group = Puppet::Type.type(:group).create(:name => nonrootgroup.name, :ensure => :present)
982 user = Puppet::Type.type(:user).create(:name => nonrootuser.name, :ensure => :present, :gid => group.title)
984 # Now add the explicit relationship
985 group[:require] = user
989 f = File.join(d, "file")
990 file = Puppet::Type.newfile(:path => f, :content => "yay")
991 dir = Puppet::Type.newfile(:path => d, :ensure => :directory, :require => file)
994 rels.each do |after, before|
995 config = mk_catalog(before, after)
996 trans = Puppet::Transaction.new(config)
997 str = "from %s to %s" % [before, after]
999 assert_nothing_raised("Failed to create graph %s" % str) do
1003 graph = trans.relationship_graph
1004 assert(graph.edge?(before, after), "did not create manual relationship %s" % str)
1005 assert(! graph.edge?(after, before), "created automatic relationship %s" % str)
1009 # #542 - make sure resources in noop mode still notify their resources,
1010 # so that users know if a service will get restarted.
1011 def test_noop_with_notify
1015 file = Puppet::Type.newfile(:path => path, :ensure => :file,
1017 exec = Puppet::Type.type(:exec).create(:command => "touch %s" % epath,
1018 :path => ENV["PATH"], :subscribe => file, :refreshonly => true,
1020 exec2 = Puppet::Type.type(:exec).create(:command => "touch %s" % spath,
1021 :path => ENV["PATH"], :subscribe => exec, :refreshonly => true,
1024 Puppet[:noop] = true
1026 assert(file.noop, "file not in noop")
1027 assert(exec.noop, "exec not in noop")
1030 assert_apply(file, exec, exec2)
1032 assert(! FileTest.exists?(path), "Created file in noop")
1033 assert(! FileTest.exists?(epath), "Executed exec in noop")
1034 assert(! FileTest.exists?(spath), "Executed second exec in noop")
1036 assert(@logs.detect { |l|
1037 l.message =~ /should be/ and l.source == file.property(:ensure).path},
1038 "did not log file change")
1039 assert(@logs.detect { |l|
1040 l.message =~ /Would have/ and l.source == exec.path },
1041 "did not log first exec trigger")
1042 assert(@logs.detect { |l|
1043 l.message =~ /Would have/ and l.source == exec2.path },
1044 "did not log second exec trigger")
1047 def test_only_stop_purging_with_relations
1053 file = Puppet::Type.newfile(:path => path, :ensure => :absent,
1054 :backup => false, :title => "file%s" % i)
1055 File.open(path, "w") { |f| f.puts "" }
1059 files[0][:ensure] = :file
1060 files[0][:require] = files[1..2]
1062 # Mark the second as purging
1065 assert_apply(*files)
1067 assert(FileTest.exists?(paths[1]), "Deleted required purging file")
1068 assert(! FileTest.exists?(paths[2]), "Did not delete non-purged file")
1074 type = Puppet::Type.newtype(:flushtest) do
1076 newproperty(:ensure) do
1091 cleanup { Puppet::Type.rmtype(:flushtest) }
1093 obj = type.create(:name => "test", :ensure => "present")
1095 # first make sure it runs through and flushes
1098 assert_equal("present", $state, "Object did not make a change")
1099 assert_equal(1, $flushed, "object was not flushed")
1101 # Now run a noop and make sure we don't flush
1102 obj[:ensure] = "other"
1106 assert_equal("present", $state, "Object made a change in noop")
1107 assert_equal(1, $flushed, "object was flushed in noop")