summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/mcx_dock_absent.pp4
-rw-r--r--examples/mcx_dock_default.pp118
-rw-r--r--examples/mcx_dock_full.pp125
-rw-r--r--examples/mcx_dock_invalid.pp9
-rw-r--r--examples/mcx_nogroup.pp118
-rw-r--r--examples/mcx_notexists_absent.pp4
-rw-r--r--lib/puppet/provider/mcx/mcxcontent.rb199
-rw-r--r--lib/puppet/type/mcx.rb114
-rwxr-xr-xspec/unit/provider/mcx/mcxcontent.rb68
-rwxr-xr-xspec/unit/type/mcx.rb62
10 files changed, 821 insertions, 0 deletions
diff --git a/examples/mcx_dock_absent.pp b/examples/mcx_dock_absent.pp
new file mode 100644
index 000000000..ef51897e0
--- /dev/null
+++ b/examples/mcx_dock_absent.pp
@@ -0,0 +1,4 @@
+mcx { '/Groups/mcx_dock':
+ ensure => 'absent',
+ content => 'absent'
+}
diff --git a/examples/mcx_dock_default.pp b/examples/mcx_dock_default.pp
new file mode 100644
index 000000000..1f65a7316
--- /dev/null
+++ b/examples/mcx_dock_default.pp
@@ -0,0 +1,118 @@
+mcx { '/Groups/mcx_dock':
+ ensure => 'present',
+ content => '<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.dock</key>
+ <dict>
+ <key>AppItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>AppItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-apps</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Mail.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Mail</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Safari.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Safari</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ </array>
+ </dict>
+ <key>DocItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>DocItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-others</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>MCXDockSpecialFolders-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>MCXDockSpecialFolders-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>MCXDockSpecialFolders</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>contents-immutable</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ <key>static-only</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ </dict>
+</dict>
+</plist>
+'
+}
diff --git a/examples/mcx_dock_full.pp b/examples/mcx_dock_full.pp
new file mode 100644
index 000000000..60760332a
--- /dev/null
+++ b/examples/mcx_dock_full.pp
@@ -0,0 +1,125 @@
+# Mac MCX Test
+
+computer { "localhost": }
+
+mcx {
+ "mcx_dock":
+ ensure => "present",
+ ds_type => "group",
+ ds_name => "mcx_dock",
+ content => '<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.dock</key>
+ <dict>
+ <key>AppItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>AppItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-apps</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Mail.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Mail</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Safari.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Safari</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ </array>
+ </dict>
+ <key>DocItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>DocItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-others</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>MCXDockSpecialFolders-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>MCXDockSpecialFolders-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>MCXDockSpecialFolders</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>contents-immutable</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ <key>static-only</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ </dict>
+</dict>
+</plist>
+'
+}
diff --git a/examples/mcx_dock_invalid.pp b/examples/mcx_dock_invalid.pp
new file mode 100644
index 000000000..35f908177
--- /dev/null
+++ b/examples/mcx_dock_invalid.pp
@@ -0,0 +1,9 @@
+# Mac MCX Test
+
+computer { "localhost": }
+
+mcx {
+ "/Groups/mcx_dock":
+ ensure => "present",
+ content => 'invalid plist'
+}
diff --git a/examples/mcx_nogroup.pp b/examples/mcx_nogroup.pp
new file mode 100644
index 000000000..ea689f33c
--- /dev/null
+++ b/examples/mcx_nogroup.pp
@@ -0,0 +1,118 @@
+mcx { '/Groups/doesnotexist':
+ ensure => 'present',
+ content => '<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.dock</key>
+ <dict>
+ <key>AppItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>AppItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-apps</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Mail.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Mail</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ <dict>
+ <key>mcx_typehint</key>
+ <integer>1</integer>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>/Applications/Safari.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ <key>file-label</key>
+ <string>Safari</string>
+ </dict>
+ <key>tile-type</key>
+ <string>file-tile</string>
+ </dict>
+ </array>
+ </dict>
+ <key>DocItems-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>DocItems-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>static-others</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>MCXDockSpecialFolders-Raw</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>upk</key>
+ <dict>
+ <key>mcx_input_key_names</key>
+ <array>
+ <string>MCXDockSpecialFolders-Raw</string>
+ </array>
+ <key>mcx_output_key_name</key>
+ <string>MCXDockSpecialFolders</string>
+ <key>mcx_remove_duplicates</key>
+ <true/>
+ </dict>
+ <key>value</key>
+ <array/>
+ </dict>
+ <key>contents-immutable</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ <key>static-only</key>
+ <dict>
+ <key>state</key>
+ <string>always</string>
+ <key>value</key>
+ <false/>
+ </dict>
+ </dict>
+</dict>
+</plist>
+'
+}
diff --git a/examples/mcx_notexists_absent.pp b/examples/mcx_notexists_absent.pp
new file mode 100644
index 000000000..ef44db10e
--- /dev/null
+++ b/examples/mcx_notexists_absent.pp
@@ -0,0 +1,4 @@
+mcx { '/Groups/foobar':
+ ensure => 'absent',
+ content => 'absent'
+}
diff --git a/lib/puppet/provider/mcx/mcxcontent.rb b/lib/puppet/provider/mcx/mcxcontent.rb
new file mode 100644
index 000000000..fdcc8cc5d
--- /dev/null
+++ b/lib/puppet/provider/mcx/mcxcontent.rb
@@ -0,0 +1,199 @@
+#--
+# Copyright (C) 2008 Jeffrey J McCune.
+
+# This program and entire repository is free software; you can
+# redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Author: Jeff McCune <mccune.jeff@gmail.com>
+
+require 'tempfile'
+
+Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do
+
+ desc "MCX Settings management using DirectoryService on OS X.
+
+This provider manages the entire MCXSettings attribute available
+to some directory services nodes. This management is 'all or nothing'
+in that discrete application domain key value pairs are not managed
+by this provider.
+
+It is recommended to use WorkGroup Manager to configure Users, Groups,
+Computers, or ComputerLists, then use 'ralsh mcx' to generate a puppet
+manifest from the resulting configuration.
+
+Original Author: Jeff McCune (mccune.jeff@gmail.com)"
+
+ # This provides a mapping of puppet types to DirectoryService
+ # type strings.
+ TypeMap = {
+ :user => "Users",
+ :group => "Groups",
+ :computer => "Computers",
+ :computergroup => "ComputerGroups",
+ }
+
+ class MCXContentProviderException < Exception
+
+ end
+
+ commands :dscl => "/usr/bin/dscl"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+
+ # self.instances is all important.
+ # This is the only class method, it returns
+ # an array of instances of this class.
+ def self.instances
+ mcx_list = []
+ for ds_type in TypeMap.keys
+ ds_path = "/Local/Default/#{TypeMap[ds_type]}"
+ output = dscl 'localhost', '-list', ds_path
+ member_list = output.split
+ for ds_name in member_list
+ content = mcxexport(ds_type, ds_name)
+ if content.empty?
+ Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data."
+ else
+ # This node has MCX data.
+ rsrc = self.new(:name => "/#{TypeMap[ds_type]}/#{ds_name}",
+ :ds_type => ds_type,
+ :ds_name => ds_name,
+ :content => content)
+ mcx_list << rsrc
+ end
+ end
+ end
+ return mcx_list
+ end
+
+ private
+
+ # mcxexport is used by instances, and therefore
+ # a class method.
+ def self.mcxexport(ds_type, ds_name)
+ ds_t = TypeMap[ds_type]
+ ds_n = ds_name.to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+
+ dscl 'localhost', '-mcxexport', ds_path
+ end
+
+ def mcximport(ds_type, ds_name, val)
+ ds_t = TypeMap[ds_type]
+ ds_n = ds_name.to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_name}"
+
+ tmp = Tempfile.new('puppet_mcx')
+ begin
+ tmp << val
+ tmp.flush
+ dscl 'localhost', '-mcximport', ds_path, tmp.path
+ ensure
+ tmp.close
+ tmp.unlink
+ end
+ end
+
+ # Given the resource name string, parse ds_type out.
+ def parse_type(name)
+ tmp = name.split('/')[1]
+ if ! tmp.is_a? String
+ raise MCXContentProviderException,
+ "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
+ end
+ # De-pluralize and downcase.
+ tmp = tmp.chop.downcase.to_sym
+ if not TypeMap.keys.member? tmp
+ raise MCXContentProviderException,
+ "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
+ end
+ return tmp
+ end
+
+ # Given the resource name string, parse ds_name out.
+ def parse_name(name)
+ ds_name = name.split('/')[2]
+ if ! ds_name.is_a? String
+ raise MCXContentProviderException,
+ "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter."
+ end
+ return ds_name
+ end
+
+ # Gather ds_type and ds_name from resource or
+ # parse it out of the name.
+ # This is a private instance method, not a class method.
+ def get_dsparams
+ ds_type = resource[:ds_type]
+ if ds_type.nil?
+ ds_type = parse_type(resource[:name])
+ end
+
+ ds_name = resource[:ds_name]
+ if ds_name.nil?
+ ds_name = parse_name(resource[:name])
+ end
+
+ rval = {
+ :ds_type => ds_type.to_sym,
+ :ds_name => ds_name,
+ }
+
+ return rval
+
+ end
+
+ public
+
+ def create
+ self.content=(resource[:content])
+ end
+
+ def destroy
+ ds_parms = get_dsparams
+ ds_t = TypeMap[ds_parms[:ds_type]]
+ ds_n = ds_parms[:ds_name].to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+
+ dscl 'localhost', '-mcxdelete', ds_path
+ end
+
+ def exists?
+ # JJM Just re-use the content method and see if it's empty.
+ begin
+ mcx = content
+ rescue Puppet::ExecutionFailure => e
+ return false
+ end
+ has_mcx = ! mcx.empty?
+ return has_mcx
+ end
+
+ def content
+ ds_parms = get_dsparams
+ mcx = self.class.mcxexport(ds_parms[:ds_type],
+ ds_parms[:ds_name])
+ return mcx
+ end
+
+ def content=(value)
+ # dscl localhost -mcximport
+ ds_parms = get_dsparams
+ mcx = mcximport(ds_parms[:ds_type],
+ ds_parms[:ds_name],
+ resource[:content])
+ return mcx
+ end
+
+end
diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb
new file mode 100644
index 000000000..ec33afd13
--- /dev/null
+++ b/lib/puppet/type/mcx.rb
@@ -0,0 +1,114 @@
+#--
+# Copyright (C) 2008 Jeffrey J McCune.
+
+# This program and entire repository is free software; you can
+# redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Author: Jeff McCune <mccune.jeff@gmail.com>
+
+Puppet::Type.newtype(:mcx) do
+
+ @doc = "MCX object management using DirectoryService on OS X.
+
+Original Author: Jeff McCune <mccune.jeff@gmail.com>
+
+The default provider of this type merely manages the XML plist as
+reported by the dscl -mcxexport command. This is similar to the
+content property of the file type in Puppet.
+
+The recommended method of using this type is to use Work Group Manager
+to manage users and groups on the local computer, record the resulting
+puppet manifest using the command 'ralsh mcx' then deploying this
+to other machines.
+"
+ feature :manages_content, \
+ "The provider can manage MCXSettings as a string.",
+ :methods => [:content, :content=]
+
+ ensurable do
+ desc "Create or remove the MCX setting."
+
+ newvalue(:present) do
+ provider.create
+ end
+
+ newvalue(:absent) do
+ provider.destroy
+ end
+
+ end
+
+ newparam(:name) do
+ desc "The name of the resource being managed.
+ The default naming convention follows Directory Service paths:
+ '/Computers/localhost'
+ '/Groups/admin'
+ '/Users/localadmin'
+
+ The ds_type and ds_name type parameters are not necessary if the
+ default naming convention is followed."
+ isnamevar
+ end
+
+ newparam(:ds_type) do
+
+ desc "The DirectoryService type this MCX setting attaches to."
+
+ newvalues(:user, :group, :computer, :computerlist)
+
+ end
+
+ newparam(:ds_name) do
+ desc "The name to attach the MCX Setting to.
+ e.g. 'localhost' when ds_type => computer. This setting is not
+ required, as it may be parsed so long as the resource name is
+ parseable. e.g. /Groups/admin where 'group' is the dstype."
+ end
+
+ newproperty(:content, :required_features => :manages_content) do
+ desc "The XML Plist. The value of MCXSettings in DirectoryService.
+ This is the standard output from the system command:
+ dscl localhost -mcxexport /Local/Default/<ds_type>/<ds_name>
+ Note that ds_type is capitalized and plural in the dscl command."
+ end
+
+ # JJM Yes, this is not DRY at all. Because of the code blocks
+ # autorequire must be done this way. I think.
+
+ def setup_autorequire(type)
+ # value returns a Symbol
+ name = value(:name)
+ ds_type = value(:ds_type)
+ ds_name = value(:ds_name)
+ if ds_type == type
+ rval = [ ds_name.to_s ]
+ else
+ rval = [ ]
+ end
+ rval
+ end
+
+ autorequire(:user) do
+ setup_autorequire(:user)
+ end
+
+ autorequire(:group) do
+ setup_autorequire(:group)
+ end
+
+ autorequire(:computer) do
+ setup_autorequire(:computer)
+ end
+
+end
diff --git a/spec/unit/provider/mcx/mcxcontent.rb b/spec/unit/provider/mcx/mcxcontent.rb
new file mode 100755
index 000000000..6cb3fc78e
--- /dev/null
+++ b/spec/unit/provider/mcx/mcxcontent.rb
@@ -0,0 +1,68 @@
+#! /usr/bin/env ruby
+#--
+# Copyright (C) 2008 Jeffrey J McCune.
+
+# This program and entire repository is free software; you can
+# redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Author: Jeff McCune <mccune.jeff@gmail.com>
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:mcx).provider(:mcxcontent)
+
+describe provider_class do
+
+ before :each do
+ # Create a mock resource
+ @resource = stub 'resource'
+
+ @provider = provider_class.new
+ @attached_to = "/Users/katie"
+
+ # A catch all; no parameters set
+ @resource.stubs(:[]).returns(nil)
+
+ # But set name, ensure and enable
+ @resource.stubs(:[]).with(:name).returns @attached_to
+ @resource.stubs(:[]).with(:enable).returns :true
+ @resource.stubs(:ref).returns "Mcx[#{@attached_to}]"
+
+ # stub out the provider methods that actually touch the filesystem
+ # or execute commands
+ @provider.stubs(:execute).returns("")
+ @provider.stubs(:resource).returns @resource
+ end
+
+ it "should have a create method." do
+ @provider.should respond_to(:create)
+ end
+
+ it "should have a destroy method." do
+ @provider.should respond_to(:destroy)
+ end
+
+ it "should have an exists? method." do
+ @provider.should respond_to(:exists?)
+ end
+
+ it "should have an content method." do
+ @provider.should respond_to(:content)
+ end
+
+ it "should have an content= method." do
+ @provider.should respond_to(:content=)
+ end
+
+end
diff --git a/spec/unit/type/mcx.rb b/spec/unit/type/mcx.rb
new file mode 100755
index 000000000..fb67f07d9
--- /dev/null
+++ b/spec/unit/type/mcx.rb
@@ -0,0 +1,62 @@
+#!/usr/bin/env ruby
+#--
+# Copyright (C) 2008 Jeffrey J McCune.
+
+# This program and entire repository is free software; you can
+# redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Author: Jeff McCune <mccune.jeff@gmail.com>
+
+# Most of this code copied from /spec/type/service.rb
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require "puppet/type/mcx"
+
+describe Puppet::Type.type(:mcx), "when validating attributes" do
+
+ [:name, :ds_type, :ds_name].each do |param|
+ it "should have a #{param} parameter" do
+ Puppet::Type.type(:mcx).attrtype(param).should == :param
+ end
+ end
+
+ [:ensure, :content].each do |param|
+ it "should have a #{param} property" do
+ Puppet::Type.type(:mcx).attrtype(param).should == :property
+ end
+ end
+
+end
+
+describe Puppet::Type.type(:mcx), "when validating attribute values" do
+
+ before do
+ @provider = stub 'provider', :class => Puppet::Type.type(:mcx).defaultprovider, :clear => nil, :controllable? => false
+ Puppet::Type.type(:mcx).defaultprovider.stubs(:new).returns(@provider)
+ end
+
+ after do
+ Puppet::Type.type(:mcx).clear
+ end
+
+ it "should support :present as a value to :ensure" do
+ Puppet::Type.type(:mcx).create(:name => "/Foo/bar", :ensure => :present)
+ end
+
+ it "should support :absent as a value to :ensure" do
+ Puppet::Type.type(:mcx).create(:name => "/Foo/bar", :ensure => :absent)
+ end
+
+end