[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5

Nick Lewis nick at puppetlabs.com
Tue May 10 08:03:36 UTC 2011


The following commit has been merged in the experimental branch:
commit b16e10dba6606b808ef195f4b57f2e8c66cf65ab
Merge: fb8509acbd947712cac094a49227d28a16a366aa 19eb1e78e115d10bfb822e510213e4fab9cd2599
Author: Nick Lewis <nick at puppetlabs.com>
Date:   Wed Jan 5 17:22:30 2011 -0800

    Merge branch '2.6.x' into next
    
    Conflicts:
    	Rakefile
    	lib/puppet/resource/type_collection.rb
    	lib/puppet/simple_graph.rb
    	lib/puppet/transaction.rb
    	lib/puppet/transaction/report.rb
    	lib/puppet/util/metric.rb
    	spec/integration/indirector/report/rest_spec.rb
    	spec/spec_specs/runnable_spec.rb
    	spec/unit/configurer_spec.rb
    	spec/unit/indirector_spec.rb
    	spec/unit/transaction/change_spec.rb

diff --combined Rakefile
index 22d4a9a,728f1e3..e790c08
--- a/Rakefile
+++ b/Rakefile
@@@ -5,8 -5,8 +5,8 @@@ $LOAD_PATH << File.join(File.dirname(__
  require 'rake'
  require 'rake/packagetask'
  require 'rake/gempackagetask'
- require 'spec'
- require 'spec/rake/spectask'
+ require 'rspec'
+ require "rspec/core/rake_task"
  
  module Puppet
      PUPPETVERSION = File.read('lib/puppet.rb')[/PUPPETVERSION *= *'(.*)'/,1] or fail "Couldn't find PUPPETVERSION"
@@@ -42,8 -42,8 +42,8 @@@ en
  desc "Create the tarball and the gem - use when releasing"
  task :puppetpackages => [:create_gem, :package]
  
- Spec::Rake::SpecTask.new do |t|
-     t.spec_opts = ['--format','s', '--loadby','mtime','--color', '--backtrace']
+ RSpec::Core::RakeTask.new do |t|
 -    t.rspec_opts = ['--format','s', '--color']
++    t.rspec_opts = ['--format','s', '--color', '--backtrace']
      t.pattern ='spec/{unit,integration}/**/*.rb'
      t.fail_on_error = false
  end
diff --combined lib/puppet/application/inspect.rb
index c76f9e4,c7be893..8c3a001
--- a/lib/puppet/application/inspect.rb
+++ b/lib/puppet/application/inspect.rb
@@@ -38,21 -38,21 +38,21 @@@ class Puppet::Application::Inspect < Pu
        Puppet::Util::Log.level = :info
      end
  
 -    Puppet::Transaction::Report.terminus_class = :rest
 -    Puppet::Resource::Catalog.terminus_class = :yaml
 +    Puppet::Transaction::Report.indirection.terminus_class = :rest
 +    Puppet::Resource::Catalog.indirection.terminus_class = :yaml
    end
  
    def run_command
      retrieval_starttime = Time.now
  
 -    unless catalog = Puppet::Resource::Catalog.find(Puppet[:certname])
 +    unless catalog = Puppet::Resource::Catalog.indirection.find(Puppet[:certname])
        raise "Could not find catalog for #{Puppet[:certname]}"
      end
  
-     retrieval_time =  Time.now - retrieval_starttime
-     @report.add_times("config_retrieval", retrieval_time)
+     @report.configuration_version = catalog.version
  
-     starttime = Time.now
+     inspect_starttime = Time.now
+     @report.add_times("config_retrieval", inspect_starttime - retrieval_starttime)
  
      catalog.to_ral.resources.each do |ral_resource|
        audited_attributes = ral_resource[:audit]
@@@ -62,16 -62,22 +62,22 @@@
  
        status = Puppet::Resource::Status.new(ral_resource)
        audited_attributes.each do |name|
-         event = ral_resource.event(:previous_value => audited_resource[name], :property => name, :status => "audit", :message => "inspected value is #{audited_resource[name].inspect}")
-         status.add_event(event)
+         next if audited_resource[name].nil?
+         # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW
+         if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent
+           event = ral_resource.event(:previous_value => audited_resource[name], :property => name, :status => "audit", :message => "inspected value is #{audited_resource[name].inspect}")
+           status.add_event(event)
+         end
        end
        @report.add_resource_status(status)
      end
  
-     @report.add_metric(:time, {"config_retrieval" => retrieval_time, "inspect" => Time.now - starttime})
+     finishtime = Time.now
+     @report.add_times("inspect", finishtime - inspect_starttime)
+     @report.finalize_report
  
      begin
 -      @report.save
 +      Puppet::Transaction::Report.indirection.save(@report)
      rescue => detail
        puts detail.backtrace if Puppet[:trace]
        Puppet.err "Could not send report: #{detail}"
diff --combined lib/puppet/configurer.rb
index 50aaa0d,d3c9025..72e387c
--- a/lib/puppet/configurer.rb
+++ b/lib/puppet/configurer.rb
@@@ -72,10 -72,6 +72,6 @@@ class Puppet::Configure
      @splayed = false
    end
  
-   def initialize_report
-     Puppet::Transaction::Report.new
-   end
- 
    # Prepare for catalog retrieval.  Downloads everything necessary, etc.
    def prepare(options)
      dostorage
@@@ -134,7 -130,7 +130,7 @@@
        Puppet.err "Failed to prepare catalog: #{detail}"
      end
  
-     options[:report] ||= initialize_report
+     options[:report] ||= Puppet::Transaction::Report.new("apply")
      report = options[:report]
      Puppet::Util::Log.newdestination(report)
  
@@@ -145,6 -141,8 +141,8 @@@
        return
      end
  
+     report.configuration_version = catalog.version
+ 
      transaction = nil
  
      begin
@@@ -168,30 -166,19 +166,30 @@@
      execute_postrun_command
  
      Puppet::Util::Log.close(report)
      send_report(report, transaction)
    end
  
-   def send_report(report, trans = nil)
-     trans.generate_report if trans
+   def send_report(report, trans)
+     report.finalize_report if trans
      puts report.summary if Puppet[:summarize]
 -    report.save if Puppet[:report]
 +    save_last_run_summary(report)
 +    if Puppet[:report]
 +      Puppet::Transaction::Report.indirection.save(report)
 +    end
    rescue => detail
      puts detail.backtrace if Puppet[:trace]
      Puppet.err "Could not send report: #{detail}"
    end
  
 +  def save_last_run_summary(report)
 +    Puppet::Util::FileLocking.writelock(Puppet[:lastrunfile], 0660) do |file|
 +      file.print YAML.dump(report.raw_summary)
 +    end
 +  rescue => detail
 +    puts detail.backtrace if Puppet[:trace]
 +    Puppet.err "Could not save last run local report: #{detail}"
 +  end
 +
    private
  
    def self.timeout
@@@ -224,7 -211,7 +222,7 @@@
    def retrieve_catalog_from_cache(fact_options)
      result = nil
      @duration = thinmark do
 -      result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true))
 +      result = Puppet::Resource::Catalog.indirection.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true))
      end
      Puppet.notice "Using cached catalog"
      result
@@@ -237,7 -224,7 +235,7 @@@
    def retrieve_new_catalog(fact_options)
      result = nil
      @duration = thinmark do
 -      result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_cache => true))
 +      result = Puppet::Resource::Catalog.indirection.find(Puppet[:certname], fact_options.merge(:ignore_cache => true))
      end
      result
    rescue SystemExit,NoMemoryError
diff --combined lib/puppet/parser/ast.rb
index 0389116,a5aaedd..122b4dd
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@@ -19,6 -19,10 +19,10 @@@ class Puppet::Parser::AS
  
    attr_accessor :parent, :scope
  
+   def inspect
+     "( #{self.class} #{self.to_s} #{@children.inspect} )"
+   end
+ 
    # don't fetch lexer comment by default
    def use_docs
      self.class.use_docs
@@@ -107,32 -111,28 +111,32 @@@ en
  require 'puppet/parser/ast/arithmetic_operator'
  require 'puppet/parser/ast/astarray'
  require 'puppet/parser/ast/asthash'
 -require 'puppet/parser/ast/branch'
  require 'puppet/parser/ast/boolean_operator'
 +require 'puppet/parser/ast/branch'
  require 'puppet/parser/ast/caseopt'
  require 'puppet/parser/ast/casestatement'
  require 'puppet/parser/ast/collection'
  require 'puppet/parser/ast/collexpr'
  require 'puppet/parser/ast/comparison_operator'
 +require 'puppet/parser/ast/definition'
  require 'puppet/parser/ast/else'
  require 'puppet/parser/ast/function'
 +require 'puppet/parser/ast/hostclass'
  require 'puppet/parser/ast/ifstatement'
  require 'puppet/parser/ast/in_operator'
  require 'puppet/parser/ast/leaf'
  require 'puppet/parser/ast/match_operator'
  require 'puppet/parser/ast/minus'
 +require 'puppet/parser/ast/node'
  require 'puppet/parser/ast/nop'
  require 'puppet/parser/ast/not'
 +require 'puppet/parser/ast/relationship'
  require 'puppet/parser/ast/resource'
  require 'puppet/parser/ast/resource_defaults'
 +require 'puppet/parser/ast/resource_instance'
  require 'puppet/parser/ast/resource_override'
  require 'puppet/parser/ast/resource_reference'
  require 'puppet/parser/ast/resourceparam'
  require 'puppet/parser/ast/selector'
  require 'puppet/parser/ast/tag'
  require 'puppet/parser/ast/vardef'
 -require 'puppet/parser/ast/relationship'
diff --combined lib/puppet/resource/type_collection.rb
index a969276,277d37b..6ab978f
--- a/lib/puppet/resource/type_collection.rb
+++ b/lib/puppet/resource/type_collection.rb
@@@ -19,12 -19,10 +19,16 @@@ class Puppet::Resource::TypeCollectio
      @watched_files = {}
    end
  
 +  def import_ast(ast, modname)
 +    ast.instantiate(modname).each do |instance|
 +      add(instance)
 +    end
 +  end
 +
+   def inspect
+     "TypeCollection" + { :hostclasses => @hostclasses.keys, :definitions => @definitions.keys, :nodes => @nodes.keys }.inspect
+   end
+ 
    def <<(thing)
      add(thing)
      self
@@@ -98,8 -96,50 +102,8 @@@
      @definitions[munge_name(name)]
    end
  
 -  def find(namespaces, name, type)
 -    #Array("") == [] for some reason
 -    namespaces = [namespaces] unless namespaces.is_a?(Array)
 -
 -    if name =~ /^::/
 -      return send(type, name.sub(/^::/, ''))
 -    end
 -
 -    namespaces.each do |namespace|
 -      ary = namespace.split("::")
 -
 -      while ary.length > 0
 -        tmp_namespace = ary.join("::")
 -        if r = find_partially_qualified(tmp_namespace, name, type)
 -          return r
 -        end
 -
 -        # Delete the second to last object, which reduces our namespace by one.
 -        ary.pop
 -      end
 -
 -      if result = send(type, name)
 -        return result
 -      end
 -    end
 -    nil
 -  end
 -
 -  def find_or_load(namespaces, name, type)
 -    name      = name.downcase
 -    namespaces = [namespaces] unless namespaces.is_a?(Array)
 -    namespaces = namespaces.collect { |ns| ns.downcase }
 -
 -    # This could be done in the load_until, but the knowledge seems to
 -    # belong here.
 -    if r = find(namespaces, name, type)
 -      return r
 -    end
 -
 -    loader.load_until(namespaces, name) { find(namespaces, name, type) }
 -  end
 -
    def find_node(namespaces, name)
 -    find("", name, :node)
 +    @nodes[munge_name(name)]
    end
  
    def find_hostclass(namespaces, name)
@@@ -116,6 -156,23 +120,6 @@@
      end
    end
  
 -  def perform_initial_import
 -    parser = Puppet::Parser::Parser.new(environment)
 -    if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != ""
 -      parser.string = code
 -    else
 -      file = Puppet.settings.value(:manifest, environment.to_s)
 -      return unless File.exist?(file)
 -      parser.file = file
 -    end
 -    parser.parse
 -  rescue => detail
 -    msg = "Could not parse for environment #{environment}: #{detail}"
 -    error = Puppet::Error.new(msg)
 -    error.set_backtrace(detail.backtrace)
 -    raise error
 -  end
 -
    def stale?
      @watched_files.values.detect { |file| file.changed? }
    end
@@@ -144,52 -201,8 +148,52 @@@
  
    private
  
 -  def find_partially_qualified(namespace, name, type)
 -    send(type, [namespace, name].join("::"))
 +  # Return a list of all possible fully-qualified names that might be
 +  # meant by the given name, in the context of namespaces.
 +  def resolve_namespaces(namespaces, name)
 +    name      = name.downcase
 +    if name =~ /^::/
 +      # name is explicitly fully qualified, so just return it, sans
 +      # initial "::".
 +      return [name.sub(/^::/, '')]
 +    end
 +    if name == ""
 +      # The name "" has special meaning--it always refers to a "main"
 +      # hostclass which contains all toplevel resources.
 +      return [""]
 +    end
 +
 +    namespaces = [namespaces] unless namespaces.is_a?(Array)
 +    namespaces = namespaces.collect { |ns| ns.downcase }
 +
 +    result = []
 +    namespaces.each do |namespace|
 +      ary = namespace.split("::")
 +
 +      # Search each namespace nesting in innermost-to-outermost order.
 +      while ary.length > 0
 +        result << "#{ary.join("::")}::#{name}"
 +        ary.pop
 +      end
 +
 +      # Finally, search the toplevel namespace.
 +      result << name
 +    end
 +
 +    return result.uniq
 +  end
 +
 +  # Resolve namespaces and find the given object.  Autoload it if
 +  # necessary.
 +  def find_or_load(namespaces, name, type)
 +    resolve_namespaces(namespaces, name).each do |fqname|
 +      if result = send(type, fqname) || loader.try_load_fqname(type, fqname)
 +        return result
 +      end
 +    end
 +
 +    # Nothing found.
 +    return nil
    end
  
    def munge_name(name)
diff --combined lib/puppet/simple_graph.rb
index 6d153b4,c5dac0f..9d7f218
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@@ -7,45 -7,127 +7,45 @@@ require 'set
  
  # A hopefully-faster graph class to replace the use of GRATR.
  class Puppet::SimpleGraph
 -  # An internal class for handling a vertex's edges.
 -  class VertexWrapper
 -    attr_accessor :in, :out, :vertex
 -
 -    # Remove all references to everything.
 -    def clear
 -      @adjacencies[:in].clear
 -      @adjacencies[:out].clear
 -      @vertex = nil
 -    end
 -
 -    def initialize(vertex)
 -      @vertex = vertex
 -      @adjacencies = {:in => {}, :out => {}}
 -    end
 -
 -    # Find adjacent vertices or edges.
 -    def adjacent(options)
 -      direction = options[:direction] || :out
 -      options[:type] ||= :vertices
 -
 -      return send(direction.to_s + "_edges") if options[:type] == :edges
 -
 -      @adjacencies[direction].keys.reject { |vertex| @adjacencies[direction][vertex].empty? }
 -    end
 -
 -    # Add an edge to our list.
 -    def add_edge(direction, edge)
 -      opposite_adjacencies(direction, edge) << edge
 -    end
 -
 -    # Return all known edges.
 -    def edges
 -      in_edges + out_edges
 -    end
 -
 -    # Test whether we share an edge with a given vertex.
 -    def has_edge?(direction, vertex)
 -      return(vertex_adjacencies(direction, vertex).length > 0 ? true : false)
 -    end
 -
 -    # Create methods for returning the degree and edges.
 -    [:in, :out].each do |direction|
 -      # LAK:NOTE If you decide to create methods for directly
 -      # testing the degree, you'll have to get the values and flatten
 -      # the results -- you might have duplicate edges, which can give
 -      # a false impression of what the degree is.  That's just
 -      # as expensive as just getting the edge list, so I've decided
 -      # to only add this method.
 -      define_method("#{direction}_edges") do
 -        @adjacencies[direction].values.inject([]) { |total, adjacent| total += adjacent.to_a; total }
 -      end
 -    end
 -
 -    # The other vertex in the edge.
 -    def other_vertex(direction, edge)
 -      case direction
 -      when :in; edge.source
 -      else
 -        edge.target
 -      end
 -    end
 -
 -    # Remove an edge from our list.  Assumes that we've already checked
 -    # that the edge is valid.
 -    def remove_edge(direction, edge)
 -      opposite_adjacencies(direction, edge).delete(edge)
 -    end
 -
 -    def to_s
 -      vertex.to_s
 -    end
 -
 -    def inspect
 -      { :@adjacencies => @adjacencies, :@vertex => @vertex.to_s }.inspect
 -    end
 -
 -    private
 -
 -    # These methods exist so we don't need a Hash with a default proc.
 -
 -    # Look up the adjacencies for a vertex at the other end of an
 -    # edge.
 -    def opposite_adjacencies(direction, edge)
 -      opposite_vertex = other_vertex(direction, edge)
 -      vertex_adjacencies(direction, opposite_vertex)
 -    end
 -
 -    # Look up the adjacencies for a given vertex.
 -    def vertex_adjacencies(direction, vertex)
 -      @adjacencies[direction][vertex] ||= Set.new
 -      @adjacencies[direction][vertex]
 -    end
 -  end
 -
 +  #
 +  # All public methods of this class must maintain (assume ^ ensure) the following invariants, where "=~=" means
 +  # equiv. up to order:
 +  #
 +  #   @in_to.keys =~= @out_to.keys =~= all vertices
 +  #   @in_to.values.collect { |x| x.values }.flatten =~= @out_from.values.collect { |x| x.values }.flatten =~= all edges
 +  #   @in_to[v1][v2] =~= @out_from[v2][v1] =~= all edges from v1 to v2
 +  #   @in_to   [v].keys =~= vertices with edges leading to   v
 +  #   @out_from[v].keys =~= vertices with edges leading from v
 +  #   no operation may shed reference loops (for gc)
 +  #   recursive operation must scale with the depth of the spanning trees, or better (e.g. no recursion over the set
 +  #       of all vertices, etc.)
 +  #
 +  # This class is intended to be used with DAGs.  However, if the
 +  # graph has a cycle, it will not cause non-termination of any of the
 +  # algorithms.  The topsort method detects and reports cycles.
 +  #
    def initialize
 -    @vertices = {}
 -    @edges = []
 +    @in_to = {}
 +    @out_from = {}
 +    @upstream_from = {}
 +    @downstream_from = {}
    end
  
    # Clear our graph.
    def clear
 -    @vertices.each { |vertex, wrapper| wrapper.clear }
 -    @vertices.clear
 -    @edges.clear
 -  end
 -
 -  # Which resources a given resource depends upon.
 -  def dependents(resource)
 -    tree_from_vertex(resource).keys
 +    @in_to.clear
 +    @out_from.clear
 +    @upstream_from.clear
 +    @downstream_from.clear
    end
  
    # Which resources depend upon the given resource.
    def dependencies(resource)
 -    # Cache the reversal graph, because it's somewhat expensive
 -    # to create.
 -    @reversal ||= reversal
 -    # Strangely, it's significantly faster to search a reversed
 -    # tree in the :out direction than to search a normal tree
 -    # in the :in direction.
 -    @reversal.tree_from_vertex(resource, :out).keys
 +    vertex?(resource) ? upstream_from_vertex(resource).keys : []
 +  end
 +
 +  def dependents(resource)
 +    vertex?(resource) ? downstream_from_vertex(resource).keys : []
    end
  
    # Whether our graph is directed.  Always true.  Used to produce dot files.
