summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-12-01 04:11:11 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-12-01 04:11:11 +0000
commitf3a0c488b884b59df790fce0192dd1a2d735ad7c (patch)
tree2efc2f2398d9ed2df6a8cb72a0db9ee01035433f
parenta7354d0e3bd77625de9da5f5846bfefbc6d88121 (diff)
downloadpuppet-f3a0c488b884b59df790fce0192dd1a2d735ad7c.tar.gz
puppet-f3a0c488b884b59df790fce0192dd1a2d735ad7c.tar.xz
puppet-f3a0c488b884b59df790fce0192dd1a2d735ad7c.zip
Most of the graphing work is now done. I have also added the generator work in transactions, but I need to migrate files to using it. Until that migration is done, files will not work correctly for many cases.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1896 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/metatype/container.rb20
-rw-r--r--lib/puppet/metatype/manager.rb8
-rw-r--r--lib/puppet/metatype/metaparams.rb87
-rw-r--r--lib/puppet/metatype/relationships.rb142
-rw-r--r--lib/puppet/pgraph.rb125
-rw-r--r--lib/puppet/relationship.rb18
-rw-r--r--lib/puppet/transaction.rb179
-rw-r--r--lib/puppet/type.rb2
-rw-r--r--lib/puppet/type/component.rb3
-rwxr-xr-xtest/lib/puppettest/support/resources.rb37
-rwxr-xr-xtest/other/overrides.rb10
-rw-r--r--test/other/pgraph.rb41
-rwxr-xr-xtest/other/relationships.rb216
-rwxr-xr-xtest/other/transactions.rb136
-rwxr-xr-xtest/types/component.rb30
-rwxr-xr-xtest/types/manager.rb44
-rwxr-xr-xtest/types/type.rb49
17 files changed, 659 insertions, 488 deletions
diff --git a/lib/puppet/metatype/container.rb b/lib/puppet/metatype/container.rb
index 3f970b7d9..9ed587a4c 100644
--- a/lib/puppet/metatype/container.rb
+++ b/lib/puppet/metatype/container.rb
@@ -78,26 +78,6 @@ class Puppet::Type
hash.clear
end
-
- if rmdeps
- Puppet::Event::Subscription.dependencies(self).each { |dep|
- #info "Deleting dependency %s" % dep
- #begin
- # self.unsubscribe(dep)
- #rescue
- # # ignore failed unsubscribes
- #end
- dep.delete
- }
- Puppet::Event::Subscription.subscribers(self).each { |dep|
- #info "Unsubscribing from %s" % dep
- begin
- dep.unsubscribe(self)
- rescue
- # ignore failed unsubscribes
- end
- }
- end
self.class.delete(self)
if defined? @parent and @parent
diff --git a/lib/puppet/metatype/manager.rb b/lib/puppet/metatype/manager.rb
index 996d9a3cc..d2749b87d 100644
--- a/lib/puppet/metatype/manager.rb
+++ b/lib/puppet/metatype/manager.rb
@@ -106,6 +106,14 @@ module Manager
klass
end
+
+ # Remove an existing defined type. Largely used for testing.
+ def rmtype(name)
+ # Then create the class.
+ klass = rmclass(name,
+ :hash => @types
+ )
+ end
# Return a Type instance by name.
def type(name)
diff --git a/lib/puppet/metatype/metaparams.rb b/lib/puppet/metatype/metaparams.rb
index e09bbc6d5..f28103a87 100644
--- a/lib/puppet/metatype/metaparams.rb
+++ b/lib/puppet/metatype/metaparams.rb
@@ -92,6 +92,47 @@ class Puppet::Type
}
end
end
+
+ # We've got four relationship metaparameters, so this method is used
+ # to reduce code duplication between them.
+ def store_relationship(param, values)
+ # We need to support values passed in as an array or as a
+ # resource reference.
+ result = []
+
+ # 'values' could be an array or a reference. If it's an array,
+ # it could be an array of references or an array of arrays.
+ if values.is_a?(Puppet::Type)
+ result << [values.class.name, values.title]
+ else
+ unless values.is_a?(Array)
+ devfail "Relationships must be resource references"
+ end
+ if values[0].is_a?(String) or values[0].is_a?(Symbol)
+ # we're a type/title array reference
+ values[0] = symbolize(values[0])
+ result << values
+ else
+ # we're an array of stuff
+ values.each do |value|
+ if value.is_a?(Puppet::Type)
+ result << [value.class.name, value.title]
+ elsif value.is_a?(Array)
+ value[0] = symbolize(value[0])
+ result << value
+ else
+ devfail "Invalid relationship %s" % value.inspect
+ end
+ end
+ end
+ end
+
+ if existing = self[param]
+ result = existing + result
+ end
+
+ result
+ end
# For each object we require, subscribe to all events that it generates. We
# might reduce the level of subscription eventually, but for now...
@@ -133,17 +174,7 @@ class Puppet::Type
# Take whatever dependencies currently exist and add these.
# Note that this probably doesn't behave correctly with unsubscribe.
munge do |requires|
- # We need to be two arrays deep...
- unless requires.is_a?(Array)
- requires = [requires]
- end
- unless requires[0].is_a?(Array)
- requires = [requires]
- end
- if values = @parent[:require]
- requires = values + requires
- end
- requires
+ @parent.store_relationship(:require, requires)
end
end
@@ -167,11 +198,7 @@ class Puppet::Type
"
munge do |requires|
- if values = @parent[:subscribe]
- requires = values + requires
- end
- requires
- # @parent.handledepends(requires, :ALL_EVENTS, :refresh)
+ @parent.store_relationship(:subscribe, requires)
end
end
@@ -295,21 +322,9 @@ class Puppet::Type
This will restart the sshd service if the sshd config file changes.}
- # Take whatever dependencies currently exist and add these.
munge do |notifies|
- # We need to be two arrays deep...
- unless notifies.is_a?(Array)
- notifies = [notifies]
- end
- unless notifies[0].is_a?(Array)
- notifies = [notifies]
- end
- if values = @parent[:notify]
- notifies = values + notifies
- end
- notifies
+ @parent.store_relationship(:notify, notifies)
end
-
end
newmetaparam(:before) do
@@ -331,21 +346,9 @@ class Puppet::Type
This will make sure all of the files are up to date before the
make command is run.}
- # Take whatever dependencies currently exist and add these.
munge do |notifies|
- # We need to be two arrays deep...
- unless notifies.is_a?(Array)
- notifies = [notifies]
- end
- unless notifies[0].is_a?(Array)
- notifies = [notifies]
- end
- if values = @parent[:notify]
- notifies = values + notifies
- end
- notifies
+ @parent.store_relationship(:before, notifies)
end
-
end
end # Puppet::Type
diff --git a/lib/puppet/metatype/relationships.rb b/lib/puppet/metatype/relationships.rb
index 714ed7690..5f2471460 100644
--- a/lib/puppet/metatype/relationships.rb
+++ b/lib/puppet/metatype/relationships.rb
@@ -18,6 +18,7 @@ class Puppet::Type
# Figure out of there are any objects we can automatically add as
# dependencies.
def autorequire
+ reqs = []
self.class.eachautorequire { |type, block|
# Ignore any types we can't find, although that would be a bit odd.
next unless typeobj = Puppet.type(type)
@@ -32,74 +33,48 @@ class Puppet::Type
list.each { |dep|
obj = nil
# Support them passing objects directly, to save some effort.
- if dep.is_a? Puppet::Type
- type = dep.class.name
- obj = dep
-
- # Now change our dependency to just the string, instead of
- # the object itself.
- dep = dep.title
- else
+ unless dep.is_a? Puppet::Type
# Skip autorequires that we aren't managing
- unless obj = typeobj[dep]
+ unless dep = typeobj[dep]
next
end
end
-
- # Skip autorequires that we already require
- next if self.requires?(obj)
-
- debug "Autorequiring %s %s" % [obj.class.name, obj.title]
- self[:require] = [type, dep]
+
+ debug "Autorequiring %s" % [dep.ref]
+ reqs << Puppet::Relationship[dep, self]
}
-
- #self.info reqs.inspect
- #self[:require] = reqs
}
+
+ return reqs
end
- # Build the dependencies associated with an individual object.
+ # Build the dependencies associated with an individual object. :in
+ # relationships are specified by the event-receivers, and :out
+ # relationships are specified by the event generator. This
+ # way 'source' and 'target' are consistent terms in both edges
+ # and events -- that is, an event targets edges whose source matches
+ # the event's source. Note that the direction of the relationship
+ # doesn't actually mean anything until you start using events --
+ # the same information is present regardless.
def builddepends
# Handle the requires
- if self[:require]
- self.handledepends(self[:require], :NONE, nil, true)
- end
-
- # And the subscriptions
- if self[:subscribe]
- self.handledepends(self[:subscribe], :ALL_EVENTS, :refresh, true)
- end
-
- if self[:notify]
- self.handledepends(self[:notify], :ALL_EVENTS, :refresh, false)
- end
-
- if self[:before]
- self.handledepends(self[:before], :NONE, nil, false)
- end
- end
-
- # return all objects that we depend on
- def eachdependency
- Puppet::Event::Subscription.dependencies(self).each { |dep|
- yield dep.source
- }
- end
-
- # return all objects subscribed to the current object
- def eachsubscriber
- Puppet::Event::Subscription.subscribers(self).each { |sub|
- yield sub.target
- }
+ {:require => [:NONE, nil, :in],
+ :subscribe => [:ALL_EVENTS, :refresh, :in],
+ :notify => [:ALL_EVENTS, :refresh, :out],
+ :before => [:NONE, nil, :out]}.collect do |type, args|
+ if self[type]
+ handledepends(self[type], *args)
+ end
+ end.flatten.reject { |r| r.nil? }
end
- def handledepends(requires, event, method, up)
+ def handledepends(requires, event, method, direction)
# Requires are specified in the form of [type, name], so they're always
# an array. But we want them to be an array of arrays.
unless requires[0].is_a?(Array)
requires = [requires]
end
- requires.each { |rname|
+ requires.collect { |rname|
# we just have a name and a type, and we need to convert it
# to an object...
type = nil
@@ -115,9 +90,9 @@ class Puppet::Type
end
self.debug("subscribes to %s" % [object])
- # Are we requiring them, or vice versa?
- source = target = nil
- if up
+ # Are we requiring them, or vice versa? See the builddepends
+ # method for further docs on this.
+ if direction == :in
source = object
target = self
else
@@ -129,61 +104,30 @@ class Puppet::Type
# we store the method to call when a given subscription is
# triggered, but the source object decides whether
subargs = {
- :event => event,
- :source => source,
- :target => target
+ :event => event
}
- if method and target.respond_to?(method)
+ if method
subargs[:callback] = method
end
- Puppet::Event::Subscription.new(subargs)
+ rel = Puppet::Relationship.new(source, target, subargs)
}
end
- def requires?(object)
- req = false
- self.eachdependency { |dep|
- if dep == object
- req = true
- break
- end
- }
-
- return req
- end
-
- def subscribe(hash)
- hash[:source] = self
- Puppet::Event::Subscription.new(hash)
-
- # add to the correct area
- #@subscriptions.push sub
- end
-
- def subscribesto?(object)
- sub = false
- self.eachsubscriber { |o|
- if o == object
- sub = true
- break
- end
- }
-
- return sub
- end
-
# Unsubscribe from a given object, possibly with a specific event.
def unsubscribe(object, event = nil)
- Puppet::Event::Subscription.dependencies(self).find_all { |sub|
- if event
- sub.match?(event)
- else
- sub.source == object
+ # First look through our own relationship params
+ [:require, :subscribe].each do |param|
+ if values = self[param]
+ newvals = values.reject { |d|
+ d == [object.class.name, object.title]
+ }
+ if newvals.length != values.length
+ self.delete(param)
+ self[param] = newvals
+ end
end
- }.each { |sub|
- sub.delete
- }
+ end
end
# we've received an event
diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb
index fba93d20c..292e25073 100644
--- a/lib/puppet/pgraph.rb
+++ b/lib/puppet/pgraph.rb
@@ -11,27 +11,6 @@ require 'puppet/relationship'
# This class subclasses a graph class in order to handle relationships
# among resources.
class Puppet::PGraph < GRATR::Digraph
- # Collect all of the targets for the list of events. Basically just iterates
- # over the sources of the events and returns all of the targets of them.
- def collect_targets(events)
- events.collect do |event|
- source = event.source
- start = source
-
- # Get all of the edges that this vertex points at
- adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
- edge.match?(event.event)
- end.collect { |event|
- target = event.target
- if target.respond_to?(:ref)
- source.info "Scheduling %s of %s" %
- [event.callback, target.ref]
- end
- target
- }
- end.flatten
- end
-
# The dependencies for a given resource.
def dependencies(resource)
tree_from_vertex(resource, :dfs).keys
@@ -49,6 +28,32 @@ class Puppet::PGraph < GRATR::Digraph
return leaves
end
+ # Collect all of the edges that the passed events match. Returns
+ # an array of edges.
+ def matching_edges(events)
+ events.collect do |event|
+ source = event.source
+
+ unless vertex?(source)
+ Puppet.warning "Got an event from invalid vertex %s" % source.ref
+ next
+ end
+
+ # Get all of the edges that this vertex should forward events
+ # to, which is the same thing as saying all edges directly below
+ # This vertex in the graph.
+ adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
+ edge.match?(event.event)
+ end.each { |edge|
+ target = edge.target
+ if target.respond_to?(:ref)
+ source.info "Scheduling %s of %s" %
+ [edge.callback, target.ref]
+ end
+ }
+ end.flatten
+ end
+
# Take container information from another graph and use it
# to replace any container vertices with their respective leaves.
# This creates direct relationships where there were previously
@@ -63,9 +68,9 @@ class Puppet::PGraph < GRATR::Digraph
next if leaves.empty?
# First create new edges for each of the :in edges
- adjacent(vertex, :direction => :in).each do |up|
+ adjacent(vertex, :direction => :in, :type => :edges).each do |edge|
leaves.each do |leaf|
- add_edge!(up, leaf)
+ add_edge!(edge.source, leaf, edge.label)
if cyclic?
raise ArgumentError,
"%s => %s results in a loop" %
@@ -75,9 +80,9 @@ class Puppet::PGraph < GRATR::Digraph
end
# Then for each of the out edges
- adjacent(vertex, :direction => :out).each do |down|
+ adjacent(vertex, :direction => :out, :type => :edges).each do |edge|
leaves.each do |leaf|
- add_edge!(leaf, down)
+ add_edge!(leaf, edge.target, edge.label)
if cyclic?
raise ArgumentError,
"%s => %s results in a loop" %
@@ -89,76 +94,10 @@ class Puppet::PGraph < GRATR::Digraph
# And finally, remove the vertex entirely.
remove_vertex!(vertex)
end
- end
-
- # Trigger any subscriptions to a child. This does an upwardly recursive
- # search -- it triggers the passed object, but also the object's parent
- # and so on up the tree.
- def trigger(child)
- obj = child
- callbacks = Hash.new { |hash, key| hash[key] = [] }
- sources = Hash.new { |hash, key| hash[key] = [] }
-
- trigged = []
- while obj
- if @targets.include?(obj)
- callbacks.clear
- sources.clear
- @targets[obj].each do |event, sub|
- # Collect all of the subs for each callback
- callbacks[sub.callback] << sub
-
- # And collect the sources for logging
- sources[event.source] << sub.callback
- end
-
- sources.each do |source, callbacklist|
- obj.debug "%s[%s] results in triggering %s" %
- [source.class.name, source.name, callbacklist.join(", ")]
- end
-
- callbacks.each do |callback, subs|
- message = "Triggering '%s' from %s dependencies" %
- [callback, subs.length]
- obj.notice message
- # At this point, just log failures, don't try to react
- # to them in any way.
- begin
- obj.send(callback)
- @resourcemetrics[:restarted] += 1
- rescue => detail
- obj.err "Failed to call %s on %s: %s" %
- [callback, obj, detail]
-
- @resourcemetrics[:failed_restarts] += 1
-
- if Puppet[:debug]
- puts detail.backtrace
- end
- end
-
- # And then add an event for it.
- trigged << Puppet::Event.new(
- :event => :triggered,
- :transaction => self,
- :source => obj,
- :message => message
- )
-
- triggered(obj, callback)
- end
- end
-
- obj = obj.parent
- end
-
- if trigged.empty?
- return nil
- else
- return trigged
- end
end
+ # For some reason, unconnected vertices do not show up in
+ # this graph.
def to_jpg(name)
gv = vertices()
Dir.chdir("/Users/luke/Desktop/pics") do
diff --git a/lib/puppet/relationship.rb b/lib/puppet/relationship.rb
index cbd15b2af..879beeab7 100644
--- a/lib/puppet/relationship.rb
+++ b/lib/puppet/relationship.rb
@@ -11,15 +11,23 @@ require 'puppet/gratr'
class Puppet::Relationship < GRATR::Edge
# Return the callback
def callback
- label[:callback]
+ if label
+ label[:callback]
+ else
+ nil
+ end
end
# Return our event.
def event
- label[:event]
+ if label
+ label[:event]
+ else
+ nil
+ end
end
- def initialize(source, target, label = nil)
+ def initialize(source, target, label = {})
if label
unless label.is_a?(Hash)
raise Puppet::DevError, "The label must be a hash"
@@ -46,6 +54,10 @@ class Puppet::Relationship < GRATR::Edge
return false
end
end
+
+ def ref
+ "%s => %s" % [source.ref, target.ref]
+ end
end
# $Id$
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 1551acbb6..6835b1b19 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -1,4 +1,4 @@
-# the class that actually walks our object/state tree, collects the changes,
+# the class that actually walks our resource/state tree, collects the changes,
# and performs them
require 'puppet'
@@ -6,13 +6,14 @@ require 'puppet/statechange'
module Puppet
class Transaction
- attr_accessor :component, :objects, :tags, :ignoreschedules, :ignoretags
+ attr_accessor :component, :resources, :tags, :ignoreschedules, :ignoretags
+ attr_accessor :relgraph
include Puppet::Util
Puppet.config.setdefaults(:transaction,
- :tags => ["", "Tags to use to find objects. If this is set, then
- only objects tagged with the specified tags will be applied.
+ :tags => ["", "Tags to use to find resources. If this is set, then
+ only resources tagged with the specified tags will be applied.
Values must be comma-separated."]
)
@@ -26,8 +27,13 @@ class Transaction
# Apply all changes for a child, returning a list of the events
# generated.
def apply(child)
- # First make sure there are no failed dependencies
- child.eachdependency do |dep|
+ child.info "applying"
+ # First make sure there are no failed dependencies. To do this,
+ # we check for failures in any of the vertexes above us. It's not
+ # enough to check the immediate dependencies, which is why we use
+ # a tree from the reversed graph.
+ p @relgraph.vertices.collect { |v| v.ref }
+ @relgraph.reversal.tree_from_vertex(child, :dfs).keys.each do |dep|
skip = false
if fails = failed?(dep)
child.notice "Dependency %s[%s] has %s failures" %
@@ -76,7 +82,7 @@ class Transaction
# event if they want
events = [change.forward].flatten.reject { |e| e.nil? }
rescue => detail
- if Puppet[:debug]
+ if Puppet[:trace]
puts detail.backtrace
end
change.state.err "change from %s to %s failed: %s" %
@@ -111,37 +117,13 @@ class Transaction
childevents
end
- # Find all of the changed objects.
+ # Find all of the changed resources.
def changed?
@changes.find_all { |change| change.changed }.collect { |change|
change.state.parent
}.uniq
end
- # Collect all of the targets for the list of events. This is an unintuitive
- # method because it recurses up through the source the event.
- def collecttargets(events)
- events.each do |event|
- source = event.source
- start = source
-
- while source
- Puppet::Event::Subscription.targets_of(event, source) do |sub|
- if target = sub.target
- start.info "Scheduling %s of %s[%s]" %
- [sub.callback, sub.target.class.name, sub.target.title]
- @targets[sub.target][event] = sub
- else
- raise Puppet::DevError,
- "Failed to find a target for %s" % sub.inspect
- end
- end
-
- source = source.parent
- end
- end
- end
-
# This method does all the actual work of running a transaction. It
# collects all of the changes, executes them, and responds to any
# necessary events.
@@ -163,9 +145,17 @@ class Transaction
Puppet::Log.newdestination(@report)
prefetch()
+
+ # Now add any dynamically generated resources
+ generate()
+
+ # Create a relationship graph from our resource graph
+ @relgraph = relationship_graph
+
+ @relgraph.to_jpg("relations")
begin
- allevents = @objects.collect { |child|
+ allevents = @relgraph.topsort.collect { |child|
events = []
if (self.ignoretags or tags.nil? or child.tagged?(tags))
if self.ignoreschedules or child.scheduled?
@@ -176,7 +166,7 @@ class Transaction
events = apply(child)
end
- # Keep track of how long we spend in each type of object
+ # Keep track of how long we spend in each type of resource
@timemetrics[child.class.name] += seconds
else
child.debug "Not scheduled"
@@ -191,7 +181,9 @@ class Transaction
end
# Collect the targets of any subscriptions to those events
- collecttargets(events)
+ @relgraph.matching_edges(events).each do |edge|
+ @targets[edge.target] << edge
+ end
# And return the events for collection
events
@@ -207,7 +199,7 @@ class Transaction
allevents
end
- # Determine whether a given object has failed.
+ # Determine whether a given resource has failed.
def failed?(obj)
if @failures[obj] > 0
return @failures[obj]
@@ -215,40 +207,63 @@ class Transaction
return false
end
end
+
+ # Collect any dynamically generated resources.
+ def generate
+ list = @resources.vertices
+ newlist = []
+ while ! list.empty?
+ list.each do |resource|
+ if resource.respond_to?(:generate)
+ made = resource.generate
+ unless made.is_a?(Array)
+ made = [made]
+ end
+ made.each do |res|
+ @resources.add_vertex!(res)
+ newlist << res
+ end
+ end
+ end
+ list.clear
+ list = newlist
+ newlist = []
+ end
+ end
- # this should only be called by a Puppet::Container object now
+ # this should only be called by a Puppet::Type::Component resource now
# and it should only receive an array
- def initialize(objects)
- @objects = objects
+ def initialize(resources)
+ @resources = resources.to_graph
@resourcemetrics = {
- :total => @objects.length,
- :out_of_sync => 0, # The number of objects that had changes
- :applied => 0, # The number of objects fixed
- :skipped => 0, # The number of objects skipped
- :restarted => 0, # The number of objects triggered
- :failed_restarts => 0, # The number of objects that fail a trigger
- :scheduled => 0 # The number of objects scheduled
+ :total => @resources.vertices.length,
+ :out_of_sync => 0, # The number of resources that had changes
+ :applied => 0, # The number of resources fixed
+ :skipped => 0, # The number of resources skipped
+ :restarted => 0, # The number of resources triggered
+ :failed_restarts => 0, # The number of resources that fail a trigger
+ :scheduled => 0 # The number of resources scheduled
}
# Metrics for distributing times across the different types.
@timemetrics = Hash.new(0)
- # The number of objects that were triggered in this run
+ # The number of resources that were triggered in this run
@triggered = Hash.new { |hash, key|
hash[key] = Hash.new(0)
}
# Targets of being triggered.
@targets = Hash.new do |hash, key|
- hash[key] = {}
+ hash[key] = []
end
# The changes we're performing
@changes = []
- # The objects that have failed and the number of failures each. This
- # is used for skipping objects because of failed dependencies.
+ # The resources that have failed and the number of failures each. This
+ # is used for skipping resources because of failed dependencies.
@failures = Hash.new do |h, key|
h[key] = 0
end
@@ -259,7 +274,7 @@ class Transaction
# Prefetch any providers that support it. We don't support prefetching
# types, just providers.
def prefetch
- @objects.collect { |obj|
+ @resources.collect { |obj|
if pro = obj.provider
pro.class
else
@@ -272,6 +287,33 @@ class Transaction
end
end
end
+
+ # Create a graph of all of the relationships in our resource graph.
+ def relationship_graph
+ graph = Puppet::PGraph.new
+
+ # First create the dependency graph
+ @resources.vertices.each do |vertex|
+ graph.add_vertex!(vertex)
+ vertex.builddepends.each do |edge|
+ graph.add_edge!(edge)
+ end
+ end
+
+ # Then splice in the container information
+ graph.splice!(@resources, Puppet::Type::Component)
+
+ # Lastly, add in any autorequires
+ graph.vertices.each do |vertex|
+ vertex.autorequire.each do |edge|
+ unless graph.edge?(edge)
+ graph.add_edge!(edge)
+ end
+ end
+ end
+
+ return graph
+ end
# Generate a transaction report.
def report
@@ -295,10 +337,10 @@ class Transaction
end
end
- # Add all of the metrics related to object count and status
+ # Add all of the metrics related to resource count and status
@report.newmetric(:resources, @resourcemetrics)
- # Record the relative time spent in each object.
+ # Record the relative time spent in each resource.
@report.newmetric(:time, @timemetrics)
# Then all of the change-related metrics
@@ -325,19 +367,21 @@ class Transaction
events = change.backward
rescue => detail
Puppet.err("%s rollback failed: %s" % [change,detail])
- if Puppet[:debug]
+ if Puppet[:trace]
puts detail.backtrace
end
next
# at this point, we would normally do error handling
# but i haven't decided what to do for that yet
- # so just record that a sync failed for a given object
+ # so just record that a sync failed for a given resource
#@@failures[change.state.parent] += 1
# this still could get hairy; what if file contents changed,
# but a chmod failed? how would i handle that error? dern
end
-
- collecttargets(events) if events
+
+ @relgraph.matching_edges(events).each do |edge|
+ @targets[edge.target] << edge
+ end
# Now check to see if there are any events for this child.
# Kind of hackish, since going backwards goes a change at a
@@ -350,7 +394,7 @@ class Transaction
end
# Trigger any subscriptions to a child. This does an upwardly recursive
- # search -- it triggers the passed object, but also the object's parent
+ # search -- it triggers the passed resource, but also the resource's parent
# and so on up the tree.
def trigger(child)
obj = child
@@ -362,12 +406,15 @@ class Transaction
if @targets.include?(obj)
callbacks.clear
sources.clear
- @targets[obj].each do |event, sub|
+ @targets[obj].each do |edge|
+ # Some edges don't have callbacks
+ next unless edge.callback
+
# Collect all of the subs for each callback
- callbacks[sub.callback] << sub
+ callbacks[edge.callback] << edge
# And collect the sources for logging
- sources[event.source] << sub.callback
+ sources[edge.source] << edge.callback
end
sources.each do |source, callbacklist|
@@ -390,7 +437,7 @@ class Transaction
@resourcemetrics[:failed_restarts] += 1
- if Puppet[:debug]
+ if Puppet[:trace]
puts detail.backtrace
end
end
@@ -417,12 +464,12 @@ class Transaction
end
end
- def triggered(object, method)
- @triggered[object][method] += 1
+ def triggered(resource, method)
+ @triggered[resource][method] += 1
end
- def triggered?(object, method)
- @triggered[object][method]
+ def triggered?(resource, method)
+ @triggered[resource][method]
end
end
end
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 1adeb1366..19de99b7c 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -301,8 +301,6 @@ class Type < Puppet::Element
# Set up all of our autorequires.
def finish
- self.autorequire
-
# Scheduling has to be done when the whole config is instantiated, so
# that file order doesn't matter in finding them.
self.schedule
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 3165d9e11..cadd586c8 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -79,7 +79,7 @@ module Puppet
# this also won't work with scheduling, but eh
def evaluate
self.finalize unless self.finalized?
- transaction = Puppet::Transaction.new(self.flatten)
+ transaction = Puppet::Transaction.new(self)
transaction.component = self
return transaction
end
@@ -102,7 +102,6 @@ module Puppet
end
unless finished.has_key?(object)
object.finish
- object.builddepends
finished[object] = true
end
end
diff --git a/test/lib/puppettest/support/resources.rb b/test/lib/puppettest/support/resources.rb
new file mode 100755
index 000000000..45d89c5fb
--- /dev/null
+++ b/test/lib/puppettest/support/resources.rb
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke A. Kanies on 2006-11-29.
+# Copyright (c) 2006. All rights reserved.
+
+module PuppetTest::Support::Resources
+ def treefile(name)
+ Puppet::Type.type(:file).create :path => "/tmp/#{name}", :mode => 0755
+ end
+
+ def treecomp(name)
+ Puppet::Type::Component.create :name => name, :type => "yay"
+ end
+
+ def treenode(name, *children)
+ comp = treecomp name
+ children.each do |c|
+ if c.is_a?(String)
+ comp.push treefile(c)
+ else
+ comp.push c
+ end
+ end
+ return comp
+ end
+
+ def mktree
+ one = treenode("one", "a", "b")
+ two = treenode("two", "c", "d")
+ middle = treenode("middle", "e", "f", two)
+ top = treenode("top", "g", "h", middle, one)
+
+ return one, two, middle, top
+ end
+end
+
+# $Id$ \ No newline at end of file
diff --git a/test/other/overrides.rb b/test/other/overrides.rb
index e25670291..2bc443980 100755
--- a/test/other/overrides.rb
+++ b/test/other/overrides.rb
@@ -27,6 +27,7 @@ class TestOverrides < Test::Unit::TestCase
basefile = File.join(basedir, "file")
assert_nothing_raised("Could not create base obj") {
baseobj = Puppet.type(:file).create(
+ :title => "base",
:path => basedir,
:recurse => true,
:mode => "755"
@@ -38,23 +39,20 @@ class TestOverrides < Test::Unit::TestCase
subfile = File.join(subdir, "file")
assert_nothing_raised("Could not create sub obj") {
subobj = Puppet.type(:file).create(
+ :title => "sub",
:path => subdir,
:recurse => true,
:mode => "644"
)
}
- comp = newcomp("overrides", baseobj, subobj)
- assert_nothing_raised("Could not eval component") {
- trans = comp.evaluate
- trans.evaluate
- }
+ assert_apply(baseobj, subobj)
assert(File.stat(basefile).mode & 007777 == 0755)
assert(File.stat(subfile).mode & 007777 == 0644)
end
- def test_zdeepoverride
+ def test_deepoverride
basedir = File.join(tmpdir(), "deepoverridetesting")
mksubdirs(basedir, 10)
diff --git a/test/other/pgraph.rb b/test/other/pgraph.rb
index c3baa7722..adf290b34 100644
--- a/test/other/pgraph.rb
+++ b/test/other/pgraph.rb
@@ -12,24 +12,31 @@ class TestPGraph < Test::Unit::TestCase
include PuppetTest
include PuppetTest::Graph
- def test_collect_targets
+ Edge = Puppet::Relationship
+
+ def test_matching_edges
graph = Puppet::PGraph.new
event = Puppet::Event.new(:source => "a", :event => :yay)
none = Puppet::Event.new(:source => "a", :event => :NONE)
- graph.add_edge!("a", "b", :event => :yay)
+ edges = {}
+
+ edges["a/b"] = Edge["a", "b", {:event => :yay, :callback => :refresh}]
+ edges["a/c"] = Edge["a", "c", {:event => :yay, :callback => :refresh}]
+
+ graph.add_edge!(edges["a/b"])
# Try it for the trivial case of one target and a matching event
- assert_equal(["b"], graph.collect_targets([event]))
+ assert_equal([edges["a/b"]], graph.matching_edges([event]))
# Make sure we get nothing with a different event
- assert_equal([], graph.collect_targets([none]))
+ assert_equal([], graph.matching_edges([none]))
# Set up multiple targets and make sure we get them all back
- graph.add_edge!("a", "c", :event => :yay)
- assert_equal(["b", "c"].sort, graph.collect_targets([event]).sort)
- assert_equal([], graph.collect_targets([none]))
+ graph.add_edge!(edges["a/c"])
+ assert_equal([edges["a/b"], edges["a/c"]].sort, graph.matching_edges([event]).sort)
+ assert_equal([], graph.matching_edges([none]))
end
def test_dependencies
@@ -49,6 +56,9 @@ class TestPGraph < Test::Unit::TestCase
one, two, middle, top = build_tree
contgraph = top.to_graph
+ # Now add a couple of child files, so that we can test whether all containers
+ # get spliced, rather than just components.
+
# Now make a dependency graph
deps = Puppet::PGraph.new
@@ -57,7 +67,7 @@ class TestPGraph < Test::Unit::TestCase
end
{one => two, "f" => "c", "h" => middle}.each do |source, target|
- deps.add_edge!(source, target)
+ deps.add_edge!(source, target, :callback => :refresh)
end
deps.to_jpg("deps-before")
@@ -66,11 +76,26 @@ class TestPGraph < Test::Unit::TestCase
assert(! deps.cyclic?, "Created a cyclic graph")
+ # Now make sure the containers got spliced correctly.
+ contgraph.leaves(middle).each do |leaf|
+ assert(deps.edge?("h", leaf), "no edge for h => %s" % leaf)
+ end
+ one.each do |oobj|
+ two.each do |tobj|
+ assert(deps.edge?(oobj, tobj), "no %s => %s edge" % [oobj, tobj])
+ end
+ end
+
nons = deps.vertices.find_all { |v| ! v.is_a?(String) }
assert(nons.empty?,
"still contain non-strings %s" % nons.inspect)
deps.to_jpg("deps-after")
+
+ deps.edges.each do |edge|
+ assert_equal({:callback => :refresh}, edge.label,
+ "Label was not copied on splice")
+ end
end
end
diff --git a/test/other/relationships.rb b/test/other/relationships.rb
index 893ef1ff4..e9c1d1c9c 100755
--- a/test/other/relationships.rb
+++ b/test/other/relationships.rb
@@ -15,37 +15,141 @@ class TestRelationships < Test::Unit::TestCase
)
}
end
+
+ def check_relationship(sources, targets, out, refresher)
+ if out
+ deps = sources.builddepends
+ sources = [sources]
+ else
+ deps = targets.builddepends
+ targets = [targets]
+ end
+ assert_instance_of(Array, deps)
+ assert(! deps.empty?, "Did not receive any relationships")
+
+ deps.each do |edge|
+ assert_instance_of(Puppet::Relationship, edge)
+ end
+
+ sources.each do |source|
+ targets.each do |target|
+ edge = deps.find { |e| e.source == source and e.target == target }
+ assert(edge, "Could not find edge for %s => %s" %
+ [source.ref, target.ref])
+
+ if refresher
+ assert_equal(:ALL_EVENTS, edge.event)
+ assert_equal(:refresh, edge.callback)
+ else
+ assert_equal(:NONE, edge.event)
+ assert_nil(edge.callback, "Got a callback with no events")
+ end
+ end
+ end
+ end
- def test_simplerel
- file1 = newfile()
- file2 = newfile()
- assert_nothing_raised {
- file1[:require] = [file2.class.name, file2.name]
- }
-
- comp = newcomp(file1, file2)
- comp.finalize
- deps = []
- assert_nothing_raised {
- file1.eachdependency { |obj|
- deps << obj
- }
- }
-
- assert_equal(1, deps.length, "Did not get dependency")
-
- assert_nothing_raised {
- file1.unsubscribe(file2)
- }
-
- deps = []
- assert_nothing_raised {
- file1.eachdependency { |obj|
- deps << obj
- }
- }
-
- assert_equal(0, deps.length, "Still have dependency")
+ # Make sure our various metaparams work correctly. We're just checking
+ # here whether they correctly set up the callbacks and the direction of
+ # the relationship.
+ def test_relationship_metaparams
+ out = {:require => false, :subscribe => false,
+ :notify => true, :before => true}
+ refreshers = [:subscribe, :notify]
+ [:require, :subscribe, :notify, :before].each do |param|
+ # Create three files to generate our events and three
+ # execs to receive them
+ files = []
+ execs = []
+ 3.times do |i|
+ files << Puppet::Type.newfile(
+ :title => "file#{i}",
+ :path => tempfile(),
+ :ensure => :file
+ )
+
+ path = tempfile()
+ execs << Puppet::Type.newexec(
+ :title => "notifytest#{i}",
+ :path => "/usr/bin:/bin",
+ :command => "touch #{path}",
+ :refreshonly => true
+ )
+ end
+
+ # Add our first relationship
+ if out[param]
+ files[0][param] = execs[0]
+ sources = files[0]
+ targets = [execs[0]]
+ else
+ execs[0][param] = files[0]
+ sources = [files[0]]
+ targets = execs[0]
+ end
+ check_relationship(sources, targets, out[param], refreshers.include?(param))
+
+ # Now add another relationship
+ if out[param]
+ files[0][param] = execs[1]
+ targets << execs[1]
+ assert_equal(targets.collect { |t| [t.class.name, t.title]},
+ files[0][param], "Incorrect target list")
+ else
+ execs[0][param] = files[1]
+ sources << files[1]
+ assert_equal(sources.collect { |t| [t.class.name, t.title]},
+ execs[0][param], "Incorrect source list")
+ end
+ check_relationship(sources, targets, out[param], refreshers.include?(param))
+
+ Puppet::Type.allclear
+ end
+ end
+
+ def test_store_relationship
+ file = Puppet::Type.newfile :path => tempfile(), :mode => 0755
+ execs = []
+ 3.times do |i|
+ execs << Puppet::Type.newexec(:title => "yay#{i}", :command => "/bin/echo yay")
+ end
+
+ # First try it with one object, specified as a reference and an array
+ result = nil
+ [execs[0], [:exec, "yay0"], ["exec", "yay0"]].each do |target|
+ assert_nothing_raised do
+ result = file.send(:store_relationship, :require, target)
+ end
+
+ assert_equal([[:exec, "yay0"]], result)
+ end
+
+ # Now try it with multiple objects
+ symbols = execs.collect { |e| [e.class.name, e.title] }
+ strings = execs.collect { |e| [e.class.name.to_s, e.title] }
+ [execs, symbols, strings].each do |target|
+ assert_nothing_raised do
+ result = file.send(:store_relationship, :require, target)
+ end
+
+ assert_equal(symbols, result)
+ end
+
+ # Make sure we can mix it up, even though this shouldn't happen
+ assert_nothing_raised do
+ result = file.send(:store_relationship, :require, [execs[0], [execs[1].class.name, execs[1].title]])
+ end
+
+ assert_equal([[:exec, "yay0"], [:exec, "yay1"]], result)
+
+ # Finally, make sure that new results get added to old. The only way
+ # to get rid of relationships is to delete the parameter.
+ file[:require] = execs[0]
+
+ assert_nothing_raised do
+ result = file.send(:store_relationship, :require, [execs[1], execs[2]])
+ end
+
+ assert_equal(symbols, result)
end
def test_newsub
@@ -107,33 +211,31 @@ class TestRelationships < Test::Unit::TestCase
assert(! sub.match?(:ALL_EVENTS), "ALL_EVENTS matched")
assert(! sub.match?(:NONE), "matched :NONE")
end
-
- def test_deletingsubs
- file1 = newfile()
- file2 = newfile()
-
- file1[:subscribe] = [:file, file2.name]
-
- comp = newcomp(file1, file2)
- comp.finalize
-
- assert(file1.requires?(file2))
-
- assert_nothing_raised {
- file1.unsubscribe(file2)
- }
- assert(!file1.requires?(file2))
-
- # Now readd it, so we can use 'remove'
- file1[:subscribe] = [:file, file2.name]
- comp.finalize
-
- assert_nothing_raised {
- file1.remove
- }
-
- assert(!comp.include?(file1))
- assert(!file2.subscribesto?(file1))
+
+ def test_autorequire
+ # We know that execs autorequire their cwd, so we'll use that
+ path = tempfile()
+
+ file = Puppet::Type.newfile(:title => "myfile", :path => path,
+ :ensure => :directory)
+ exec = Puppet::Type.newexec(:title => "myexec", :cwd => path,
+ :command => "/bin/echo")
+
+ reqs = nil
+ assert_nothing_raised do
+ reqs = exec.autorequire
+ end
+ assert_equal([Puppet::Relationship[file, exec]], reqs)
+
+ # Now make sure that these relationships are added to the transaction's
+ # relgraph
+ trans = Puppet::Transaction.new(newcomp(file, exec))
+ assert_nothing_raised do
+ trans.evaluate
+ end
+
+ graph = trans.relgraph
+ assert(graph.edge?(file, exec), "autorequire edge was not created")
end
end
diff --git a/test/other/transactions.rb b/test/other/transactions.rb
index 985e9a0c5..c143b3a0c 100755
--- a/test/other/transactions.rb
+++ b/test/other/transactions.rb
@@ -4,11 +4,13 @@ $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'puppet'
require 'puppettest'
+require 'puppettest/support/resources'
# $Id$
class TestTransactions < Test::Unit::TestCase
include PuppetTest::FileTesting
+ include PuppetTest::Support::Resources
def test_reports
path1 = tempfile()
@@ -59,6 +61,10 @@ class TestTransactions < Test::Unit::TestCase
type = Puppet::Type.newtype(name) do
newparam(:name) {}
end
+
+ cleanup do
+ Puppet::Type.rmtype(name)
+ end
# Now create a provider
type.provide(:prefetch) do
@@ -69,10 +75,9 @@ class TestTransactions < Test::Unit::TestCase
# Now create an instance
inst = type.create :name => "yay"
-
-
+
# Create a transaction
- trans = Puppet::Transaction.new([inst])
+ trans = Puppet::Transaction.new(newcomp(inst))
# Make sure prefetch works
assert_nothing_raised do
@@ -94,7 +99,7 @@ class TestTransactions < Test::Unit::TestCase
path = tempfile()
firstpath = tempfile()
secondpath = tempfile()
- file = Puppet::Type.newfile(:path => path, :content => "yayness")
+ file = Puppet::Type.newfile(:title => "file", :path => path, :content => "yayness")
first = Puppet::Type.newexec(:title => "first",
:command => "/bin/echo first > #{firstpath}",
:subscribe => [:file, path],
@@ -299,7 +304,9 @@ class TestTransactions < Test::Unit::TestCase
assert(FileTest.exists?(execfile), "Execfile does not exist")
end
- def test_refreshAcrossTwoComponents
+ # Verify that one component requiring another causes the contained
+ # resources in the requiring component to get refreshed.
+ def test_refresh_across_two_components
transaction = nil
file = newfile()
execfile = File.join(tmpdir(), "exectestingness2")
@@ -318,7 +325,7 @@ class TestTransactions < Test::Unit::TestCase
# 'subscribe' expects an array of arrays
#component[:require] = [[file.class.name,file.name]]
- ecomp[:subscribe] = [[fcomp.class.name,fcomp.name]]
+ ecomp[:subscribe] = fcomp
exec[:refreshonly] = true
trans = assert_events([], component)
@@ -329,7 +336,6 @@ class TestTransactions < Test::Unit::TestCase
}
trans = assert_events([:file_changed, :file_changed, :triggered], component)
-
end
# Make sure that multiple subscriptions get triggered.
@@ -386,7 +392,7 @@ class TestTransactions < Test::Unit::TestCase
end
# Make sure that unscheduled and untagged objects still respond to events
- def test_unscheduledanduntaggedresponse
+ def test_unscheduled_and_untagged_response
Puppet::Type.type(:schedule).mkdefaultschedules
Puppet[:ignoreschedules] = false
file = Puppet.type(:file).create(
@@ -444,21 +450,127 @@ class TestTransactions < Test::Unit::TestCase
:title => "mkdir"
)
- file = Puppet::Type.type(:file).create(
+ file1 = Puppet::Type.type(:file).create(
+ :title => "file1",
:path => tempfile(),
- :require => ["exec", "mkdir"],
+ :require => exec,
:ensure => :file
)
- comp = newcomp(exec, file)
+ file2 = Puppet::Type.type(:file).create(
+ :title => "file2",
+ :path => tempfile(),
+ :require => file1,
+ :ensure => :file
+ )
+
+ comp = newcomp(exec, file1, file2)
comp.finalize
assert_apply(comp)
- assert(! FileTest.exists?(file[:path]),
+ assert(! FileTest.exists?(file1[:path]),
"File got created even tho its dependency failed")
+ assert(! FileTest.exists?(file2[:path]),
+ "File got created even tho its deep dependency failed")
+ end
+ end
+
+ def f(n)
+ Puppet::Type.type(:file)["/tmp/#{n.to_s}"]
+ end
+
+ def test_relationship_graph
+ one, two, middle, top = mktree
+
+ {one => two, "f" => "c", "h" => middle}.each do |source, target|
+ if source.is_a?(String)
+ source = f(source)
+ end
+ if target.is_a?(String)
+ target = f(target)
+ end
+ target[:require] = source
+ end
+
+ trans = Puppet::Transaction.new(top)
+
+ graph = nil
+ assert_nothing_raised do
+ graph = trans.relationship_graph
+ end
+
+ assert_instance_of(Puppet::PGraph, graph,
+ "Did not get relationship graph")
+
+ # Make sure all of the components are gone
+ comps = graph.vertices.find_all { |v| v.is_a?(Puppet::Type::Component)}
+ assert(comps.empty?, "Deps graph still contains components")
+
+ # It must be reversed because of how topsort works
+ sorted = graph.topsort.reverse
+
+ # Now make sure the appropriate edges are there and are in the right order
+ assert(graph.dependencies(f(:f)).include?(f(:c)),
+ "c not marked a dep of f")
+ assert(sorted.index(f(:c)) < sorted.index(f(:f)),
+ "c is not before f")
+
+ one.each do |o|
+ two.each do |t|
+ assert(graph.dependencies(o).include?(t),
+ "%s not marked a dep of %s" % [t.ref, o.ref])
+ assert(sorted.index(t) < sorted.index(o),
+ "%s is not before %s" % [t.ref, o.ref])
+ end
+ end
+
+ trans.resources.leaves(middle).each do |child|
+ assert(graph.dependencies(f(:h)).include?(child),
+ "%s not marked a dep of h" % [child.ref])
+ assert(sorted.index(child) < sorted.index(f(:h)),
+ "%s is not before h" % child.ref)
+ end
+
+ # Lastly, make sure our 'g' vertex made it into the relationship
+ # graph, since it's not involved in any relationships.
+ assert(graph.vertex?(f(:g)),
+ "Lost vertexes with no relations")
+
+ graph.to_jpg("normal_relations")
end
+
+ def test_generate
+ # Create a bogus type that generates new instances with shorter
+ Puppet::Type.newtype(:generator) do
+ newparam(:name, :namevar => true)
+
+ def generate
+ ret = []
+ if title.length > 1
+ ret << self.class.create(:title => title[0..-2])
+ end
+ ret
+ end
+ end
+ cleanup do
+ Puppet::Type.rmtype(:generator)
+ end
+
+ yay = Puppet::Type.newgenerator :title => "yay"
+ rah = Puppet::Type.newgenerator :title => "rah"
+ comp = newcomp(yay, rah)
+ trans = comp.evaluate
+
+ assert_nothing_raised do
+ trans.generate
+ end
+
+ %w{ya ra y r}.each do |name|
+ assert(trans.resources.vertex?(Puppet::Type.type(:generator)[name]),
+ "Generated %s was not a vertex" % name)
+ end
end
end
diff --git a/test/types/component.rb b/test/types/component.rb
index 28d6748a0..3fdc7bfe2 100755
--- a/test/types/component.rb
+++ b/test/types/component.rb
@@ -4,6 +4,7 @@ $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'puppet'
require 'puppettest'
+require 'puppettest/support/resources'
# $Id$
@@ -105,35 +106,6 @@ class TestComponent < Test::Unit::TestCase
}
}
end
-
- def treefile(name)
- @file.create :path => "/tmp/#{name}", :mode => 0755
- end
-
- def treecomp(name)
- @type.create :name => name, :type => "yay"
- end
-
- def treenode(name, *children)
- comp = treecomp name
- children.each do |c|
- if c.is_a?(String)
- comp.push treefile(c)
- else
- comp.push c
- end
- end
- return comp
- end
-
- def mktree
- one = treenode("one", "a", "b")
- two = treenode("two", "c", "d")
- middle = treenode("middle", "e", "f", two)
- top = treenode("top", "g", "h", middle, one)
-
- return one, two, middle, top
- end
def test_to_graph
one, two, middle, top = mktree
diff --git a/test/types/manager.rb b/test/types/manager.rb
new file mode 100755
index 000000000..f4353c128
--- /dev/null
+++ b/test/types/manager.rb
@@ -0,0 +1,44 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke A. Kanies on 2006-11-29.
+# Copyright (c) 2006. All rights reserved.
+
+$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
+
+require 'puppet'
+require 'puppettest'
+
+class TestTypeManager < Test::Unit::TestCase
+ include PuppetTest
+
+ class FakeManager
+ extend Puppet::MetaType::Manager
+ def self.clear
+ @types = {}
+ end
+ end
+
+ def teardown
+ super
+ FakeManager.clear
+ end
+
+ # Make sure we can remove defined types
+ def test_rmtype
+ assert_nothing_raised {
+ FakeManager.newtype :testing do
+ newparam(:name, :namevar => true)
+ end
+ }
+ assert(FakeManager.type(:testing), "Did not get fake type")
+
+ assert_nothing_raised do
+ FakeManager.rmtype(:testing)
+ end
+
+ assert_nil(FakeManager.type(:testing), "Type was not removed")
+ assert(! defined?(FakeManager::Testing), "Constant was not removed")
+ end
+end
+
+# $Id$ \ No newline at end of file
diff --git a/test/types/type.rb b/test/types/type.rb
index 4be929ae9..821a9524b 100755
--- a/test/types/type.rb
+++ b/test/types/type.rb
@@ -411,55 +411,6 @@ end
"newparam method got replaced by newtype")
end
- def test_notify_metaparam
- file = Puppet::Type.newfile(
- :path => tempfile(),
- :notify => ["exec", "notifytest"],
- :ensure => :file
- )
-
- path = tempfile()
- exec = Puppet::Type.newexec(
- :title => "notifytest",
- :path => "/usr/bin:/bin",
- :command => "touch #{path}",
- :refreshonly => true
- )
-
- assert_apply(file, exec)
-
- assert(exec.requires?(file),
- "Notify did not correctly set up the requirement chain.")
-
- assert(FileTest.exists?(path),
- "Exec path did not get created.")
- end
-
- def test_before_metaparam
- file = Puppet::Type.newfile(
- :path => tempfile(),
- :before => ["exec", "beforetest"],
- :content => "yaytest"
- )
-
- path = tempfile()
- exec = Puppet::Type.newexec(
- :title => "beforetest",
- :command => "/bin/cp #{file[:path]} #{path}"
- )
-
- assert_apply(file, exec)
-
- assert(exec.requires?(file),
- "Before did not correctly set up the requirement chain.")
-
- assert(FileTest.exists?(path),
- "Exec path did not get created.")
-
- assert_equal("yaytest", File.read(path),
- "Exec did not correctly copy file.")
- end
-
def test_newstate_options
# Create a type with a fake provider
providerclass = Class.new do