#!/usr/bin/env ruby

$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/

require 'puppet'
require 'puppet/rails'
require 'puppet/parser/interpreter'
require 'puppet/parser/parser'
require 'puppet/network/client'
require 'puppettest'
require 'puppettest/parsertesting'
require 'puppettest/resourcetesting'
require 'puppettest/railstesting'

class TestRailsHost < Test::Unit::TestCase
    include PuppetTest::ParserTesting
    include PuppetTest::ResourceTesting
    include PuppetTest::RailsTesting

    def setup
        super
        railsinit if Puppet.features.rails?
    end

    def teardown
        railsteardown if Puppet.features.rails?
        super
    end

    def test_includerails
        assert_nothing_raised {
            require 'puppet/rails'
        }
    end

    # Don't do any tests w/out this class
    if Puppet.features.rails?
    def test_store
        @interp, @scope, @source = mkclassframing
        # First make some objects
        resources = []
        4.times { |i|
            # Make a file
            resources << mkresource(:type => "file",
                :title => "/tmp/file#{i.to_s}",
                :params => {:owner => "user#{i}"})

            # And an exec, so we're checking multiple types
            resources << mkresource(:type => "exec",
                :title => "/bin/echo file#{i.to_s}",
                :params => {:user => "user#{i}"})
        }

        # Now collect our facts
        facts = {"hostname" => Facter.value(:hostname), "test1" => "funtest",
            "ipaddress" => Facter.value(:ipaddress)}

        # Now try storing our crap
        host = nil
        assert_nothing_raised {
            host = Puppet::Rails::Host.store(
                :resources => resources,
                :facts => facts,
                :name => facts["hostname"],
                :classes => ["one", "two::three", "four"]
            )
        }

        assert(host, "Did not create host")

        host = nil
        assert_nothing_raised {
            host = Puppet::Rails::Host.find_by_name(facts["hostname"])
        }
        assert(host, "Could not find host object")

        assert(host.resources, "No objects on host")

        facts.each do |fact, value|
            assert_equal(value, host.fact(fact), "fact %s is wrong" % fact)
        end
        assert_equal(facts["ipaddress"], host.ip, "IP did not get set")

        count = 0
        host.resources.each do |resource|
            assert_equal(host, resource.host)
            count += 1
            i = nil
            if resource[:title] =~ /file([0-9]+)/
                i = $1
            else
                raise "Got weird resource %s" % resource.inspect
            end
            assert(resource[:restype] != "", "Did not get a type from the resource")
            case resource["restype"]
            when "file":
                assert_equal("user#{i}", resource.parameter("owner"),
                    "got no owner for %s" % resource.ref)
            when "exec":
                assert_equal("user#{i}", resource.parameter("user"),
                    "got no user for %s" % resource.ref)
            else
                raise "Unknown type %s" % resource[:restype].inspect
            end
        end

        assert_equal(8, count, "Did not get enough resources")

        # Now remove a couple of resources
        resources.reject! { |r| r.title =~ /file3/ }

        # Change a few resources
        resources.find_all { |r| r.title =~ /file2/ }.each do |r|
            r.set("loglevel", "notice", r.source)
        end

        # And add a new resource
        resources << mkresource(:type => "file",
            :title => "/tmp/file_added",
            :params => {:owner => "user_added"})

        # And change some facts
        facts["test2"] = "yaytest"
        facts["test3"] = "funtest"
        facts.delete("test1")
        host = nil
        assert_nothing_raised {
            host = Puppet::Rails::Host.store(
                :resources => resources,
                :facts => facts,
                :name => facts["hostname"],
                :classes => ["one", "two::three", "four"]
            )
        }

        # Make sure it sets the last_compile time
        assert_nothing_raised do
            assert_instance_of(Time, host.last_compile, "did not set last_compile")
        end

        assert_nil(host.fact('test1'), "removed fact was not deleted")
        facts.each do |fact, value|
            assert_equal(value, host.fact(fact), "fact %s is wrong" % fact)
        end

        # And check the changes we made.
        assert(! host.resources.find(:all).detect { |r| r.title =~ /file3/ },
            "Removed resources are still present")

        res = host.resources.find_by_title("/tmp/file_added")
        assert(res, "New resource was not added")
        assert_equal("user_added", res.parameter("owner"), "user info was not stored")

        # This actually works in real life, but I can't get it to work in testing.
        # I expect it's a caching problem.
        count = 0
        host.resources.find(:all).find_all { |r| r.title =~ /file2/ }.each do |r|
            r.save
            puts "%s => %s" % [r.ref, r.parameters.inspect]
            assert_equal("notice", r.parameter("loglevel"),
                "loglevel was not added")
            case r.restype
            when "file":
                assert_equal("fake", r.parameter("owner"), "owner was not modified")
            when "exec":
                assert_equal("fake", r.parameter("user"), "user was not modified")
            else
                raise "invalid resource type %s" % r.restype
            end
        end
    end
    else
        $stderr.puts "Install Rails for Rails and Caching tests"
    end
end

# $Id: host.rb 2296 2007-03-18 22:48:57Z luke $


syntax highlighted by Code2HTML, v. 0.9.1