@@@ -55,7 -137,8 +55,7 @@@
  
    # Determine all of the leaf nodes below a given vertex.
    def leaves(vertex, direction = :out)
 -    tree = tree_from_vertex(vertex, direction)
 -    l = tree.keys.find_all { |c| adjacent(c, :direction => direction).empty? }
 +    tree_from_vertex(vertex, direction).keys.find_all { |c| adjacent(c, :direction => direction).empty? }
    end
  
    # Collect all of the edges that the passed events match.  Returns
@@@ -70,7 -153,9 +70,7 @@@
      # 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.name)
 -    end
 +    @out_from[source].values.flatten.find_all { |edge| edge.match?(event.name) }
    end
  
    # Return a reversed version of this graph.
@@@ -78,50 -163,20 +78,50 @@@
      result = self.class.new
      vertices.each { |vertex| result.add_vertex(vertex) }
      edges.each do |edge|
 -      newedge = edge.class.new(edge.target, edge.source, edge.label)
 -      result.add_edge(newedge)
 +      result.add_edge edge.class.new(edge.target, edge.source, edge.label)
      end
      result
    end
  
    # Return the size of the graph.
    def size
 -    @vertices.length
 +    vertices.size
    end
  
 -  # Return the graph as an array.
    def to_a
 -    @vertices.keys
 +    vertices
 +  end
 +
 +  # Provide a topological sort with cycle reporting
 +  def topsort_with_cycles
 +    degree = {}
 +    zeros = []
 +    result = []
 +
 +    # Collect each of our vertices, with the number of in-edges each has.
 +    vertices.each do |v|
 +      edges = @in_to[v].dup
 +      zeros << v if edges.empty?
 +      degree[v] = edges
 +    end
 +
 +    # Iterate over each 0-degree vertex, decrementing the degree of
 +    # each of its out-edges.
 +    while v = zeros.pop
 +      result << v
 +      @out_from[v].each { |v2,es| 
 +        degree[v2].delete(v)
 +        zeros << v2 if degree[v2].empty?
 +      }
 +    end
 +
 +    # If we have any vertices left with non-zero in-degrees, then we've found a cycle.
 +    if cycles = degree.values.reject { |ns| ns.empty? } and cycles.length > 0
 +      message = cycles.collect { |edges| '('+edges.collect { |e| e.to_s }.join(", ")+')' }.join(", ")
 +      raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz"
 +    end
 +
 +    result
    end
  
    # Provide a topological sort.
@@@ -131,24 -186,26 +131,24 @@@
      result = []
  
      # Collect each of our vertices, with the number of in-edges each has.
 -    @vertices.each do |name, wrapper|
 -      edges = wrapper.in_edges
 -      zeros << wrapper if edges.length == 0
 -      degree[wrapper.vertex] = edges
 +    vertices.each do |v|
 +      edges = @in_to[v]
 +      zeros << v if edges.empty?
 +      degree[v] = edges.length
      end
  
      # Iterate over each 0-degree vertex, decrementing the degree of
      # each of its out-edges.
 -    while wrapper = zeros.pop
 -      result << wrapper.vertex
 -      wrapper.out_edges.each do |edge|
 -        degree[edge.target].delete(edge)
 -        zeros << @vertices[edge.target] if degree[edge.target].length == 0
 -      end
 +    while v = zeros.pop
 +      result << v
 +      @out_from[v].each { |v2,es| 
 +        zeros << v2 if (degree[v2] -= 1) == 0
 +      }
      end
  
      # If we have any vertices left with non-zero in-degrees, then we've found a cycle.
 -    if cycles = degree.find_all { |vertex, edges| edges.length > 0 } and cycles.length > 0
 -      message = cycles.collect { |vertex, edges| edges.collect { |e| e.to_s }.join(", ") }.join(", ")
 -      raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz"
 +    if cycles = degree.values.reject { |ns| ns == 0  } and cycles.length > 0
 +      topsort_with_cycles
      end
  
      result
@@@ -156,80 -213,103 +156,80 @@@
  
    # Add a new vertex to the graph.
    def add_vertex(vertex)
 -    @reversal = nil
 -    return false if vertex?(vertex)
 -    setup_vertex(vertex)
 -    true # don't return the VertexWrapper instance.
 +    @in_to[vertex]    ||= {}
 +    @out_from[vertex] ||= {}
    end
  
    # Remove a vertex from the graph.
 -  def remove_vertex!(vertex)
 -    return nil unless vertex?(vertex)
 -    @vertices[vertex].edges.each { |edge| remove_edge!(edge) }
 -    @edges -= @vertices[vertex].edges
 -    @vertices[vertex].clear
 -    @vertices.delete(vertex)
 +  def remove_vertex!(v)
 +    return unless vertex?(v)
 +    @upstream_from.clear
 +    @downstream_from.clear
 +    (@in_to[v].values+ at out_from[v].values).flatten.each { |e| remove_edge!(e) }
 +    @in_to.delete(v)
 +    @out_from.delete(v)
    end
  
    # Test whether a given vertex is in the graph.
 -  def vertex?(vertex)
 -    @vertices.include?(vertex)
 +  def vertex?(v)
 +    @in_to.include?(v)
    end
  
    # Return a list of all vertices.
    def vertices
 -    @vertices.keys
 +    @in_to.keys
    end
  
    # Add a new edge.  The graph user has to create the edge instance,
    # since they have to specify what kind of edge it is.
 -  def add_edge(source, target = nil, label = nil)
 -    @reversal = nil
 -    if target
 -      edge = Puppet::Relationship.new(source, target, label)
 -    else
 -      edge = source
 -    end
 -    [edge.source, edge.target].each { |vertex| setup_vertex(vertex) unless vertex?(vertex) }
 -    @vertices[edge.source].add_edge :out, edge
 -    @vertices[edge.target].add_edge :in, edge
 -    @edges << edge
 -    true
 +  def add_edge(e,*a)
 +    return add_relationship(e,*a) unless a.empty?
 +    @upstream_from.clear
 +    @downstream_from.clear
 +    add_vertex(e.source)
 +    add_vertex(e.target)
 +    @in_to[   e.target][e.source] ||= []; @in_to[   e.target][e.source] |= [e]
 +    @out_from[e.source][e.target] ||= []; @out_from[e.source][e.target] |= [e]
    end
  
 -  # Find a matching edge.  Note that this only finds the first edge,
 -  # not all of them or whatever.
 -  def edge(source, target)
 -    @edges.each_with_index { |test_edge, index| return test_edge if test_edge.source == source and test_edge.target == target }
 +  def add_relationship(source, target, label = nil)
 +    add_edge Puppet::Relationship.new(source, target, label)
    end
  
 -  def edge_label(source, target)
 -    return nil unless edge = edge(source, target)
 -    edge.label
 +  # Find all matching edges.
 +  def edges_between(source, target)
 +    (@out_from[source] || {})[target] || []
    end
  
    # Is there an edge between the two vertices?
    def edge?(source, target)
 -    return false unless vertex?(source) and vertex?(target)
 -
 -    @vertices[source].has_edge?(:out, target)
 +    vertex?(source) and vertex?(target) and @out_from[source][target]
    end
  
    def edges
 -    @edges.dup
 +    @in_to.values.collect { |x| x.values }.flatten
    end
  
 -  # Remove an edge from our graph.
 -  def remove_edge!(edge)
 -    @vertices[edge.source].remove_edge(:out, edge)
 -    @vertices[edge.target].remove_edge(:in, edge)
 -
 -    @edges.delete(edge)
 -    nil
 +  def each_edge
 +    @in_to.each { |t,ns| ns.each { |s,es| es.each { |e| yield e }}}
    end
  
 -  # Find adjacent edges.
 -  def adjacent(vertex, options = {})
 -    return [] unless wrapper = @vertices[vertex]
 -    wrapper.adjacent(options)
 +  # Remove an edge from our graph.
 +  def remove_edge!(e)
 +    if edge?(e.source,e.target)
 +      @upstream_from.clear
 +      @downstream_from.clear
 +      @in_to   [e.target].delete e.source if (@in_to   [e.target][e.source] -= [e]).empty?
 +      @out_from[e.source].delete e.target if (@out_from[e.source][e.target] -= [e]).empty?
 +    end
    end
  
 -  private
 -
 -  # An internal method that skips the validation, so we don't have
 -  # duplicate validation calls.
 -  def setup_vertex(vertex)
 -    @vertices[vertex] = VertexWrapper.new(vertex)
 +  # Find adjacent edges.
 +  def adjacent(v, options = {})
 +    return [] unless ns = (options[:direction] == :in) ? @in_to[v] : @out_from[v]
 +    (options[:type] == :edges) ? ns.values.flatten : ns.keys
    end
 -
 -  public
 -
 -#    # For some reason, unconnected vertices do not show up in
 -#    # this graph.
 -#    def to_jpg(path, name)
 -#        gv = vertices
 -#        Dir.chdir(path) do
 -#            induced_subgraph(gv).write_to_graphic_file('jpg', name)
 -#        end
 -#    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
@@@ -305,26 -385,6 +305,26 @@@
      predecessor
    end
  
 +  def downstream_from_vertex(v)
 +    return @downstream_from[v] if @downstream_from[v]
 +    result = @downstream_from[v] = {}
 +    @out_from[v].keys.each do |node|
 +      result[node] = 1
 +      result.update(downstream_from_vertex(node))
 +    end
 +    result
 +  end
 +
 +  def upstream_from_vertex(v)
 +    return @upstream_from[v] if @upstream_from[v]
 +    result = @upstream_from[v] = {}
 +    @in_to[v].keys.each do |node|
 +      result[node] = 1
 +      result.update(upstream_from_vertex(node))
 +    end
 +    result
 +  end
 +
    # LAK:FIXME This is just a paste of the GRATR code with slight modifications.
  
    # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
@@@ -366,6 -426,18 +366,6 @@@
      system('dotty', dotfile)
    end
  
 -  # Use +dot+ to create a graphical representation of the graph.  Returns the
 -  # filename of the graphics file.
 -  def write_to_graphic_file (fmt='png', dotfile='graph')
 -    src = dotfile + '.dot'
 -    dot = dotfile + '.' + fmt
 -
 -    File.open(src, 'w') {|f| f << self.to_dot << "\n"}
 -
 -    system( "dot -T#{fmt} #{src} -o #{dot}" )
 -    dot
 -  end
 -
    # Produce the graph files if requested.
    def write_graph(name)
      return unless Puppet[:graph]
@@@ -377,73 -449,4 +377,77 @@@
        f.puts to_dot("name" => name.to_s.capitalize)
      }
    end
 +
 +  # This flag may be set to true to use the new YAML serialzation
 +  # format (where @vertices is a simple list of vertices rather than a
 +  # list of VertexWrapper objects).  Deserialization supports both
 +  # formats regardless of the setting of this flag.
 +  class << self
 +    attr_accessor :use_new_yaml_format
 +  end
 +  self.use_new_yaml_format = false
 +
 +  # Stub class to allow graphs to be represented in YAML using the old
 +  # (version 2.6) format.
 +  class VertexWrapper
 +    attr_reader :vertex, :adjacencies
 +    def initialize(vertex, adjacencies)
 +      @vertex = vertex
 +      @adjacencies = adjacencies
 +    end
++
++    def inspect
++      { :@adjacencies => @adjacencies, :@vertex => @vertex.to_s }.inspect
++    end
 +  end
 +
 +  # instance_variable_get is used by Object.to_zaml to get instance
 +  # variables.  Override it so that we can simulate the presence of
 +  # instance variables @edges and @vertices for serialization.
 +  def instance_variable_get(v)
 +    case v.to_s
 +    when '@edges' then
 +      edges
 +    when '@vertices' then
 +      if self.class.use_new_yaml_format
 +        vertices
 +      else
 +        result = {}
 +        vertices.each do |vertex|
 +          adjacencies = {}
 +          [:in, :out].each do |direction|
 +            adjacencies[direction] = {}
 +            adjacent(vertex, :direction => direction, :type => :edges).each do |edge|
 +              other_vertex = direction == :in ? edge.source : edge.target
 +              (adjacencies[direction][other_vertex] ||= Set.new).add(edge)
 +            end
 +          end
 +          result[vertex] = Puppet::SimpleGraph::VertexWrapper.new(vertex, adjacencies)
 +        end
 +        result
 +      end
 +    else
 +      super(v)
 +    end
 +  end
 +
 +  def to_yaml_properties
 +    other_vars = instance_variables.reject { |v| %w{@in_to @out_from @upstream_from @downstream_from}.include?(v) }
 +    (other_vars + %w{@vertices @edges}).sort.uniq
 +  end
 +
 +  def yaml_initialize(tag, var)
 +    initialize()
 +    vertices = var.delete('vertices')
 +    edges = var.delete('edges')
 +    if vertices.is_a?(Hash)
 +      # Support old (2.6) format
 +      vertices = vertices.keys
 +    end
 +    vertices.each { |v| add_vertex(v) }
 +    edges.each { |e| add_edge(e) }
 +    var.each do |varname, value|
 +      instance_variable_set("@#{varname}", value)
 +    end
 +  end
  end
diff --combined lib/puppet/transaction.rb
index 4c0ea9a,aa650ee..eba601c
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@@ -6,7 -6,6 +6,6 @@@ require 'puppet/util/tagging
  require 'puppet/application'
  
  class Puppet::Transaction
-   require 'puppet/transaction/change'
    require 'puppet/transaction/event'
    require 'puppet/transaction/event_manager'
    require 'puppet/transaction/resource_harness'
@@@ -222,12 -221,6 +221,6 @@@
      end
    end
  
-   # Generate a transaction report.
-   def generate_report
-     @report.calculate_metrics
-     @report
-   end
- 
    # Should we ignore tags?
    def ignore_tags?
      ! (@catalog.host_config? or Puppet[:name] == "puppet")
@@@ -238,7 -231,7 +231,7 @@@
    def initialize(catalog)
      @catalog = catalog
  
-     @report = Report.new
 -    @report = Report.new("apply", catalog.version)
++    @report = Puppet::Transaction::Report.new("apply")
  
      @event_manager = Puppet::Transaction::EventManager.new(self)
  
@@@ -285,26 -278,6 +278,6 @@@
      catalog.relationship_graph
    end
  
-   # Send off the transaction report.
-   def send_report
-     begin
-       report = generate_report
-     rescue => detail
-       Puppet.err "Could not generate report: #{detail}"
-       return
-     end
- 
-     puts report.summary if Puppet[:summarize]
- 
-     if Puppet[:report]
-       begin
-         Puppet::Transaction::Report.indirection.save(report)
-       rescue => detail
-         Puppet.err "Reporting failed: #{detail}"
-       end
-     end
-   end
- 
    def add_resource_status(status)
      report.add_resource_status status
    end
diff --combined lib/puppet/transaction/report.rb
index 492d15d,8e04759..16fee42
--- a/lib/puppet/transaction/report.rb
+++ b/lib/puppet/transaction/report.rb
@@@ -10,7 -10,8 +10,8 @@@ class Puppet::Transaction::Repor
  
    indirects :report, :terminus_class => :processor
  
-   attr_reader :resource_statuses, :logs, :metrics, :host, :time, :kind
+   attr_accessor :configuration_version
+   attr_reader :resource_statuses, :logs, :metrics, :host, :time, :kind, :status
  
    # This is necessary since Marshall doesn't know how to
    # dump hash with default proc (see below @records)
@@@ -42,14 -43,26 +43,26 @@@
      @resource_statuses[status.resource] = status
    end
  
-   def calculate_metrics
-     calculate_resource_metrics
-     calculate_time_metrics
-     calculate_change_metrics
-     calculate_event_metrics
+   def compute_status(resource_metrics, change_metric)
+     if (resource_metrics["failed"] || 0) > 0
+       'failed'
+     elsif change_metric > 0
+       'changed'
+     else
+       'unchanged'
+     end
+   end
+ 
+   def finalize_report
+     resource_metrics = add_metric(:resources, calculate_resource_metrics)
+     add_metric(:time, calculate_time_metrics)
+     change_metric = calculate_change_metric
+     add_metric(:changes, {"total" => change_metric})
+     add_metric(:events, calculate_event_metrics)
+     @status = compute_status(resource_metrics, change_metric)
    end
  
-   def initialize(kind = "apply")
+   def initialize(kind, configuration_version=nil)
      @metrics = {}
      @logs = []
      @resource_statuses = {}
@@@ -57,98 -70,85 +70,103 @@@
      @host = Puppet[:certname]
      @time = Time.now
      @kind = kind
+     @report_format = 2
+     @puppet_version = Puppet.version
+     @configuration_version = configuration_version
+     @status = 'failed' # assume failed until the report is finalized
    end
  
    def name
      host
    end
  
 -  # Provide a summary of this report.
 +  # Provide a human readable textual summary of this report.
    def summary
 +    report = raw_summary
 +
      ret = ""
 +    report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key|
 +      ret += "#{Puppet::Util::Metric.labelize(key)}:\n"
  
 -    @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric|
 -      ret += "#{metric.label}:\n"
 -      metric.values.sort { |a,b|
 +      report[key].keys.sort { |a,b|
          # sort by label
 -        if a[0] == :total
 +        if a == :total
            1
 -        elsif b[0] == :total
 +        elsif b == :total
            -1
          else
 -          a[1] <=> b[1]
 +          report[key][a].to_s <=> report[key][b].to_s
          end
 -      }.each do |name, label, value|
 +      }.each do |label|
 +        value = report[key][label]
          next if value == 0
          value = "%0.2f" % value if value.is_a?(Float)
 -        ret += "   %15s %s\n" % [label + ":", value]
 +        ret += "   %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value]
        end
      end
      ret
    end
  
 +  # Provide a raw hash summary of this report.
 +  def raw_summary
 +    report = {}
 +
 +    @metrics.each do |name, metric|
 +      key = metric.name.to_s
 +      report[key] = {}
 +      metric.values.each do |name, label, value|
 +        report[key][name.to_s] = value
 +      end
 +      report[key]["total"] = 0 unless key == "time" or report[key].include?("total")
 +    end
 +    (report["time"] ||= {})["last_run"] = Time.now.tv_sec
 +    report
 +  end
 +
    # Based on the contents of this report's metrics, compute a single number
    # that represents the report. The resulting number is a bitmask where
    # individual bits represent the presence of different metrics.
    def exit_status
      status = 0
-     status |= 2 if @metrics["changes"][:total] > 0
-     status |= 4 if @metrics["resources"][:failed] > 0
+     status |= 2 if @metrics["changes"]["total"] > 0
+     status |= 4 if @metrics["resources"]["failed"] > 0
      status
    end
  
+   def to_yaml_properties
+     (instance_variables - ["@external_times"]).sort
+   end
+ 
    private
  
-   def calculate_change_metrics
-     metrics = Hash.new(0)
-     resource_statuses.each do |name, status|
-       metrics[:total] += status.change_count if status.change_count
-     end
-     add_metric(:changes, metrics)
+   def calculate_change_metric
+     resource_statuses.map { |name, status| status.change_count || 0 }.inject(0) { |a,b| a+b }
    end
  
    def calculate_event_metrics
      metrics = Hash.new(0)
+     metrics["total"] = 0
      resource_statuses.each do |name, status|
