diff options
-rw-r--r-- | lib/puppet/resource.rb | 72 | ||||
-rwxr-xr-x | spec/unit/resource.rb | 152 |
2 files changed, 221 insertions, 3 deletions
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index b4458e638..862aadf99 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -1,15 +1,84 @@ require 'puppet' require 'puppet/util/tagging' require 'puppet/resource/reference' +require 'puppet/util/json' # The simplest resource class. Eventually it will function as the # base class for all resource-like behaviour. class Puppet::Resource include Puppet::Util::Tagging + extend Puppet::Util::Json include Enumerable attr_accessor :file, :line, :catalog, :exported attr_writer :type, :title + ATTRIBUTES = [:file, :line, :exported] + + def self.from_json(json) + raise ArgumentError, "No resource type provided in json data" unless type = json['type'] + raise ArgumentError, "No resource title provided in json data" unless title = json['title'] + + resource = new(type, title) + + if params = json['parameters'] + params.each { |param, value| resource[param] = value } + end + + if tags = json['tags'] + tags.each { |tag| resource.tag(tag) } + end + + ATTRIBUTES.each do |a| + if value = json[a.to_s] + resource.send(a.to_s + "=", value) + end + end + + resource.exported ||= false + + resource + end + + def to_json(*args) + raise "Cannot convert to JSON unless the 'json' library is installed" unless Puppet.features.json? + + data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param| + next hash unless value = self.send(param) + hash[param.to_s] = value + hash + end + + data["exported"] ||= false + + params = self.to_hash.inject({}) do |hash, ary| + param, value = ary + + # Don't duplicate the title as the namevar + next hash if param == namevar and value == title + value = [value] unless value.is_a?(Array) + hash[param] = value + hash + end + + unless params.empty? + data["parameters"] = params + end + + res = { + 'json_class' => self.class.name, + 'data' => data + } + #data.each do |key, value| + # puts "Converting %s (%s)" % [key, value.inspect] + # p value + # value.to_json(*args) + # key.to_json(*args) + #end + #puts "Converted all" + #p res + res.to_json(*args) + end + # Proxy these methods to the parameters hash. It's likely they'll # be overridden at some point, but this works for now. %w{has_key? keys length delete empty? <<}.each do |method| @@ -83,9 +152,6 @@ class Puppet::Resource unless result.include?(namevar) result[namevar] = title end - if result.has_key?(nil) - raise "wtf? %s" % namevar.inspect - end result end diff --git a/spec/unit/resource.rb b/spec/unit/resource.rb index 5d838b233..c993f8d98 100755 --- a/spec/unit/resource.rb +++ b/spec/unit/resource.rb @@ -353,4 +353,156 @@ describe Puppet::Resource do end end end + + describe "when converting to json" do + confine "Missing 'json' library" => Puppet.features.json? + + def json_output_should + @resource.class.expects(:json_create).with { |hash| yield hash } + end + + it "should include the json util module" do + Puppet::Resource.metaclass.ancestors.should be_include(Puppet::Util::Json) + end + + # LAK:NOTE For all of these tests, we convert back to the resource so we can + # trap the actual data structure then. + it "should set its json_class to 'Puppet::Resource'" do + JSON.parse(Puppet::Resource.new("file", "yay").to_json).should be_instance_of(Puppet::Resource) + end + + it "should set its type to the provided type" do + JSON.parse(Puppet::Resource.new("File", "/foo").to_json).type.should == "File" + end + + it "should set its title to the provided title" do + JSON.parse(Puppet::Resource.new("File", "/foo").to_json).title.should == "/foo" + end + + it "should include all tags from the resource" do + resource = Puppet::Resource.new("File", "/foo") + resource.tag("yay") + + JSON.parse(resource.to_json).tags.should == resource.tags + end + + it "should include the file if one is set" do + resource = Puppet::Resource.new("File", "/foo") + resource.file = "/my/file" + + JSON.parse(resource.to_json).file.should == "/my/file" + end + + it "should include the line if one is set" do + resource = Puppet::Resource.new("File", "/foo") + resource.line = 50 + + JSON.parse(resource.to_json).line.should == 50 + end + + it "should include the 'exported' value if one is set" do + resource = Puppet::Resource.new("File", "/foo") + resource.exported = true + + JSON.parse(resource.to_json).exported.should be_true + end + + it "should set 'exported' to false if no value is set" do + resource = Puppet::Resource.new("File", "/foo") + + JSON.parse(resource.to_json).exported.should be_false + end + + it "should set all of its parameters as the 'parameters' entry" do + resource = Puppet::Resource.new("File", "/foo") + resource[:foo] = %w{bar eh} + resource[:fee] = %w{baz} + + result = JSON.parse(resource.to_json) + result["foo"].should == %w{bar eh} + result["fee"].should == %w{baz} + end + + it "should set all parameter values as arrays" do + resource = Puppet::Resource.new("File", "/foo") + resource[:foo] = "bar" + JSON.parse(resource.to_json)["foo"].should == %w{bar} + end + end + + describe "when converting from json" do + confine "Missing 'json' library" => Puppet.features.json? + + def json_result_should + Puppet::Resource.expects(:new).with { |hash| yield hash } + end + + before do + @data = { + 'type' => "file", + 'title' => "yay", + } + end + + it "should set its type to the provided type" do + Puppet::Resource.from_json(@data).type.should == "File" + end + + it "should set its title to the provided title" do + Puppet::Resource.from_json(@data).title.should == "yay" + end + + it "should set its title to the provided title" do + Puppet::Resource.from_json(@data).title.should == "yay" + end + + it "should tag the resource with any provided tags" do + @data['tags'] = %w{foo bar} + resource = Puppet::Resource.from_json(@data) + resource.tags.should be_include("foo") + resource.tags.should be_include("bar") + end + + it "should set its file to the provided file" do + @data['file'] = "/foo/bar" + Puppet::Resource.from_json(@data).file.should == "/foo/bar" + end + + it "should set its line to the provided line" do + @data['line'] = 50 + Puppet::Resource.from_json(@data).line.should == 50 + end + + it "should 'exported' to true if set in the json data" do + @data['exported'] = true + Puppet::Resource.from_json(@data).exported.should be_true + end + + it "should 'exported' to false if not set in the json data" do + Puppet::Resource.from_json(@data).exported.should be_false + end + + it "should fail if no title is provided" do + @data.delete('title') + lambda { Puppet::Resource.from_json(@data) }.should raise_error(ArgumentError) + end + + it "should fail if no type is provided" do + @data.delete('type') + lambda { Puppet::Resource.from_json(@data) }.should raise_error(ArgumentError) + end + + it "should set each of the provided parameters" do + @data['parameters'] = {'foo' => %w{one two}, 'fee' => %w{three four}} + resource = Puppet::Resource.from_json(@data) + resource['foo'].should == %w{one two} + resource['fee'].should == %w{three four} + end + + it "should convert single-value array parameters to normal values" do + @data['parameters'] = {'foo' => %w{one}} + resource = Puppet::Resource.from_json(@data) + resource['foo'].should == %w{one} + end + end end |