-       metrics[:total] += status.events.length
+       metrics["total"] += status.events.length
        status.events.each do |event|
          metrics[event.status] += 1
        end
      end
  
-     add_metric(:events, metrics)
+     metrics
    end
  
    def calculate_resource_metrics
      metrics = Hash.new(0)
-     metrics[:total] = resource_statuses.length
+     metrics["total"] = resource_statuses.length
  
      resource_statuses.each do |name, status|
 -
        Puppet::Resource::Status::STATES.each do |state|
-         metrics[state] += 1 if status.send(state)
+         metrics[state.to_s] += 1 if status.send(state)
        end
      end
  
-     add_metric(:resources, metrics)
+     metrics
    end
  
    def calculate_time_metrics
@@@ -162,6 -162,8 +180,8 @@@
        metrics[name.to_s.downcase] = value
      end
  
-     add_metric(:time, metrics)
+     metrics["total"] = metrics.values.inject(0) { |a,b| a+b }
+ 
+     metrics
    end
  end
diff --combined lib/puppet/type/file.rb
index b346127,eee948c..457afd4
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@@ -587,7 -587,7 +587,7 @@@ Puppet::Type.newtype(:file) d
  
    def perform_recursion(path)
  
 -    Puppet::FileServing::Metadata.search(
 +    Puppet::FileServing::Metadata.indirection.search(
  
        path,
        :links => self[:links],
@@@ -797,3 -797,5 +797,5 @@@ require 'puppet/type/file/group
  require 'puppet/type/file/mode'
  require 'puppet/type/file/type'
  require 'puppet/type/file/selcontext'  # SELinux file context
+ require 'puppet/type/file/ctime'
+ require 'puppet/type/file/mtime'
diff --combined lib/puppet/util/log.rb
index 9a9e291,3fdac3f..2f9f356
--- a/lib/puppet/util/log.rb
+++ b/lib/puppet/util/log.rb
@@@ -58,7 -58,6 +58,7 @@@ class Puppet::Util::Lo
      destinations.keys.each { |dest|
        close(dest)
      }
 +    raise Puppet::DevError.new("Log.close_all failed to close #{@destinations.keys.inspect}") if !@destinations.empty?
    end
  
    # Flush any log destinations that support such operations.
@@@ -190,7 -189,7 +190,7 @@@
      @levels.include?(level)
    end
  
-   attr_accessor :time, :remote, :file, :line, :version, :source
+   attr_accessor :time, :remote, :file, :line, :source
    attr_reader :level, :message
  
    def initialize(args)
@@@ -204,7 -203,7 +204,7 @@@
        tags.each { |t| self.tag(t) }
      end
  
-     [:file, :line, :version].each do |attr|
+     [:file, :line].each do |attr|
        next unless value = args[attr]
        send(attr.to_s + "=", value)
      end
@@@ -235,7 -234,7 +235,7 @@@
  
        descriptors[:tags].each { |t| tag(t) }
  
-       [:file, :line, :version].each do |param|
+       [:file, :line].each do |param|
          next unless descriptors[param]
          send(param.to_s + "=", descriptors[param])
        end
diff --combined lib/puppet/util/metric.rb
index 7fdc695,09bbb61..835e1d6
--- a/lib/puppet/util/metric.rb
+++ b/lib/puppet/util/metric.rb
@@@ -122,7 -122,7 +122,7 @@@ class Puppet::Util::Metri
    def initialize(name,label = nil)
      @name = name.to_s
  
 -    @label = label || labelize(name)
 +    @label = label || self.class.labelize(name)
  
      @values = []
    end
@@@ -132,7 -132,8 +132,8 @@@
    end
  
    def newvalue(name,value,label = nil)
+     raise ArgumentError.new("metric name #{name.inspect} is not a string") unless name.is_a? String
 -    label ||= labelize(name)
 +    label ||= self.class.labelize(name)
      @values.push [name,label,value]
    end
  
@@@ -173,8 -174,10 +174,8 @@@
      @values.sort { |a, b| a[1] <=> b[1] }
    end
  
 -  private
 -
    # Convert a name into a label.
 -  def labelize(name)
 +  def self.labelize(name)
      name.to_s.capitalize.gsub("_", " ")
    end
  end
diff --combined spec/integration/application/apply_spec.rb
index 382449e,363aa34..876f555
--- a/spec/integration/application/apply_spec.rb
+++ b/spec/integration/application/apply_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet_spec/files'
  
@@@ -9,8 -9,7 +9,7 @@@ require 'puppet/application/apply
  describe "apply" do
    include PuppetSpec::Files
  
-   describe "when applying provided catalogs" do
-     confine "PSON library is missing; cannot test applying catalogs" => Puppet.features.pson?
+   describe "when applying provided catalogs", :if => Puppet.features.pson? do
      it "should be able to apply catalogs provided in a file in pson" do
        file_to_create = tmpfile("pson_catalog")
        catalog = Puppet::Resource::Catalog.new
diff --combined spec/integration/configurer_spec.rb
index a0a4d73,9a8b66f..825b632
--- a/spec/integration/configurer_spec.rb
+++ b/spec/integration/configurer_spec.rb
@@@ -1,12 -1,10 +1,12 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  require 'puppet/configurer'
  
  describe Puppet::Configurer do
 +  include PuppetSpec::Files
 +
    describe "when downloading plugins" do
      it "should use the :pluginsignore setting, split on whitespace, for ignoring remote files" do
        resource = Puppet::Type.type(:notify).new :name => "yay"
@@@ -19,50 -17,19 +19,50 @@@
    end
  
    describe "when running" do
 -    it "should send a transaction report with valid data" do
 -      catalog = Puppet::Resource::Catalog.new
 -      catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing"))
 +    before(:each) do
 +      @catalog = Puppet::Resource::Catalog.new
 +      @catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing"))
  
 -      configurer = Puppet::Configurer.new
 +      # Make sure we don't try to persist the local state after the transaction ran, 
 +      # because it will fail during test (the state file is in an not existing directory)
 +      # and we need the transaction to be successful to be able to produce a summary report
 +      @catalog.host_config = false
 +
 +      @configurer = Puppet::Configurer.new
 +    end
 +
 +    it "should send a transaction report with valid data" do
  
 -      Puppet::Transaction::Report.indirection.expects(:save).with do |x, report|
 +      @configurer.stubs(:save_last_run_summary)
 +      Puppet::Transaction::Report.indirection.expects(:save).with do |report, x|
          report.time.class == Time and report.logs.length > 0
        end
  
        Puppet[:report] = true
  
 -      configurer.run :catalog => catalog
 +      @configurer.run :catalog => @catalog
 +    end
 +
 +    it "should save a correct last run summary" do
-       report = Puppet::Transaction::Report.new
-       report.stubs(:save)
++      report = Puppet::Transaction::Report.new("apply")
++      Puppet::Transaction::Report.indirection.stubs(:save)
 +
 +      Puppet[:lastrunfile] = tmpfile("lastrunfile")
 +      Puppet[:report] = true
 +
 +      @configurer.run :catalog => @catalog, :report => report
 +
 +      summary = nil
 +      File.open(Puppet[:lastrunfile], "r") do |fd|
 +        summary = YAML.load(fd.read)
 +      end
 +
 +      summary.should be_a(Hash)
 +      %w{time changes events resources}.each do |key|
 +        summary.should be_key(key)
 +      end
 +      summary["time"].should be_key("notify")
 +      summary["time"]["last_run"].should >= Time.now.tv_sec
      end
    end
  end
diff --combined spec/integration/network/formats_spec.rb
index 44d1679,d141abf..8eb963e
--- a/spec/integration/network/formats_spec.rb
+++ b/spec/integration/network/formats_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/network/formats'
  
@@@ -46,8 -46,7 +46,7 @@@ describe Puppet::Network::FormatHandler
  end
  
  describe Puppet::Network::FormatHandler.format(:pson) do
-   describe "when pson is absent" do
-     confine "'pson' library is present" => (! Puppet.features.pson?)
+   describe "when pson is absent", :if => (! Puppet.features.pson?) do
  
      before do
        @pson = Puppet::Network::FormatHandler.format(:pson)
@@@ -58,9 -57,7 +57,7 @@@
      end
    end
  
-   describe "when pson is available" do
-     confine "Missing 'pson' library" => Puppet.features.pson?
- 
+   describe "when pson is available", :if => Puppet.features.pson? do
      before do
        @pson = Puppet::Network::FormatHandler.format(:pson)
      end
diff --combined spec/integration/network/server/mongrel_spec.rb
index 45e1f81,c2815b5..aeaaad6
--- a/spec/integration/network/server/mongrel_spec.rb
+++ b/spec/integration/network/server/mongrel_spec.rb
@@@ -1,12 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  require 'puppet/network/server'
  require 'socket'
  
  describe Puppet::Network::Server do
-   describe "when using mongrel" do
-     confine "Mongrel is not available" => Puppet.features.mongrel?
+   describe "when using mongrel", :if => Puppet.features.mongrel? do
  
      before :each do
        Puppet[:servertype] = 'mongrel'
diff --combined spec/integration/provider/mailalias/aliases_spec.rb
index 685cbd2,1bce13f..bce9374
--- a/spec/integration/provider/mailalias/aliases_spec.rb
+++ b/spec/integration/provider/mailalias/aliases_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppettest/support/utils'
  require 'puppettest/fileparsing'
@@@ -8,7 -8,6 +8,6 @@@
  provider_class = Puppet::Type.type(:mailalias).provider(:aliases)
  
  describe provider_class do
-   include PuppetTest
    include PuppetTest::FileParsing
    include PuppetTest::Support::Utils
  
diff --combined spec/integration/resource/catalog_spec.rb
index a3e4024,da2b704..2116265
--- a/spec/integration/resource/catalog_spec.rb
+++ b/spec/integration/resource/catalog_spec.rb
@@@ -3,11 -3,10 +3,10 @@@
  #  Created by Luke Kanies on 2007-4-8.
  #  Copyright (c) 2008. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  describe Puppet::Resource::Catalog do
-   describe "when pson is available" do
-     confine "PSON library is missing" => Puppet.features.pson?
+   describe "when pson is available", :if => Puppet.features.pson? do
      it "should support pson" do
        Puppet::Resource::Catalog.supported_formats.should be_include(:pson)
      end
@@@ -30,7 -29,7 +29,7 @@@
        terminus.expects(:path).with("me").returns "/my/yaml/file"
  
        FileTest.expects(:exist?).with("/my/yaml/file").returns false
 -      Puppet::Resource::Catalog.find("me").should be_nil
 +      Puppet::Resource::Catalog.indirection.find("me").should be_nil
      end
  
      it "should be able to delegate to the :compiler terminus" do
@@@ -42,10 -41,10 +41,10 @@@
        node = mock 'node'
        node.stub_everything
  
 -      Puppet::Node.expects(:find).returns(node)
 +      Puppet::Node.indirection.expects(:find).returns(node)
        compiler.expects(:compile).with(node).returns nil
  
 -      Puppet::Resource::Catalog.find("me").should be_nil
 +      Puppet::Resource::Catalog.indirection.find("me").should be_nil
      end
  
      it "should pass provided node information directly to the terminus" do
@@@ -55,7 -54,7 +54,7 @@@
  
        node = mock 'node'
        terminus.expects(:find).with { |request| request.options[:use_node] == node }
 -      Puppet::Resource::Catalog.find("me", :use_node => node)
 +      Puppet::Resource::Catalog.indirection.find("me", :use_node => node)
      end
    end
  end
diff --combined spec/integration/transaction/report_spec.rb
index 09b0292,e7d952e..c38f310
--- a/spec/integration/transaction/report_spec.rb
+++ b/spec/integration/transaction/report_spec.rb
@@@ -3,7 -3,7 +3,7 @@@
  #  Created by Luke Kanies on 2008-4-8.
  #  Copyright (c) 2008. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  describe Puppet::Transaction::Report do
    describe "when using the indirector" do
@@@ -19,11 -19,11 +19,11 @@@
  
        Facter.stubs(:value).returns "host.domain.com"
  
-       report = Puppet::Transaction::Report.new
+       report = Puppet::Transaction::Report.new("apply")
  
        terminus.expects(:process).with(report)
  
 -      report.save
 +      Puppet::Transaction::Report.indirection.save(report)
      end
    end
  end
diff --combined spec/shared_behaviours/file_serving.rb
index 9159445,450fff8..8417344
--- a/spec/shared_behaviours/file_serving.rb
+++ b/spec/shared_behaviours/file_serving.rb
@@@ -3,7 -3,7 +3,7 @@@
  #  Created by Luke Kanies on 2007-10-18.
  #  Copyright (c) 2007. All rights reserved.
  
- describe "Puppet::FileServing::Files", :shared => true do
+ shared_examples_for "Puppet::FileServing::Files" do
    it "should use the rest terminus when the 'puppet' URI scheme is used and a host name is present" do
      uri = "puppet://myhost/fakemod/my/file"
  
@@@ -12,7 -12,7 +12,7 @@@
      term = @indirection.terminus(:rest)
      @indirection.stubs(:terminus).with(:rest).returns term
      term.expects(:find)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet' or 'apply'" do
@@@ -21,7 -21,7 +21,7 @@@
      Puppet.settings.stubs(:value).with(:name).returns("puppetd")
      Puppet.settings.stubs(:value).with(:modulepath).returns("")
      @indirection.terminus(:rest).expects(:find)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'puppet'" do
@@@ -32,7 -32,7 +32,7 @@@
      Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever")
      @indirection.terminus(:file_server).expects(:find)
      @indirection.terminus(:file_server).stubs(:authorized?).returns(true)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'apply'" do
@@@ -43,19 -43,19 +43,19 @@@
      Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever")
      @indirection.terminus(:file_server).expects(:find)
      @indirection.terminus(:file_server).stubs(:authorized?).returns(true)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the file terminus when the 'file' URI scheme is used" do
      uri = "file:///fakemod/my/file"
      @indirection.terminus(:file).expects(:find)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the file terminus when a fully qualified path is provided" do
      uri = "/fakemod/my/file"
      @indirection.terminus(:file).expects(:find)
 -    @test_class.find(uri)
 +    @indirection.find(uri)
    end
  
    it "should use the configuration to test whether the request is allowed" do
@@@ -66,6 -66,6 +66,6 @@@
  
      @indirection.terminus(:file_server).expects(:find)
      mount.expects(:allowed?).returns(true)
 -    @test_class.find(uri, :node => "foo", :ip => "bar")
 +    @indirection.find(uri, :node => "foo", :ip => "bar")
    end
  end
diff --combined spec/spec_helper.rb
index 0c4b076,ed4e826..84ef3f2
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@@ -6,29 -6,31 +6,31 @@@ dir = File.expand_path(File.dirname(__F
  $LOAD_PATH.unshift("#{dir}/")
  $LOAD_PATH.unshift("#{dir}/lib") # a spec-specific test lib dir
  $LOAD_PATH.unshift("#{dir}/../lib")
+ $LOAD_PATH.unshift("#{dir}/../test/lib")
  
  # Don't want puppet getting the command line arguments for rake or autotest
  ARGV.clear
  
  require 'puppet'
  require 'mocha'
- gem 'rspec', '>=1.2.9'
- require 'spec/autorun'
+ gem 'rspec', '>=2.0.0'
  
  # So everyone else doesn't have to include this base constant.
  module PuppetSpec
    FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
  end
  
+ module PuppetTest
+ end
+ 
  require 'lib/puppet_spec/files'
  require 'monkey_patches/alias_should_to_must'
- require 'monkey_patches/add_confine_and_runnable_to_rspec_dsl'
  require 'monkey_patches/publicize_methods'
  
- Spec::Runner.configure do |config|
+ RSpec.configure do |config|
    config.mock_with :mocha
  
-   config.prepend_after :each do
+   config.after :each do
      Puppet.settings.clear
      Puppet::Node::Environment.clear
      Puppet::Util::Storage.clear
@@@ -58,7 -60,7 +60,7 @@@
      Puppet::Util::Log.close_all
    end
  
-   config.prepend_before :each do
+   config.before :each do
      # these globals are set by Application
      $puppet_application_mode = nil
      $puppet_application_name = nil
@@@ -72,7 -74,7 +74,7 @@@
      Puppet.settings[:bindaddress] = "127.0.0.1"
  
      @logs = []
 -    Puppet::Util::Log.newdestination(@logs)
 +    Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
    end
  end
  
diff --combined spec/unit/application/apply_spec.rb
index e2b6ff5,4e17442..8aaa5d8
--- a/spec/unit/application/apply_spec.rb
+++ b/spec/unit/application/apply_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/application/apply'
  require 'puppet/file_bucket/dipper'
@@@ -57,7 -57,6 +57,7 @@@ describe Puppet::Application::Apply d
        Puppet.stubs(:parse_config)
        Puppet::FileBucket::Dipper.stubs(:new)
        STDIN.stubs(:read)
 +      Puppet::Transaction::Report.indirection.stubs(:cache_class=)
  
        @apply.options.stubs(:[]).with(any_parameters)
      end
@@@ -115,11 -114,6 +115,11 @@@
        lambda { @apply.setup }.should raise_error(SystemExit)
      end
  
 +    it "should tell the report handler to cache locally as yaml" do
 +      Puppet::Transaction::Report.indirection.expects(:cache_class=).with(:yaml)
 +
 +      @apply.setup
 +    end
    end
  
    describe "when executing" do
@@@ -149,16 -143,17 +149,16 @@@
  
      describe "the parseonly command" do
        before :each do
 -        Puppet.stubs(:[]).with(:environment)
 +        @environment = Puppet::Node::Environment.new("env")
 +        Puppet.stubs(:[]).with(:environment).returns(@environment)
          Puppet.stubs(:[]).with(:manifest).returns("site.pp")
          Puppet.stubs(:err)
          @apply.stubs(:exit)
          @apply.options.stubs(:[]).with(:code).returns "some code"
 -        @collection = stub_everything
 -        Puppet::Resource::TypeCollection.stubs(:new).returns(@collection)
        end
  
 -      it "should use a Puppet Resource Type Collection to parse the file" do
 -        @collection.expects(:perform_initial_import)
 +      it "should use the environment to parse the file" do
 +        @environment.stubs(:perform_initial_import)
          @apply.parseonly
        end
  
@@@ -168,7 -163,7 +168,7 @@@
        end
  
        it "should exit with exit code 1 if error" do
 -        @collection.stubs(:perform_initial_import).raises(Puppet::ParseError)
 +        @environment.stubs(:perform_initial_import).raises(Puppet::ParseError)
          @apply.expects(:exit).with(1)
          @apply.parseonly
        end
@@@ -185,14 -180,14 +185,14 @@@
          @apply.options.stubs(:[])
  
          @facts = stub_everything 'facts'
 -        Puppet::Node::Facts.stubs(:find).returns(@facts)
 +        Puppet::Node::Facts.indirection.stubs(:find).returns(@facts)
  
          @node = stub_everything 'node'
 -        Puppet::Node.stubs(:find).returns(@node)
 +        Puppet::Node.indirection.stubs(:find).returns(@node)
  
          @catalog = stub_everything 'catalog'
          @catalog.stubs(:to_ral).returns(@catalog)
 -        Puppet::Resource::Catalog.stubs(:find).returns(@catalog)
 +        Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog)
  
          STDIN.stubs(:read)
  
@@@ -248,25 -243,25 +248,25 @@@
        end
  
        it "should collect the node facts" do
 -        Puppet::Node::Facts.expects(:find).returns(@facts)
 +        Puppet::Node::Facts.indirection.expects(:find).returns(@facts)
  
          @apply.main
        end
  
        it "should raise an error if we can't find the node" do
 -        Puppet::Node::Facts.expects(:find).returns(nil)
 +        Puppet::Node::Facts.indirection.expects(:find).returns(nil)
  
          lambda { @apply.main }.should raise_error
        end
  
        it "should look for the node" do
 -        Puppet::Node.expects(:find).returns(@node)
 +        Puppet::Node.indirection.expects(:find).returns(@node)
  
          @apply.main
        end
  
        it "should raise an error if we can't find the node" do
 -        Puppet::Node.expects(:find).returns(nil)
 +        Puppet::Node.indirection.expects(:find).returns(nil)
  
          lambda { @apply.main }.should raise_error
        end
@@@ -292,7 -287,7 +292,7 @@@
        end
  
        it "should compile the catalog" do
 -        Puppet::Resource::Catalog.expects(:find).returns(@catalog)
 +        Puppet::Resource::Catalog.indirection.expects(:find).returns(@catalog)
  
          @apply.main
        end
@@@ -323,15 -318,6 +323,15 @@@
          @apply.main
        end
  
 +      it "should save the last run summary" do
 +        Puppet.stubs(:[]).with(:noop).returns(false)
-         report = stub 'report'
-         Puppet::Configurer.any_instance.stubs(:initialize_report).returns(report)
++        report = Puppet::Transaction::Report.new("apply")
++        Puppet::Transaction::Report.stubs(:new).returns(report)
 +
 +        Puppet::Configurer.any_instance.expects(:save_last_run_summary).with(report)
 +        @apply.main
 +      end
 +
        describe "with detailed_exitcodes" do
          it "should exit with report's computed exit status" do
            Puppet.stubs(:[]).with(:noop).returns(false)
diff --combined spec/unit/application/kick_spec.rb
index 2278741,c18a84d..ce0e0c7
--- a/spec/unit/application/kick_spec.rb
+++ b/spec/unit/application/kick_spec.rb
@@@ -1,12 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/application/kick'
  
- describe Puppet::Application::Kick do
- 
-   confine "Kick's eventloops can only start on POSIX" => Puppet.features.posix?
+ describe Puppet::Application::Kick, :if => Puppet.features.posix? do
  
    before :each do
      require 'puppet/util/ldap/connection'
@@@ -163,7 -161,7 +161,7 @@@
          @kick.options.stubs(:[]).with(:all).returns(true)
          @kick.stubs(:puts)
  
 -        Puppet::Node.expects(:search).with("whatever",:fqdn => :something).returns([])
 +        Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => :something).returns([])
  
          @kick.setup
        end
@@@ -172,7 -170,7 +170,7 @@@
          @kick.options.stubs(:[]).with(:all).returns(true)
          @kick.stubs(:puts)
  
 -        Puppet::Node.expects(:search).with("whatever",:fqdn => nil).returns([])
 +        Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => nil).returns([])
  
          @kick.setup
        end
@@@ -182,7 -180,7 +180,7 @@@
          @kick.stubs(:puts)
          @kick.classes = ['class']
  
 -        Puppet::Node.expects(:search).with("whatever", :class => "class", :fqdn => nil).returns([])
 +        Puppet::Node.indirection.expects(:search).with("whatever", :class => "class", :fqdn => nil).returns([])
  
          @kick.setup
        end
@@@ -279,7 -277,7 +277,7 @@@
          end
  
          it "should call run on a Puppet::Run for the given host" do
 -          @agent_run.expects(:save).with('https://host:8139/production/run/host').returns(@agent_run)
 +          Puppet::Run.indirection.expects(:save).with(@agent_run, 'https://host:8139/production/run/host').returns(@agent_run)
  
            @kick.run_for_host('host')
          end
diff --combined spec/unit/application/master_spec.rb
index cf85931,074249a..1173752
--- a/spec/unit/application/master_spec.rb
+++ b/spec/unit/application/master_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/application/master'
  require 'puppet/daemon'
@@@ -14,13 -14,12 +14,13 @@@ describe Puppet::Application::Master d
      Puppet::Util::Log.stubs(:newdestination)
      Puppet::Util::Log.stubs(:level=)
  
 -    Puppet::Node.stubs(:terminus_class=)
 -    Puppet::Node.stubs(:cache_class=)
 -    Puppet::Node::Facts.stubs(:terminus_class=)
 -    Puppet::Node::Facts.stubs(:cache_class=)
 -    Puppet::Transaction::Report.stubs(:terminus_class=)
 -    Puppet::Resource::Catalog.stubs(:terminus_class=)
 +    Puppet::Node.indirection.stubs(:terminus_class=)
 +    Puppet::Node.indirection.stubs(:cache_class=)
 +    Puppet::Node::Facts.indirection.stubs(:terminus_class=)
 +    Puppet::Node::Facts.indirection.stubs(:cache_class=)
 +    Puppet::Transaction::Report.indirection.stubs(:terminus_class=)
 +    Puppet::Resource::Catalog.indirection.stubs(:terminus_class=)
 +    Puppet::SSL::Host.stubs(:ca_location=)
    end
  
    it "should operate in master run_mode" do
@@@ -184,7 -183,7 +184,7 @@@
      end
  
      it "should cache class in yaml" do
 -      Puppet::Node.expects(:cache_class=).with(:yaml)
 +      Puppet::Node.indirection.expects(:cache_class=).with(:yaml)
  
        @master.setup
      end
@@@ -258,15 -257,16 +258,15 @@@
  
      describe "the parseonly command" do
        before :each do
 -        Puppet.stubs(:[]).with(:environment)
 +        @environment = Puppet::Node::Environment.new("env")
 +        Puppet.stubs(:[]).with(:environment).returns(@environment)
          Puppet.stubs(:[]).with(:manifest).returns("site.pp")
          Puppet.stubs(:err)
          @master.stubs(:exit)
        end
  
        it "should use a Puppet Resource Type Collection to parse the file" do
 -        @collection.expects(:perform_initial_import)
 +        @environment.expects(:perform_initial_import)
          @master.parseonly
        end
  
@@@ -276,7 -276,7 +276,7 @@@
        end
  
        it "should exit with exit code 1 if error" do
 -        @collection.stubs(:perform_initial_import).raises(Puppet::ParseError)
 +        @environment.stubs(:perform_initial_import).raises(Puppet::ParseError)
          @master.expects(:exit).with(1)
          @master.parseonly
        end
@@@ -299,7 -299,7 +299,7 @@@
  
        it "should compile a catalog for the specified node" do
          @master.options[:node] = "foo"
 -        Puppet::Resource::Catalog.expects(:find).with("foo").returns Puppet::Resource::Catalog.new
 +        Puppet::Resource::Catalog.indirection.expects(:find).with("foo").returns Puppet::Resource::Catalog.new
          $stdout.stubs(:puts)
  
          @master.compile
@@@ -307,7 -307,7 +307,7 @@@
  
        it "should convert the catalog to a pure-resource catalog and use 'jj' to pretty-print the catalog" do
          catalog = Puppet::Resource::Catalog.new
 -        Puppet::Resource::Catalog.expects(:find).returns catalog
 +        Puppet::Resource::Catalog.indirection.expects(:find).returns catalog
  
          catalog.expects(:to_resource).returns("rescat")
  
@@@ -319,7 -319,7 +319,7 @@@
  
        it "should exit with error code 30 if no catalog can be found" do
          @master.options[:node] = "foo"
 -        Puppet::Resource::Catalog.expects(:find).returns nil
 +        Puppet::Resource::Catalog.indirection.expects(:find).returns nil
          @master.expects(:exit).with(30)
          $stderr.expects(:puts)
  
@@@ -328,7 -328,7 +328,7 @@@
  
        it "should exit with error code 30 if there's a failure" do
          @master.options[:node] = "foo"
 -        Puppet::Resource::Catalog.expects(:find).raises ArgumentError
 +        Puppet::Resource::Catalog.indirection.expects(:find).raises ArgumentError
          @master.expects(:exit).with(30)
          $stderr.expects(:puts)
  
@@@ -412,9 -412,7 +412,7 @@@
          @master.main
        end
  
-       describe "with --rack" do
-         confine "Rack is not available" => Puppet.features.rack?
- 
+       describe "with --rack", :if => Puppet.features.rack? do
          before do
            require 'puppet/network/http/rack'
            Puppet::Network::HTTP::Rack.stubs(:new).returns(@app)
diff --combined spec/unit/application_spec.rb
index 6f1c03b,f68a7e2..65e4821
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  require 'puppet/application'
  require 'puppet'
@@@ -160,9 -160,7 +160,7 @@@ describe Puppet::Application d
        end
      end
  
-     describe 'on POSIX systems' do
-       confine "HUP works only on POSIX systems" => Puppet.features.posix?
- 
+     describe 'on POSIX systems', :if => Puppet.features.posix? do
        it 'should signal process with HUP after block if restart requested during block execution' do
          Puppet::Application.run_status = nil
          target = mock 'target'
@@@ -224,8 -222,7 +222,7 @@@
        @app.parse_options
      end
  
-     describe "when using --help" do
-       confine "rdoc" => Puppet.features.usage?
+     describe "when using --help", :if => Puppet.features.usage? do
  
        it "should call RDoc::usage and exit" do
          @app.expects(:exit)
diff --combined spec/unit/configurer_spec.rb
index 705417d,cf73a37..6b4998c
--- a/spec/unit/configurer_spec.rb
+++ b/spec/unit/configurer_spec.rb
@@@ -3,12 -3,12 +3,12 @@@
  #  Created by Luke Kanies on 2007-11-12.
  #  Copyright (c) 2007. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  require 'puppet/configurer'
  
  describe Puppet::Configurer do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @agent = Puppet::Configurer.new
    end
  
@@@ -72,24 -72,18 +72,16 @@@
    end
  end
  
- describe Puppet::Configurer, "when initializing a report" do
-   it "should return an instance of a transaction report" do
-     Puppet.settings.stubs(:use).returns(true)
-     @agent = Puppet::Configurer.new
-     @agent.initialize_report.should be_instance_of(Puppet::Transaction::Report)
-   end
- end
- 
  describe Puppet::Configurer, "when executing a catalog run" do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @agent = Puppet::Configurer.new
      @agent.stubs(:prepare)
      @agent.stubs(:facts_for_uploading).returns({})
      @catalog = Puppet::Resource::Catalog.new
      @catalog.stubs(:apply)
      @agent.stubs(:retrieve_catalog).returns @catalog
 -
 -    Puppet::Util::Log.stubs(:newdestination)
 -    Puppet::Util::Log.stubs(:close)
 +    @agent.stubs(:save_last_run_summary)
    end
  
    it "should prepare for the run" do
@@@ -99,33 -93,32 +91,33 @@@
    end
  
    it "should initialize a transaction report if one is not provided" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
 -    Puppet::Transaction::Report.expects(:new).returns report
++    Puppet::Transaction::Report.expects(:new).at_least_once.returns report
  
      @agent.run
    end
  
    it "should pass the new report to the catalog" do
-     report = Puppet::Transaction::Report.new
-     @agent.stubs(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.stubs(:new).returns report
      @catalog.expects(:apply).with{|options| options[:report] == report}
  
      @agent.run
    end
  
    it "should use the provided report if it was passed one" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).never
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).never
      @catalog.expects(:apply).with{|options| options[:report] == report}
  
      @agent.run(:report => report)
    end
  
    it "should set the report as a log destination" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns report
  
 +    @agent.stubs(:send_report)
      Puppet::Util::Log.expects(:newdestination).with(report)
  
      @agent.run
@@@ -175,16 -168,16 +167,16 @@@
    end
  
    it "should send the report" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
      @agent.expects(:send_report).with { |r, trans| r == report }
  
      @agent.run
    end
  
    it "should send the transaction report with a reference to the transaction if a run was actually made" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
  
      trans = stub 'transaction'
      @catalog.expects(:apply).returns trans
@@@ -197,8 -190,8 +189,8 @@@
    it "should send the transaction report even if the catalog could not be retrieved" do
      @agent.expects(:retrieve_catalog).returns nil
  
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
      @agent.expects(:send_report)
  
      @agent.run
@@@ -207,25 -200,25 +199,26 @@@
    it "should send the transaction report even if there is a failure" do
      @agent.expects(:retrieve_catalog).raises "whatever"
  
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
      @agent.expects(:send_report)
  
      lambda { @agent.run }.should raise_error
    end
  
    it "should remove the report as a log destination when the run is finished" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
+ 
 -    Puppet::Util::Log.expects(:close).with(report)
 +    report.expects(:<<).at_least_once
  
      @agent.run
 +    Puppet::Util::Log.destinations.should_not include(report)
    end
  
    it "should return the report as the result of the run" do
-     report = Puppet::Transaction::Report.new
-     @agent.expects(:initialize_report).returns report
+     report = Puppet::Transaction::Report.new("apply")
+     Puppet::Transaction::Report.expects(:new).returns(report)
  
      @agent.run.should equal(report)
    end
@@@ -233,24 -226,15 +226,16 @@@ en
  
  describe Puppet::Configurer, "when sending a report" do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @configurer = Puppet::Configurer.new
 +    @configurer.stubs(:save_last_run_summary)
  
-     @report = Puppet::Transaction::Report.new
+     @report = Puppet::Transaction::Report.new("apply")
      @trans = stub 'transaction'
    end
  
-   it "should require a report" do
-     lambda { @configurer.send_report }.should raise_error(ArgumentError)
-   end
- 
-   it "should allow specification of a transaction" do
-     lambda { @configurer.send_report(@report, @trans)  }.should_not raise_error(ArgumentError)
-   end
- 
-   it "should use any provided transaction to add metrics to the report" do
-     @trans.expects(:generate_report)
+   it "should finalize the report" do
+     @report.expects(:finalize_report)
      @configurer.send_report(@report, @trans)
    end
  
@@@ -260,87 -244,43 +245,87 @@@
      @report.expects(:summary).returns "stuff"
  
      @configurer.expects(:puts).with("stuff")
-     @configurer.send_report(@report)
+     @configurer.send_report(@report, nil)
    end
  
    it "should not print a report summary if not configured to do so" do
      Puppet.settings[:summarize] = false
  
      @configurer.expects(:puts).never
-     @configurer.send_report(@report)
+     @configurer.send_report(@report, nil)
    end
  
    it "should save the report if reporting is enabled" do
      Puppet.settings[:report] = true
  
 -    @report.expects(:save)
 +    Puppet::Transaction::Report.indirection.expects(:save).with(@report)
-     @configurer.send_report(@report)
+     @configurer.send_report(@report, nil)
    end
  
    it "should not save the report if reporting is disabled" do
      Puppet.settings[:report] = false
  
--    @report.expects(:save).never
-     @configurer.send_report(@report)
++    Puppet::Transaction::Report.indirection.expects(:save).never
++    @configurer.send_report(@report, nil)
 +  end
 +
 +  it "should save the last run summary if reporting is enabled" do
 +    Puppet.settings[:report] = true
 +
 +    @configurer.expects(:save_last_run_summary).with(@report)
-     @configurer.send_report(@report)
++    @configurer.send_report(@report, nil)
 +  end
 +
 +  it "should not save the last run summary if reporting is disabled" do
 +    Puppet.settings[:report] = false
 +
 +    @configurer.expects(:save_last_run_summary).never
-     @configurer.send_report(@report)
+     @configurer.send_report(@report, nil)
    end
  
    it "should log but not fail if saving the report fails" do
      Puppet.settings[:report] = true
  
 -    @report.expects(:save).raises "whatever"
 +    Puppet::Transaction::Report.indirection.expects(:save).with(@report).raises "whatever"
  
      Puppet.expects(:err)
-     lambda { @configurer.send_report(@report) }.should_not raise_error
+     lambda { @configurer.send_report(@report, nil) }.should_not raise_error
    end
  end
  
 +describe Puppet::Configurer, "when saving the summary report file" do
 +  before do
-     Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
 +    @configurer = Puppet::Configurer.new
 +
 +    @report = stub 'report'
 +    @trans = stub 'transaction'
 +    @lastrunfd = stub 'lastrunfd'
 +    Puppet::Util::FileLocking.stubs(:writelock).yields(@lastrunfd)
 +  end
 +
 +  it "should write the raw summary to the lastrunfile setting value" do
 +    Puppet::Util::FileLocking.expects(:writelock).with(Puppet[:lastrunfile], 0660)
 +    @configurer.save_last_run_summary(@report)
 +  end
 +
 +  it "should write the raw summary as yaml" do
 +    @report.expects(:raw_summary).returns("summary")
 +    @lastrunfd.expects(:print).with(YAML.dump("summary"))
 +    @configurer.save_last_run_summary(@report)
 +  end
 +
 +  it "should log but not fail if saving the last run summary fails" do
 +    Puppet::Util::FileLocking.expects(:writelock).raises "exception"
 +    Puppet.expects(:err)
 +    lambda { @configurer.save_last_run_summary(@report) }.should_not raise_error
 +  end
 +
 +end
 +
  describe Puppet::Configurer, "when retrieving a catalog" do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @agent = Puppet::Configurer.new
      @agent.stubs(:facts_for_uploading).returns({})
  
@@@ -358,15 -298,15 +343,15 @@@
      end
  
      it "should first look in the cache for a catalog" do
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.never
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.never
  
        @agent.retrieve_catalog.should == @catalog
      end
  
      it "should compile a new catalog if none is found in the cache" do
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
  
        @agent.retrieve_catalog.should == @catalog
      end
@@@ -375,7 -315,7 +360,7 @@@
    describe "when not using a REST terminus for catalogs" do
      it "should not pass any facts when retrieving the catalog" do
        @agent.expects(:facts_for_uploading).never
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options|
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options|
          options[:facts].nil?
        }.returns @catalog
  
@@@ -386,7 -326,7 +371,7 @@@
    describe "when using a REST terminus for catalogs" do
      it "should pass the prepared facts and the facts format as arguments when retrieving the catalog" do
        @agent.expects(:facts_for_uploading).returns(:facts => "myfacts", :facts_format => :foo)
 -      Puppet::Resource::Catalog.expects(:find).with { |name, options|
 +      Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options|
          options[:facts] == "myfacts" and options[:facts_format] == :foo
        }.returns @catalog
  
@@@ -395,7 -335,7 +380,7 @@@
    end
  
    it "should use the Catalog class to get its catalog" do
 -    Puppet::Resource::Catalog.expects(:find).returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).returns @catalog
  
      @agent.retrieve_catalog
    end
@@@ -403,20 -343,20 +388,20 @@@
    it "should use its certname to retrieve the catalog" do
      Facter.stubs(:value).returns "eh"
      Puppet.settings[:certname] = "myhost.domain.com"
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog
  
      @agent.retrieve_catalog
    end
  
    it "should default to returning a catalog retrieved directly from the server, skipping the cache" do
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
  
      @agent.retrieve_catalog.should == @catalog
    end
  
    it "should log and return the cached catalog when no catalog can be retrieved from the server" do
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
  
      Puppet.expects(:notice)
  
@@@ -424,15 -364,15 +409,15 @@@
    end
  
    it "should not look in the cache for a catalog if one is returned from the server" do
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never
  
      @agent.retrieve_catalog.should == @catalog
    end
  
    it "should return the cached catalog when retrieving the remote catalog throws an exception" do
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh"
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh"
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
  
      @agent.retrieve_catalog.should == @catalog
    end
@@@ -440,7 -380,7 +425,7 @@@
    it "should log and return nil if no catalog can be retrieved from the server and :usecacheonfailure is disabled" do
      Puppet.stubs(:[])
      Puppet.expects(:[]).with(:usecacheonfailure).returns false
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
  
      Puppet.expects(:warning)
  
@@@ -448,21 -388,21 +433,21 @@@
    end
  
    it "should return nil if no cached catalog is available and no catalog can be retrieved from the server" do
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
 -    Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
 +    Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
  
      @agent.retrieve_catalog.should be_nil
    end
  
    it "should convert the catalog before returning" do
 -    Puppet::Resource::Catalog.stubs(:find).returns @catalog
 +    Puppet::Resource::Catalog.indirection.stubs(:find).returns @catalog
  
      @agent.expects(:convert_catalog).with { |cat, dur| cat == @catalog }.returns "converted catalog"
      @agent.retrieve_catalog.should == "converted catalog"
    end
  
    it "should return nil if there is an error while retrieving the catalog" do
 -    Puppet::Resource::Catalog.expects(:find).at_least_once.raises "eh"
 +    Puppet::Resource::Catalog.indirection.expects(:find).at_least_once.raises "eh"
  
      @agent.retrieve_catalog.should be_nil
    end
@@@ -470,7 -410,7 +455,7 @@@ en
  
  describe Puppet::Configurer, "when converting the catalog" do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @agent = Puppet::Configurer.new
  
      @catalog = Puppet::Resource::Catalog.new
@@@ -504,7 -444,7 +489,7 @@@ en
  
  describe Puppet::Configurer, "when preparing for a run" do
    before do
--    Puppet.settings.stubs(:use).returns(true)
++    Puppet::Util::Settings.any_instance.stubs(:use).returns(true)
      @agent = Puppet::Configurer.new
      @agent.stubs(:dostorage)
      @agent.stubs(:download_fact_plugins)
diff --combined spec/unit/file_serving/metadata_spec.rb
index 58db3a4,dd40324..34794cc
--- a/spec/unit/file_serving/metadata_spec.rb
+++ b/spec/unit/file_serving/metadata_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/file_serving/metadata'
  
@@@ -230,8 -230,8 +230,8 @@@ describe Puppet::FileServing::Metadata
        @metadata.destination.should == "/path/to/link"
      end
  
-     it "should produce tab-separated mode, type, owner, group, and destination for xmlrpc" do
-       pending "We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow."
+     pending "should produce tab-separated mode, type, owner, group, and destination for xmlrpc" do
+       # "We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow."
        @metadata.attributes_with_tabs.should == "#{0755}\tlink\t10\t20\t/path/to/link"
      end
  
@@@ -255,8 -255,8 +255,8 @@@ describe Puppet::FileServing::Metadata
        @file.collect
        @file.destination.should == "/some/other/path"
      end
-     it "should not collect the checksum if links are :manage" do
-       pending "We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow."
+     pending "should not collect the checksum if links are :manage" do
+       # We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow.
        @file.collect
        @file.checksum.should be_nil
      end
diff --combined spec/unit/indirector/catalog/active_record_spec.rb
index 27310e4,a368fb3..da1d775
--- a/spec/unit/indirector/catalog/active_record_spec.rb
+++ b/spec/unit/indirector/catalog/active_record_spec.rb
@@@ -1,11 -1,9 +1,9 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  
- describe "Puppet::Resource::Catalog::ActiveRecord" do
-   confine "Missing Rails" => Puppet.features.rails?
- 
+ describe "Puppet::Resource::Catalog::ActiveRecord", :if => Puppet.features.rails? do
    require 'puppet/rails'
  
    before :all do
diff --combined spec/unit/indirector/facts/active_record_spec.rb
index 6e425e9,e96e010..71e19e3
--- a/spec/unit/indirector/facts/active_record_spec.rb
+++ b/spec/unit/indirector/facts/active_record_spec.rb
@@@ -1,13 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppet/rails'
  require 'puppet/node/facts'
  
- describe "Puppet::Node::Facts::ActiveRecord" do
-   confine "Missing Rails" => Puppet.features.rails?
- 
+ describe "Puppet::Node::Facts::ActiveRecord", :if => Puppet.features.rails? do
    before do
      require 'puppet/indirector/facts/active_record'
      Puppet.features.stubs(:rails?).returns true
diff --combined spec/unit/indirector/facts/couch_spec.rb
index 82a8287,e3a9d7f..1f86b56
--- a/spec/unit/indirector/facts/couch_spec.rb
+++ b/spec/unit/indirector/facts/couch_spec.rb
@@@ -1,11 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppet/node/facts'
  
- describe "Puppet::Node::Facts::Couch" do
-   confine "couchrest gem is missing; cannot test couch terminus" => Puppet.features.couchdb?
+ describe "Puppet::Node::Facts::Couch", :if => Puppet.features.couchdb? do
    require 'puppet/indirector/facts/couch' if Puppet.features.couchdb?
  
    before do
diff --combined spec/unit/indirector/indirection_spec.rb
index 77e55ac,1e774fb..3f6e71f
--- a/spec/unit/indirector/indirection_spec.rb
+++ b/spec/unit/indirector/indirection_spec.rb
@@@ -1,10 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/indirector/indirection'
  
- describe "Indirection Delegator", :shared => true do
+ shared_examples_for "Indirection Delegator" do
    it "should create a request object with the appropriate method name and all of the passed arguments" do
      request = Puppet::Indirector::Request.new(:indirection, :find, "me")
  
@@@ -64,7 -64,7 +64,7 @@@
    end
  end
  
- describe "Delegation Authorizer", :shared => true do
+ shared_examples_for "Delegation Authorizer" do
    before do
      # So the :respond_to? turns out correctly.
      class << @terminus
@@@ -386,6 -386,9 +386,6 @@@ describe Puppet::Indirector::Indirectio
      describe "and storing a model instance" do
        before { @method = :save }
  
 -      it_should_behave_like "Indirection Delegator"
 -      it_should_behave_like "Delegation Authorizer"
 -
        it "should return the result of the save" do
          @terminus.stubs(:save).returns "foo"
          @indirection.save(@instance).should == "foo"
diff --combined spec/unit/indirector/ldap_spec.rb
index bafaa20,c071f87..2178a87
--- a/spec/unit/indirector/ldap_spec.rb
+++ b/spec/unit/indirector/ldap_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/indirector/ldap'
  
@@@ -110,9 -110,7 +110,7 @@@ describe Puppet::Indirector::Ldap d
      end
    end
  
-   describe "when connecting to ldap" do
-     confine "LDAP is not available" => Puppet.features.ldap?
- 
+   describe "when connecting to ldap", :if => Puppet.features.ldap? do
      it "should create and start a Util::Ldap::Connection instance" do
        conn = mock 'connection', :connection => "myconn", :start => nil
        Puppet::Util::Ldap::Connection.expects(:instance).returns conn
@@@ -135,9 -133,7 +133,7 @@@
      end
    end
  
-   describe "when reconnecting to ldap" do
-     confine "Not running on culain as root" => (Puppet.features.root? and Facter.value("hostname") == "culain")
- 
+   describe "when reconnecting to ldap", :if => (Puppet.features.root? and Facter.value("hostname") == "culain") do
      it "should reconnect to ldap when connections are lost"
    end
  end
diff --combined spec/unit/indirector/node/active_record_spec.rb
index 6c272a9,69229e1..65b0e1f
--- a/spec/unit/indirector/node/active_record_spec.rb
+++ b/spec/unit/indirector/node/active_record_spec.rb
@@@ -1,14 -1,12 +1,12 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppet/node'
  
- describe "Puppet::Node::ActiveRecord" do
+ describe "Puppet::Node::ActiveRecord", :if => Puppet.features.rails? && Puppet.features.sqlite? do
    include PuppetSpec::Files
  
-   confine "Missing Rails" => Puppet.features.rails?
-   confine "Missing sqlite" => Puppet.features.sqlite?
    before do
      require 'puppet/indirector/node/active_record'
    end
diff --combined spec/unit/indirector/queue_spec.rb
index 803ad57,00463ee..7732e41
--- a/spec/unit/indirector/queue_spec.rb
+++ b/spec/unit/indirector/queue_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  require 'puppet/indirector/queue'
  
  class Puppet::Indirector::Queue::TestClient
@@@ -26,9 -26,7 +26,7 @@@ class FooExampleDat
    end
  end
  
- describe Puppet::Indirector::Queue do
-   confine "PSON library is missing; cannot test queueing" => Puppet.features.pson?
- 
+ describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do
    before :each do
      @model = mock 'model'
      @indirection = stub 'indirection', :name => :my_queue, :register_terminus_type => nil, :model => @model
diff --combined spec/unit/indirector/rest_spec.rb
index 7298e01,5f0fe36..03bb2bb
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@@ -1,9 -1,9 +1,9 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  require 'puppet/indirector/rest'
  
- describe "a REST http call", :shared => true do
+ shared_examples_for "a REST http call" do
    it "should accept a path" do
      lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError)
    end
diff --combined spec/unit/module_spec.rb
index ad72d88,37dad7e..8f1c794
--- a/spec/unit/module_spec.rb
+++ b/spec/unit/module_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  describe Puppet::Module do
    before do
@@@ -504,9 -504,7 +504,7 @@@ describe Puppet::Module d
      Puppet::Module.new("yay")
    end
  
-   describe "when loading the medatada file" do
-     confine "Cannot test module metadata without json" => Puppet.features.json?
- 
+   describe "when loading the medatada file", :if => Puppet.features.json? do
      before do
        @data = {
          :license => "GPL2",
diff --combined spec/unit/network/formats_spec.rb
index 26d6418,2c58a05..30e88c5
--- a/spec/unit/network/formats_spec.rb
+++ b/spec/unit/network/formats_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/network/formats'
  
@@@ -69,9 -69,8 +69,8 @@@ describe "Puppet Network Format" d
      end
    end
  
-   describe "base64 compressed yaml" do
+   describe "base64 compressed yaml", :if => Puppet.features.zlib? do
      yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml)
-     confine "We must have zlib" => Puppet.features.zlib?
  
      before do
        @yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml)
@@@ -265,9 -264,7 +264,7 @@@
      Puppet::Network::FormatHandler.format(:pson).should_not be_nil
    end
  
-   describe "pson" do
-     confine "Missing 'pson' library" => Puppet.features.pson?
- 
+   describe "pson", :if => Puppet.features.pson? do
      before do
        @pson = Puppet::Network::FormatHandler.format(:pson)
      end
diff --combined spec/unit/network/http/compression_spec.rb
index 96d2eaf,c5bbbb0..d44c5f1
--- a/spec/unit/network/http/compression_spec.rb
+++ b/spec/unit/network/http/compression_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  describe "http compression" do
  
@@@ -37,9 -37,7 +37,7 @@@
      end
    end
  
-   describe "when zlib is available" do
-     confine "Zlib is missing" => Puppet.features.zlib?
- 
+   describe "when zlib is available", :if => Puppet.features.zlib? do
      before(:each) do
        Puppet.features.stubs(:zlib?).returns true
  
diff --combined spec/unit/network/http/mongrel/rest_spec.rb
index 42ba2d6,fb24521..086fec5
--- a/spec/unit/network/http/mongrel/rest_spec.rb
+++ b/spec/unit/network/http/mongrel/rest_spec.rb
@@@ -1,11 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../../spec_helper')
  
  require 'puppet/network/http'
  
- describe "Puppet::Network::HTTP::MongrelREST" do
-   confine "Mongrel is not available" => Puppet.features.mongrel?
+ describe "Puppet::Network::HTTP::MongrelREST", :if => Puppet.features.mongrel? do
    before do
      require 'puppet/network/http/mongrel/rest'
    end
diff --combined spec/unit/network/http/mongrel_spec.rb
index 573c758,1e24be0..5a67a3f
--- a/spec/unit/network/http/mongrel_spec.rb
+++ b/spec/unit/network/http/mongrel_spec.rb
@@@ -3,12 -3,10 +3,10 @@@
  #  Created by Rick Bradley on 2007-10-15.
  #  Copyright (c) 2007. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  require 'puppet/network/http'
  
- describe "Puppet::Network::HTTP::Mongrel", "after initializing" do
-   confine "Mongrel is not available" => Puppet.features.mongrel?
- 
+ describe "Puppet::Network::HTTP::Mongrel", "after initializing", :if => Puppet.features.mongrel? do
    it "should not be listening" do
      require 'puppet/network/http/mongrel'
  
@@@ -16,9 -14,7 +14,7 @@@
    end
  end
  
- describe "Puppet::Network::HTTP::Mongrel", "when turning on listening" do
-   confine "Mongrel is not available" => Puppet.features.mongrel?
- 
+ describe "Puppet::Network::HTTP::Mongrel", "when turning on listening", :if => Puppet.features.mongrel? do
    before do
      require 'puppet/network/http/mongrel'
  
@@@ -100,9 -96,7 +96,7 @@@
    end
  end
  
- describe "Puppet::Network::HTTP::Mongrel", "when turning off listening" do
-   confine "Mongrel is not available" => Puppet.features.mongrel?
- 
+ describe "Puppet::Network::HTTP::Mongrel", "when turning off listening", :if => Puppet.features.mongrel? do
    before do
      @mock_mongrel = mock('mongrel httpserver')
      @mock_mongrel.stubs(:run)
diff --combined spec/unit/network/http/rack/rest_spec.rb
index 31cba59,3eed4a2..dd49fa0
--- a/spec/unit/network/http/rack/rest_spec.rb
+++ b/spec/unit/network/http/rack/rest_spec.rb
@@@ -1,12 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../../spec_helper')
  require 'puppet/network/http/rack' if Puppet.features.rack?
  require 'puppet/network/http/rack/rest'
  
- describe "Puppet::Network::HTTP::RackREST" do
-   confine "Rack is not available" => Puppet.features.rack?
- 
+ describe "Puppet::Network::HTTP::RackREST", :if => Puppet.features.rack? do
    it "should include the Puppet::Network::HTTP::Handler module" do
      Puppet::Network::HTTP::RackREST.ancestors.should be_include(Puppet::Network::HTTP::Handler)
    end
diff --combined spec/unit/network/http/rack/xmlrpc_spec.rb
index cc398bf,e641152..e8ae47b
--- a/spec/unit/network/http/rack/xmlrpc_spec.rb
+++ b/spec/unit/network/http/rack/xmlrpc_spec.rb
@@@ -1,13 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../../spec_helper')
  require 'puppet/network/handler'
  require 'puppet/network/http/rack' if Puppet.features.rack?
  require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack?
  
- describe "Puppet::Network::HTTP::RackXMLRPC" do
-   confine "Rack is not available" => Puppet.features.rack?
- 
+ describe "Puppet::Network::HTTP::RackXMLRPC", :if => Puppet.features.rack? do
    describe "when initializing" do
      it "should create an Puppet::Network::XMLRPCServer" do
        Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything
diff --combined spec/unit/network/http/rack_spec.rb
index 66a845a,434294c..75d3fdb
--- a/spec/unit/network/http/rack_spec.rb
+++ b/spec/unit/network/http/rack_spec.rb
@@@ -1,12 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  require 'puppet/network/handler'
  require 'puppet/network/http/rack' if Puppet.features.rack?
  
- describe "Puppet::Network::HTTP::Rack" do
-   confine "Rack is not available" => Puppet.features.rack?
- 
+ describe "Puppet::Network::HTTP::Rack", :if => Puppet.features.rack? do
    describe "while initializing" do
  
      it "should require a protocol specification" do
diff --combined spec/unit/parameter_spec.rb
index 8359570,f8ab05d..c9ef32f
--- a/spec/unit/parameter_spec.rb
+++ b/spec/unit/parameter_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  require 'puppet/parameter'
  
@@@ -52,8 -52,7 +52,7 @@@ describe Puppet::Parameter d
      @resource.expects(:line).returns 10
      @resource.expects(:file).returns "file"
      @resource.expects(:tags).returns %w{one two}
-     @resource.expects(:version).returns 50
-     @parameter.source_descriptors.should == {:tags=>["one", "two", "foo"], :path=>"//foo", :version=>50, :file => "file", :line => 10}
+     @parameter.source_descriptors.should == {:tags=>["one", "two", "foo"], :path=>"//foo", :file => "file", :line => 10}
    end
  
    describe "when returning the value" do
diff --combined spec/unit/parser/collector_spec.rb
index ff81795,4cab26c..100a04d
--- a/spec/unit/parser/collector_spec.rb
+++ b/spec/unit/parser/collector_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/rails'
  require 'puppet/parser/collector'
@@@ -263,9 -263,7 +263,7 @@@ describe Puppet::Parser::Collector, "wh
    end
  end
  
- describe Puppet::Parser::Collector, "when collecting exported resources" do
-   confine "Cannot test Rails integration without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Parser::Collector, "when collecting exported resources", :if => Puppet.features.rails? do
    before do
      @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode"))
      @scope = Puppet::Parser::Scope.new :compiler => @compiler
@@@ -469,9 -467,7 +467,7 @@@
    end
  end
  
- describe Puppet::Parser::Collector, "when building its ActiveRecord query for collecting exported resources" do
-   confine "Cannot test Rails integration without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Parser::Collector, "when building its ActiveRecord query for collecting exported resources", :if => Puppet.features.rails? do
    before do
      @scope = stub 'scope', :host => "myhost", :debug => nil
      @compiler = mock 'compile'
diff --combined spec/unit/parser/lexer_spec.rb
index 67d7582,8603269..58978ff
--- a/spec/unit/parser/lexer_spec.rb
+++ b/spec/unit/parser/lexer_spec.rb
@@@ -1,11 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/parser/lexer'
  
  # This is a special matcher to match easily lexer output
- Spec::Matchers.define :be_like do |*expected|
+ RSpec::Matchers.define :be_like do |*expected|
    match do |actual|
      expected.zip(actual).all? { |e,a| !e or a[0] == e or (e.is_a? Array and a[0] == e[0] and (a[1] == e[1] or (a[1].is_a?(Hash) and a[1][:value] == e[1]))) }
    end
@@@ -651,7 -651,8 +651,8 @@@ describe "Puppet::Parser::Lexer in the 
    end
  end
  
- require 'puppettest/support/utils'
+ require File.dirname(__FILE__) + '/../../../test/lib/puppettest'
+ require File.dirname(__FILE__) + '/../../../test/lib/puppettest/support/utils'
  describe "Puppet::Parser::Lexer in the old tests when lexing example files" do
    extend PuppetTest::Support::Utils
    textfiles do |file|
diff --combined spec/unit/provider/mount/parsed_spec.rb
index a9d00e9,5a1c986..fc4df97
--- a/spec/unit/provider/mount/parsed_spec.rb
+++ b/spec/unit/provider/mount/parsed_spec.rb
@@@ -3,7 -3,7 +3,7 @@@
  #  Created by Luke Kanies on 2007-9-12.
  #  Copyright (c) 2006. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppettest/support/utils'
  require 'puppettest/fileparsing'
@@@ -157,8 -157,7 +157,7 @@@ describe provider_class d
      end
    end
  
-   describe provider_class, " when parsing information about the root filesystem" do
-     confine "Mount type not tested on Darwin" => Facter["operatingsystem"].value != "Darwin"
+   describe provider_class, " when parsing information about the root filesystem", :if => Facter["operatingsystem"].value != "Darwin" do
      include ParsedMountTesting
  
      before do
diff --combined spec/unit/rails/host_spec.rb
index 9883a7d,4244f11..e83135c
--- a/spec/unit/rails/host_spec.rb
+++ b/spec/unit/rails/host_spec.rb
@@@ -1,10 -1,8 +1,8 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
- describe "Puppet::Rails::Host" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe "Puppet::Rails::Host", :if => Puppet.features.rails? do
    def column(name, type)
      ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false)
    end
diff --combined spec/unit/rails/param_value_spec.rb
index f36f242,f67022a..9a725cf
--- a/spec/unit/rails/param_value_spec.rb
+++ b/spec/unit/rails/param_value_spec.rb
@@@ -1,11 -1,9 +1,9 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  require 'puppet/rails'
  
- describe "Puppet::Rails::ParamValue" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe "Puppet::Rails::ParamValue", :if => Puppet.features.rails? do
    def column(name, type)
      ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false)
    end
diff --combined spec/unit/rails/resource_spec.rb
index 277996b,e5bd8a6..3fbbbc7
--- a/spec/unit/rails/resource_spec.rb
+++ b/spec/unit/rails/resource_spec.rb
@@@ -1,11 -1,9 +1,9 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  require 'puppet/rails'
  
- describe "Puppet::Rails::Resource" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe "Puppet::Rails::Resource", :if => Puppet.features.rails? do
    def column(name, type)
      ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false)
    end
diff --combined spec/unit/rails_spec.rb
index 71ede5a,02b54ef..a08485e
--- a/spec/unit/rails_spec.rb
+++ b/spec/unit/rails_spec.rb
@@@ -1,11 -1,9 +1,9 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  require 'puppet/rails'
  
- describe Puppet::Rails, "when initializing any connection" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Rails, "when initializing any connection", :if => Puppet.features.rails? do
    before do
      Puppet.settings.stubs(:use)
      @logger = mock 'logger'
@@@ -77,9 -75,7 +75,7 @@@
    end
  end
  
- describe Puppet::Rails, "when initializing a sqlite3 connection" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Rails, "when initializing a sqlite3 connection", :if => Puppet.features.rails? do
    it "should provide the adapter, log_level, and database arguments" do
      Puppet.settings.expects(:value).with(:dbadapter).returns("sqlite3")
      Puppet.settings.expects(:value).with(:rails_loglevel).returns("testlevel")
@@@ -93,9 -89,7 +89,7 @@@
    end
  end
  
- describe Puppet::Rails, "when initializing a mysql connection" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Rails, "when initializing a mysql connection", :if => Puppet.features.rails? do
    it "should provide the adapter, log_level, and host, port, username, password, database, and reconnect arguments" do
      Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
@@@ -190,9 -184,7 +184,7 @@@
    end
  end
  
- describe Puppet::Rails, "when initializing a postgresql connection" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Rails, "when initializing a postgresql connection", :if => Puppet.features.rails? do
    it "should provide the adapter, log_level, and host, port, username, password, connections, and database arguments" do
      Puppet.settings.stubs(:value).with(:dbadapter).returns("postgresql")
      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
@@@ -263,9 -255,7 +255,7 @@@
    end
  end
  
- describe Puppet::Rails, "when initializing an Oracle connection" do
-   confine "Cannot test without ActiveRecord" => Puppet.features.rails?
- 
+ describe Puppet::Rails, "when initializing an Oracle connection", :if => Puppet.features.rails? do
    it "should provide the adapter, log_level, and username, password, and database arguments" do
      Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced")
      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
diff --combined spec/unit/relationship_spec.rb
index a72966a,9ce6c56..362d74c
--- a/spec/unit/relationship_spec.rb
+++ b/spec/unit/relationship_spec.rb
@@@ -3,7 -3,7 +3,7 @@@
  #  Created by Luke Kanies on 2007-11-1.
  #  Copyright (c) 2006. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  require 'puppet/relationship'
  
  describe Puppet::Relationship do
@@@ -155,9 -155,7 +155,7 @@@ describe Puppet::Relationship, " when m
    end
  end
  
- describe Puppet::Relationship, "when converting to pson" do
-   confine "Missing 'pson' library" => Puppet.features.pson?
- 
+ describe Puppet::Relationship, "when converting to pson", :if => Puppet.features.pson? do
    before do
      @edge = Puppet::Relationship.new(:a, :b, :event => :random, :callback => :whatever)
    end
@@@ -190,9 -188,7 +188,7 @@@
    end
  end
  
- describe Puppet::Relationship, "when converting from pson" do
-   confine "Missing 'pson' library" => Puppet.features.pson?
- 
+ describe Puppet::Relationship, "when converting from pson", :if => Puppet.features.pson? do
    before do
      @event = "random"
      @callback = "whatever"
diff --combined spec/unit/resource/catalog_spec.rb
index 1af48a5,9427214..42850c2
--- a/spec/unit/resource/catalog_spec.rb
+++ b/spec/unit/resource/catalog_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  describe Puppet::Resource::Catalog, "when compiling" do
  
@@@ -374,7 -374,7 +374,7 @@@
        @original.add_edge(@r1, at r2)
        @original.filter do |r|
          r == @r1
 -      end.edge(@r1, at r2).should be_empty
 +      end.edge?(@r1, at r2).should_not be
      end
    end
  
@@@ -818,6 -818,12 +818,6 @@@
        Puppet::Util::Cacher.expire
      end
  
 -    it "should redirect to the indirection for retrieval" do
 -      Puppet::Resource::Catalog.stubs(:indirection).returns(@indirection)
 -      @indirection.expects(:find)
 -      Puppet::Resource::Catalog.find(:myconfig)
 -    end
 -
      it "should use the value of the 'catalog_terminus' setting to determine its terminus class" do
        # Puppet only checks the terminus setting the first time you ask
        # so this returns the object to the clean state
@@@ -874,9 -880,7 +874,7 @@@
    end
  end
  
- describe Puppet::Resource::Catalog, "when converting to pson" do
-   confine "Missing 'pson' library" => Puppet.features.pson?
- 
+ describe Puppet::Resource::Catalog, "when converting to pson", :if => Puppet.features.pson? do
    before do
      @catalog = Puppet::Resource::Catalog.new("myhost")
    end
@@@ -927,16 -931,14 +925,14 @@@
      @catalog.add_edge(one, two)
      @catalog.add_edge(two, three)
  
 -    @catalog.edge(one, two  ).expects(:to_pson_data_hash).returns "one_two_pson"
 -    @catalog.edge(two, three).expects(:to_pson_data_hash).returns "two_three_pson"
 +    @catalog.edges_between(one, two  )[0].expects(:to_pson_data_hash).returns "one_two_pson"
 +    @catalog.edges_between(two, three)[0].expects(:to_pson_data_hash).returns "two_three_pson"
  
      PSON.parse(@catalog.to_pson,:create_additions => false)['data']['edges'].sort.should == %w{one_two_pson two_three_pson}.sort
    end
  end
  
- describe Puppet::Resource::Catalog, "when converting from pson" do
-   confine "Missing 'pson' library" => Puppet.features.pson?
- 
+ describe Puppet::Resource::Catalog, "when converting from pson", :if => Puppet.features.pson? do
    def pson_result_should
      Puppet::Resource::Catalog.expects(:new).with { |hash| yield hash }
    end
diff --combined spec/unit/resource/status_spec.rb
index ce83e5d,4e76fa4..343b8d3
--- a/spec/unit/resource/status_spec.rb
+++ b/spec/unit/resource/status_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/resource/status'
  
@@@ -10,7 -10,12 +10,12 @@@ describe Puppet::Resource::Status d
      @status = Puppet::Resource::Status.new(@resource)
    end
  
-   [:node, :version, :file, :line, :current_values, :skipped_reason, :status, :evaluation_time, :change_count].each do |attr|
+   it "should compute type and title correctly" do
+     @status.resource_type.should == "File"
+     @status.title.should == "/my/file"
+   end
+ 
+   [:node, :file, :line, :current_values, :status, :evaluation_time].each do |attr|
      it "should support #{attr}" do
        @status.send(attr.to_s + "=", "foo")
        @status.send(attr).should == "foo"
@@@ -38,7 -43,7 +43,7 @@@
      Puppet::Resource::Status.new(@resource).source_description.should == "/my/path"
    end
  
-   [:file, :line, :version].each do |attr|
+   [:file, :line].each do |attr|
      it "should copy the resource's #{attr}" do
        @resource.expects(attr).returns "foo"
        Puppet::Resource::Status.new(@resource).send(attr).should == "foo"
@@@ -74,7 -79,7 +79,7 @@@
        @status.send_log :notice, "my message"
      end
  
-     [:file, :line, :version].each do |attr|
+     [:file, :line].each do |attr|
        it "should pass the #{attr}" do
          Puppet::Util::Log.expects(:new).with { |args| args[attr] == "my val" }
          @status.send(attr.to_s + "=", "my val")
@@@ -100,4 -105,49 +105,49 @@@
      (@status << event).should equal(@status)
      @status.events.should == [event]
    end
+ 
+   it "should count the number of successful events and set changed" do
+     3.times{ @status << Puppet::Transaction::Event.new(:status => 'success') }
+     @status.change_count.should == 3
+ 
+     @status.changed.should == true
+     @status.out_of_sync.should == true
+   end
+ 
+   it "should not start with any changes" do
+     @status.change_count.should == 0
+ 
+     @status.changed.should == false
+     @status.out_of_sync.should == false
+   end
+ 
+   it "should not treat failure, audit, or noop events as changed" do
+     ['failure', 'audit', 'noop'].each do |s| @status << Puppet::Transaction::Event.new(:status => s) end
+     @status.change_count.should == 0
+     @status.changed.should == false
+   end
+ 
+   it "should not treat audit events as out of sync" do
+     @status << Puppet::Transaction::Event.new(:status => 'audit')
+     @status.out_of_sync_count.should == 0
+     @status.out_of_sync.should == false
+   end
+ 
+   ['failure', 'noop', 'success'].each do |event_status|
+     it "should treat #{event_status} events as out of sync" do
+       3.times do @status << Puppet::Transaction::Event.new(:status => event_status) end
+       @status.out_of_sync_count.should == 3
+       @status.out_of_sync.should == true
+     end
+   end
+ 
+   describe "When converting to YAML" do
+     it "should include only documented attributes" do
+       @status.file = "/foo.rb"
+       @status.line = 27
+       @status.evaluation_time = 2.7
+       @status.tags = %w{one two}
+       @status.to_yaml_properties.should == Puppet::Resource::Status::YAML_ATTRIBUTES.sort
+     end
+   end
  end
diff --combined spec/unit/resource_spec.rb
index 8be3ec9,877b6b6..32b03ad
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  require 'puppet/resource'
  
  describe Puppet::Resource do
@@@ -585,9 -585,7 +585,7 @@@
      end
    end
  
-   describe "when converting to pson" do
-     confine "Missing 'pson' library" => Puppet.features.pson?
- 
+   describe "when converting to pson", :if => Puppet.features.pson? do
      def pson_output_should
        @resource.class.expects(:pson_create).with { |hash| yield hash }
      end
@@@ -666,9 -664,7 +664,7 @@@
      end
    end
  
-   describe "when converting from pson" do
-     confine "Missing 'pson' library" => Puppet.features.pson?
- 
+   describe "when converting from pson", :if => Puppet.features.pson? do
      def pson_result_should
        Puppet::Resource.expects(:new).with { |hash| yield hash }
      end
diff --combined spec/unit/ssl/certificate_authority/interface_spec.rb
index 7eeb2c0,5cf4073..2e4a3fc
--- a/spec/unit/ssl/certificate_authority/interface_spec.rb
+++ b/spec/unit/ssl/certificate_authority/interface_spec.rb
@@@ -1,10 -1,10 +1,10 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppet/ssl/certificate_authority'
  
- describe "a normal interface method", :shared => true do
+ shared_examples_for "a normal interface method" do
    it "should call the method on the CA for each host specified if an array was provided" do
      @ca.expects(@method).with("host1")
      @ca.expects(@method).with("host2")
diff --combined spec/unit/transaction/event_spec.rb
index 9128e85,6ed1472..c77716c
--- a/spec/unit/transaction/event_spec.rb
+++ b/spec/unit/transaction/event_spec.rb
@@@ -1,11 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/transaction/event'
  
  describe Puppet::Transaction::Event do
-   [:previous_value, :desired_value, :property, :resource, :name, :message, :node, :version, :file, :line, :tags].each do |attr|
+   [:previous_value, :desired_value, :property, :resource, :name, :message, :file, :line, :tags, :audited].each do |attr|
      it "should support #{attr}" do
        event = Puppet::Transaction::Event.new
        event.send(attr.to_s + "=", "foo")
@@@ -46,6 -46,12 +46,12 @@@
      Puppet::Transaction::Event.new.time.should be_instance_of(Time)
    end
  
+   describe "audit property" do
+     it "should default to false" do
+       Puppet::Transaction::Event.new.audited.should == false
+     end
+   end
+ 
    describe "when sending logs" do
      before do
        Puppet::Util::Log.stubs(:new)
@@@ -83,7 -89,7 +89,7 @@@
        Puppet::Transaction::Event.new(:tags => %w{one two}).send_log
      end
  
-     [:file, :line, :version].each do |attr|
+     [:file, :line].each do |attr|
        it "should pass the #{attr}" do
          Puppet::Util::Log.expects(:new).with { |args| args[attr] == "my val" }
          Puppet::Transaction::Event.new(attr => "my val").send_log
@@@ -105,4 -111,17 +111,17 @@@
        Puppet::Transaction::Event.new(:resource => "Foo[bar]").send_log
      end
    end
+ 
+   describe "When converting to YAML" do
+     it "should include only documented attributes" do
+       resource = Puppet::Type.type(:file).new(:title => "/tmp/foo")
+       event = Puppet::Transaction::Event.new(:source_description => "/my/param", :resource => resource,
+                                              :file => "/foo.rb", :line => 27, :tags => %w{one two},
+                                              :desired_value => 7, :historical_value => 'Brazil',
+                                              :message => "Help I'm trapped in a spec test",
+                                              :name => :mode_changed, :previous_value => 6, :property => :mode,
+                                              :status => 'success')
+       event.to_yaml_properties.should == Puppet::Transaction::Event::YAML_ATTRIBUTES.sort
+     end
+   end
  end
diff --combined spec/unit/transaction/report_spec.rb
index 860cd99,766d4f1..a3bfe1e
--- a/spec/unit/transaction/report_spec.rb
+++ b/spec/unit/transaction/report_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/transaction/report'
  
@@@ -11,30 -11,36 +11,36 @@@ describe Puppet::Transaction::Report d
  
    it "should set its host name to the certname" do
      Puppet.settings.expects(:value).with(:certname).returns "myhost"
-     Puppet::Transaction::Report.new.host.should == "myhost"
+     Puppet::Transaction::Report.new("apply").host.should == "myhost"
    end
  
    it "should return its host name as its name" do
-     r = Puppet::Transaction::Report.new
+     r = Puppet::Transaction::Report.new("apply")
      r.name.should == r.host
    end
  
    it "should create an initialization timestamp" do
      Time.expects(:now).returns "mytime"
-     Puppet::Transaction::Report.new.time.should == "mytime"
-   end
- 
-   it "should have a default 'kind' of 'apply'" do
-     Puppet::Transaction::Report.new.kind.should == "apply"
+     Puppet::Transaction::Report.new("apply").time.should == "mytime"
    end
  
    it "should take a 'kind' as an argument" do
      Puppet::Transaction::Report.new("inspect").kind.should == "inspect"
    end
  
+   it "should take a 'configuration_version' as an argument" do
+     Puppet::Transaction::Report.new("inspect", "some configuration version").configuration_version.should == "some configuration version"
+   end
+ 
+   it "should be able to set configuration_version" do
+     report = Puppet::Transaction::Report.new("inspect")
+     report.configuration_version = "some version"
+     report.configuration_version.should == "some version"
+   end
+ 
    describe "when accepting logs" do
      before do
-       @report = Puppet::Transaction::Report.new
+       @report = Puppet::Transaction::Report.new("apply")
      end
  
      it "should add new logs to the log list" do
@@@ -50,7 -56,7 +56,7 @@@
  
    describe "when accepting resource statuses" do
      before do
-       @report = Puppet::Transaction::Report.new
+       @report = Puppet::Transaction::Report.new("apply")
      end
  
      it "should add each status to its status list" do
@@@ -61,13 -67,20 +67,13 @@@
    end
  
    describe "when using the indirector" do
 -    it "should redirect :find to the indirection" do
 -      @indirection = stub 'indirection', :name => :report
 -      Puppet::Transaction::Report.stubs(:indirection).returns(@indirection)
 -      @indirection.expects(:find)
 -      Puppet::Transaction::Report.find(:report)
 -    end
 -
      it "should redirect :save to the indirection" do
        Facter.stubs(:value).returns("eh")
        @indirection = stub 'indirection', :name => :report
        Puppet::Transaction::Report.stubs(:indirection).returns(@indirection)
-       report = Puppet::Transaction::Report.new
+       report = Puppet::Transaction::Report.new("apply")
        @indirection.expects(:save)
 -      report.save
 +      Puppet::Transaction::Report.indirection.save(report)
      end
  
      it "should default to the 'processor' terminus" do
@@@ -75,7 -88,7 +81,7 @@@
      end
  
      it "should delegate its name attribute to its host method" do
-       report = Puppet::Transaction::Report.new
+       report = Puppet::Transaction::Report.new("apply")
        report.expects(:host).returns "me"
        report.name.should == "me"
      end
@@@ -87,30 -100,37 +93,37 @@@
  
    describe "when computing exit status" do
      it "should produce 2 if changes are present" do
-       report = Puppet::Transaction::Report.new
-       report.add_metric("changes", {:total => 1})
-       report.add_metric("resources", {:failed => 0})
+       report = Puppet::Transaction::Report.new("apply")
+       report.add_metric("changes", {"total" => 1})
+       report.add_metric("resources", {"failed" => 0})
        report.exit_status.should == 2
      end
  
      it "should produce 4 if failures are present" do
-       report = Puppet::Transaction::Report.new
-       report.add_metric("changes", {:total => 0})
-       report.add_metric("resources", {:failed => 1})
+       report = Puppet::Transaction::Report.new("apply")
+       report.add_metric("changes", {"total" => 0})
+       report.add_metric("resources", {"failed" => 1})
        report.exit_status.should == 4
      end
  
      it "should produce 6 if both changes and failures are present" do
-       report = Puppet::Transaction::Report.new
-       report.add_metric("changes", {:total => 1})
-       report.add_metric("resources", {:failed => 1})
+       report = Puppet::Transaction::Report.new("apply")
+       report.add_metric("changes", {"total" => 1})
+       report.add_metric("resources", {"failed" => 1})
        report.exit_status.should == 6
      end
    end
  
-   describe "when calculating metrics" do
+   describe "before finalizing the report" do
+     it "should have a status of 'failed'" do
+       report = Puppet::Transaction::Report.new("apply")
+       report.status.should == 'failed'
+     end
+   end
+ 
+   describe "when finalizing the report" do
      before do
-       @report = Puppet::Transaction::Report.new
+       @report = Puppet::Transaction::Report.new("apply")
      end
  
      def metric(name, value)
@@@ -122,7 -142,7 +135,7 @@@
      end
  
      def add_statuses(count, type = :file)
-       3.times do |i|
+       count.times do |i|
          status = Puppet::Resource::Status.new(Puppet::Type.type(type).new(:title => "/my/path#{i}"))
          yield status if block_given?
          @report.add_resource_status status
@@@ -132,7 -152,7 +145,7 @@@
  
      [:time, :resources, :changes, :events].each do |type|
        it "should add #{type} metrics" do
-         @report.calculate_metrics
+         @report.finalize_report
          @report.metrics[type.to_s].should be_instance_of(Puppet::Transaction::Metric)
        end
      end
@@@ -141,25 -161,38 +154,38 @@@
        it "should provide the total number of resources" do
          add_statuses(3)
  
-         @report.calculate_metrics
-         metric(:resources, :total).should == 3
+         @report.finalize_report
+         metric(:resources, "total").should == 3
        end
  
        Puppet::Resource::Status::STATES.each do |state|
          it "should provide the number of #{state} resources as determined by the status objects" do
            add_statuses(3) { |status| status.send(state.to_s + "=", true) }
  
-           @report.calculate_metrics
-           metric(:resources, state).should == 3
+           @report.finalize_report
+           metric(:resources, state.to_s).should == 3
          end
        end
+ 
+       it "should mark the report as 'failed' if there are failing resources" do
+         add_statuses(1) { |status| status.failed = true }
+         @report.finalize_report
+         @report.status.should == 'failed'
+       end
      end
  
      describe "for changes" do
-       it "should provide the number of changes from the resource statuses" do
-         add_statuses(3) { |status| status.change_count = 3 }
-         @report.calculate_metrics
-         metric(:changes, :total).should == 9
+       it "should provide the number of changes from the resource statuses and mark the report as 'changed'" do
+         add_statuses(3) { |status| 3.times { status << Puppet::Transaction::Event.new(:status => 'success') } }
+         @report.finalize_report
+         metric(:changes, "total").should == 9
+         @report.status.should == 'changed'
+       end
+ 
+       it "should provide a total even if there are no changes, and mark the report as 'unchanged'" do
+         @report.finalize_report
+         metric(:changes, "total").should == 0
+         @report.status.should == 'unchanged'
        end
      end
  
@@@ -175,7 -208,7 +201,7 @@@
            status.evaluation_time = 3
          end
  
-         @report.calculate_metrics
+         @report.finalize_report
  
          metric(:time, "file").should == 3
          metric(:time, "exec").should == 6
@@@ -184,18 -217,32 +210,32 @@@
  
        it "should add any provided times from external sources" do
          @report.add_times :foobar, 50
-         @report.calculate_metrics
+         @report.finalize_report
          metric(:time, "foobar").should == 50
        end
+ 
+       it "should have a total time" do
+         add_statuses(3, :file) do |status|
+           status.evaluation_time = 1.25
+         end
+         @report.add_times :config_retrieval, 0.5
+         @report.finalize_report
+         metric(:time, "total").should == 4.25
+       end
      end
  
      describe "for events" do
        it "should provide the total number of events" do
          add_statuses(3) do |status|
-           3.times { |i| status.add_event(Puppet::Transaction::Event.new) }
+           3.times { |i| status.add_event(Puppet::Transaction::Event.new :status => 'success') }
          end
-         @report.calculate_metrics
-         metric(:events, :total).should == 9
+         @report.finalize_report
+         metric(:events, "total").should == 9
+       end
+ 
+       it "should provide the total even if there are no events" do
+         @report.finalize_report
+         metric(:events, "total").should == 0
        end
  
        Puppet::Transaction::Event::EVENT_STATUSES.each do |status_name|
@@@ -208,7 -255,7 +248,7 @@@
              end
            end
  
-           @report.calculate_metrics
+           @report.finalize_report
            metric(:events, status_name).should == 9
          end
        end
@@@ -223,24 -270,21 +263,32 @@@
        trans = catalog.apply
  
        @report = trans.report
-       @report.calculate_metrics
+       @report.finalize_report
      end
  
 -    %w{Changes Total Resources}.each do |main|
 -      it "should include information on #{main} in the summary" do
 +    %w{changes time resources events}.each do |main|
 +      it "should include the key #{main} in the raw summary hash" do
 +        @report.raw_summary.should be_key main
 +      end
 +    end
 +
 +    it "should include the last run time in the raw summary hash" do
 +      Time.stubs(:now).returns(Time.utc(2010,11,10,12,0,24))
 +      @report.raw_summary["time"]["last_run"].should == 1289390424
 +    end
 +
 +    %w{Changes Total Resources Time Events}.each do |main|
 +      it "should include information on #{main} in the textual summary" do
          @report.summary.should be_include(main)
        end
      end
    end
+ 
+   describe "when outputting yaml" do
+     it "should not include @external_times" do
+       report = Puppet::Transaction::Report.new('apply')
+       report.add_times('config_retrieval', 1.0)
+       report.to_yaml_properties.should_not include('@external_times')
+     end
+   end
  end
diff --combined spec/unit/transaction/resource_harness_spec.rb
index 9a8b1e2,65c148a..0ec31be
--- a/spec/unit/transaction/resource_harness_spec.rb
+++ b/spec/unit/transaction/resource_harness_spec.rb
@@@ -1,6 -1,7 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 -require 'puppet_spec/files'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/transaction/resource_harness'
  
@@@ -48,354 -49,238 +48,238 @@@ describe Puppet::Transaction::ResourceH
        @harness.evaluate(@resource).should be_failed
      end
  
      it "should store the resource's evaluation time in the resource status" do
        @harness.evaluate(@resource).evaluation_time.should be_instance_of(Float)
      end
- 
-     it "should set the change count to the total number of changes" do
-       changes = %w{a b c d}
-       @harness.expects(:changes_to_perform).returns changes
-       @harness.expects(:apply_changes).with(@status, changes)
-       @harness.evaluate(@resource).change_count.should == 4
-     end
    end
  
-   describe "when creating changes" do
-     before do
-       @current_state = Puppet::Resource.new(:file, "/my/file")
-       @resource.stubs(:retrieve).returns @current_state
-       Puppet.features.stubs(:root?).returns true
-     end
- 
-     it "should retrieve the current values from the resource" do
-       @resource.expects(:retrieve).returns @current_state
-       @harness.changes_to_perform(@status, @resource)
-     end
- 
-     it "should cache that the resource was checked" do
-       @harness.expects(:cache).with { |resource, name, time| name == :checked and time.is_a?(Time) }
-       @harness.changes_to_perform(@status, @resource)
-     end
- 
-     it "should create changes with the appropriate property and current value" do
-       @resource[:ensure] = :present
-       @current_state[:ensure] = :absent
- 
-       change = stub 'change'
-       Puppet::Transaction::Change.expects(:new).with(@resource.parameter(:ensure), :absent).returns change
- 
-       @harness.changes_to_perform(@status, @resource)[0].should equal(change)
-     end
- 
-     it "should not attempt to manage properties that do not have desired values set" do
-       mode = @resource.newattr(:mode)
-       @current_state[:mode] = :absent
- 
-       mode.expects(:insync?).never
- 
-       @harness.changes_to_perform(@status, @resource)
-     end
- 
- #   it "should copy audited parameters" do
- #     @resource[:audit] = :mode
- #     @harness.cache(@resource, :mode, "755")
- #     @harness.changes_to_perform(@status, @resource)
- #     @resource[:mode].should == "755"
- #   end
- 
-     it "should mark changes created as a result of auditing as auditing changes" do
-       @current_state[:mode] = 0644
-       @resource[:audit] = :mode
-       @harness.cache(@resource, :mode, "755")
-       @harness.changes_to_perform(@status, @resource)[0].must be_auditing
-     end
- 
-     describe "and the 'ensure' parameter is present but not in sync" do
-       it "should return a single change for the 'ensure' parameter" do
-         @resource[:ensure] = :present
-         @resource[:mode] = "755"
-         @current_state[:ensure] = :absent
-         @current_state[:mode] = :absent
- 
-         @resource.stubs(:retrieve).returns @current_state
- 
-         changes = @harness.changes_to_perform(@status, @resource)
-         changes.length.should == 1
-         changes[0].property.name.should == :ensure
-       end
-     end
- 
-     describe "and the 'ensure' parameter should be set to 'absent', and is correctly set to 'absent'" do
-       it "should return no changes" do
-         @resource[:ensure] = :absent
-         @resource[:mode] = "755"
-         @current_state[:ensure] = :absent
-         @current_state[:mode] = :absent
- 
-         @harness.changes_to_perform(@status, @resource).should == []
-       end
-     end
- 
-     describe "and the 'ensure' parameter is 'absent' and there is no 'desired value'" do
-       it "should return no changes" do
-         @resource.newattr(:ensure)
-         @resource[:mode] = "755"
-         @current_state[:ensure] = :absent
-         @current_state[:mode] = :absent
- 
-         @harness.changes_to_perform(@status, @resource).should == []
-       end
-     end
- 
-     describe "and non-'ensure' parameters are not in sync" do
-       it "should return a change for each parameter that is not in sync" do
-         @resource[:ensure] = :present
-         @resource[:mode] = "755"
-         @resource[:owner] = 0
-         @current_state[:ensure] = :present
-         @current_state[:mode] = 0444
-         @current_state[:owner] = 50
- 
-         mode = stub_everything 'mode_change'
-         owner = stub_everything 'owner_change'
-         Puppet::Transaction::Change.expects(:new).with(@resource.parameter(:mode), 0444).returns mode
-         Puppet::Transaction::Change.expects(:new).with(@resource.parameter(:owner), 50).returns owner
- 
-         changes = @harness.changes_to_perform(@status, @resource)
-         changes.length.should == 2
-         changes.should be_include(mode)
-         changes.should be_include(owner)
-       end
-     end
- 
-     describe "and all parameters are in sync" do
-       it "should return an empty array" do
-         @resource[:ensure] = :present
-         @resource[:mode] = "755"
-         @current_state[:ensure] = :present
-         @current_state[:mode] = "755"
-         @harness.changes_to_perform(@status, @resource).should == []
+   def events_to_hash(events)
+     events.map do |event|
+       hash = {}
+       event.instance_variables.each do |varname|
+         hash[varname] = event.instance_variable_get(varname.to_sym)
        end
+       hash
      end
    end
  
    describe "when applying changes" do
-     before do
-       @change1 = stub 'change1', :apply => stub("event", :status => "success"), :auditing? => false
-       @change2 = stub 'change2', :apply => stub("event", :status => "success"), :auditing? => false
-       @changes = [@change1, @change2]
-     end
- 
-     it "should apply the change" do
-       @change1.expects(:apply).returns( stub("event", :status => "success") )
-       @change2.expects(:apply).returns( stub("event", :status => "success") )
- 
-       @harness.apply_changes(@status, @changes)
-     end
- 
-     it "should mark the resource as changed" do
-       @harness.apply_changes(@status, @changes)
- 
-       @status.should be_changed
-     end
- 
-     it "should queue the resulting event" do
-       @harness.apply_changes(@status, @changes)
- 
-       @status.events.should be_include(@change1.apply)
-       @status.events.should be_include(@change2.apply)
-     end
- 
-     it "should cache the new value if it is an auditing change" do
-       @change1.expects(:auditing?).returns true
-       property = stub 'property', :name => "foo", :resource => "myres"
-       @change1.stubs(:property).returns property
-       @change1.stubs(:is).returns "myval"
- 
-       @harness.apply_changes(@status, @changes)
- 
-       @harness.cached("myres", "foo").should == "myval"
-     end
- 
-     describe "when there's not an existing audited value" do
-       it "should save the old value before applying the change if it's audited" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0750).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "750"
- 
-         (File.stat(test_file).mode & 0777).should == 0755
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/mode: mode changed '750' to '755'",
-           "notice: /#{resource}/mode: audit change: newly-recorded recorded value 750"
-         ]
-       end
- 
-       it "should audit the value if there's no change" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0755).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "755"
- 
-         (File.stat(test_file).mode & 0777).should == 0755
- 
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/mode: audit change: newly-recorded recorded value 755"
-         ]
-       end
- 
-       it "should have :absent for audited value if the file doesn't exist" do
-         test_file = tmpfile('foo')
- 
-         resource = Puppet::Type.type(:file).new :ensure => 'present', :path => test_file, :mode => '755', :audit => :mode
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == :absent
- 
-         (File.stat(test_file).mode & 0777).should == 0755
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/ensure: created",
-           "notice: /#{resource}/mode: audit change: newly-recorded recorded value absent"
-         ]
-       end
- 
-       it "should do nothing if there are no changes to make and the stored value is correct" do
-         test_file = tmpfile('foo')
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode, :ensure => 'absent'
-         @harness.cache(resource, :mode, :absent)
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == :absent
- 
-         File.exists?(test_file).should == false
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ []
-       end
-     end
- 
-     describe "when there's an existing audited value" do
-       it "should save the old value before applying the change" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0750).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :audit => :mode
-         @harness.cache(resource, :mode, '555')
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "750"
- 
-         (File.stat(test_file).mode & 0777).should == 0750
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to 750"
-         ]
-       end
- 
-       it "should save the old value before applying the change" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0750).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode
-         @harness.cache(resource, :mode, '555')
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "750"
- 
-         (File.stat(test_file).mode & 0777).should == 0755
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/mode: mode changed '750' to '755' (previously recorded value was 555)"
-         ]
-       end
- 
-       it "should audit the value if there's no change" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0755).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode
-         @harness.cache(resource, :mode, '555')
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "755"
- 
-         (File.stat(test_file).mode & 0777).should == 0755
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to 755"
-         ]
-       end
- 
-       it "should have :absent for audited value if the file doesn't exist" do
-         test_file = tmpfile('foo')
- 
-         resource = Puppet::Type.type(:file).new :ensure => 'present', :path => test_file, :mode => '755', :audit => :mode
-         @harness.cache(resource, :mode, '555')
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == :absent
- 
-         (File.stat(test_file).mode & 0777).should == 0755
- 
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [
-           "notice: /#{resource}/ensure: created", "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to absent"
-         ]
-       end
- 
-       it "should do nothing if there are no changes to make and the stored value is correct" do
-         test_file = tmpfile('foo')
-         File.open(test_file, "w", 0755).close
- 
-         resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode
-         @harness.cache(resource, :mode, '755')
- 
-         @harness.evaluate(resource)
-         @harness.cached(resource, :mode).should == "755"
- 
-         (File.stat(test_file).mode & 0777).should == 0755
-         @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ []
-       end
+     [false, true].each do |noop_mode|; describe (noop_mode ? "in noop mode" : "in normal mode") do
+       [nil, '750'].each do |machine_state|; describe (machine_state ? "with a file initially present" : "with no file initially present") do
+         [nil, '750', '755'].each do |yaml_mode|
+           [nil, :file, :absent].each do |yaml_ensure|; describe "with mode=#{yaml_mode.inspect} and ensure=#{yaml_ensure.inspect} stored in state.yml" do
+             [false, true].each do |auditing_ensure|
+               [false, true].each do |auditing_mode|
+                 auditing = []
+                 auditing.push(:mode) if auditing_mode
+                 auditing.push(:ensure) if auditing_ensure
+                 [nil, :file, :absent].each do |ensure_property| # what we set "ensure" to in the manifest
+                   [nil, '750', '755'].each do |mode_property| # what we set "mode" to in the manifest
+                     manifest_settings = {}
+                     manifest_settings[:audit] = auditing if !auditing.empty?
+                     manifest_settings[:ensure] = ensure_property if ensure_property
+                     manifest_settings[:mode] = mode_property if mode_property
+                     describe "with manifest settings #{manifest_settings.inspect}" do; it "should behave properly" do
+                       # Set up preconditions
+                       test_file = tmpfile('foo')
+                       if machine_state
+                         File.open(test_file, 'w', machine_state.to_i(8)).close
+                       end
+ 
+                       Puppet[:noop] = noop_mode
+                       params = { :path => test_file, :backup => false }
+                       params.merge!(manifest_settings)
+                       resource = Puppet::Type.type(:file).new params
+ 
+                       @harness.cache(resource, :mode, yaml_mode) if yaml_mode
+                       @harness.cache(resource, :ensure, yaml_ensure) if yaml_ensure
+ 
+                       fake_time = Time.utc(2011, 'jan', 3, 12, 24, 0)
+                       Time.stubs(:now).returns(fake_time) # So that Puppet::Resource::Status objects will compare properly
+ 
+                       resource.expects(:err).never # make sure no exceptions get swallowed
+                       status = @harness.evaluate(resource) # do the thing
+ 
+                       # check that the state of the machine has been properly updated
+                       expected_logs = []
+                       expected_status_events = []
+                       if auditing_mode
+                         @harness.cached(resource, :mode).should == (machine_state || :absent)
+                       else
+                         @harness.cached(resource, :mode).should == yaml_mode
+                       end
+                       if auditing_ensure
+                         @harness.cached(resource, :ensure).should == (machine_state ? :file : :absent)
+                       else
+                         @harness.cached(resource, :ensure).should == yaml_ensure
+                       end
+                       if ensure_property == :file
+                         file_would_be_there_if_not_noop = true
+                       elsif ensure_property == nil
+                         file_would_be_there_if_not_noop = machine_state != nil
+                       else # ensure_property == :absent
+                         file_would_be_there_if_not_noop = false
+                       end
+                       file_should_be_there = noop_mode ? machine_state != nil : file_would_be_there_if_not_noop
+                       File.exists?(test_file).should == file_should_be_there
+                       if file_should_be_there
+                         if noop_mode
+                           expected_file_mode = machine_state
+                         else
+                           expected_file_mode = mode_property || machine_state
+                         end
+                         if !expected_file_mode
+                           # we didn't specify a mode and the file was created, so mode comes from umode
+                         else
+                           file_mode = File.stat(test_file).mode & 0777
+                           file_mode.should == expected_file_mode.to_i(8)
+                         end
+                       end
+ 
+                       # Test log output for the "mode" parameter
+                       previously_recorded_mode_already_logged = false
+                       mode_status_msg = nil
+                       if machine_state && file_would_be_there_if_not_noop && mode_property && machine_state != mode_property
+                         if noop_mode
+                           what_happened = "current_value #{machine_state}, should be #{mode_property} (noop)"
+                           expected_status = 'noop'
+                         else
+                           what_happened = "mode changed '#{machine_state}' to '#{mode_property}'"
+                           expected_status = 'success'
+                         end
+                         if auditing_mode && yaml_mode && yaml_mode != machine_state
+                           previously_recorded_mode_already_logged = true
+                           mode_status_msg = "#{what_happened} (previously recorded value was #{yaml_mode})"
+                         else
+                           mode_status_msg = what_happened
+                         end
+                         expected_logs << "notice: /#{resource}/mode: #{mode_status_msg}"
+                       end
+                       if @harness.cached(resource, :mode) && @harness.cached(resource, :mode) != yaml_mode
+                         if yaml_mode
+                           unless previously_recorded_mode_already_logged
+                             mode_status_msg = "audit change: previously recorded value #{yaml_mode} has been changed to #{@harness.cached(resource, :mode)}"
+                             expected_logs << "notice: /#{resource}/mode: #{mode_status_msg}"
+                             expected_status = 'audit'
+                           end
+                         else
+                           expected_logs << "notice: /#{resource}/mode: audit change: newly-recorded value #{@harness.cached(resource, :mode)}"
+                         end
+                       end
+                       if mode_status_msg
+                         expected_status_events << Puppet::Transaction::Event.new(
+                             :source_description => "/#{resource}/mode", :resource => resource, :file => nil,
+                             :line => nil, :tags => %w{file}, :desired_value => mode_property,
+                             :historical_value => yaml_mode, :message => mode_status_msg, :name => :mode_changed,
+                             :previous_value => machine_state || :absent, :property => :mode, :status => expected_status,
+                             :audited => auditing_mode)
+                       end
+ 
+                       # Test log output for the "ensure" parameter
+                       previously_recorded_ensure_already_logged = false
+                       ensure_status_msg = nil
+                       if file_would_be_there_if_not_noop != (machine_state != nil)
+                         if noop_mode
+                           what_happened = "current_value #{machine_state ? 'file' : 'absent'}, should be #{file_would_be_there_if_not_noop ? 'file' : 'absent'} (noop)"
+                           expected_status = 'noop'
+                         else
+                           what_happened = file_would_be_there_if_not_noop ? 'created' : 'removed'
+                           expected_status = 'success'
+                         end
+                         if auditing_ensure && yaml_ensure && yaml_ensure != (machine_state ? :file : :absent)
+                           previously_recorded_ensure_already_logged = true
+                           ensure_status_msg = "#{what_happened} (previously recorded value was #{yaml_ensure})"
+                         else
+                           ensure_status_msg = "#{what_happened}"
+                         end
+                         expected_logs << "notice: /#{resource}/ensure: #{ensure_status_msg}"
+                       end
+                       if @harness.cached(resource, :ensure) && @harness.cached(resource, :ensure) != yaml_ensure
+                         if yaml_ensure
+                           unless previously_recorded_ensure_already_logged
+                             ensure_status_msg = "audit change: previously recorded value #{yaml_ensure} has been changed to #{@harness.cached(resource, :ensure)}"
+                             expected_logs << "notice: /#{resource}/ensure: #{ensure_status_msg}"
+                             expected_status = 'audit'
+                           end
+                         else
+                           expected_logs << "notice: /#{resource}/ensure: audit change: newly-recorded value #{@harness.cached(resource, :ensure)}"
+                         end
+                       end
+                       if ensure_status_msg
+                         if ensure_property == :file
+                           ensure_event_name = :file_created
+                         elsif ensure_property == nil
+                           ensure_event_name = :file_changed
+                         else # ensure_property == :absent
+                           ensure_event_name = :file_removed
+                         end
+                         expected_status_events << Puppet::Transaction::Event.new(
+                             :source_description => "/#{resource}/ensure", :resource => resource, :file => nil,
+                             :line => nil, :tags => %w{file}, :desired_value => ensure_property,
+                             :historical_value => yaml_ensure, :message => ensure_status_msg, :name => ensure_event_name,
+                             :previous_value => machine_state ? :file : :absent, :property => :ensure,
+                             :status => expected_status, :audited => auditing_ensure)
+                       end
+ 
+                       # Actually check the logs.
+                       @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ expected_logs
+ 
+                       # All the log messages should show up as events except the "newly-recorded" ones.
+                       expected_event_logs = @logs.reject {|l| l.message =~ /newly-recorded/ }
+                       status.events.map {|e| e.message}.should =~ expected_event_logs.map {|l| l.message }
+                       events_to_hash(status.events).should =~ events_to_hash(expected_status_events)
+ 
+                       # Check change count - this is the number of changes that actually occurred.
+                       expected_change_count = 0
+                       if (machine_state != nil) != file_should_be_there
+                         expected_change_count = 1
+                       elsif machine_state != nil
+                         if expected_file_mode != machine_state
+                           expected_change_count = 1
+                         end
+                       end
+                       status.change_count.should == expected_change_count
+ 
+                       # Check out of sync count - this is the number
+                       # of changes that would have occurred in
+                       # non-noop mode.
+                       expected_out_of_sync_count = 0
+                       if (machine_state != nil) != file_would_be_there_if_not_noop
+                         expected_out_of_sync_count = 1
+                       elsif machine_state != nil
+                         if mode_property != nil && mode_property != machine_state
+                           expected_out_of_sync_count = 1
+                         end
+                       end
+                       if !noop_mode
+                         expected_out_of_sync_count.should == expected_change_count
+                       end
+                       status.out_of_sync_count.should == expected_out_of_sync_count
+ 
+                       # Check legacy summary fields
+                       status.changed.should == (expected_change_count != 0)
+                       status.out_of_sync.should == (expected_out_of_sync_count != 0)
+ 
+                       # Check the :synced field on state.yml
+                       synced_should_be_set = !noop_mode && status.changed
+                       (@harness.cached(resource, :synced) != nil).should == synced_should_be_set
+                     end; end
+                   end
+                 end
+               end
+             end
+           end; end
+         end
+       end; end
+     end; end
+ 
+     it "should not apply changes if allow_changes?() returns false" do
+       test_file = tmpfile('foo')
+       resource = Puppet::Type.type(:file).new :path => test_file, :backup => false, :ensure => :file
+       resource.expects(:err).never # make sure no exceptions get swallowed
+       @harness.expects(:allow_changes?).with(resource).returns false
+       status = @harness.evaluate(resource)
+       File.exists?(test_file).should == false
      end
    end
  
diff --combined spec/unit/transaction_spec.rb
index b5341e4,862413a..3677bfd
--- a/spec/unit/transaction_spec.rb
+++ b/spec/unit/transaction_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  require 'puppet/transaction'
  
@@@ -58,11 -58,6 +58,6 @@@ describe Puppet::Transaction d
      @transaction.report.resource_statuses[resource.to_s].should equal(status)
    end
  
-   it "should calculate metrics on and report the report when asked to generate a report" do
-     @transaction.report.expects(:calculate_metrics)
-     @transaction.generate_report.should equal(@transaction.report)
-   end
- 
    it "should consider a resource to be failed if a status instance exists for that resource and indicates it is failed" do
      resource = Puppet::Type.type(:notify).new :name => "yayness"
      status = Puppet::Resource::Status.new(resource)
@@@ -94,7 -89,7 +89,7 @@@
    end
  
    it "should be possible to replace the report object" do
-     report = Puppet::Transaction::Report.new
+     report = Puppet::Transaction::Report.new("apply")
      @transaction.report = report
  
      @transaction.report.should == report
diff --combined spec/unit/type/augeas_spec.rb
index 2332bb0,d2e40f0..dece395
--- a/spec/unit/type/augeas_spec.rb
+++ b/spec/unit/type/augeas_spec.rb
@@@ -1,13 -1,11 +1,11 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  augeas = Puppet::Type.type(:augeas)
  
  describe augeas do
-   describe "when augeas is present" do
-     confine "Augeas is unavailable" => Puppet.features.augeas?
- 
+   describe "when augeas is present", :if => Puppet.features.augeas? do
      it "should have a default provider inheriting from Puppet::Provider" do
        augeas.defaultprovider.ancestors.should be_include(Puppet::Provider)
      end
diff --combined spec/unit/type/file_spec.rb
index a5742aa,22921d8..31d3d6b
--- a/spec/unit/type/file_spec.rb
+++ b/spec/unit/type/file_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  describe Puppet::Type.type(:file) do
    before do
@@@ -208,8 -208,7 +208,7 @@@
      end
    end
  
-   describe "when using Microsoft Windows filenames" do
-     confine "Only works on Microsoft Windows" => Puppet.features.microsoft_windows?
+   describe "when using Microsoft Windows filenames", :if => Puppet.features.microsoft_windows? do
      describe "on Microsoft Windows systems" do
        before do
          Puppet.features.stubs(:posix?).returns(false)
@@@ -271,8 -270,7 +270,7 @@@
    end
  
    describe "when using UNC filenames" do
-     describe "on Microsoft Windows systems" do
-       confine "Only works on Microsoft Windows" => Puppet.features.microsoft_windows?
+     describe "on Microsoft Windows systems", :if => Puppet.features.microsoft_windows? do
        before do
          Puppet.features.stubs(:posix?).returns(false)
          Puppet.features.stubs(:microsoft_windows?).returns(true)
@@@ -381,9 -379,9 +379,9 @@@
  
  
                  @resource = Puppet::Type.type(:file).new(
-                 
+ 
              :path => @link,
-         
+ 
              :mode => "755"
            )
            @catalog.add_resource @resource
@@@ -510,47 -508,47 +508,47 @@@
  
    describe "when executing a recursive search" do
      it "should use Metadata to do its recursion" do
 -      Puppet::FileServing::Metadata.expects(:search)
 +      Puppet::FileServing::Metadata.indirection.expects(:search)
        @file.perform_recursion(@file[:path])
      end
  
      it "should use the provided path as the key to the search" do
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| key == "/foo" }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| key == "/foo" }
        @file.perform_recursion("/foo")
      end
  
      it "should return the results of the metadata search" do
 -      Puppet::FileServing::Metadata.expects(:search).returns "foobar"
 +      Puppet::FileServing::Metadata.indirection.expects(:search).returns "foobar"
        @file.perform_recursion(@file[:path]).should == "foobar"
      end
  
      it "should pass its recursion value to the search" do
        @file[:recurse] = true
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurse] == true }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
        @file.perform_recursion(@file[:path])
      end
  
      it "should pass true if recursion is remote" do
        @file[:recurse] = :remote
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurse] == true }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
        @file.perform_recursion(@file[:path])
      end
  
      it "should pass its recursion limit value to the search" do
        @file[:recurselimit] = 10
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurselimit] == 10 }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurselimit] == 10 }
        @file.perform_recursion(@file[:path])
      end
  
      it "should configure the search to ignore or manage links" do
        @file[:links] = :manage
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:links] == :manage }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:links] == :manage }
        @file.perform_recursion(@file[:path])
      end
  
      it "should pass its 'ignore' setting to the search if it has one" do
        @file[:ignore] = %w{.svn CVS}
 -      Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} }
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} }
        @file.perform_recursion(@file[:path])
      end
    end
@@@ -597,7 -595,7 +595,7 @@@
  
      it "should set checksum_type to none if this file checksum is none" do
        @file[:checksum] = :none
 -      Puppet::FileServing::Metadata.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata]
 +      Puppet::FileServing::Metadata.indirection.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata]
        @file.expects(:newchild).with("my/file").returns "fiebar"
        @file.recurse_local
      end
@@@ -1058,7 -1056,7 +1056,7 @@@
      before do
        @type_class = Puppet::Type.type(:file)
      end
-     
+ 
      it "should have a regexp that captures the entire string, except for a terminating slash" do
        patterns = @type_class.title_patterns
        string = "abc/\n\tdef/"
diff --combined spec/unit/type/package_spec.rb
index 8414ac3,662fe47..3db9c77
--- a/spec/unit/type/package_spec.rb
+++ b/spec/unit/type/package_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  describe Puppet::Type.type(:package) do
    before do
@@@ -121,7 -121,7 +121,7 @@@
        before { @package[:ensure] = :purged }
  
        it "should do nothing if it is :purged" do
-         @provider.expects(:properties).returns(:ensure => :purged)
+         @provider.expects(:properties).returns(:ensure => :purged).at_least_once
          @catalog.apply
        end
  
@@@ -141,7 -141,7 +141,7 @@@
  
        [:purged, :absent].each do |state|
          it "should do nothing if it is #{state.to_s}" do
-           @provider.expects(:properties).returns(:ensure => state)
+           @provider.expects(:properties).returns(:ensure => state).at_least_once
            @catalog.apply
          end
        end
@@@ -162,7 -162,7 +162,7 @@@
  
        [:present, :latest, "1.0"].each do |state|
          it "should do nothing if it is #{state.to_s}" do
-           @provider.expects(:properties).returns(:ensure => state)
+           @provider.expects(:properties).returns(:ensure => state).at_least_once
            @catalog.apply
          end
        end
diff --combined spec/unit/type_spec.rb
index 165e1ee,b7a0897..d1143d9
--- a/spec/unit/type_spec.rb
+++ b/spec/unit/type_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  
  describe Puppet::Type do
    it "should include the Cacher module" do
@@@ -116,7 -116,7 +116,7 @@@
      catalog.version = 50
      catalog.add_resource resource
  
-     resource.source_descriptors.should == {:version=>50, :tags=>["mount", "foo"], :path=>"/Mount[foo]"}
+     resource.source_descriptors.should == {:tags=>["mount", "foo"], :path=>"/Mount[foo]"}
    end
  
    it "should consider its type to be the name of its class" do
@@@ -153,7 -153,7 +153,7 @@@
        @resource.event.default_log_level.should == :warning
      end
  
-     {:file => "/my/file", :line => 50, :tags => %{foo bar}, :version => 50}.each do |attr, value|
+     {:file => "/my/file", :line => 50, :tags => %{foo bar}}.each do |attr, value|
        it "should set the #{attr}" do
          @resource.stubs(attr).returns value
          @resource.event.send(attr).should == value
diff --combined spec/unit/util/checksums_spec.rb
index 5fdf9fe,a8bc12b..954dc65
--- a/spec/unit/util/checksums_spec.rb
+++ b/spec/unit/util/checksums_spec.rb
@@@ -3,7 -3,7 +3,7 @@@
  #  Created by Luke Kanies on 2007-9-22.
  #  Copyright (c) 2007. All rights reserved.
  
 -require File.dirname(__FILE__) + '/../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
  
  require 'puppet/util/checksums'
  
@@@ -140,7 -140,9 +140,9 @@@ describe Puppet::Util::Checksums d
        end
  
        it "should return nil for streams" do
-         @summer.send(sum.to_s + "_stream").should be_nil
+         expectation = stub "expectation"
+         expectation.expects(:do_something!).at_least_once
+         @summer.send(sum.to_s + "_stream"){ |checksum| checksum << "anything" ; expectation.do_something!  }.should be_nil
        end
      end
    end
@@@ -149,5 -151,11 +151,11 @@@
      it "should return an empty string" do
        @summer.none_file("/my/file").should == ""
      end
+ 
+     it "should return an empty string for streams" do
+       expectation = stub "expectation"
+       expectation.expects(:do_something!).at_least_once
+       @summer.none_stream{ |checksum| checksum << "anything" ; expectation.do_something!  }.should == ""
+     end
    end
  end
diff --combined spec/unit/util/log_spec.rb
index ea5d598,f3fd1b0..a6f1173
--- a/spec/unit/util/log_spec.rb
+++ b/spec/unit/util/log_spec.rb
@@@ -7,7 -7,7 +7,7 @@@ require 'puppet/util/log
  describe Puppet::Util::Log do
    it "should write a given message to the specified destination" do
      arraydest = []
 -    Puppet::Util::Log.newdestination(arraydest)
 +    Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(arraydest))
      Puppet::Util::Log.new(:level => :notice, :message => "foo")
      message = arraydest.last.message
      message.should == "foo"
@@@ -87,7 -87,7 +87,7 @@@
      it "should flush the log queue when the first destination is specified" do
        Puppet::Util::Log.close_all
        Puppet::Util::Log.expects(:flushqueue)
 -      Puppet::Util::Log.newdestination([])
 +      Puppet::Util::Log.newdestination(:console)
      end
  
      it "should convert the level to a symbol if it's passed in as a string" do
@@@ -120,7 -120,7 +120,7 @@@
        Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => "foo")
      end
  
-     [:file, :line, :version].each do |attr|
+     [:file, :line].each do |attr|
        it "should use #{attr} if provided" do
          Puppet::Util::Log.any_instance.expects(attr.to_s + "=").with "foo"
          Puppet::Util::Log.new(:level => "notice", :message => :foo, attr => "foo")
@@@ -177,23 -177,12 +177,12 @@@
          log = Puppet::Util::Log.new(:level => "notice", :message => :foo)
          log.expects(:tag).with("tag")
          log.expects(:tag).with("tag2")
-         log.expects(:version=).with(100)
  
          log.source = source
  
          log.source.should == "path"
        end
  
-       it "should copy over any version information" do
-         catalog = Puppet::Resource::Catalog.new
-         catalog.version = 25
-         source = Puppet::Type.type(:file).new :path => "/foo/bar"
-         catalog.add_resource source
- 
-         log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => source)
-         log.version.should == 25
-       end
- 
        it "should copy over any file and line information" do
          source = Puppet::Type.type(:file).new :path => "/foo/bar"
          source.file = "/my/file"
@@@ -212,4 -201,22 +201,22 @@@
        end
      end
    end
+ 
+   describe "to_yaml" do
+     it "should not include the @version attribute" do
+       log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :version => 100)
+       log.to_yaml_properties.should_not include('@version')
+     end
+ 
+     it "should include attributes @level, @message, @source, @tags, and @time" do
+       log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :version => 100)
+       log.to_yaml_properties.should == %w{@level @message @source @tags @time}
+     end
+ 
+     it "should include attributes @file and @line if specified" do
+       log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :file => "foo", :line => 35)
+       log.to_yaml_properties.should include('@file')
+       log.to_yaml_properties.should include('@line')
+     end
+   end
  end
diff --combined spec/unit/util/queue/stomp_spec.rb
index 3b893fe,c33f1a6..a11d532
--- a/spec/unit/util/queue/stomp_spec.rb
+++ b/spec/unit/util/queue/stomp_spec.rb
@@@ -1,20 -1,16 +1,16 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  require 'puppet/util/queue'
  
- describe Puppet::Util::Queue do
-   confine "Missing Stomp" => Puppet.features.stomp?
- 
+ describe Puppet::Util::Queue, :if => Puppet.features.stomp? do
    it 'should load :stomp client appropriately' do
      Puppet.settings.stubs(:value).returns 'faux_queue_source'
      Puppet::Util::Queue.queue_type_to_class(:stomp).name.should == 'Puppet::Util::Queue::Stomp'
    end
  end
  
- describe 'Puppet::Util::Queue::Stomp' do
-   confine "Missing Stomp" => Puppet.features.stomp?
- 
+ describe 'Puppet::Util::Queue::Stomp', :if => Puppet.features.stomp? do
    before do
      # So we make sure we never create a real client instance.
      # Otherwise we'll try to connect, and that's bad.
diff --combined spec/unit/util/settings/file_setting_spec.rb
index fc07635,dcfb6e3..a2049e2
--- a/spec/unit/util/settings/file_setting_spec.rb
+++ b/spec/unit/util/settings/file_setting_spec.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../../../spec_helper'
 +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
  
  require 'puppet/util/settings'
  require 'puppet/util/settings/file_setting'
@@@ -146,9 -146,7 +146,7 @@@ describe Puppet::Util::Settings::FileSe
        @file.to_resource.should be_instance_of(Puppet::Resource)
      end
  
-     describe "on POSIX systems" do
-       confine "no /dev on Microsoft Windows" => Puppet.features.posix?
- 
+     describe "on POSIX systems", :if => Puppet.features.posix? do
        it "should skip files in /dev" do
          @settings.stubs(:value).with(:mydir).returns "/dev/file"
          @file.to_resource.should be_nil
diff --combined test/other/report.rb
index ce7d31e,eacf163..fb20647
--- a/test/other/report.rb
+++ b/test/other/report.rb
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env ruby
  
 -require File.dirname(__FILE__) + '/../lib/puppettest'
 +require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
  
  require 'puppet'
  require 'puppet/reports'
@@@ -68,7 -68,7 +68,7 @@@ class TestReports < Test::Unit::TestCas
  
    def test_store_report
      # Create a bunch of log messages in an array.
-     report = Puppet::Transaction::Report.new
+     report = Puppet::Transaction::Report.new("apply")
  
      # We have to reuse reporting here because of something going on in the
      # server/report.rb file

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list